Skip to content

Commit

Permalink
Integrate minidump generate to udmp_parser module + PYI definitions (
Browse files Browse the repository at this point in the history
…#15)

- Split `udmp_parser.utils` into a separate file, add a `generate_minidump` function. A variant of this function is added to the `pyproject.toml::project.scripts` to generate a `.exe` when `pip install`-ing it
- Add type hints (`.pyi` file) for the python bindings (fix #12)
- Fix one missing class (`MemoryInfoListStream_t` -> `MemoryInfoListStream`) which wasn't exposed before

Co-authored-by: 0vercl0k <[email protected]>
  • Loading branch information
hugsy and 0vercl0k authored Aug 27, 2023
1 parent a8d1490 commit f7bf64a
Show file tree
Hide file tree
Showing 10 changed files with 648 additions and 197 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# udmp-parser: A Cross-Platform C++ parser library for Windows user minidumps

![Build status](https://github.com/0vercl0k/udmp-parser/workflows/Builds/badge.svg)
[![Downloads](https://static.pepy.tech/badge/udmp-parser/month)](https://pepy.tech/project/udmp-parser)

This is a cross-platform (Windows / Linux / OSX / x86 / x64) C++ library that parses Windows user [minidump](https://docs.microsoft.com/en-us/windows/win32/debug/minidump-files) dumps (`.dump /m` and **not** `.dump /f` in WinDbg usermode).

Expand Down
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
VERSION 0.5.0
)

set(PROJECT_AUTHOR 0vercl0k)
Expand Down
6 changes: 3 additions & 3 deletions src/lib/udmp-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ namespace fs = std::filesystem;
namespace udmpparser {

#ifdef NDEBUG
void DbgPrintf(const char *Format, ...) { (void)Format; }
static void DbgPrintf(const char *Format, ...) { (void)Format; }
#else
void DbgPrintf(const char *Format, ...) {
static void DbgPrintf(const char *Format, ...) {
va_list ArgList;
va_start(ArgList, Format);
vfprintf(stderr, Format, ArgList);
Expand Down Expand Up @@ -226,7 +226,7 @@ struct Context64_t {
uint128_t Xmm13;
uint128_t Xmm14;
uint128_t Xmm15;
uint8_t Padding[0x60];
std::array<uint8_t, 0x60> Padding;
std::array<uint128_t, 26> VectorRegister;
uint64_t VectorControl;
uint64_t DebugControl;
Expand Down
9 changes: 8 additions & 1 deletion src/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@ list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")

find_package(nanobind CONFIG REQUIRED)

nanobind_add_module(udmp_parser NB_STATIC src/udmp_parser.cc)
set(CMAKE_CXX_STANDARD 20)

nanobind_add_module(udmp_parser NB_STATIC src/udmp_parser_utils.cc src/udmp_parser.cc)

if(MSVC)
target_link_libraries(udmp_parser PRIVATE DbgHelp.lib)
endif(MSVC)

if(BUILD_PYTHON_PACKAGE)
#
# Those directives are only used when creating a standalone `udmp_parser` python package
#
target_include_directories(udmp_parser PRIVATE ../lib)
install(TARGETS udmp_parser LIBRARY DESTINATION .)
install(DIRECTORY udmp_parser-stubs DESTINATION .)
else()
#
# This is the general case, when built from the root cmakefile
Expand Down
9 changes: 5 additions & 4 deletions src/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"

[project]
name = "udmp-parser"
version = "0.4.3"
version = "0.5.0"
description = "A Cross-Platform C++ parser library for Windows user minidumps."
readme = "README.md"
requires-python = ">=3.8"
Expand All @@ -21,6 +21,9 @@ dependencies = []
[project.urls]
Homepage = "https://github.com/0vercl0k/udmp-parser"

[project.scripts]
generate_minidump = "udmp_parser.utils:generate_minidump_from_command_line"

[tool.isort]
profile = "black"

Expand All @@ -29,9 +32,7 @@ wheel.py-api = "cp312"
minimum-version = "0.4"
build-dir = "build/{wheel_tag}"
cmake.minimum-version = "3.20"
cmake.args = [
"-DBUILD_PYTHON_PACKAGE:BOOL=ON",
]
cmake.args = ["-DBUILD_PYTHON_PACKAGE:BOOL=ON"]

[tool.cibuildwheel]
build-verbosity = 1
Expand Down
104 changes: 15 additions & 89 deletions src/python/src/udmp_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Released under MIT License, by 0vercl0k - 2023
//
// With contribution from:
// * hugsy - (github.com / hugsy)
// * hugsy - (github.com/hugsy)
//

#include "udmp-parser.h"
Expand All @@ -23,7 +23,12 @@

namespace nb = nanobind;

void udmp_parser_utils_module(nb::module_ &m);

NB_MODULE(udmp_parser, m) {

udmp_parser_utils_module(m);

nb::enum_<udmpparser::ProcessorArch_t>(m, "ProcessorArch")
.value("X86", udmpparser::ProcessorArch_t::X86)
.value("ARM", udmpparser::ProcessorArch_t::ARM)
Expand Down Expand Up @@ -193,6 +198,14 @@ NB_MODULE(udmp_parser, m) {
.def_ro("StreamType", &udmpparser::dmp::Directory_t::StreamType)
.def_ro("Location", &udmpparser::dmp::Directory_t::Location);

nb::class_<udmpparser::dmp::MemoryInfoListStream_t>(m, "MemoryInfoListStream")
.def_ro("SizeOfHeader",
&udmpparser::dmp::MemoryInfoListStream_t::SizeOfHeader)
.def_ro("SizeOfEntry",
&udmpparser::dmp::MemoryInfoListStream_t::SizeOfEntry)
.def_ro("NumberOfEntries",
&udmpparser::dmp::MemoryInfoListStream_t::NumberOfEntries);

nb::class_<udmpparser::dmp::Memory64ListStreamHdr_t>(m,
"Memory64ListStreamHdr")
.def_ro("NumberOfMemoryRanges",
Expand Down Expand Up @@ -315,7 +328,7 @@ NB_MODULE(udmp_parser, m) {
.def("__repr__", &udmpparser::MemBlock_t::to_string);
;

nb::class_<udmpparser::Module_t>(m, "Modules")
nb::class_<udmpparser::Module_t>(m, "Module")
.def(nb::init<const udmpparser::dmp::ModuleEntry_t &, const std::string &,
const void *, const void *>(),
nb::rv_policy::take_ownership)
Expand Down Expand Up @@ -374,91 +387,4 @@ NB_MODULE(udmp_parser, m) {
.def_ro_static("major", &udmpparser::Version::Major)
.def_ro_static("minor", &udmpparser::Version::Minor)
.def_ro_static("release", &udmpparser::Version::Release);

auto utils = m.def_submodule("utils", "Helper functions");
utils.def(
"TypeToString",
[](const uint32_t Type) -> std::string {
switch (Type) {
case 0x2'00'00: {
return "MEM_PRIVATE";
}
case 0x4'00'00: {
return "MEM_MAPPED";
}
case 0x1'00'00'00: {
return "MEM_IMAGE";
}
}
return "";
},
"Get a string representation of the memory type");

utils.def(
"StateToString",
[](const uint32_t State) {
switch (State) {
case 0x10'00: {
return "MEM_COMMIT";
}

case 0x20'00: {
return "MEM_RESERVE";
}

case 0x1'00'00: {
return "MEM_FREE";
}
}
return "";
},
"Get a string representation of the memory state");

utils.def(
"ProtectionToString",
[](const uint32_t Protection) {
struct {
const char *Name = nullptr;
uint32_t Mask = 0;
} Flags[] = {
{"PAGE_NOACCESS", 0x01},
{"PAGE_READONLY", 0x02},
{"PAGE_READWRITE", 0x04},
{"PAGE_WRITECOPY", 0x08},
{"PAGE_EXECUTE", 0x10},
{"PAGE_EXECUTE_READ", 0x20},
{"PAGE_EXECUTE_READWRITE", 0x40},
{"PAGE_EXECUTE_WRITECOPY", 0x80},
{"PAGE_GUARD", 0x100},
{"PAGE_NOCACHE", 0x200},
{"PAGE_WRITECOMBINE", 0x400},
{"PAGE_TARGETS_INVALID", 0x4000'0000},
};
std::stringstream ss;
uint32_t KnownFlags = 0;

for (const auto &Flag : Flags) {
if ((Protection & Flag.Mask) == 0) {
continue;
}

ss << Flag.Name << ",";
KnownFlags |= Flag.Mask;
}

const uint32_t MissingFlags = (~KnownFlags) & Protection;
if (MissingFlags) {
ss << std::hex << "0x" << MissingFlags;
}

std::string ProtectionString = ss.str();
if (ProtectionString.size() > 1 &&
ProtectionString[ProtectionString.size() - 1] == ',') {
ProtectionString =
ProtectionString.substr(0, ProtectionString.size() - 1);
}

return ProtectionString;
},
"Get a string representation of the memory protection");
}
Loading

0 comments on commit f7bf64a

Please sign in to comment.