Skip to content

Commit f7bf64a

Browse files
hugsy0vercl0k
andauthored
Integrate minidump generate to udmp_parser module + PYI definitions (#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]>
1 parent a8d1490 commit f7bf64a

File tree

10 files changed

+648
-197
lines changed

10 files changed

+648
-197
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# udmp-parser: A Cross-Platform C++ parser library for Windows user minidumps
22

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

56
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).
67

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ project(
99
udmp-parser
1010
DESCRIPTION "A Cross-Platform C++ parser library for Windows user minidumps."
1111
HOMEPAGE_URL https://github.com/0vercl0k/udmp-parser
12-
VERSION 0.4
12+
VERSION 0.5.0
1313
)
1414

1515
set(PROJECT_AUTHOR 0vercl0k)

src/lib/udmp-parser.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ namespace fs = std::filesystem;
7575
namespace udmpparser {
7676

7777
#ifdef NDEBUG
78-
void DbgPrintf(const char *Format, ...) { (void)Format; }
78+
static void DbgPrintf(const char *Format, ...) { (void)Format; }
7979
#else
80-
void DbgPrintf(const char *Format, ...) {
80+
static void DbgPrintf(const char *Format, ...) {
8181
va_list ArgList;
8282
va_start(ArgList, Format);
8383
vfprintf(stderr, Format, ArgList);
@@ -226,7 +226,7 @@ struct Context64_t {
226226
uint128_t Xmm13;
227227
uint128_t Xmm14;
228228
uint128_t Xmm15;
229-
uint8_t Padding[0x60];
229+
std::array<uint8_t, 0x60> Padding;
230230
std::array<uint128_t, 26> VectorRegister;
231231
uint64_t VectorControl;
232232
uint64_t DebugControl;

src/python/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,21 @@ list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")
2424

2525
find_package(nanobind CONFIG REQUIRED)
2626

27-
nanobind_add_module(udmp_parser NB_STATIC src/udmp_parser.cc)
27+
set(CMAKE_CXX_STANDARD 20)
28+
29+
nanobind_add_module(udmp_parser NB_STATIC src/udmp_parser_utils.cc src/udmp_parser.cc)
30+
31+
if(MSVC)
32+
target_link_libraries(udmp_parser PRIVATE DbgHelp.lib)
33+
endif(MSVC)
2834

2935
if(BUILD_PYTHON_PACKAGE)
3036
#
3137
# Those directives are only used when creating a standalone `udmp_parser` python package
3238
#
3339
target_include_directories(udmp_parser PRIVATE ../lib)
3440
install(TARGETS udmp_parser LIBRARY DESTINATION .)
41+
install(DIRECTORY udmp_parser-stubs DESTINATION .)
3542
else()
3643
#
3744
# This is the general case, when built from the root cmakefile

src/python/pyproject.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
44

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

24+
[project.scripts]
25+
generate_minidump = "udmp_parser.utils:generate_minidump_from_command_line"
26+
2427
[tool.isort]
2528
profile = "black"
2629

@@ -29,9 +32,7 @@ wheel.py-api = "cp312"
2932
minimum-version = "0.4"
3033
build-dir = "build/{wheel_tag}"
3134
cmake.minimum-version = "3.20"
32-
cmake.args = [
33-
"-DBUILD_PYTHON_PACKAGE:BOOL=ON",
34-
]
35+
cmake.args = ["-DBUILD_PYTHON_PACKAGE:BOOL=ON"]
3536

3637
[tool.cibuildwheel]
3738
build-verbosity = 1

src/python/src/udmp_parser.cc

Lines changed: 15 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Released under MIT License, by 0vercl0k - 2023
55
//
66
// With contribution from:
7-
// * hugsy - (github.com / hugsy)
7+
// * hugsy - (github.com/hugsy)
88
//
99

1010
#include "udmp-parser.h"
@@ -23,7 +23,12 @@
2323

2424
namespace nb = nanobind;
2525

26+
void udmp_parser_utils_module(nb::module_ &m);
27+
2628
NB_MODULE(udmp_parser, m) {
29+
30+
udmp_parser_utils_module(m);
31+
2732
nb::enum_<udmpparser::ProcessorArch_t>(m, "ProcessorArch")
2833
.value("X86", udmpparser::ProcessorArch_t::X86)
2934
.value("ARM", udmpparser::ProcessorArch_t::ARM)
@@ -193,6 +198,14 @@ NB_MODULE(udmp_parser, m) {
193198
.def_ro("StreamType", &udmpparser::dmp::Directory_t::StreamType)
194199
.def_ro("Location", &udmpparser::dmp::Directory_t::Location);
195200

201+
nb::class_<udmpparser::dmp::MemoryInfoListStream_t>(m, "MemoryInfoListStream")
202+
.def_ro("SizeOfHeader",
203+
&udmpparser::dmp::MemoryInfoListStream_t::SizeOfHeader)
204+
.def_ro("SizeOfEntry",
205+
&udmpparser::dmp::MemoryInfoListStream_t::SizeOfEntry)
206+
.def_ro("NumberOfEntries",
207+
&udmpparser::dmp::MemoryInfoListStream_t::NumberOfEntries);
208+
196209
nb::class_<udmpparser::dmp::Memory64ListStreamHdr_t>(m,
197210
"Memory64ListStreamHdr")
198211
.def_ro("NumberOfMemoryRanges",
@@ -315,7 +328,7 @@ NB_MODULE(udmp_parser, m) {
315328
.def("__repr__", &udmpparser::MemBlock_t::to_string);
316329
;
317330

318-
nb::class_<udmpparser::Module_t>(m, "Modules")
331+
nb::class_<udmpparser::Module_t>(m, "Module")
319332
.def(nb::init<const udmpparser::dmp::ModuleEntry_t &, const std::string &,
320333
const void *, const void *>(),
321334
nb::rv_policy::take_ownership)
@@ -374,91 +387,4 @@ NB_MODULE(udmp_parser, m) {
374387
.def_ro_static("major", &udmpparser::Version::Major)
375388
.def_ro_static("minor", &udmpparser::Version::Minor)
376389
.def_ro_static("release", &udmpparser::Version::Release);
377-
378-
auto utils = m.def_submodule("utils", "Helper functions");
379-
utils.def(
380-
"TypeToString",
381-
[](const uint32_t Type) -> std::string {
382-
switch (Type) {
383-
case 0x2'00'00: {
384-
return "MEM_PRIVATE";
385-
}
386-
case 0x4'00'00: {
387-
return "MEM_MAPPED";
388-
}
389-
case 0x1'00'00'00: {
390-
return "MEM_IMAGE";
391-
}
392-
}
393-
return "";
394-
},
395-
"Get a string representation of the memory type");
396-
397-
utils.def(
398-
"StateToString",
399-
[](const uint32_t State) {
400-
switch (State) {
401-
case 0x10'00: {
402-
return "MEM_COMMIT";
403-
}
404-
405-
case 0x20'00: {
406-
return "MEM_RESERVE";
407-
}
408-
409-
case 0x1'00'00: {
410-
return "MEM_FREE";
411-
}
412-
}
413-
return "";
414-
},
415-
"Get a string representation of the memory state");
416-
417-
utils.def(
418-
"ProtectionToString",
419-
[](const uint32_t Protection) {
420-
struct {
421-
const char *Name = nullptr;
422-
uint32_t Mask = 0;
423-
} Flags[] = {
424-
{"PAGE_NOACCESS", 0x01},
425-
{"PAGE_READONLY", 0x02},
426-
{"PAGE_READWRITE", 0x04},
427-
{"PAGE_WRITECOPY", 0x08},
428-
{"PAGE_EXECUTE", 0x10},
429-
{"PAGE_EXECUTE_READ", 0x20},
430-
{"PAGE_EXECUTE_READWRITE", 0x40},
431-
{"PAGE_EXECUTE_WRITECOPY", 0x80},
432-
{"PAGE_GUARD", 0x100},
433-
{"PAGE_NOCACHE", 0x200},
434-
{"PAGE_WRITECOMBINE", 0x400},
435-
{"PAGE_TARGETS_INVALID", 0x4000'0000},
436-
};
437-
std::stringstream ss;
438-
uint32_t KnownFlags = 0;
439-
440-
for (const auto &Flag : Flags) {
441-
if ((Protection & Flag.Mask) == 0) {
442-
continue;
443-
}
444-
445-
ss << Flag.Name << ",";
446-
KnownFlags |= Flag.Mask;
447-
}
448-
449-
const uint32_t MissingFlags = (~KnownFlags) & Protection;
450-
if (MissingFlags) {
451-
ss << std::hex << "0x" << MissingFlags;
452-
}
453-
454-
std::string ProtectionString = ss.str();
455-
if (ProtectionString.size() > 1 &&
456-
ProtectionString[ProtectionString.size() - 1] == ',') {
457-
ProtectionString =
458-
ProtectionString.substr(0, ProtectionString.size() - 1);
459-
}
460-
461-
return ProtectionString;
462-
},
463-
"Get a string representation of the memory protection");
464390
}

0 commit comments

Comments
 (0)