From e7db5cb829ac3393df8765381fcf8179f16bbe57 Mon Sep 17 00:00:00 2001 From: 0vercl0k <1476421+0vercl0k@users.noreply.github.com> Date: Tue, 22 Aug 2023 17:07:32 -0700 Subject: [PATCH] cleanups, black --- src/CMakeLists.txt | 2 +- src/python/pyproject.toml | 2 +- src/python/src/udmp_parser_utils.cc | 110 +++++++++------------- src/python/udmp_parser-stubs/__init__.pyi | 37 ++++++++ src/python/udmp_parser-stubs/utils.pyi | 13 ++- 5 files changed, 90 insertions(+), 74 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 79158b3..cbf3f80 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,7 @@ project( udmp-parser DESCRIPTION "A Cross-Platform C++ parser library for Windows user minidumps." HOMEPAGE_URL https://github.com/0vercl0k/udmp-parser - VERSION 0.4.4 + VERSION 0.5.0 ) set(PROJECT_AUTHOR 0vercl0k) diff --git a/src/python/pyproject.toml b/src/python/pyproject.toml index 4b185df..2f7a236 100644 --- a/src/python/pyproject.toml +++ b/src/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build" [project] name = "udmp-parser" -version = "0.4.4" +version = "0.5.0" description = "A Cross-Platform C++ parser library for Windows user minidumps." readme = "README.md" requires-python = ">=3.8" diff --git a/src/python/src/udmp_parser_utils.cc b/src/python/src/udmp_parser_utils.cc index c255e98..27f2e43 100644 --- a/src/python/src/udmp_parser_utils.cc +++ b/src/python/src/udmp_parser_utils.cc @@ -9,69 +9,51 @@ #include "udmp-parser.h" +#include #include -#include - #include #include #include -#if defined(_WIN32) -#include -#include -#else -#include -#endif // _WIN32 - namespace nb = nanobind; -using namespace nb::literals; - -template -using GenericHandle = std::unique_ptr; -#if defined(_WIN32) -using UniqueHandle = GenericHandle; -#else -using UniqueHandle = GenericHandle; -#endif -#if defined(_WIN32) -static auto -GenerateMinidumpFromProcessId(uint32_t TargetPid, - std::filesystem::path &MiniDumpFilePath) -> int { - auto hFile = UniqueHandle{ - ::CreateFileW(MiniDumpFilePath.wstring().c_str(), GENERIC_WRITE, 0, - nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)}; - if (!hFile) { - return -1; +#ifdef _WIN32 +#include +#include + +bool GenerateMinidumpFromProcessId( + const uint32_t TargetPid, const std::filesystem::path &MiniDumpFilePath) { + const HANDLE File = + CreateFileA(MiniDumpFilePath.string().c_str(), GENERIC_WRITE, 0, nullptr, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (File == INVALID_HANDLE_VALUE) { + return false; } - auto hProcess = - UniqueHandle{::OpenProcess(PROCESS_ALL_ACCESS, false, TargetPid)}; - if (!hProcess) { - return -2; + const HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS, false, TargetPid); + if (Process == INVALID_HANDLE_VALUE) { + CloseHandle(File); + return false; } - MINIDUMP_EXCEPTION_INFORMATION exceptionInfo{}; - MINIDUMP_TYPE flags = static_cast( - MINIDUMP_TYPE::MiniDumpWithFullMemory | - MINIDUMP_TYPE::MiniDumpWithDataSegs | MINIDUMP_TYPE::MiniDumpScanMemory | - MINIDUMP_TYPE::MiniDumpWithHandleData | - MINIDUMP_TYPE::MiniDumpWithFullMemoryInfo); - - const auto bSuccess = - ::MiniDumpWriteDump(hProcess.get(), TargetPid, hFile.get(), flags, - &exceptionInfo, nullptr, nullptr); - return bSuccess ? 0 : -3; + MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo = {}; + const auto Flags = MINIDUMP_TYPE::MiniDumpWithFullMemory | + MINIDUMP_TYPE::MiniDumpWithDataSegs | + MINIDUMP_TYPE::MiniDumpScanMemory | + MINIDUMP_TYPE::MiniDumpWithHandleData | + MINIDUMP_TYPE::MiniDumpWithFullMemoryInfo; + + const auto Success = + MiniDumpWriteDump(Process, TargetPid, File, MINIDUMP_TYPE(Flags), + &ExceptionInfo, nullptr, nullptr); + + CloseHandle(Process); + CloseHandle(File); + return Success; } #endif void udmp_parser_utils_module(nb::module_ &m) { - auto utils = m.def_submodule("utils", "Helper functions"); utils.def( @@ -161,38 +143,30 @@ void udmp_parser_utils_module(nb::module_ &m) { "Get a string representation of the memory protection"); #if defined(_WIN32) - utils.def( - "generate_minidump", GenerateMinidumpFromProcessId, "TargetPid"_a, - "MiniDumpFilePath"_a, - "Generate a minidump for the target ProcessId, write it to the given " - "path. Returns 0 on success, non-zero on error."); -#endif // _WIN32 + utils.def("generate_minidump", GenerateMinidumpFromProcessId, "TargetPid", + "MiniDumpFilePath", + "Generate a minidump for TargetPid and save it to the given path. " + "Returns true on success."); utils.def( "generate_minidump_from_command_line", - []() -> int { -#if defined(_WIN32) + []() -> bool { nb::module_ sys = nb::module_::import_("sys"); nb::list argv = sys.attr("argv"); if (!argv.is_valid()) { - return 1; + return false; } if (argv.size() != 3) { - return 2; + return false; } auto a1 = nb::str(nb::handle(argv[1])); + const auto TargetPid = uint32_t(std::atol(a1.c_str())); auto a2 = nb::str(nb::handle(argv[2])); - - uint32_t TargetPid = static_cast(std::atol(a1.c_str())); - std::filesystem::path MinidumpPath{a2.c_str()}; - return GenerateMinidumpFromProcessId(TargetPid, MinidumpPath); -#else - ::puts("This command only works on Windows"); - return 0; -#endif // _WIN32 + return GenerateMinidumpFromProcessId(TargetPid, a2.c_str()); }, - "Generate a minidump for the target ProcessId, write it to the given " - "path. Returns 0 on success, non-zero on error."); + "Generate a minidump for the target TargetPid, write it to the given " + "path. Returns true on success."); +#endif // _WIN32 } diff --git a/src/python/udmp_parser-stubs/__init__.pyi b/src/python/udmp_parser-stubs/__init__.pyi index 703b7fd..a9a780a 100644 --- a/src/python/udmp_parser-stubs/__init__.pyi +++ b/src/python/udmp_parser-stubs/__init__.pyi @@ -3,6 +3,7 @@ from typing import Union, Optional, overload from enum import Enum, IntEnum import udmp_parser + class ProcessorArch(IntEnum): X86 = 0 ARM = 5 @@ -10,12 +11,15 @@ class ProcessorArch(IntEnum): AMD64 = 9 Unknown = 0xFFFF + class Arch(IntEnum): X86 = 0 X64 = 1 + kWOW64_SIZE_OF_80387_REGISTERS: int = 80 + class FloatingSaveArea32: ControlWord: int StatusWord: int @@ -27,6 +31,7 @@ class FloatingSaveArea32: RegisterArea: bytearray # size =kWOW64_SIZE_OF_80387_REGISTERS Cr0NpxState: int + class Context32: ContextFlags: int Dr0: int @@ -54,10 +59,12 @@ class Context32: SegSs: int ExtendedRegisters: bytearray # size =kWOW64_MAXIMUM_SUPPORTED_EXTENSION + class uint128_t: Low: int High: int + class Context64: P1Home: int P2Home: int @@ -136,16 +143,19 @@ class Context64: LastExceptionToRip: int LastExceptionFromRip: int + class Directory: StreamType: StreamType = StreamType.Unused LocationDescriptor32_t: int + class FileMap: def InBounds(self, arg0: int, arg1: int, /) -> bool: ... def MapFile(self, arg: str, /) -> bool: ... def ViewBase(self) -> int: ... def __init__(self) -> None: ... + class FixedFileInfo: Signature: int = 0 StrucVersion: int = 0 @@ -161,6 +171,7 @@ class FixedFileInfo: FileDateMS: int = 0 FileDateLS: int = 0 + class Header: Signature: int Version: int @@ -175,12 +186,14 @@ class Header: ValidFlagsMask: int def LooksGood(self) -> bool: ... + def __init__(*args, **kwargs): """ Initialize self. See help(type(self)) for accurate signature. """ ... + class LocationDescriptor32: DataSize: int Rva: int @@ -191,6 +204,7 @@ class LocationDescriptor32: """ ... + class LocationDescriptor64: DataSize: int Rva: int @@ -201,6 +215,7 @@ class LocationDescriptor64: """ ... + class MemBlock: BaseAddress: int AllocationBase: int @@ -215,10 +230,12 @@ class MemBlock: def __init__(self, arg: udmp_parser.MemoryInfo, /) -> None: ... def __str__(self) -> str: ... + class Memory64ListStreamHdr: StartOfMemoryRange: int DataSize: int + class MemoryDescriptor: ThreadId: int SuspendCount: int @@ -228,6 +245,7 @@ class MemoryDescriptor: Stack: MemoryDescriptor ThreadContext: LocationDescriptor32 + class ThreadEntry: ThreadId: int SuspendCount: int @@ -237,6 +255,7 @@ class ThreadEntry: Stack: MemoryDescriptor ThreadContext: LocationDescriptor32 + class Thread_t: ThreadId: int SuspendCount: int @@ -245,15 +264,18 @@ class Thread_t: Teb: int Context: Union[UnknownContext, Context32, Context64] + class MemoryDescriptor64: StartOfMemoryRange: int DataSize: int + class MemoryInfoListStream: SizeOfHeader: int SizeOfEntry: int NumberOfEntries: int + class MemoryInfo: BaseAddress: int AllocationBase: int @@ -265,6 +287,7 @@ class MemoryInfo: Type: int __alignment2: int + class Module: BaseAddress: int AllocationBase: int @@ -279,6 +302,7 @@ class Module: def Data(self) -> int: ... def __str__(self) -> str: ... + class StreamType(IntEnum): Unused = 0 ThreadList = 3 @@ -288,6 +312,7 @@ class StreamType(IntEnum): Memory64List = 9 MemoryInfoList = 16 + class SystemInfoStream: ProcessorArchitecture: ProcessorArch ProcessorLevel: int @@ -302,6 +327,7 @@ class SystemInfoStream: SuiteMask: int Reserved2: int + class ExceptionRecord: ExceptionCode: int ExceptionFlags: int @@ -311,12 +337,14 @@ class ExceptionRecord: __unusedAlignment: int ExceptionInformation: list[int] # size=kEXCEPTION_MAXIMUM_PARAMETERS + class ExceptionStream: ThreadId: int __alignment: int ExceptionRecord: ExceptionRecord ThreadContext: LocationDescriptor32 + class UnknownContext: def __init__(*args, **kwargs): """ @@ -324,36 +352,45 @@ class UnknownContext: """ ... + class UserDumpParser: def ForegroundThreadId(self) -> Optional[int]: ... + def GetMemoryBlock(self, arg: int, /) -> udmp_parser.MemBlock: """ Access a specific MemoryBlock """ ... + def Memory(self) -> dict[int, udmp_parser.MemBlock]: ... + def Modules(self) -> dict[int, udmp_parser.Modules]: """ Get the minidump modules """ ... + def Parse(self, arg: os.PathLike, /) -> bool: """ Parse the minidump given in argument. """ ... + def ReadMemory(self, arg0: int, arg1: int, /) -> Optional[list[int]]: """ Read bytes from memory """ ... + def Threads(self) -> dict[int, udmp_parser.Thread]: """ Get the minidump threads """ ... + def __init__(self) -> None: ... + class version: def __init__(*args, **kwargs): """ diff --git a/src/python/udmp_parser-stubs/utils.pyi b/src/python/udmp_parser-stubs/utils.pyi index d76bb3e..401fad4 100644 --- a/src/python/udmp_parser-stubs/utils.pyi +++ b/src/python/udmp_parser-stubs/utils.pyi @@ -1,31 +1,36 @@ import os + def ProtectionToString(arg: int, /) -> str: """ Get a string representation of the memory protection """ ... + def StateToString(arg: int, /) -> str: """ Get a string representation of the memory state """ ... + def TypeToString(arg: int, /) -> str: """ Get a string representation of the memory type """ ... -def generate_minidump(TargetPid: int, MiniDumpFilePath: os.PathLike) -> int: + +def generate_minidump(TargetPid: int, MiniDumpFilePath: os.PathLike) -> bool: """ - Generate a minidump for the target ProcessId, write it to the given path. Returns 0 on success, non-zero on error. + Generate a minidump for TargetPid and save it to the given path. Returns true on success. """ ... -def generate_minidump_from_command_line() -> int: + +def generate_minidump_from_command_line() -> bool: """ - Generate a minidump for the target ProcessId, write it to the given path. Returns 0 on success, non-zero on error. + Generate a minidump for the target TargetPid, write it to the given path. Returns true on success. """ ...