├── dbghelp_support_files ├── x64 │ ├── symsrv.dll │ └── dbghelp.dll └── x86 │ ├── symsrv.dll │ └── dbghelp.dll ├── DbgHelpUtils ├── dump_hex.h ├── write_header.h ├── throw_on_error.h ├── windows_setup.h ├── guid_utils.h ├── enable_module_loading.h ├── udt_kind_type.h ├── exception_utils.h ├── overload.h ├── function_table_entry_type.h ├── thread_info_utils.h ├── stream_handle_object_information.cpp ├── block_range_match_result.h ├── hash_combine.h ├── get_last_address.h ├── assert_value.h ├── symbol_type_walker.cpp ├── module_match.h ├── register_names.h ├── mini_dump_type.h ├── user_range.h ├── data_kind.h ├── stream_unloaded_module.cpp ├── stream_thread_name.cpp ├── find_thread_stack.h ├── stream_token_info.cpp ├── heap_node_type.h ├── mini_dump_stream_type.h ├── string_stream.h ├── symbol_info_buffer.cpp ├── lfh_subsegment_location_utils.h ├── symbol_info_buffer.h ├── segment_heap_options.cpp ├── time_utils.h ├── module_match.cpp ├── filesystem_utils.h ├── join.h ├── stream_thread_info.cpp ├── stream_module_name.cpp ├── string_utils.h ├── process_heap_graph_heap_entry.cpp ├── graph_node_variable_symbol_reference_data.h ├── process_heap_graph_thread_stack_entry.cpp ├── comment_stream_a.h ├── comment_stream_w.h ├── process_heap_graph_symbol_entry.cpp ├── cv_info_pdb70.cpp ├── process_heap_graph_thread_context_entry.cpp ├── system_time_utils.h ├── windows_error.h ├── memory_range.h ├── exception_stream.cpp ├── heap_match_utils.h ├── null_stream.h ├── symbol_type_walker.h ├── hex_dump.h ├── segment_heap_options.h ├── string_stream.cpp ├── comment_stream_a.cpp ├── stream_unloaded_module.h ├── stream_module_name.h ├── stream_module.cpp ├── guid_utils.cpp ├── common_symbol_utils.h ├── local_variable.h ├── symbol_type_info_cache.h ├── stream_token_info.h ├── comment_stream_w.cpp ├── basic_type.h ├── symbol_address_info.h ├── memory_info_utils.h ├── stream_thread_ex.cpp ├── system_module_list.h ├── stream_handle_object_information.h ├── exit_scope.h ├── global_symbol.h ├── process_heap_graph_thread_stack_entry.h ├── stream_thread_info.h ├── stream_thread_name.h ├── system_memory_info_stream.cpp ├── pe_file_memory_mapping.h ├── exception_stream.h ├── string_conversation.h ├── global_symbols.h ├── process_heap_graph_thread_context_entry.h ├── global_symbol.cpp ├── global_symbols.cpp ├── process_heap_graph_symbol_entry.h ├── memory_info_list_stream.h ├── stream_module.h ├── lfh_subsegment_location_utils.cpp ├── string_compare.h ├── process_heap_graph_heap_entry.h ├── process_heap_graph_global_variable_entry.cpp ├── handle_operation_list_stream.h ├── system_memory_info_stream.h ├── token_info_list_stream.h ├── stream_function_entry.cpp ├── symbol_type_info_cache.cpp ├── thread_names_list_stream.h ├── page_range_flags_utils.h ├── thread_info_list_stream.h ├── process_heap_entry_reference.cpp ├── process_heap_graph_global_variable_entry.h ├── cache_manager.h ├── stream_thread.cpp ├── cv_info_pdb70.h ├── process_vm_counters_stream.cpp ├── thread_ex_list_stream.h ├── thread_info_utils.cpp ├── heap_match_utils.cpp ├── locale_number_formatting.h ├── time_utils.cpp ├── sym_tag_enum.h ├── wide_runtime_error.h ├── tagged_bool.h ├── i_symbol_load_callback.h ├── statistic_view_options.h ├── process_vm_counters_stream.h ├── stream_thread.h ├── thread_names_list_stream.cpp ├── stream_thread_ex.h ├── memory_info_list_stream.cpp ├── thread_list_stream.h ├── stream_handle.cpp ├── handle_operation_list_stream.cpp ├── function_table_stream.h ├── module_list_stream.h ├── stream_function_descriptor.cpp ├── chrono_unit_convert_to_string.h ├── stream_function_entry.h ├── process_environment_variables.h ├── unit_convert_to_string.h ├── i_stack_walk_callback.h ├── process_heap_entry_reference.h ├── stream_function_descriptor.h ├── find_thread_stack.cpp ├── handle_data_stream.h ├── allocation_stack_trace_helper.h ├── system_info_stream.h ├── misc_info_stream.h ├── thread_info_list_stream.cpp ├── thread_ex_list_stream.cpp ├── stream_handle.h ├── by_size_frequency_view.h ├── windows_error.cpp ├── segment_heap_utils.h ├── list_entry_walker.h ├── range_units.h ├── by_size_ranges_frequency_view.h ├── call_convention.h ├── heap_ucr_descriptor.h ├── misc_info_stream.cpp ├── lfh_heap.h ├── process_heaps_statistics.h ├── by_stacktrace_frequency_view.h ├── unloaded_module_list_stream.h ├── memory_list_stream.h ├── process_heap_entry_symbol_address_reference.cpp ├── rtl_balanced_links_walker.h ├── rtl_rb_tree_walker.h ├── handles.h ├── by_application_callsite_frequency_view.h ├── memory64_list_stream.h ├── handle_data_stream.cpp ├── stream_thread_context.cpp ├── thread_list_stream.cpp ├── crc.h └── flags_string_utils.h ├── .gitmodules ├── MiniDumper ├── dump_mini_dump_comment.h ├── system_modules.json ├── resource.h ├── dump_mini_dump_info.h ├── dump_mini_dump_exception.h ├── dump_mini_dump_module.h ├── dump_mini_dump_memory.h ├── dump_mini_dump_comment.cpp ├── dump_mini_dump.h ├── symbol_engine_ui.h ├── dump_mini_dump_app_info.h ├── dump_mini_dump_streams.h ├── MiniDumper.exe.manifest ├── common_symbol_lookup_utils.h ├── dump_mini_dump_symbols.h └── dump_mini_dump_thread.h ├── AllocationSetupTests ├── ResultSet.h └── AllocationSetupTests.vcxproj.filters ├── CMake ├── DefaultCXX.cmake └── DefaultFortran.cmake ├── .gitignore ├── ValidateHeapEntries ├── symbol_engine_ui.h ├── ValidateHeapEntries.vcxproj.filters └── symbol_engine_ui.cpp └── LICENSE /dbghelp_support_files/x64/symsrv.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shanepowell/DbgHelpUtils/HEAD/dbghelp_support_files/x64/symsrv.dll -------------------------------------------------------------------------------- /dbghelp_support_files/x86/symsrv.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shanepowell/DbgHelpUtils/HEAD/dbghelp_support_files/x86/symsrv.dll -------------------------------------------------------------------------------- /dbghelp_support_files/x64/dbghelp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shanepowell/DbgHelpUtils/HEAD/dbghelp_support_files/x64/dbghelp.dll -------------------------------------------------------------------------------- /dbghelp_support_files/x86/dbghelp.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shanepowell/DbgHelpUtils/HEAD/dbghelp_support_files/x86/dbghelp.dll -------------------------------------------------------------------------------- /DbgHelpUtils/dump_hex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tagged_bool.h" 3 | 4 | namespace dlg_help_utils 5 | { 6 | using dump_hex_t = tagged_bool; 7 | } 8 | -------------------------------------------------------------------------------- /DbgHelpUtils/write_header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tagged_bool.h" 3 | 4 | namespace dlg_help_utils 5 | { 6 | using write_header_t = tagged_bool; 7 | } 8 | -------------------------------------------------------------------------------- /DbgHelpUtils/throw_on_error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tagged_bool.h" 3 | 4 | namespace dlg_help_utils 5 | { 6 | using throw_on_error_t = tagged_bool; 7 | } 8 | -------------------------------------------------------------------------------- /DbgHelpUtils/windows_setup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef WIN32_LEAN_AND_MEAN 3 | #define WIN32_LEAN_AND_MEAN 4 | #endif 5 | #ifndef NOMINMAX 6 | #define NOMINMAX 7 | #endif 8 | #include 9 | -------------------------------------------------------------------------------- /DbgHelpUtils/guid_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows_setup.h" 3 | #include 4 | 5 | namespace dlg_help_utils::guid_utils 6 | { 7 | std::wstring to_string(GUID const& guid); 8 | } 9 | -------------------------------------------------------------------------------- /DbgHelpUtils/enable_module_loading.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "tagged_bool.h" 3 | 4 | namespace dlg_help_utils 5 | { 6 | using enable_module_loading_t = tagged_bool; 7 | } 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libraries/json_struct"] 2 | path = libraries/json_struct 3 | url = https://github.com/jorgen/json_struct 4 | [submodule "libraries/lyra"] 5 | path = libraries/lyra 6 | url = https://github.com/bfgroup/Lyra.git 7 | -------------------------------------------------------------------------------- /DbgHelpUtils/udt_kind_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace dlg_help_utils::dbg_help 4 | { 5 | enum class udt_kind_type 6 | { 7 | struct_type = 0, 8 | class_type = 1, 9 | union_type = 2, 10 | interface_type = 3 11 | }; 12 | } -------------------------------------------------------------------------------- /DbgHelpUtils/exception_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils::exception_utils 5 | { 6 | std::wstring_view exception_code_to_string(uint32_t exception_code); 7 | std::wstring exception_flags_to_string(uint32_t exception_flags); 8 | } 9 | -------------------------------------------------------------------------------- /DbgHelpUtils/overload.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace dlg_help_utils 4 | { 5 | template 6 | struct overload : Ts ... { 7 | using Ts::operator() ...; 8 | }; 9 | 10 | template overload(Ts...) -> overload; 11 | } -------------------------------------------------------------------------------- /DbgHelpUtils/function_table_entry_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace dlg_help_utils 4 | { 5 | enum class function_table_entry_type 6 | { 7 | unknown, 8 | fpo_data, 9 | image_function_entry, 10 | image_function_entry_64, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_info_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils::thread_info_utils 6 | { 7 | std::wstring dump_flags_to_string(uint32_t dump_flags); 8 | std::vector dump_flags_to_strings(uint32_t dump_flags); 9 | } 10 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_handle_object_information.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_handle_object_information.h" 2 | 3 | namespace dlg_help_utils 4 | { 5 | stream_handle_object_information::stream_handle_object_information(MINIDUMP_HANDLE_OBJECT_INFORMATION const& info) 6 | : info_{info} 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /DbgHelpUtils/block_range_match_result.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace dlg_help_utils::heap 4 | { 5 | enum class block_range_match_result 6 | { 7 | block_match, 8 | block_contains, 9 | user_contains_block, 10 | block_partially_contains, 11 | block_no_match 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /DbgHelpUtils/hash_combine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils 5 | { 6 | template 7 | void hash_combine(S& seed, const T& v) 8 | { 9 | std::hash hasher; 10 | seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /DbgHelpUtils/get_last_address.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | template 8 | uint64_t get_last_address(T entry) 9 | { 10 | return entry.user_address() + std::max(entry.user_requested_size().count(), 1LL) - 1; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DbgHelpUtils/assert_value.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace dlg_help_utils 3 | { 4 | template 5 | struct assert_value 6 | { 7 | static_assert(AssertionValue, "Assertion failed "); 8 | static bool const value = AssertionValue; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /DbgHelpUtils/symbol_type_walker.cpp: -------------------------------------------------------------------------------- 1 | #include "symbol_type_walker.h" 2 | 3 | #include "mini_dump_memory_walker.h" 4 | 5 | namespace dlg_help_utils::stream_stack_dump 6 | { 7 | symbol_type_walker::symbol_type_walker(mini_dump_memory_walker const& walker, std::wstring const& match_pattern) 8 | : symbols_{walker.symbol_walk(match_pattern)} 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DbgHelpUtils/module_match.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include 5 | 6 | namespace dlg_help_utils 7 | { 8 | class stream_module_name; 9 | } 10 | 11 | namespace dlg_help_utils::module_match 12 | { 13 | [[nodiscard]] bool module_name_match(stream_module_name const& key, std::wstring_view const& module_name); 14 | } 15 | -------------------------------------------------------------------------------- /DbgHelpUtils/register_names.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include 5 | 6 | // ReSharper disable once CommentTypo 7 | // Found in "$(VSINSTALLDIR)\DIA SDK\include" 8 | #include 9 | 10 | namespace dlg_help_utils::register_names 11 | { 12 | std::wstring_view get_register_name(CV_HREG_e register_type); 13 | } 14 | -------------------------------------------------------------------------------- /DbgHelpUtils/mini_dump_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | #include 5 | #include 6 | 7 | // ReSharper disable once CppUnusedIncludeDirective 8 | #include 9 | 10 | namespace dlg_help_utils::mini_dump_type 11 | { 12 | std::vector to_strings(MINIDUMP_TYPE type); 13 | } 14 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_comment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | class mini_dump; 8 | } 9 | 10 | void dump_mini_dump_comment_w_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 11 | void dump_mini_dump_comment_a_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 12 | -------------------------------------------------------------------------------- /DbgHelpUtils/user_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include 4 | #include 5 | 6 | namespace dlg_help_utils 7 | { 8 | struct user_range 9 | { 10 | uint64_t start; 11 | uint64_t size; 12 | 13 | auto operator<=>(user_range const&) const = default; // NOLINT(clang-diagnostic-unused-member-function) 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /MiniDumper/system_modules.json: -------------------------------------------------------------------------------- 1 | { 2 | "systemmodules": [ 3 | "ntdll.dll", 4 | "kernelbase.dll", 5 | "kernel32.dll", 6 | "msvcp140.dll", 7 | "msvcp140d.dll", 8 | "ucrtbase.dll", 9 | "ucrtbased.dll", 10 | "vcruntime140.dll", 11 | "vcruntime140d.dll", 12 | "vcruntime140_1.dll", 13 | "vcruntime140_1d.dll", 14 | "sechost.dll" 15 | ] 16 | } -------------------------------------------------------------------------------- /DbgHelpUtils/data_kind.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace dlg_help_utils::dbg_help 3 | { 4 | enum class data_kind 5 | { 6 | data_is_local, 7 | data_is_unknown, 8 | data_is_static_local, 9 | data_is_param, 10 | data_is_object_ptr, 11 | data_is_file_static, 12 | data_is_global, 13 | data_is_member, 14 | data_is_static_member, 15 | data_is_constant 16 | }; 17 | } -------------------------------------------------------------------------------- /DbgHelpUtils/stream_unloaded_module.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_unloaded_module.h" 2 | 3 | #include "mini_dump.h" 4 | #include "string_stream.h" 5 | 6 | namespace dlg_help_utils 7 | { 8 | stream_unloaded_module::stream_unloaded_module(mini_dump const& dump, MINIDUMP_UNLOADED_MODULE const& module) 9 | : stream_module_name{string_stream::to_string(dump, module.ModuleNameRva)} 10 | , module_{module} 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread_name.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_thread_name.h" 2 | 3 | #include "mini_dump.h" 4 | #include "string_stream.h" 5 | 6 | namespace dlg_help_utils 7 | { 8 | stream_thread_name::stream_thread_name(mini_dump const& dump, MINIDUMP_THREAD_NAME const& thread) 9 | : is_valid_{true} 10 | , thread_{&thread} 11 | { 12 | name_ = string_stream::to_string(dump, thread_->RvaOfThreadName); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DbgHelpUtils/find_thread_stack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | class mini_dump; 8 | 9 | struct thread_stack 10 | { 11 | void const* stack{nullptr}; 12 | uint32_t stack_size{}; 13 | uint64_t stack_start_address{}; 14 | }; 15 | 16 | std::optional find_thread_stack(mini_dump const& mini_dump, uint32_t thread_id); 17 | }; 18 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_token_info.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_token_info.h" 2 | 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | stream_token_info::stream_token_info(MINIDUMP_TOKEN_INFO_HEADER const& header) 8 | : header_(header) 9 | { 10 | if (header_.TokenSize > 0) 11 | { 12 | data_ = reinterpret_cast(&header_) + sizeof(MINIDUMP_TOKEN_INFO_HEADER); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DbgHelpUtils/heap_node_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace dlg_help_utils::heap 4 | { 5 | enum class heap_node_type 6 | { 7 | nt_heap_lfh_entry, 8 | nt_heap_segment_entry, 9 | nt_heap_virtual_entry, 10 | segment_backend_entry, 11 | segment_entry, 12 | segment_lfh_entry, 13 | segment_large_entry, 14 | dph_entry, 15 | dph_virtual_entry, 16 | memory_range 17 | }; 18 | } -------------------------------------------------------------------------------- /DbgHelpUtils/mini_dump_stream_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | #include 7 | 8 | namespace dlg_help_utils::mini_dump_stream_type 9 | { 10 | std::wstring to_wstring(MINIDUMP_STREAM_TYPE type); 11 | std::wstring to_enum_wstring(MINIDUMP_STREAM_TYPE type); 12 | MINIDUMP_STREAM_TYPE from_wstring(std::wstring const& type); 13 | } 14 | -------------------------------------------------------------------------------- /DbgHelpUtils/string_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | #include 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | class mini_dump; 10 | 11 | namespace string_stream 12 | { 13 | std::wstring_view to_string(mini_dump const& dump, RVA rva); 14 | std::wstring_view to_string(mini_dump const& dump, RVA64 rva); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DbgHelpUtils/symbol_info_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "symbol_info_buffer.h" 2 | 3 | namespace dlg_help_utils::dbg_help 4 | { 5 | std::shared_ptr symbol_info_buffer::make() 6 | { 7 | auto rv = std::make_shared(); 8 | memset(rv.get(), 0, rv->buffer.size()); 9 | rv->info.SizeOfStruct = sizeof(SYMBOL_INFOW); 10 | rv->info.MaxNameLen = MAX_SYM_NAME; 11 | return rv; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MiniDumper/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Resource.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /DbgHelpUtils/lfh_subsegment_location_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include 4 | 5 | namespace dlg_help_utils::lfh_subsegment_location_utils 6 | { 7 | enum class location 8 | { 9 | available_subsegment_list = 0, 10 | full_subsegment_list = 1, 11 | retiring_subsegment_list = 2 12 | }; 13 | 14 | std::wstring_view dump_page_range_flags_to_string(location value); 15 | } 16 | -------------------------------------------------------------------------------- /DbgHelpUtils/symbol_info_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows_setup.h" 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace dlg_help_utils::dbg_help 9 | { 10 | union symbol_info_buffer 11 | { 12 | std::array buffer; 13 | SYMBOL_INFOW info; 14 | 15 | static std::shared_ptr make(); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /DbgHelpUtils/segment_heap_options.cpp: -------------------------------------------------------------------------------- 1 | #include "segment_heap_options.h" 2 | 3 | namespace dlg_help_utils::heap 4 | { 5 | segment_heap_options::segment_heap_options(uint16_t const front_padding_windows10_min_version, uint16_t const front_padding_windows10_max_version) 6 | : front_padding_windows10_min_version_{front_padding_windows10_min_version} 7 | , front_padding_windows10_max_version_{front_padding_windows10_max_version} 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /DbgHelpUtils/time_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows_setup.h" 3 | #include 4 | #include 5 | 6 | namespace dlg_help_utils::time_utils 7 | { 8 | std::wstring to_local_time(time_t timestamp); 9 | std::wstring to_utc_time(time_t timestamp); 10 | time_t filetime_to_time_t(FILETIME ft); 11 | time_t filetime_to_time_t(uint64_t ft); 12 | std::chrono::milliseconds duration_to_ms(uint64_t duration); // 100-nanosecond internals to ms 13 | } 14 | -------------------------------------------------------------------------------- /DbgHelpUtils/module_match.cpp: -------------------------------------------------------------------------------- 1 | #include "module_match.h" 2 | 3 | #include 4 | 5 | #include "stream_module_name.h" 6 | #include "string_compare.h" 7 | 8 | namespace dlg_help_utils::module_match 9 | { 10 | bool module_name_match(stream_module_name const& key, std::wstring_view const& module_name) 11 | { 12 | return string_compare::iequals(key.filename_with_extension(), module_name) || string_compare::iequals(key.filename_without_extension(), module_name); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DbgHelpUtils/filesystem_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace dlg_help_utils::filesystem_utils 9 | { 10 | [[nodiscard]] bool wildcard_match(std::wstring_view value, std::wstring_view match); 11 | [[nodiscard]] std::experimental::generator enumerate_files(std::vector const& paths, std::function const& on_error); 12 | } 13 | -------------------------------------------------------------------------------- /DbgHelpUtils/join.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils 5 | { 6 | template 7 | std::string join(V const& v, std::string_view const& delimiter) 8 | { 9 | std::string out; 10 | auto i = std::begin(v); 11 | auto e = std::end(v); 12 | if (i != std::end(v)) 13 | { 14 | out += *i++; 15 | for (; i != e; ++i) out.append(delimiter).append(*i); 16 | } 17 | return out; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread_info.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_thread_info.h" 2 | 3 | #include "mini_dump.h" 4 | #include "thread_names_list_stream.h" 5 | 6 | namespace dlg_help_utils 7 | { 8 | stream_thread_info::stream_thread_info(MINIDUMP_THREAD_INFO const& thread_info, 9 | thread_names_list_stream const& names_list) 10 | : thread_info_{thread_info} 11 | , thread_name_{names_list.get_thread_name_for_thread_id(thread_info.ThreadId)} 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | class mini_dump; 8 | } 9 | 10 | void dump_mini_dump_system_info_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 11 | void dump_mini_dump_misc_info_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 12 | void dump_mini_dump_process_vm_counters_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 13 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_module_name.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_module_name.h" 2 | 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | stream_module_name::stream_module_name(std::wstring_view const& name) 8 | : name_{name} 9 | { 10 | std::filesystem::path const path{name_}; 11 | auto filename_with_extension_path = path.filename(); 12 | filename_with_extension_ = filename_with_extension_path.wstring(); 13 | filename_without_extension_ = filename_with_extension_path.replace_extension().wstring(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DbgHelpUtils/string_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils::string_compare 5 | { 6 | [[nodiscard]] inline std::wstring to_lower(std::wstring_view const& str) 7 | { 8 | std::wstring rv{str}; 9 | std::ignore = _wcslwr_s(rv.data(), rv.size() + 1); 10 | return rv; 11 | } 12 | 13 | [[nodiscard]] inline std::wstring to_upper(std::wstring_view const& str) 14 | { 15 | std::wstring rv{str}; 16 | std::ignore = _wcsupr_s(rv.data(), rv.size() + 1); 17 | return rv; 18 | } 19 | } -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_heap_entry.cpp: -------------------------------------------------------------------------------- 1 | #include "process_heap_graph_heap_entry.h" 2 | 3 | namespace dlg_help_utils::heap::allocation_graph 4 | { 5 | process_heap_graph_heap_entry::process_heap_graph_heap_entry(process_heap_entry heap_entry, process_heap_graph_heap_entry_type const type) 6 | : process_heap_graph_node{heap_entry.user_address(), type == process_heap_graph_heap_entry_type::system_allocation ? process_heap_graph_node_type::system_allocation : process_heap_graph_node_type::allocation} 7 | , heap_entry_{std::move(heap_entry)} 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_exception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class dump_file_options; 6 | 7 | namespace dlg_help_utils 8 | { 9 | namespace dbg_help 10 | { 11 | class symbol_engine; 12 | } 13 | 14 | class mini_dump; 15 | } 16 | 17 | void dump_mini_dump_exception_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, 18 | dump_file_options const& options, 19 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 20 | -------------------------------------------------------------------------------- /DbgHelpUtils/graph_node_variable_symbol_reference_data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "symbol_type_info.h" 5 | 6 | namespace dlg_help_utils::heap::allocation_graph 7 | { 8 | struct graph_node_variable_symbol_reference_data 9 | { 10 | uint64_t parent_node_index{}; 11 | uint64_t parent_address{}; 12 | uint64_t variable_offset{}; 13 | uint64_t variable_address{}; 14 | dbg_help::symbol_type_info parent_symbol_type; 15 | dbg_help::symbol_type_info variable_symbol_type; 16 | std::wstring name; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_thread_stack_entry.cpp: -------------------------------------------------------------------------------- 1 | #include "process_heap_graph_thread_stack_entry.h" 2 | 3 | namespace dlg_help_utils::heap::allocation_graph 4 | { 5 | process_heap_graph_thread_stack_entry::process_heap_graph_thread_stack_entry(mini_dump_memory_stream stack_stream, uint32_t const thread_id, std::wstring thread_name) 6 | : process_heap_graph_node{stack_stream.current_address(), process_heap_graph_node_type::root} 7 | , stack_stream_{std::move(stack_stream)} 8 | , thread_id_{thread_id} 9 | , thread_name_{std::move(thread_name)} 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /DbgHelpUtils/comment_stream_a.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils 5 | { 6 | class mini_dump; 7 | 8 | class comment_stream_a 9 | { 10 | public: 11 | explicit comment_stream_a(mini_dump const& dump, size_t index = 0); 12 | 13 | [[nodiscard]] bool found() const { return found_; } 14 | [[nodiscard]] size_t index() const { return index_; } 15 | [[nodiscard]] std::wstring const& comment() const { return comment_; } 16 | 17 | private: 18 | bool found_{false}; 19 | size_t index_; 20 | std::wstring comment_; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /DbgHelpUtils/comment_stream_w.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils 5 | { 6 | class mini_dump; 7 | 8 | class comment_stream_w 9 | { 10 | public: 11 | explicit comment_stream_w(mini_dump const& dump, size_t index = 0); 12 | 13 | [[nodiscard]] bool found() const { return found_; } 14 | [[nodiscard]] size_t index() const { return index_; } 15 | [[nodiscard]] std::wstring const& comment() const { return comment_; } 16 | 17 | private: 18 | bool found_{false}; 19 | size_t index_; 20 | std::wstring comment_; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_symbol_entry.cpp: -------------------------------------------------------------------------------- 1 | #include "process_heap_graph_symbol_entry.h" 2 | 3 | namespace dlg_help_utils::heap::allocation_graph 4 | { 5 | process_heap_graph_symbol_entry::process_heap_graph_symbol_entry(uint64_t const address, dbg_help::symbol_type_info symbol_type, std::optional const thread_id, std::wstring thread_name) 6 | : process_heap_graph_node{address, process_heap_graph_node_type::root} 7 | , address_{address} 8 | , symbol_type_{std::move(symbol_type)} 9 | , thread_id_{thread_id} 10 | , thread_name_{std::move(thread_name)} 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DbgHelpUtils/cv_info_pdb70.cpp: -------------------------------------------------------------------------------- 1 | #include "cv_info_pdb70.h" 2 | 3 | #include "string_conversation.h" 4 | 5 | namespace dlg_help_utils 6 | { 7 | cv_info_pdb70::cv_info_pdb70(void const* data, size_t const length) 8 | { 9 | if (length < sizeof(CV_INFO_PDB70)) 10 | { 11 | return; 12 | } 13 | 14 | cv_ = static_cast(data); 15 | if (is_valid()) 16 | { 17 | pdb_file_name_ = string_conversation::acp_to_wstring(std::string_view{ 18 | reinterpret_cast(cv_->PdbFileName) 19 | }); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_thread_context_entry.cpp: -------------------------------------------------------------------------------- 1 | #include "process_heap_graph_thread_context_entry.h" 2 | 3 | namespace dlg_help_utils::heap::allocation_graph 4 | { 5 | process_heap_graph_thread_context_entry::process_heap_graph_thread_context_entry(CV_HREG_e const register_type, uint64_t const register_data, uint32_t const thread_id, std::wstring thread_name) 6 | : process_heap_graph_node{0, process_heap_graph_node_type::root} 7 | , register_type_{register_type} 8 | , register_data_{register_data} 9 | , thread_id_{thread_id} 10 | , thread_name_{std::move(thread_name)} 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AllocationSetupTests/ResultSet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #pragma warning(push) 6 | #pragma warning(disable : 4267 4457 4100) 7 | #include 8 | #pragma warning(pop) 9 | 10 | struct Allocation 11 | { 12 | uint64_t pointer; 13 | size_t size; 14 | char fill_char; 15 | bool allocated; 16 | 17 | JS_OBJ(pointer, size, fill_char, allocated); // NOLINT 18 | }; 19 | 20 | struct ResultSet 21 | { 22 | std::vector first_allocations; 23 | std::vector second_allocations; 24 | 25 | JS_OBJ(first_allocations, second_allocations); 26 | }; 27 | -------------------------------------------------------------------------------- /DbgHelpUtils/system_time_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | 5 | #include 6 | #include 7 | 8 | namespace dlg_help_utils::system_time_utils 9 | { 10 | inline std::wstring to_wstring(SYSTEMTIME const& st) 11 | { 12 | return std::format(L"{0}/{1}/{2} {3:>02}:{4:>02}:{5:>02}.{6}", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); 13 | } 14 | 15 | inline std::wostream& operator<<(std::wostream& os, SYSTEMTIME const& st) 16 | { 17 | os << to_wstring(st); 18 | return os; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /DbgHelpUtils/windows_error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows_setup.h" 3 | #include 4 | 5 | namespace dlg_help_utils::windows_error 6 | { 7 | [[noreturn]] void throw_windows_api_error(std::wstring_view const& api, std::wstring_view const& optional_data, DWORD ec = GetLastError()); 8 | [[noreturn]] void throw_windows_api_error(std::wstring_view const& api, DWORD ec = GetLastError()); 9 | 10 | std::wstring get_windows_error_string(DWORD ec, std::wstring const& dll_source_path); 11 | 12 | inline std::wstring get_windows_error_string(DWORD const ec) 13 | { 14 | return get_windows_error_string(ec, {}); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DbgHelpUtils/memory_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include 4 | #include 5 | 6 | #include "size_units.h" 7 | 8 | namespace dlg_help_utils 9 | { 10 | struct memory_range 11 | { 12 | uint64_t start_range; 13 | uint64_t end_range; 14 | 15 | auto operator<=>(memory_range const&) const = default; // NOLINT(clang-diagnostic-unused-member-function) 16 | }; 17 | 18 | inline size_units::base_16::bytes size(memory_range const& range) 19 | { 20 | return size_units::to(range.end_range - range.start_range); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /DbgHelpUtils/exception_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "exception_stream.h" 2 | 3 | #include "mini_dump.h" 4 | 5 | namespace dlg_help_utils 6 | { 7 | exception_stream::exception_stream(mini_dump const& dump, size_t const index) 8 | { 9 | index_ = index; 10 | auto const* entry = dump.find_stream_type(ExceptionStream, index_); 11 | if (entry == nullptr) 12 | { 13 | return; 14 | } 15 | 16 | exception_ = static_cast(dump.rva32(entry->Location)); 17 | found_ = true; 18 | 19 | thread_context_ = stream_thread_context{dump, exception_->ThreadContext}; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DbgHelpUtils/heap_match_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "block_range_match_result.h" 5 | #include "size_units.h" 6 | 7 | namespace dlg_help_utils::stream_stack_dump 8 | { 9 | class mini_dump_memory_walker; 10 | } 11 | 12 | namespace dlg_help_utils::heap 13 | { 14 | enum class heap_node_type; 15 | 16 | class heap_match_utils 17 | { 18 | public: 19 | static [[nodiscard]] block_range_match_result does_memory_match_to_range(uint64_t user_address 20 | , size_units::base_16::bytes user_size 21 | , uint64_t block_address 22 | , size_units::base_16::bytes block_size); 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /DbgHelpUtils/null_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class null_stream : public std::wostream 5 | { 6 | private: 7 | class null_buffer : public std::wstreambuf 8 | { 9 | public: 10 | int_type overflow( int_type const ch ) override 11 | { 12 | return ch; 13 | } 14 | 15 | // ReSharper disable once IdentifierTypo 16 | std::streamsize xsputn( [[maybe_unused]] const char_type* s, std::streamsize const count ) override 17 | { 18 | return count; 19 | } 20 | } nb_; 21 | 22 | public: 23 | null_stream() 24 | : std::wostream{&nb_} 25 | { 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /CMake/DefaultCXX.cmake: -------------------------------------------------------------------------------- 1 | include("${CMAKE_CURRENT_LIST_DIR}/Default.cmake") 2 | 3 | set_config_specific_property("OUTPUT_DIRECTORY" "${CMAKE_SOURCE_DIR}$<$>:/${CMAKE_VS_PLATFORM_NAME}>/${PROPS_CONFIG}") 4 | 5 | if(MSVC) 6 | create_property_reader("DEFAULT_CXX_EXCEPTION_HANDLING") 7 | create_property_reader("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT") 8 | 9 | set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") 10 | set_config_specific_property("DEFAULT_CXX_EXCEPTION_HANDLING" "/EHsc") 11 | set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi") 12 | endif() 13 | -------------------------------------------------------------------------------- /DbgHelpUtils/symbol_type_walker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils::dbg_help 6 | { 7 | class symbol_type_info; 8 | enum class sym_tag_enum; 9 | } 10 | 11 | namespace dlg_help_utils::stream_stack_dump 12 | { 13 | class mini_dump_memory_walker; 14 | 15 | class symbol_type_walker 16 | { 17 | public: 18 | symbol_type_walker(mini_dump_memory_walker const& walker, std::wstring const& match_pattern = {}); 19 | 20 | [[nodiscard]] std::vector const& all_symbols() const { return symbols_; } 21 | 22 | private: 23 | std::vector symbols_; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /DbgHelpUtils/hex_dump.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include 5 | 6 | #include "write_header.h" 7 | 8 | namespace dlg_help_utils 9 | { 10 | class mini_dump_memory_stream; 11 | } 12 | 13 | namespace dlg_help_utils::hex_dump 14 | { 15 | void hex_dump(std::wostream& os, void const* data, uint64_t length, size_t indent = 0, write_header_t write_header = write_header_t{true}, uint64_t bytes_per_row = 0x10, uint64_t offset = 0ULL); 16 | void hex_dump(std::wostream& os, mini_dump_memory_stream& stream, uint64_t length, size_t indent = 0, write_header_t write_header = write_header_t{true}, uint64_t bytes_per_row = 0x10, uint64_t offset = 0ULL); 17 | } 18 | -------------------------------------------------------------------------------- /DbgHelpUtils/segment_heap_options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils::heap 5 | { 6 | class segment_heap_options 7 | { 8 | public: 9 | segment_heap_options(uint16_t front_padding_windows10_min_version, uint16_t front_padding_windows10_max_version); 10 | 11 | [[nodiscard]] uint16_t front_padding_windows10_min_version() const { return front_padding_windows10_min_version_; } 12 | [[nodiscard]] uint16_t front_padding_windows10_max_version() const { return front_padding_windows10_max_version_; } 13 | 14 | private: 15 | uint16_t front_padding_windows10_min_version_; 16 | uint16_t front_padding_windows10_max_version_; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /DbgHelpUtils/string_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "string_stream.h" 2 | #include "mini_dump.h" 3 | 4 | namespace dlg_help_utils::string_stream 5 | { 6 | std::wstring_view to_string(mini_dump const& dump, RVA const rva) 7 | { 8 | if (rva == 0) return {}; 9 | auto const* name = static_cast(dump.rva32(rva)); 10 | return std::wstring_view{name->Buffer, name->Length / 2}; 11 | } 12 | 13 | std::wstring_view to_string(mini_dump const& dump, RVA64 const rva) 14 | { 15 | if (rva == 0) return {}; 16 | auto const* name = static_cast(dump.rva64(rva)); 17 | return std::wstring_view{name->Buffer, name->Length / 2}; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DbgHelpUtils/comment_stream_a.cpp: -------------------------------------------------------------------------------- 1 | #include "comment_stream_a.h" 2 | 3 | #include 4 | 5 | #include "mini_dump.h" 6 | #include "string_conversation.h" 7 | 8 | namespace dlg_help_utils 9 | { 10 | comment_stream_a::comment_stream_a(mini_dump const& dump, size_t const index) 11 | { 12 | index_ = index; 13 | auto const* entry = dump.find_stream_type(CommentStreamA, index_); 14 | if (entry == nullptr) 15 | { 16 | return; 17 | } 18 | 19 | found_ = true; 20 | comment_ = string_conversation::acp_to_wstring(std::string_view{ 21 | static_cast(dump.rva32(entry->Location)), entry->Location.DataSize 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_unloaded_module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | #include "stream_module_name.h" 8 | 9 | namespace dlg_help_utils 10 | { 11 | class mini_dump; 12 | 13 | class stream_unloaded_module : public stream_module_name 14 | { 15 | public: 16 | explicit stream_unloaded_module(mini_dump const& dump, MINIDUMP_UNLOADED_MODULE const& module); 17 | 18 | MINIDUMP_UNLOADED_MODULE const* operator->() const { return &module_; } 19 | 20 | private: 21 | MINIDUMP_UNLOADED_MODULE const& module_; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_module_name.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils 5 | { 6 | class stream_module_name 7 | { 8 | public: 9 | explicit stream_module_name(std::wstring_view const& name); 10 | 11 | [[nodiscard]] std::wstring_view const& name() const { return name_; } 12 | [[nodiscard]] std::wstring const& filename_with_extension() const { return filename_with_extension_; } 13 | [[nodiscard]] std::wstring const& filename_without_extension() const { return filename_without_extension_; } 14 | 15 | private: 16 | std::wstring_view name_; 17 | std::wstring filename_with_extension_; 18 | std::wstring filename_without_extension_; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_module.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_module.h" 2 | 3 | #include "mini_dump.h" 4 | #include "string_stream.h" 5 | 6 | namespace dlg_help_utils 7 | { 8 | stream_module::stream_module(mini_dump const& dump, MINIDUMP_MODULE const& module) 9 | : stream_module_name{string_stream::to_string(dump, module.ModuleNameRva)} 10 | , module_{module} 11 | { 12 | if (module_.CvRecord.DataSize > 0) 13 | { 14 | cv_record_ = dump.rva32(module_.CvRecord); 15 | pdb_info_ = cv_info_pdb70{cv_record_, module_.CvRecord.DataSize}; 16 | } 17 | 18 | if (module_.MiscRecord.DataSize > 0) 19 | { 20 | misc_record_ = dump.rva32(module_.MiscRecord); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DbgHelpUtils/guid_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "guid_utils.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "wide_runtime_error.h" 7 | #include "windows_error.h" 8 | 9 | #pragma comment(lib, "rpcrt4.lib") 10 | 11 | using namespace std::string_view_literals; 12 | 13 | namespace dlg_help_utils::guid_utils 14 | { 15 | std::wstring to_string(GUID const& guid) 16 | { 17 | RPC_WSTR rpc_string; 18 | if (auto const status = UuidToStringW(&guid, &rpc_string); status != RPC_S_OK) 19 | { 20 | windows_error::throw_windows_api_error(L"UuidToStringW"sv); 21 | } 22 | 23 | std::wstring rv(reinterpret_cast(rpc_string)); 24 | RpcStringFreeW(&rpc_string); 25 | return rv; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /DbgHelpUtils/common_symbol_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | class memory64_list_stream; 8 | class memory_list_stream; 9 | class thread_names_list_stream; 10 | class mini_dump; 11 | } 12 | 13 | namespace dlg_help_utils::common_symbol_utils 14 | { 15 | 16 | std::vector get_teb_addresses(mini_dump const& mini_dump, thread_names_list_stream const& names_list, memory_list_stream const& memory_list, memory64_list_stream const& memory64_list); 17 | void gather_system_addresses(mini_dump const& mini_dump, thread_names_list_stream const& names_list, memory_list_stream const& memory_list, memory64_list_stream const& memory64_list, std::set& system_area_addresses); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /DbgHelpUtils/local_variable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CommentTypo 4 | // Found in "$(VSINSTALLDIR)\DIA SDK\include" 5 | #include 6 | 7 | #include "symbol_type_info.h" 8 | 9 | namespace dlg_help_utils::dbg_help 10 | { 11 | struct registry_info 12 | { 13 | CV_HREG_e register_type{}; 14 | uint64_t value{}; 15 | uint64_t value_size{}; 16 | }; 17 | 18 | struct frame_data_info 19 | { 20 | int32_t data_offset{}; 21 | uint64_t data_address{}; 22 | uint32_t data_size{}; 23 | }; 24 | 25 | struct local_variable 26 | { 27 | symbol_type_info symbol_info; 28 | std::optional registry_value{}; 29 | std::optional frame_data{}; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /DbgHelpUtils/symbol_type_info_cache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "symbol_type_info.h" 5 | 6 | namespace dlg_help_utils::dbg_help 7 | { 8 | class symbol_type_info_cache 9 | { 10 | public: 11 | void create_cached_symbol_type_info(HANDLE process, DWORD64 module_base, ULONG type_index, std::wstring_view export_name = {}); 12 | [[nodiscard]] std::optional get_symbol_type_info(HANDLE process, DWORD64 module_base, ULONG type_index) const; 13 | [[nodiscard]] symbol_type_info get_or_create_symbol_type_info(HANDLE process, DWORD64 module_base, ULONG type_index, std::wstring_view export_name = {}); 14 | 15 | private: 16 | std::unordered_set cache_; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class dump_file_options; 6 | 7 | namespace dlg_help_utils 8 | { 9 | class cache_manager; 10 | 11 | namespace dbg_help 12 | { 13 | class symbol_engine; 14 | } 15 | 16 | class mini_dump; 17 | } 18 | 19 | void dump_mini_dump_module_list_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, dump_file_options const& options); 20 | void dump_mini_dump_unloaded_module_list_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 21 | 22 | void dump_mini_dump_loaded_modules(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, dlg_help_utils::cache_manager& cache, dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 23 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_token_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | class stream_token_info 10 | { 11 | public: 12 | stream_token_info(MINIDUMP_TOKEN_INFO_HEADER const& header); 13 | 14 | MINIDUMP_TOKEN_INFO_HEADER const* operator->() const { return &header_; } 15 | [[nodiscard]] void const* data() const { return data_; } 16 | [[nodiscard]] size_t size() const { return header_.TokenSize - sizeof(MINIDUMP_TOKEN_INFO_HEADER); } 17 | 18 | private: 19 | MINIDUMP_TOKEN_INFO_HEADER const& header_; 20 | void const* data_{nullptr}; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /DbgHelpUtils/comment_stream_w.cpp: -------------------------------------------------------------------------------- 1 | #include "comment_stream_w.h" 2 | 3 | #include 4 | 5 | #include "mini_dump.h" 6 | 7 | namespace dlg_help_utils 8 | { 9 | comment_stream_w::comment_stream_w(mini_dump const& dump, size_t const index) 10 | { 11 | index_ = index; 12 | auto const* entry = dump.find_stream_type(CommentStreamW, index_); 13 | if (entry == nullptr) 14 | { 15 | return; 16 | } 17 | 18 | if ((entry->Location.DataSize % 2) != 0) 19 | { 20 | throw std::runtime_error{"invalid CommentStreamW data"}; 21 | } 22 | 23 | found_ = true; 24 | comment_ = std::wstring_view{ 25 | static_cast(dump.rva32(entry->Location)), entry->Location.DataSize / 2 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DbgHelpUtils/basic_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace dlg_help_utils::dbg_help 4 | { 5 | enum class basic_type 6 | { 7 | NoType = 0, 8 | Void = 1, 9 | Char = 2, 10 | WChar = 3, 11 | Int = 6, 12 | UInt = 7, 13 | Float = 8, 14 | BCD = 9, 15 | Bool = 10, 16 | Long = 13, 17 | ULong = 14, 18 | Currency = 25, 19 | Date = 26, 20 | Variant = 27, 21 | Complex = 28, 22 | Bit = 29, 23 | // ReSharper disable once IdentifierTypo 24 | BSTR = 30, 25 | // ReSharper disable once CppInconsistentNaming 26 | // ReSharper disable once IdentifierTypo 27 | HResult = 31, 28 | Char16 = 32, // char16_t 29 | Char32 = 33, // char32_t 30 | Char8 = 34, // char8_t 31 | }; 32 | } -------------------------------------------------------------------------------- /DbgHelpUtils/symbol_address_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "local_variable.h" 6 | 7 | namespace dlg_help_utils::dbg_help 8 | { 9 | class symbol_type_info; 10 | struct local_variable; 11 | 12 | struct symbol_address_info 13 | { 14 | std::wstring module_name; 15 | std::wstring symbol_name; 16 | std::wstring file_name; 17 | DWORD line_number{}; 18 | DWORD64 module_displacement{}; 19 | DWORD64 symbol_displacement{}; 20 | DWORD line_displacement{}; 21 | bool in_line{false}; 22 | bool found{false}; 23 | bool frame_content_found{false}; 24 | DWORD64 address; 25 | DWORD64 stack; 26 | std::vector local_variables; 27 | std::vector parameters; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class dump_file_options; 6 | 7 | namespace dlg_help_utils 8 | { 9 | class mini_dump; 10 | } 11 | 12 | void dump_mini_dump_memory_list_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, 13 | dump_file_options const& options); 14 | void dump_mini_dump_memory64_list_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, 15 | dump_file_options const& options); 16 | void dump_mini_dump_memory_info_list_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 17 | void dump_mini_dump_system_memory_info_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 18 | -------------------------------------------------------------------------------- /DbgHelpUtils/memory_info_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils::memory_info_utils 6 | { 7 | // see https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants 8 | std::wstring memory_protection_options_to_string(uint32_t memory_protection_options); 9 | std::vector memory_protection_options_to_strings(uint32_t memory_protection_options); 10 | 11 | // see https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info 12 | std::wstring_view memory_state_to_string(uint32_t state); 13 | std::wstring_view memory_type_to_string(uint32_t type); 14 | 15 | std::wstring system_memory_info_flags_to_string(uint16_t flags); 16 | std::vector system_memory_info_flags_to_strings(uint16_t flags); 17 | } 18 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread_ex.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_thread_ex.h" 2 | 3 | #include "mini_dump.h" 4 | #include "thread_names_list_stream.h" 5 | 6 | namespace dlg_help_utils 7 | { 8 | stream_thread_ex::stream_thread_ex(mini_dump const& dump, MINIDUMP_THREAD_EX const& thread, 9 | thread_names_list_stream const& names_list) 10 | : thread_{thread} 11 | , thread_name_{names_list.get_thread_name_for_thread_id(thread.ThreadId)} 12 | { 13 | if (thread_.Stack.Memory.Rva != 0) 14 | { 15 | stack_ = dump.rva32(thread_.Stack.Memory); 16 | } 17 | if (thread_.BackingStore.Memory.Rva != 0) 18 | { 19 | backing_store_ = dump.rva32(thread_.BackingStore.Memory); 20 | } 21 | thread_context_ = stream_thread_context{dump, thread_.ThreadContext}; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DbgHelpUtils/system_module_list.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | class unloaded_module_list_stream; 10 | class module_list_stream; 11 | } 12 | 13 | namespace dlg_help_utils::heap 14 | { 15 | class system_module_list 16 | { 17 | public: 18 | explicit system_module_list(std::vector const& system_modules_names); 19 | system_module_list(); 20 | 21 | [[nodiscard]] bool is_system_module(std::wstring const& module_name) const; 22 | [[nodiscard]] std::unordered_set generate_system_module_bases(module_list_stream const& module_list, unloaded_module_list_stream const& unloaded_module_list) const; 23 | 24 | private: 25 | std::set system_modules_names_; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /CMake/DefaultFortran.cmake: -------------------------------------------------------------------------------- 1 | include("${CMAKE_CURRENT_LIST_DIR}/Default.cmake") 2 | 3 | set_config_specific_property("OUTPUT_DIRECTORY" "${CMAKE_CURRENT_SOURCE_DIR}$<$>:/${CMAKE_VS_PLATFORM_NAME}>/${PROPS_CONFIG}") 4 | 5 | get_target_property(${PROPS_TARGET}_BINARY_DIR ${PROPS_TARGET} BINARY_DIR) 6 | set(DEFAULT_FORTRAN_MODULES_DIR "${${PROPS_TARGET}_BINARY_DIR}/${PROPS_TARGET}.Modules.dir") 7 | set_target_properties(${PROPS_TARGET} PROPERTIES Fortran_MODULE_DIRECTORY ${DEFAULT_FORTRAN_MODULES_DIR}) 8 | 9 | if(${CMAKE_GENERATOR} MATCHES "Visual Studio") 10 | # Hack for visual studio generator (https://gitlab.kitware.com/cmake/cmake/issues/19552) 11 | add_custom_command(TARGET ${PROPS_TARGET} PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/${CMAKE_CFG_INTDIR}) 12 | endif() -------------------------------------------------------------------------------- /DbgHelpUtils/stream_handle_object_information.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | #include 7 | 8 | namespace dlg_help_utils 9 | { 10 | class stream_handle_object_information 11 | { 12 | public: 13 | explicit stream_handle_object_information(MINIDUMP_HANDLE_OBJECT_INFORMATION const& info); 14 | 15 | MINIDUMP_HANDLE_OBJECT_INFORMATION const* operator->() const { return &info_; } 16 | 17 | [[nodiscard]] void const* data() const 18 | { 19 | return reinterpret_cast(&info_) + sizeof(MINIDUMP_HANDLE_OBJECT_INFORMATION); 20 | } 21 | 22 | private: 23 | MINIDUMP_HANDLE_OBJECT_INFORMATION const& info_; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /DbgHelpUtils/exit_scope.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | template 8 | class scope_exit 9 | { 10 | public: 11 | scope_exit(F&& value) 12 | : value_{std::forward(value)} 13 | { 14 | } 15 | 16 | ~scope_exit() 17 | { 18 | value_(); 19 | } 20 | 21 | scope_exit(scope_exit const&) = delete; 22 | scope_exit(scope_exit&&) = delete; 23 | 24 | scope_exit& operator=(scope_exit const&) = delete; 25 | scope_exit& operator=(scope_exit&&) = delete; 26 | 27 | private: 28 | F value_; 29 | }; 30 | 31 | template 32 | auto make_scope_exit(F&& value) 33 | { 34 | return scope_exit(std::forward(value)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /DbgHelpUtils/global_symbol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "memory_range.h" 3 | #include "mini_dump_memory_stream.h" 4 | #include "symbol_type_info.h" 5 | 6 | namespace dlg_help_utils::stream_stack_dump 7 | { 8 | class mini_dump_memory_walker; 9 | } 10 | 11 | namespace dlg_help_utils::process 12 | { 13 | class global_symbol 14 | { 15 | public: 16 | global_symbol(stream_stack_dump::mini_dump_memory_walker const& walker, dbg_help::symbol_type_info symbol_info); 17 | 18 | [[nodiscard]] dbg_help::symbol_type_info const& symbol_type() const { return symbol_info_; } 19 | [[nodiscard]] mini_dump_memory_stream stream() const; 20 | 21 | [[nodiscard]] memory_range variable_memory_range() const; 22 | 23 | private: 24 | stream_stack_dump::mini_dump_memory_walker const* walker_; 25 | dbg_help::symbol_type_info symbol_info_; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_thread_stack_entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mini_dump_memory_stream.h" 3 | #include "process_heap_graph_node.h" 4 | 5 | namespace dlg_help_utils::heap::allocation_graph 6 | { 7 | 8 | class process_heap_graph_thread_stack_entry : public process_heap_graph_node 9 | { 10 | public: 11 | process_heap_graph_thread_stack_entry(mini_dump_memory_stream stack_stream, uint32_t thread_id, std::wstring thread_name); 12 | 13 | [[nodiscard]] mini_dump_memory_stream stack_stream() const { return stack_stream_; } 14 | [[nodiscard]] uint32_t thread_id() const { return thread_id_; } 15 | [[nodiscard]] std::wstring const& thread_name() const { return thread_name_; } 16 | 17 | private: 18 | mini_dump_memory_stream stack_stream_; 19 | uint32_t thread_id_; 20 | std::wstring thread_name_; 21 | }; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | #include "stream_thread_name.h" 8 | 9 | namespace dlg_help_utils 10 | { 11 | class thread_names_list_stream; 12 | 13 | class stream_thread_info 14 | { 15 | public: 16 | explicit stream_thread_info(MINIDUMP_THREAD_INFO const& thread_info, 17 | thread_names_list_stream const& names_list); 18 | 19 | MINIDUMP_THREAD_INFO const* operator->() const { return &thread_info_; } 20 | [[nodiscard]] std::wstring_view const& thread_name() const { return thread_name_.name(); } 21 | 22 | private: 23 | MINIDUMP_THREAD_INFO const& thread_info_; 24 | stream_thread_name thread_name_; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread_name.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | #include 5 | 6 | // ReSharper disable once CppUnusedIncludeDirective 7 | #include 8 | 9 | namespace dlg_help_utils 10 | { 11 | class mini_dump; 12 | 13 | class stream_thread_name 14 | { 15 | public: 16 | stream_thread_name() = default; 17 | explicit stream_thread_name(mini_dump const& dump, MINIDUMP_THREAD_NAME const& thread); 18 | 19 | [[nodiscard]] bool is_valid() const { return is_valid_; } 20 | MINIDUMP_THREAD_NAME const* operator->() const { return thread_; } 21 | [[nodiscard]] std::wstring_view const& name() const { return name_; } 22 | 23 | private: 24 | bool is_valid_{false}; 25 | MINIDUMP_THREAD_NAME const* thread_{nullptr}; 26 | std::wstring_view name_; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #ignore thumbnails created by windows 2 | Thumbs.db 3 | #Ignore files build by Visual Studio 4 | *.user 5 | *.aps 6 | *.pch 7 | *.vspscc 8 | *_i.c 9 | *_p.c 10 | *.ncb 11 | *.suo 12 | *.bak 13 | *.cache 14 | *.ilk 15 | *.log 16 | [Bb]in 17 | [Dd]ebug*/ 18 | *.sbr 19 | obj/ 20 | [Rr]elease*/ 21 | _ReSharper*/ 22 | *.obj 23 | *.exe 24 | *.pdb 25 | *.tlb 26 | *.tlh 27 | *.lib 28 | [Tt]est[Rr]esult* 29 | [Bb]uild[Ll]og.* 30 | ipch 31 | testCaseCollection.xml 32 | *.opensdf 33 | *.sdf 34 | *.opendb 35 | *.db 36 | .vs/ 37 | .vscode/ 38 | /packages 39 | vcpkg_installed 40 | /*.dll 41 | /CrashDumps 42 | /failed 43 | /vs2022x64DebugCrashDumps 44 | /vs2022x64ReleaseCrashDumps 45 | /vs2022x86DebugCrashDumps 46 | /vs2022x86ReleaseCrashDumps 47 | /vs2019x64DebugCrashDumps 48 | /vs2019x64ReleaseCrashDumps 49 | /vs2019x86DebugCrashDumps 50 | /vs2019x86ReleaseCrashDumps 51 | /report.log 52 | /ReportVs2019.log 53 | /ReportVs2022.log 54 | /build 55 | -------------------------------------------------------------------------------- /DbgHelpUtils/system_memory_info_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "system_memory_info_stream.h" 2 | 3 | #include "mini_dump.h" 4 | #include "string_stream.h" 5 | 6 | using namespace std::string_view_literals; 7 | 8 | namespace dlg_help_utils 9 | { 10 | system_memory_info_stream::system_memory_info_stream(mini_dump const& dump, size_t const index) 11 | { 12 | index_ = index; 13 | auto const* entry = dump.find_stream_type(SystemMemoryInfoStream, index_); 14 | if (entry == nullptr) 15 | { 16 | return; 17 | } 18 | 19 | auto const* data = dump.rva32(entry->Location); 20 | found_ = true; 21 | 22 | if (entry->Location.DataSize >= sizeof(MINIDUMP_SYSTEM_MEMORY_INFO_1)) 23 | { 24 | system_memory_info_version_ = 1; 25 | system_memory_info_ = static_cast(data); 26 | is_valid_ = true; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /DbgHelpUtils/pe_file_memory_mapping.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "pe_file.h" 5 | 6 | namespace dlg_help_utils 7 | { 8 | class pe_file_memory_mapping 9 | { 10 | public: 11 | pe_file_memory_mapping() = default; 12 | 13 | [[nodiscard]] bool is_pe_file_loaded(uint64_t address) const; 14 | void load_pe_file(std::wstring const& path, uint64_t module_base); 15 | void unload_pe_file(uint64_t module_base); 16 | 17 | [[nodiscard]] void const* find_address_range(uint64_t address, uint64_t length) const; 18 | [[nodiscard]] void const* find_any_address_range(uint64_t address, uint64_t& length) const; 19 | 20 | private: 21 | [[nodiscard]] std::map::const_iterator find_loaded_pe_file(uint64_t address) const; 22 | 23 | private: 24 | std::map loaded_pe_files_; 25 | std::map loaded_module_range_; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /DbgHelpUtils/exception_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | #include "stream_thread_context.h" 8 | 9 | namespace dlg_help_utils 10 | { 11 | class mini_dump; 12 | 13 | class exception_stream 14 | { 15 | public: 16 | explicit exception_stream(mini_dump const& dump, size_t index = 0); 17 | 18 | [[nodiscard]] bool found() const { return found_; } 19 | [[nodiscard]] size_t index() const { return index_; } 20 | [[nodiscard]] MINIDUMP_EXCEPTION_STREAM const& exception() const { return *exception_; } 21 | [[nodiscard]] stream_thread_context const& thread_context() const { return thread_context_; } 22 | 23 | private: 24 | bool found_{false}; 25 | size_t index_{}; 26 | MINIDUMP_EXCEPTION_STREAM const* exception_{nullptr}; 27 | stream_thread_context thread_context_{}; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /DbgHelpUtils/string_conversation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils::string_conversation 6 | { 7 | // convert UTF-8 string to wstring 8 | std::wstring utf8_to_wstring(const char* str); 9 | std::wstring utf8_to_wstring(std::string_view const& str); 10 | 11 | // convert wstring to UTF-8 string 12 | std::string wstring_to_utf8(std::wstring_view const& str); 13 | 14 | // convert ACP string to wstring 15 | std::wstring acp_to_wstring(std::string_view const& str); 16 | 17 | // convert code page string to wstring 18 | std::tuple code_page_string_to_wstring(char const* str, size_t length, uint32_t code_page); 19 | std::tuple to_code_page_string(wchar_t const* str, size_t length, uint32_t code_page); 20 | } 21 | 22 | inline std::wstring to_wstring(std::wstring_view const& str) 23 | { 24 | return std::wstring{str.data(), str.length()}; 25 | } 26 | -------------------------------------------------------------------------------- /DbgHelpUtils/global_symbols.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "sym_tag_enum.h" 7 | 8 | namespace dlg_help_utils::dbg_help 9 | { 10 | class symbol_type_info; 11 | } 12 | 13 | namespace dlg_help_utils::stream_stack_dump 14 | { 15 | class mini_dump_memory_walker; 16 | } 17 | 18 | namespace dlg_help_utils::process 19 | { 20 | class global_symbol; 21 | 22 | class global_symbols 23 | { 24 | public: 25 | global_symbols(stream_stack_dump::mini_dump_memory_walker const& walker, std::wstring const& match_pattern = {}); 26 | 27 | [[nodiscard]] std::experimental::generator all_symbols() const; 28 | 29 | private: 30 | static bool is_variable_symbol(dbg_help::sym_tag_enum tag); 31 | 32 | private: 33 | stream_stack_dump::mini_dump_memory_walker const* walker_; 34 | std::vector symbols_; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_thread_context_entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "process_heap_graph_node.h" 6 | 7 | namespace dlg_help_utils::heap::allocation_graph 8 | { 9 | class process_heap_graph_thread_context_entry : public process_heap_graph_node 10 | { 11 | public: 12 | process_heap_graph_thread_context_entry(CV_HREG_e register_type, uint64_t register_data, uint32_t thread_id, std::wstring thread_name); 13 | 14 | [[nodiscard]] CV_HREG_e register_type() const { return register_type_; } 15 | [[nodiscard]] uint64_t register_data() const { return register_data_; } 16 | [[nodiscard]] uint32_t thread_id() const { return thread_id_; } 17 | [[nodiscard]] std::wstring const& thread_name() const { return thread_name_; } 18 | 19 | private: 20 | CV_HREG_e register_type_; 21 | uint64_t register_data_; 22 | uint32_t thread_id_; 23 | std::wstring thread_name_; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /DbgHelpUtils/global_symbol.cpp: -------------------------------------------------------------------------------- 1 | #include "global_symbol.h" 2 | 3 | #include "mini_dump_memory_walker.h" 4 | 5 | namespace dlg_help_utils::process 6 | { 7 | global_symbol::global_symbol(stream_stack_dump::mini_dump_memory_walker const& walker, dbg_help::symbol_type_info symbol_info) 8 | : walker_{&walker} 9 | , symbol_info_{std::move(symbol_info)} 10 | { 11 | } 12 | 13 | mini_dump_memory_stream global_symbol::stream() const 14 | { 15 | auto const address = symbol_type().address(); 16 | if(auto const length = symbol_type().length(); address.has_value() && length.has_value()) 17 | { 18 | return walker_->get_process_memory_stream(address.value(), length.value()); 19 | } 20 | 21 | return {}; 22 | } 23 | 24 | memory_range global_symbol::variable_memory_range() const 25 | { 26 | auto const start = symbol_type().address().value_or(0); 27 | return {start, start + symbol_type().length().value_or(0) }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ValidateHeapEntries/symbol_engine_ui.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "DbgHelpUtils/i_symbol_load_callback.h" 3 | #include "DbgHelpUtils/null_stream.h" 4 | 5 | class symbol_engine_ui : public dlg_help_utils::dbg_help::i_symbol_load_callback 6 | { 7 | public: 8 | symbol_engine_ui(bool no_output); 9 | 10 | [[nodiscard]] bool deferred_symbol_load_cancel(std::wstring_view const& module_name) override; 11 | void deferred_symbol_load_partial(std::wstring_view const& module_name) override; 12 | void start_download(std::wstring_view const& module_name) override; 13 | void download_percent(unsigned percent) override; 14 | void download_complete() override; 15 | [[nodiscard]] std::wostream& log_stream() const override; 16 | [[nodiscard]] bool symbol_load_debug() const override; 17 | [[nodiscard]] bool symbol_load_debug_memory() const override; 18 | 19 | private: 20 | bool no_output_; 21 | std::wstring module_; 22 | std::wstring last_percent_; 23 | mutable null_stream null_stream_; 24 | }; 25 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_comment.cpp: -------------------------------------------------------------------------------- 1 | #include "dump_mini_dump_comment.h" 2 | 3 | #include "DbgHelpUtils/comment_stream_a.h" 4 | #include "DbgHelpUtils/comment_stream_w.h" 5 | #include "DbgHelpUtils/mini_dump.h" 6 | 7 | using namespace std; 8 | using namespace dlg_help_utils; 9 | 10 | void dump_mini_dump_comment_w_stream_data(std::wostream& log, mini_dump const& mini_dump, size_t const index) 11 | { 12 | comment_stream_w const comment{mini_dump, index}; 13 | 14 | if (!comment.found()) 15 | { 16 | log << L"CommentStreamW not found!\n"; 17 | return; 18 | } 19 | 20 | log << comment.comment() << L'\n'; 21 | log << L'\n'; 22 | } 23 | 24 | void dump_mini_dump_comment_a_stream_data(std::wostream& log, mini_dump const& mini_dump, size_t const index) 25 | { 26 | comment_stream_a const comment{mini_dump, index}; 27 | 28 | if (!comment.found()) 29 | { 30 | log << L"CommentStreamA not found!\n"; 31 | return; 32 | } 33 | 34 | log << comment.comment() << L'\n'; 35 | log << L'\n'; 36 | } 37 | -------------------------------------------------------------------------------- /DbgHelpUtils/global_symbols.cpp: -------------------------------------------------------------------------------- 1 | #include "global_symbols.h" 2 | 3 | #include "global_symbol.h" 4 | #include "mini_dump_memory_walker.h" 5 | #include "symbol_engine.h" 6 | 7 | namespace dlg_help_utils::process 8 | { 9 | global_symbols::global_symbols(stream_stack_dump::mini_dump_memory_walker const& walker, std::wstring const& match_pattern) 10 | : walker_{&walker} 11 | , symbols_{walker.symbol_walk(match_pattern)} 12 | { 13 | } 14 | 15 | std::experimental::generator global_symbols::all_symbols() const 16 | { 17 | for (auto const& symbol : symbols_) 18 | { 19 | if(auto tag = symbol.sym_tag(); is_variable_symbol(tag.value_or(dbg_help::sym_tag_enum::Null))) 20 | { 21 | co_yield global_symbol{*walker_, symbol}; 22 | } 23 | } 24 | } 25 | 26 | bool global_symbols::is_variable_symbol(dbg_help::sym_tag_enum const tag) 27 | { 28 | return tag == dbg_help::sym_tag_enum::PublicSymbol || tag == dbg_help::sym_tag_enum::Data; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_symbol_entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "process_heap_graph_node.h" 5 | #include "symbol_type_info.h" 6 | 7 | namespace dlg_help_utils::heap::allocation_graph 8 | { 9 | class process_heap_graph_symbol_entry : public process_heap_graph_node 10 | { 11 | public: 12 | process_heap_graph_symbol_entry(uint64_t address, dbg_help::symbol_type_info symbol_type, std::optional thread_id = std::nullopt, std::wstring thread_name = {}); 13 | 14 | [[nodiscard]] uint64_t address() const { return address_; } 15 | [[nodiscard]] dbg_help::symbol_type_info const& symbol_type() const { return symbol_type_; } 16 | [[nodiscard]] std::optional thread_id() const { return thread_id_; } 17 | [[nodiscard]] std::wstring const& thread_name() const { return thread_name_; } 18 | 19 | private: 20 | uint64_t address_; 21 | dbg_help::symbol_type_info symbol_type_; 22 | std::optional thread_id_; 23 | std::wstring thread_name_; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /DbgHelpUtils/memory_info_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | #include 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | class mini_dump; 10 | 11 | class memory_info_list_stream 12 | { 13 | public: 14 | explicit memory_info_list_stream(mini_dump const& dump, size_t index = 0); 15 | 16 | [[nodiscard]] bool found() const { return found_; } 17 | [[nodiscard]] bool is_valid() const { return is_valid_; } 18 | [[nodiscard]] size_t index() const { return index_; } 19 | [[nodiscard]] ULONG64 size() const { return memory_info_list_->NumberOfEntries; } 20 | 21 | [[nodiscard]] std::experimental::generator list() const; 22 | 23 | private: 24 | bool found_{false}; 25 | bool is_valid_{false}; 26 | size_t index_; 27 | MINIDUMP_MEMORY_INFO_LIST const* memory_info_list_{nullptr}; 28 | MINIDUMP_MEMORY_INFO const* list_{nullptr}; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | #include "cv_info_pdb70.h" 8 | #include "stream_module_name.h" 9 | 10 | namespace dlg_help_utils 11 | { 12 | class mini_dump; 13 | 14 | class stream_module : public stream_module_name 15 | { 16 | public: 17 | explicit stream_module(mini_dump const& dump, MINIDUMP_MODULE const& module); 18 | 19 | MINIDUMP_MODULE const* operator->() const { return &module_; } 20 | [[nodiscard]] void const* cv_record() const { return cv_record_; } 21 | [[nodiscard]] cv_info_pdb70 const& pdb_info() const { return pdb_info_; } 22 | [[nodiscard]] void const* misc_record() const { return misc_record_; } 23 | 24 | private: 25 | MINIDUMP_MODULE const& module_; 26 | void const* cv_record_{nullptr}; 27 | cv_info_pdb70 pdb_info_{}; 28 | void const* misc_record_{nullptr}; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /DbgHelpUtils/lfh_subsegment_location_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "lfh_subsegment_location_utils.h" 2 | 3 | #include 4 | 5 | using namespace std::string_view_literals; 6 | 7 | namespace 8 | { 9 | 10 | using dlg_help_utils::lfh_subsegment_location_utils::location; 11 | 12 | std::unordered_map g_location_descriptions = 13 | { 14 | {static_cast(location::available_subsegment_list), L"AvailableSubsegmentList"sv}, 15 | {static_cast(location::full_subsegment_list ), L"FullSubsegmentList"sv}, 16 | {static_cast(location::retiring_subsegment_list ), L"RetiringSubsegmentList"sv}, 17 | }; 18 | } 19 | 20 | namespace dlg_help_utils::lfh_subsegment_location_utils 21 | { 22 | std::wstring_view dump_page_range_flags_to_string(location value) 23 | { 24 | if (auto const it = g_location_descriptions.find(static_cast(value)); it != g_location_descriptions.end()) 25 | { 26 | return it->second; 27 | } 28 | 29 | return L"unknown"sv; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /DbgHelpUtils/string_compare.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace dlg_help_utils::string_compare 5 | { 6 | [[nodiscard]] inline bool iequals(std::wstring_view const& str1, std::wstring_view const& str2) 7 | { 8 | if(str1.length() != str2.length()) 9 | { 10 | return false; 11 | } 12 | 13 | return _wcsnicmp(str1.data(), str2.data(), str1.length()) == 0; 14 | } 15 | 16 | [[nodiscard]] inline bool equals(std::wstring_view const& str1, std::wstring_view const& str2) 17 | { 18 | if(str1.length() != str2.length()) 19 | { 20 | return false; 21 | } 22 | 23 | return wcsncmp(str1.data(), str2.data(), str1.length()) == 0; 24 | } 25 | 26 | [[nodiscard]] inline bool i_ends_with(std::wstring_view const& str1, std::wstring_view const& str2) 27 | { 28 | if(str1.length() < str2.length()) 29 | { 30 | return false; 31 | } 32 | 33 | return _wcsnicmp(str1.data() + str1.length() - str2.length(), str2.data(), str2.length()) == 0; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_heap_entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include 4 | 5 | #include "process_heap_entry.h" 6 | #include "process_heap_graph_node.h" 7 | 8 | namespace dlg_help_utils::heap::allocation_graph 9 | { 10 | enum class process_heap_graph_heap_entry_type 11 | { 12 | allocation, 13 | system_allocation, 14 | }; 15 | 16 | class process_heap_graph_heap_entry : public process_heap_graph_node 17 | { 18 | public: 19 | process_heap_graph_heap_entry(process_heap_entry heap_entry, process_heap_graph_heap_entry_type type); 20 | 21 | [[nodiscard]] process_heap_entry const& heap_entry() const { return heap_entry_; } 22 | 23 | std::strong_ordering operator<=>(process_heap_graph_heap_entry const& b) const 24 | { 25 | return get_sort_key() <=> b.get_sort_key(); 26 | } 27 | 28 | private: 29 | [[nodiscard]] uint64_t get_sort_key() const { return heap_entry().user_address(); } 30 | 31 | private: 32 | process_heap_entry heap_entry_; 33 | }; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_global_variable_entry.cpp: -------------------------------------------------------------------------------- 1 | #include "process_heap_graph_global_variable_entry.h" 2 | 3 | #include 4 | 5 | using namespace std::string_literals; 6 | 7 | namespace dlg_help_utils::heap::allocation_graph 8 | { 9 | process_heap_graph_global_variable_entry::process_heap_graph_global_variable_entry(process::global_symbol variable, std::optional base_heap_entry) 10 | : process_heap_graph_node{variable.symbol_type().address().value_or(0), process_heap_graph_node_type::root} 11 | , variable_{std::move(variable)} 12 | , name_{generate_global_variable_name()} 13 | , base_heap_entry_{std::move(base_heap_entry)} 14 | { 15 | } 16 | 17 | std::wstring process_heap_graph_global_variable_entry::generate_global_variable_name() const 18 | { 19 | auto const name = variable().symbol_type().name(); 20 | if(!name.has_value()) 21 | { 22 | return std::format(L"", variable().symbol_type().sym_index()); 23 | } 24 | return std::wstring{name.value()}; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DbgHelpUtils/handle_operation_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | #include 5 | #include 6 | #include 7 | 8 | namespace dlg_help_utils 9 | { 10 | class mini_dump; 11 | 12 | class handle_operation_list_stream 13 | { 14 | public: 15 | explicit handle_operation_list_stream(mini_dump const& dump, size_t index = 0); 16 | 17 | [[nodiscard]] bool found() const { return found_; } 18 | [[nodiscard]] bool is_valid() const { return is_valid_; } 19 | [[nodiscard]] size_t index() const { return index_; } 20 | [[nodiscard]] ULONG64 size() const { return handle_operation_list_->NumberOfEntries; } 21 | 22 | [[nodiscard]] std::experimental::generator list() const; 23 | 24 | private: 25 | bool found_{false}; 26 | bool is_valid_{false}; 27 | size_t index_; 28 | MINIDUMP_HANDLE_OPERATION_LIST const* handle_operation_list_{nullptr}; 29 | AVRF_HANDLE_OPERATION const* list_{nullptr}; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /DbgHelpUtils/system_memory_info_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | class mini_dump; 10 | 11 | class system_memory_info_stream 12 | { 13 | public: 14 | explicit system_memory_info_stream(mini_dump const& dump, size_t index = 0); 15 | 16 | [[nodiscard]] bool found() const { return found_; } 17 | [[nodiscard]] bool is_valid() const { return is_valid_; } 18 | [[nodiscard]] size_t index() const { return index_; } 19 | [[nodiscard]] size_t system_memory_info_version() const { return system_memory_info_version_; } 20 | 21 | [[nodiscard]] MINIDUMP_SYSTEM_MEMORY_INFO_1 const& system_memory_misc_info() const 22 | { 23 | return *system_memory_info_; 24 | } 25 | 26 | private: 27 | bool found_{false}; 28 | bool is_valid_{false}; 29 | size_t index_{}; 30 | size_t system_memory_info_version_{}; 31 | MINIDUMP_SYSTEM_MEMORY_INFO_1 const* system_memory_info_{nullptr}; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Shane Powell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /DbgHelpUtils/token_info_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | #include 5 | #include 6 | 7 | #include "stream_token_info.h" 8 | 9 | namespace dlg_help_utils 10 | { 11 | class mini_dump; 12 | 13 | class token_info_list_stream 14 | { 15 | public: 16 | explicit token_info_list_stream(mini_dump const& dump, size_t index = 0); 17 | 18 | [[nodiscard]] bool found() const { return found_; } 19 | [[nodiscard]] bool is_valid() const { return is_valid_; } 20 | [[nodiscard]] size_t index() const { return index_; } 21 | [[nodiscard]] ULONG64 size() const { return token_info_list_->TokenListEntries; } 22 | 23 | [[nodiscard]] std::experimental::generator list() const; 24 | 25 | private: 26 | bool found_{false}; 27 | bool is_valid_{false}; 28 | size_t index_; 29 | void const* end_list_{nullptr}; 30 | MINIDUMP_TOKEN_INFO_LIST const* token_info_list_{nullptr}; 31 | MINIDUMP_TOKEN_INFO_HEADER const* list_{nullptr}; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | class dump_file_options; 7 | 8 | namespace dlg_help_utils 9 | { 10 | class cache_manager; 11 | class mini_dump; 12 | } 13 | 14 | bool process_dump_file(std::wostream& log, std::wstring const& file_name, std::wstring const& base_diff_file_name, dump_file_options & options); 15 | void dump_mini_dump_header(std::wostream& log, dlg_help_utils::mini_dump const& dump_file, dump_file_options const& options); 16 | void process_invalid_user_mode_dump(std::wostream& log, dlg_help_utils::mini_dump const& dump_file, dump_file_options const& options); 17 | void process_x86_kernel_memory_dump(std::wostream& log, dlg_help_utils::mini_dump const& dump_file, dump_file_options const& options); 18 | void process_x64_kernel_memory_dump(std::wostream& log, dlg_help_utils::mini_dump const& dump_file, dump_file_options const& options); 19 | void process_user_mode_dump(std::wostream& log, dlg_help_utils::mini_dump const& dump_file, std::unique_ptr const& base_diff_dump, dump_file_options & options); 20 | void display_version_information(std::wostream& log); 21 | -------------------------------------------------------------------------------- /MiniDumper/symbol_engine_ui.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | 4 | #include "dump_file_options.h" 5 | #include "DbgHelpUtils/i_symbol_load_callback.h" 6 | #include "DbgHelpUtils/null_stream.h" 7 | 8 | class symbol_engine_ui : public dlg_help_utils::dbg_help::i_symbol_load_callback 9 | { 10 | public: 11 | explicit symbol_engine_ui(dump_file_options const& options); 12 | 13 | [[nodiscard]] bool deferred_symbol_load_cancel(std::wstring_view const& module_name) override; 14 | void deferred_symbol_load_partial(std::wstring_view const& module_name) override; 15 | void start_download(std::wstring_view const& module_name) override; 16 | void download_percent(unsigned percent) override; 17 | void download_complete() override; 18 | [[nodiscard]] std::wostream& log_stream() const override; 19 | [[nodiscard]] bool symbol_load_debug() const override; 20 | [[nodiscard]] bool symbol_load_debug_memory() const override; 21 | 22 | private: 23 | dump_file_options const& options_; 24 | std::wstring module_; 25 | std::wstring last_percent_; 26 | mutable null_stream null_stream_; 27 | }; 28 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_function_entry.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_function_entry.h" 2 | 3 | namespace dlg_help_utils 4 | { 5 | stream_function_entry::stream_function_entry(size_t const index, void const* function_entry, 6 | uint32_t const size_of_function_entry, 7 | function_table_entry_type const entry_type) 8 | : index_{index} 9 | , size_of_function_entry_{size_of_function_entry} 10 | , function_entry_{function_entry} 11 | , entry_type_{entry_type} 12 | , fpo_data_{ 13 | entry_type == function_table_entry_type::fpo_data ? static_cast(function_entry) : nullptr 14 | } 15 | , image_function_entry_{ 16 | entry_type == function_table_entry_type::image_function_entry 17 | ? static_cast(function_entry) 18 | : nullptr 19 | } 20 | , image_function_entry_64_{entry_type == function_table_entry_type::image_function_entry_64 ? static_cast(function_entry) : nullptr} 21 | { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DbgHelpUtils/symbol_type_info_cache.cpp: -------------------------------------------------------------------------------- 1 | #include "symbol_type_info_cache.h" 2 | 3 | namespace dlg_help_utils::dbg_help 4 | { 5 | void symbol_type_info_cache::create_cached_symbol_type_info(HANDLE const process, DWORD64 const module_base, ULONG const type_index, std::wstring_view const export_name) 6 | { 7 | std::ignore = get_or_create_symbol_type_info(process, module_base, type_index, export_name); 8 | } 9 | 10 | std::optional symbol_type_info_cache::get_symbol_type_info(HANDLE const process, DWORD64 const module_base, ULONG const type_index) const 11 | { 12 | auto const it = cache_.find(symbol_type_info{symbol_type_info::key_compare_only{}, process, module_base, type_index}); 13 | if(it == cache_.end()) 14 | { 15 | return std::nullopt; 16 | } 17 | 18 | return *it; 19 | } 20 | 21 | symbol_type_info symbol_type_info_cache::get_or_create_symbol_type_info(HANDLE const process, DWORD64 const module_base, ULONG const type_index, std::wstring_view const export_name) 22 | { 23 | return *cache_.insert(symbol_type_info{*this, process, module_base, type_index, export_name}).first; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_names_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | 4 | // ReSharper disable once CppUnusedIncludeDirective 5 | #include "windows_setup.h" 6 | #include 7 | #include 8 | 9 | #include "stream_thread_name.h" 10 | 11 | namespace dlg_help_utils 12 | { 13 | class mini_dump; 14 | 15 | class thread_names_list_stream 16 | { 17 | public: 18 | explicit thread_names_list_stream(mini_dump const& dump, size_t index = 0); 19 | 20 | [[nodiscard]] bool found() const { return found_; } 21 | [[nodiscard]] size_t index() const { return index_; } 22 | [[nodiscard]] MINIDUMP_THREAD_NAME_LIST const& thread_names_list() const { return *thread_name_list_; } 23 | 24 | [[nodiscard]] std::experimental::generator list() const; 25 | [[nodiscard]] stream_thread_name get_thread_name_for_thread_id(uint32_t thread_id) const; 26 | 27 | private: 28 | mini_dump const& dump_; 29 | bool found_{false}; 30 | size_t index_; 31 | MINIDUMP_THREAD_NAME_LIST const* thread_name_list_{nullptr}; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /DbgHelpUtils/page_range_flags_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace dlg_help_utils::page_range_flags_utils 7 | { 8 | enum class page_range_flags : uint16_t { 9 | PAGE_RANGE_FLAGS_LFH_SUBSEGMENT = 0x01, 10 | PAGE_RANGE_FLAGS_COMMITTED = 0x02, 11 | PAGE_RANGE_FLAGS_ALLOCATED = 0x04, 12 | PAGE_RANGE_FLAGS_FIRST = 0x08, 13 | PAGE_RANGE_FLAGS_VS_SUBSEGMENT = 0x20, 14 | 15 | PAGE_RANGE_FREE = PAGE_RANGE_FLAGS_COMMITTED, 16 | PAGE_RANGE_VARIABLE_ALLOC = PAGE_RANGE_FLAGS_LFH_SUBSEGMENT | PAGE_RANGE_FLAGS_COMMITTED | PAGE_RANGE_FLAGS_ALLOCATED | PAGE_RANGE_FLAGS_FIRST, 17 | PAGE_RANGE_LFH_SUBSEGMENT = PAGE_RANGE_FLAGS_LFH_SUBSEGMENT | PAGE_RANGE_FLAGS_COMMITTED | PAGE_RANGE_FLAGS_FIRST, 18 | PAGE_RANGE_BACKEND_SUBSEGMENT = PAGE_RANGE_FLAGS_LFH_SUBSEGMENT | PAGE_RANGE_FLAGS_COMMITTED, 19 | }; 20 | 21 | std::wstring dump_page_range_flags_to_string(page_range_flags flags); 22 | std::vector dump_page_range_flags_to_strings(page_range_flags flags); 23 | 24 | std::wstring_view dump_page_range_to_string(page_range_flags value); 25 | } -------------------------------------------------------------------------------- /DbgHelpUtils/thread_info_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | #include 7 | 8 | #include "stream_thread_info.h" 9 | 10 | namespace dlg_help_utils 11 | { 12 | class mini_dump; 13 | 14 | class thread_info_list_stream 15 | { 16 | public: 17 | explicit thread_info_list_stream(mini_dump const& dump, size_t index = 0); 18 | 19 | [[nodiscard]] bool found() const { return found_; } 20 | [[nodiscard]] bool is_valid() const { return is_valid_; } 21 | [[nodiscard]] size_t index() const { return index_; } 22 | [[nodiscard]] ULONG64 size() const { return thread_info_list_->NumberOfEntries; } 23 | 24 | [[nodiscard]] std::experimental::generator list() const; 25 | 26 | private: 27 | mini_dump const& dump_; 28 | bool found_{false}; 29 | bool is_valid_{false}; 30 | size_t index_; 31 | MINIDUMP_THREAD_INFO_LIST const* thread_info_list_{nullptr}; 32 | MINIDUMP_THREAD_INFO const* list_{nullptr}; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_entry_reference.cpp: -------------------------------------------------------------------------------- 1 | #include "process_heap_entry_reference.h" 2 | 3 | #include "process_heap_graph_node.h" 4 | 5 | namespace dlg_help_utils::heap::allocation_graph 6 | { 7 | process_heap_entry_reference::process_heap_entry_reference(uint64_t const to_offset, uint64_t const to_pointer, uint64_t const from_offset, uint64_t const from_pointer, process_heap_graph_node const& heap_entry) 8 | : to_offset_{to_offset} 9 | , to_pointer_{to_pointer} 10 | , from_offset_{from_offset} 11 | , from_pointer_{from_pointer} 12 | , node_index_{heap_entry.index()} 13 | , variable_symbol_info_{std::nullopt} 14 | { 15 | } 16 | 17 | process_heap_entry_reference::process_heap_entry_reference(uint64_t const to_offset, uint64_t const to_pointer, uint64_t const from_offset, uint64_t const from_pointer, process_heap_graph_node const& heap_entry, graph_node_variable_symbol_reference_data const& variable_symbol_info) 18 | : to_offset_{to_offset} 19 | , to_pointer_{to_pointer} 20 | , from_offset_{from_offset} 21 | , from_pointer_{from_pointer} 22 | , node_index_{heap_entry.index()} 23 | , variable_symbol_info_{variable_symbol_info} 24 | { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_graph_global_variable_entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "global_symbol.h" 4 | #include "process_heap_graph_heap_entry.h" 5 | 6 | namespace dlg_help_utils::heap::allocation_graph 7 | { 8 | class process_heap_graph_global_variable_entry : public process_heap_graph_node 9 | { 10 | public: 11 | process_heap_graph_global_variable_entry(process::global_symbol variable, std::optional base_heap_entry); 12 | [[nodiscard]] process::global_symbol const& variable() const { return variable_; } 13 | [[nodiscard]] std::optional const& base_heap_entry() const { return base_heap_entry_; } 14 | 15 | std::strong_ordering operator<=>(process_heap_graph_global_variable_entry const& b) const 16 | { 17 | return get_sort_key() <=> b.get_sort_key(); 18 | } 19 | 20 | private: 21 | [[nodiscard]] std::wstring get_sort_key() const { return name_; } 22 | [[nodiscard]] std::wstring generate_global_variable_name() const; 23 | 24 | private: 25 | process::global_symbol variable_; 26 | std::wstring name_; 27 | std::optional base_heap_entry_; 28 | }; 29 | } -------------------------------------------------------------------------------- /DbgHelpUtils/cache_manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | 10 | class cache_manager 11 | { 12 | public: 13 | template 14 | [[nodiscard]] bool has_cache() const 15 | { 16 | return cache_.contains(std::type_index{typeid(T)}); 17 | } 18 | 19 | template 20 | [[nodiscard]] T& get_cache() 21 | { 22 | auto const key = std::type_index{typeid(T)}; 23 | auto it = cache_.find(key); 24 | if(it == cache_.end()) 25 | { 26 | cache_[key] = std::make_any(); 27 | it = cache_.find(key); 28 | } 29 | 30 | return std::any_cast(it->second); 31 | } 32 | 33 | template 34 | [[nodiscard]] T const& get_cache() const 35 | { 36 | auto const it = cache_.find(std::type_index{typeid(T)}); 37 | if(it == cache_.end()) 38 | { 39 | throw std::runtime_error{std::format("No cache found for cache type [{}]", typeid(T).name())}; 40 | } 41 | 42 | return std::any_cast(it->second); 43 | } 44 | 45 | private: 46 | std::unordered_map cache_; 47 | }; 48 | 49 | } -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_thread.h" 2 | 3 | 4 | #include "memory64_list_stream.h" 5 | #include "memory_list_stream.h" 6 | #include "mini_dump.h" 7 | #include "thread_names_list_stream.h" 8 | 9 | namespace dlg_help_utils 10 | { 11 | stream_thread::stream_thread(mini_dump const& dump, MINIDUMP_THREAD const& thread, 12 | thread_names_list_stream const& names_list, memory_list_stream const& memory_list, 13 | memory64_list_stream const& memory64_list) 14 | : thread_{thread} 15 | , thread_name_{names_list.get_thread_name_for_thread_id(thread.ThreadId)} 16 | { 17 | if (thread_.Stack.Memory.Rva != 0) 18 | { 19 | stack_ = dump.rva32(thread_.Stack.Memory); 20 | } 21 | else if (memory_list.found()) 22 | { 23 | stack_ = memory_list.find_address_range(thread_.Stack.StartOfMemoryRange, thread_.Stack.Memory.DataSize); 24 | } 25 | else if (memory64_list.found()) 26 | { 27 | stack_ = memory64_list.find_address_range(thread_.Stack.StartOfMemoryRange, thread_.Stack.Memory.DataSize); 28 | } 29 | 30 | thread_context_ = stream_thread_context{dump, thread_.ThreadContext}; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /DbgHelpUtils/cv_info_pdb70.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows_setup.h" 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | class cv_info_pdb70 8 | { 9 | public: 10 | cv_info_pdb70() = default; 11 | explicit cv_info_pdb70(void const* data, size_t length); 12 | 13 | [[nodiscard]] bool is_valid() const { return cv_ != nullptr && cv_->CvSignature == CV_SIGNATURE_RSDS; } 14 | [[nodiscard]] GUID const& get_signature() const { return cv_->Signature; } 15 | [[nodiscard]] DWORD get_age() const { return cv_->Age; } 16 | [[nodiscard]] std::wstring const& get_pdb_file_name() const { return pdb_file_name_; } 17 | 18 | private: 19 | // ReSharper disable CppInconsistentNaming 20 | // ReSharper disable once IdentifierTypo 21 | // ReSharper disable once CommentTypo 22 | static constexpr DWORD CV_SIGNATURE_RSDS{0x53445352}; // 'SDSR' 23 | 24 | struct CV_INFO_PDB70 25 | { 26 | DWORD CvSignature; 27 | GUID Signature; 28 | DWORD Age; 29 | BYTE PdbFileName[1]; 30 | }; 31 | 32 | // ReSharper restore CppInconsistentNaming 33 | 34 | CV_INFO_PDB70 const* cv_{nullptr}; 35 | std::wstring pdb_file_name_; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_vm_counters_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "process_vm_counters_stream.h" 2 | 3 | #include "mini_dump.h" 4 | #include "string_stream.h" 5 | 6 | using namespace std::string_view_literals; 7 | 8 | namespace dlg_help_utils 9 | { 10 | process_vm_counters_stream::process_vm_counters_stream(mini_dump const& dump, size_t const index) 11 | { 12 | index_ = index; 13 | auto const* entry = dump.find_stream_type(ProcessVmCountersStream, index_); 14 | if (entry == nullptr) 15 | { 16 | return; 17 | } 18 | 19 | auto const* data = dump.rva32(entry->Location); 20 | found_ = true; 21 | 22 | if (entry->Location.DataSize >= sizeof(MINIDUMP_PROCESS_VM_COUNTERS_1)) 23 | { 24 | process_vm_counters_version_ = 1; 25 | process_vm_counters_ = static_cast(data); 26 | is_valid_ = true; 27 | } 28 | else 29 | { 30 | return; 31 | } 32 | 33 | if (entry->Location.DataSize >= sizeof(MINIDUMP_PROCESS_VM_COUNTERS_2)) 34 | { 35 | process_vm_counters_version_ = 2; 36 | process_vm_counters_2_ = static_cast(data); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_ex_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | 4 | // ReSharper disable once CppUnusedIncludeDirective 5 | #include "windows_setup.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include "stream_thread_ex.h" 11 | 12 | namespace dlg_help_utils 13 | { 14 | class mini_dump; 15 | 16 | class thread_ex_list_stream 17 | { 18 | public: 19 | explicit thread_ex_list_stream(mini_dump const& dump, size_t index = 0); 20 | 21 | [[nodiscard]] bool found() const { return found_; } 22 | [[nodiscard]] size_t index() const { return index_; } 23 | [[nodiscard]] MINIDUMP_THREAD_EX_LIST const& thread_list() const { return *thread_list_; } 24 | 25 | [[nodiscard]] std::experimental::generator list() const; 26 | 27 | [[nodiscard]] std::optional find_thread(ULONG32 thread_id, 28 | thread_names_list_stream const& names_list) const; 29 | 30 | private: 31 | mini_dump const& dump_; 32 | bool found_{false}; 33 | size_t index_; 34 | MINIDUMP_THREAD_EX_LIST const* thread_list_{nullptr}; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_info_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "thread_info_utils.h" 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | #include 8 | 9 | #include "flags_string_utils.h" 10 | #include "stream_hex_dump.h" 11 | 12 | using namespace std::string_view_literals; 13 | 14 | namespace 15 | { 16 | std::map const dump_flag_masks = 17 | { 18 | {MINIDUMP_THREAD_INFO_ERROR_THREAD, L"Error Thread"sv}, 19 | {MINIDUMP_THREAD_INFO_WRITING_THREAD, L"Writing Thread"sv}, 20 | {MINIDUMP_THREAD_INFO_EXITED_THREAD, L"Exited Thread"sv}, 21 | {MINIDUMP_THREAD_INFO_INVALID_INFO, L"Invalid Info"sv}, 22 | {MINIDUMP_THREAD_INFO_INVALID_CONTEXT, L"Invalid Context"sv}, 23 | {MINIDUMP_THREAD_INFO_INVALID_TEB, L"Invalid TEB"sv}, 24 | }; 25 | } 26 | 27 | namespace dlg_help_utils::thread_info_utils 28 | { 29 | std::wstring dump_flags_to_string(uint32_t const dump_flags) 30 | { 31 | return flags_string_utils::generate_flags_string(dump_flags, dump_flag_masks); 32 | } 33 | 34 | std::vector dump_flags_to_strings(uint32_t const dump_flags) 35 | { 36 | return flags_string_utils::generate_flags_strings(dump_flags, dump_flag_masks); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /DbgHelpUtils/heap_match_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "heap_match_utils.h" 2 | 3 | #include "stream_utils.h" 4 | 5 | namespace dlg_help_utils::heap 6 | { 7 | block_range_match_result heap_match_utils::does_memory_match_to_range(uint64_t const user_address 8 | , size_units::base_16::bytes const user_size 9 | , uint64_t const block_address 10 | , size_units::base_16::bytes const block_size) 11 | { 12 | if(user_address == block_address && user_size == block_size) 13 | { 14 | return block_range_match_result::block_match; 15 | } 16 | 17 | if(user_address >= block_address && user_address + user_size.count() <= block_address + block_size.count()) 18 | { 19 | return block_range_match_result::block_contains; 20 | } 21 | 22 | if(block_address >= user_address && block_address + block_size.count() <= user_address + user_size.count()) 23 | { 24 | return block_range_match_result::user_contains_block; 25 | } 26 | 27 | if(user_address < block_address + block_size.count() && user_address + user_size.count() > block_address) 28 | { 29 | return block_range_match_result::block_partially_contains; 30 | } 31 | 32 | return block_range_match_result::block_no_match; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /DbgHelpUtils/locale_number_formatting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "windows_setup.h" 5 | #include 6 | 7 | #include "tagged_bool.h" 8 | 9 | namespace locale_formatting 10 | { 11 | namespace detail 12 | { 13 | NUMBERFMTW get_default_number_format_w(); 14 | } // namespace detail 15 | 16 | using floating_point_formatting_t = dlg_help_utils::tagged_bool; 17 | 18 | template 19 | std::wstring to_wstring(T value, floating_point_formatting_t const floating_point_formatting = floating_point_formatting_t{false}) 20 | { 21 | auto v = std::to_wstring(value); 22 | std::wstring rv; 23 | 24 | auto fmt = detail::get_default_number_format_w(); 25 | if (!floating_point_formatting) 26 | { 27 | fmt.NumDigits = 0; 28 | } 29 | 30 | // ReSharper disable once CppZeroConstantCanBeReplacedWithNullptr 31 | if (auto const size = GetNumberFormatEx(LOCALE_NAME_USER_DEFAULT, 0, v.c_str(), &fmt, nullptr, 0); size > 0) 32 | { 33 | rv.resize(static_cast(size) - 1); 34 | GetNumberFormatEx(LOCALE_NAME_USER_DEFAULT, 0, v.c_str(), &fmt, rv.data(), size); 35 | } 36 | 37 | return rv; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_app_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class dump_file_options; 6 | 7 | namespace dlg_help_utils 8 | { 9 | namespace dbg_help 10 | { 11 | class symbol_engine; 12 | } 13 | 14 | class mini_dump; 15 | } 16 | 17 | void dump_mini_dump_token_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, 18 | dump_file_options const& options); 19 | void dump_mini_dump_function_table_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, 20 | dump_file_options const& options); 21 | void dump_mini_dump_handle_operation_list_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, 22 | dump_file_options const& options, 23 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 24 | void dump_mini_dump_handle_data_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, 25 | dump_file_options const& options); 26 | void dump_mini_dump_ipt_trace_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 27 | -------------------------------------------------------------------------------- /DbgHelpUtils/time_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "time_utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace dlg_help_utils::time_utils 8 | { 9 | std::wstring to_local_time(time_t const timestamp) 10 | { 11 | tm local_tm{}; 12 | std::ignore = localtime_s(&local_tm, ×tamp); 13 | 14 | std::wostringstream oss; 15 | oss << std::put_time(&local_tm, L"%c %Z"); 16 | return std::move(oss).str(); 17 | } 18 | 19 | std::wstring to_utc_time(time_t const timestamp) 20 | { 21 | tm utc_tm{}; 22 | std::ignore = gmtime_s(&utc_tm, ×tamp); 23 | std::wostringstream oss; 24 | oss << std::put_time(&utc_tm, L"%c"); 25 | return std::move(oss).str(); 26 | } 27 | 28 | time_t filetime_to_time_t(FILETIME const ft) 29 | { 30 | ULARGE_INTEGER ull; 31 | ull.LowPart = ft.dwLowDateTime; 32 | ull.HighPart = ft.dwHighDateTime; 33 | return filetime_to_time_t(ull.QuadPart); 34 | } 35 | 36 | time_t filetime_to_time_t(uint64_t const ft) 37 | { 38 | return static_cast(ft / 10000000ULL - 11644473600ULL); 39 | } 40 | 41 | std::chrono::milliseconds duration_to_ms(uint64_t const duration) 42 | { 43 | return std::chrono::milliseconds{duration / 10000ULL}; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DbgHelpUtils/sym_tag_enum.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace dlg_help_utils::dbg_help 3 | { 4 | // ReSharper disable CppInconsistentNaming 5 | // ReSharper disable IdentifierTypo 6 | 7 | enum class sym_tag_enum 8 | { 9 | Null, 10 | Exe, 11 | Compiland, 12 | CompilandDetails, 13 | CompilandEnv, 14 | Function, 15 | Block, 16 | Data, 17 | Annotation, 18 | Label, 19 | PublicSymbol, 20 | UDT, 21 | Enum, 22 | FunctionType, 23 | PointerType, 24 | ArrayType, 25 | BaseType, 26 | Typedef, 27 | BaseClass, 28 | Friend, 29 | FunctionArgType, 30 | FuncDebugStart, 31 | FuncDebugEnd, 32 | UsingNamespace, 33 | VTableShape, 34 | VTable, 35 | Custom, 36 | Thunk, 37 | CustomType, 38 | ManagedType, 39 | Dimension, 40 | CallSite, 41 | InlineSite, 42 | BaseInterface, 43 | VectorType, 44 | MatrixType, 45 | HLSLType, 46 | Caller, 47 | Callee, 48 | Export, 49 | HeapAllocationSite, 50 | CoffGroup, 51 | Inlinee, 52 | Max 53 | }; 54 | 55 | // ReSharper restore IdentifierTypo 56 | // ReSharper restore CppInconsistentNaming 57 | } 58 | -------------------------------------------------------------------------------- /DbgHelpUtils/wide_runtime_error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "string_conversation.h" 5 | 6 | namespace dlg_help_utils::exceptions 7 | { 8 | class wide_runtime_error : public std::runtime_error 9 | { 10 | public: 11 | wide_runtime_error(std::wstring message) 12 | : runtime_error(string_conversation::wstring_to_utf8(message)) 13 | , message_{std::move(message)} 14 | { 15 | } 16 | 17 | wide_runtime_error(std::wstring const& message, std::exception const& e) 18 | : runtime_error(std::format("{0} : Inner Exception: {1}", string_conversation::wstring_to_utf8(message), e.what())) 19 | , message_{std::format(L"{0} : Inner Exception: {1}", message, string_conversation::utf8_to_wstring(e.what()))} 20 | { 21 | } 22 | 23 | wide_runtime_error(std::wstring const& message, wide_runtime_error const& e) 24 | : runtime_error(std::format("{0} : Inner Exception: {1}", string_conversation::wstring_to_utf8(message), e.what())) 25 | , message_{std::format(L"{0} : Inner Exception: {1}", message, e.message())} 26 | { 27 | } 28 | 29 | [[nodiscard]] std::wstring const& message() const { return message_; } 30 | 31 | private: 32 | std::wstring message_; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /DbgHelpUtils/tagged_bool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace dlg_help_utils 3 | { 4 | namespace tagged_bool_ns // artificial namespace to prevent ADL into namespace explicit 5 | { 6 | template 7 | class tagged_bool 8 | { 9 | bool value_; 10 | 11 | template 12 | friend class tagged_bool; 13 | 14 | public: 15 | 16 | constexpr explicit tagged_bool(const bool v) : value_{ v } {} 17 | 18 | constexpr explicit tagged_bool(int) = delete; 19 | constexpr explicit tagged_bool(double) = delete; 20 | constexpr explicit tagged_bool(void*) = delete; 21 | 22 | template 23 | constexpr explicit tagged_bool(tagged_bool b) : value_{ b.value } {} 24 | 25 | constexpr explicit operator bool() const { return value_; } 26 | constexpr tagged_bool operator!() const { return tagged_bool{ !value_ }; } 27 | 28 | friend constexpr bool operator==(tagged_bool l, tagged_bool r) { return l.value_ == r.value_; } 29 | friend constexpr bool operator!=(tagged_bool l, tagged_bool r) { return l.value_ != r.value_; } 30 | }; 31 | } 32 | 33 | using tagged_bool_ns::tagged_bool; // with this tagged_bool is in namespace explicit but with disabled ADL 34 | } -------------------------------------------------------------------------------- /DbgHelpUtils/i_symbol_load_callback.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable CppUnusedIncludeDirective 4 | #include 5 | #include 6 | // ReSharper restore CppUnusedIncludeDirective 7 | 8 | namespace dlg_help_utils::dbg_help 9 | { 10 | class i_symbol_load_callback 11 | { 12 | public: 13 | i_symbol_load_callback() = default; 14 | virtual ~i_symbol_load_callback() = default; 15 | 16 | i_symbol_load_callback(i_symbol_load_callback const&) = default; 17 | i_symbol_load_callback(i_symbol_load_callback &&) = default; 18 | 19 | i_symbol_load_callback& operator=(i_symbol_load_callback const&) = default; 20 | i_symbol_load_callback& operator=(i_symbol_load_callback &&) = default; 21 | 22 | [[nodiscard]] virtual bool deferred_symbol_load_cancel(std::wstring_view const& module_name) = 0; 23 | virtual void deferred_symbol_load_partial(std::wstring_view const& module_name) = 0; 24 | virtual void start_download(std::wstring_view const& module_name) = 0; 25 | virtual void download_percent(unsigned percent) = 0; 26 | virtual void download_complete() = 0; 27 | [[nodiscard]] virtual std::wostream& log_stream() const = 0; 28 | [[nodiscard]] virtual bool symbol_load_debug() const = 0; 29 | [[nodiscard]] virtual bool symbol_load_debug_memory() const = 0; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /DbgHelpUtils/statistic_view_options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "process_heaps_statistic_view.h" 3 | #include "size_units.h" 4 | 5 | namespace dlg_help_utils::heap::statistic_views 6 | { 7 | 8 | class statistic_view_options 9 | { 10 | public: 11 | statistic_view_options() = default; 12 | 13 | [[nodiscard]] size_units::base_16::bytes& range_size() { return range_size_; } 14 | [[nodiscard]] size_units::base_16::bytes const& range_size() const { return range_size_; } 15 | 16 | [[nodiscard]] process_heaps_statistic_view::sort_column_type& view_sort_column() { return view_sort_column_; } 17 | [[nodiscard]] process_heaps_statistic_view::sort_column_type const& view_sort_column() const { return view_sort_column_; } 18 | 19 | [[nodiscard]] process_heaps_statistic_view::sort_order_type& view_sort_order() { return view_sort_order_; } 20 | [[nodiscard]] process_heaps_statistic_view::sort_order_type const& view_sort_order() const { return view_sort_order_; } 21 | 22 | private: 23 | size_units::base_16::bytes range_size_{size_units::base_16::kilobytes{1}}; 24 | process_heaps_statistic_view::sort_column_type view_sort_column_{process_heaps_statistic_view::sort_column_type::size}; 25 | process_heaps_statistic_view::sort_order_type view_sort_order_{process_heaps_statistic_view::sort_order_type::ascending}; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_vm_counters_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | class mini_dump; 10 | 11 | class process_vm_counters_stream 12 | { 13 | public: 14 | explicit process_vm_counters_stream(mini_dump const& dump, size_t index = 0); 15 | 16 | [[nodiscard]] bool found() const { return found_; } 17 | [[nodiscard]] bool is_valid() const { return is_valid_; } 18 | [[nodiscard]] size_t index() const { return index_; } 19 | [[nodiscard]] size_t process_vm_counters_version() const { return process_vm_counters_version_; } 20 | 21 | [[nodiscard]] MINIDUMP_PROCESS_VM_COUNTERS_1 const& process_vm_counters() const 22 | { 23 | return *process_vm_counters_; 24 | } 25 | 26 | [[nodiscard]] MINIDUMP_PROCESS_VM_COUNTERS_2 const& process_vm_counters_2() const 27 | { 28 | return *process_vm_counters_2_; 29 | } 30 | 31 | private: 32 | bool found_{false}; 33 | bool is_valid_{false}; 34 | size_t index_{}; 35 | size_t process_vm_counters_version_{0}; 36 | MINIDUMP_PROCESS_VM_COUNTERS_1 const* process_vm_counters_{nullptr}; 37 | MINIDUMP_PROCESS_VM_COUNTERS_2 const* process_vm_counters_2_{nullptr}; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | #include "stream_thread_context.h" 8 | #include "stream_thread_name.h" 9 | 10 | namespace dlg_help_utils 11 | { 12 | class memory64_list_stream; 13 | class memory_list_stream; 14 | class thread_names_list_stream; 15 | class mini_dump; 16 | 17 | class stream_thread 18 | { 19 | public: 20 | explicit stream_thread(mini_dump const& dump, MINIDUMP_THREAD const& thread, 21 | thread_names_list_stream const& names_list, memory_list_stream const& memory_list, 22 | memory64_list_stream const& memory64_list); 23 | 24 | MINIDUMP_THREAD const* operator->() const { return &thread_; } 25 | [[nodiscard]] void const* stack() const { return stack_; } 26 | [[nodiscard]] stream_thread_context const& thread_context() const { return thread_context_; } 27 | [[nodiscard]] std::wstring_view const& thread_name() const { return thread_name_.name(); } 28 | 29 | private: 30 | MINIDUMP_THREAD const& thread_; 31 | void const* stack_{nullptr}; 32 | stream_thread_context thread_context_{}; 33 | stream_thread_name thread_name_; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /ValidateHeapEntries/ValidateHeapEntries.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_names_list_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "thread_names_list_stream.h" 2 | 3 | #include "mini_dump.h" 4 | 5 | namespace dlg_help_utils 6 | { 7 | thread_names_list_stream::thread_names_list_stream(mini_dump const& dump, size_t const index) 8 | : dump_{dump} 9 | , index_{index} 10 | { 11 | auto const* entry = dump.find_stream_type(ThreadNamesStream, index_); 12 | if (entry == nullptr) 13 | { 14 | return; 15 | } 16 | 17 | thread_name_list_ = static_cast(dump.rva32(entry->Location)); 18 | found_ = true; 19 | } 20 | 21 | std::experimental::generator thread_names_list_stream::list() const // NOLINT(bugprone-reserved-identifier) 22 | { 23 | for (size_t index = 0; index < thread_name_list_->NumberOfThreadNames; ++index) 24 | { 25 | co_yield stream_thread_name{dump_, thread_name_list_->ThreadNames[index]}; 26 | } 27 | } 28 | 29 | stream_thread_name thread_names_list_stream::get_thread_name_for_thread_id(uint32_t const thread_id) const 30 | { 31 | if (found()) 32 | { 33 | for (auto const& entry : list()) 34 | { 35 | if (entry->ThreadId == thread_id) 36 | { 37 | return entry; 38 | } 39 | } 40 | } 41 | 42 | return {}; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AllocationSetupTests/AllocationSetupTests.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread_ex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | // ReSharper disable once CppUnusedIncludeDirective 8 | #include 9 | 10 | #include "stream_thread_context.h" 11 | #include "stream_thread_name.h" 12 | 13 | namespace dlg_help_utils 14 | { 15 | class thread_names_list_stream; 16 | class mini_dump; 17 | 18 | class stream_thread_ex 19 | { 20 | public: 21 | explicit stream_thread_ex(mini_dump const& dump, MINIDUMP_THREAD_EX const& thread, 22 | thread_names_list_stream const& names_list); 23 | 24 | MINIDUMP_THREAD_EX const* operator->() const { return &thread_; } 25 | [[nodiscard]] void const* stack() const { return stack_; } 26 | [[nodiscard]] stream_thread_context const& thread_context() const { return thread_context_; } 27 | [[nodiscard]] void const* backing_store() const { return backing_store_; } 28 | [[nodiscard]] std::wstring_view const& thread_name() const { return thread_name_.name(); } 29 | 30 | private: 31 | MINIDUMP_THREAD_EX const& thread_; 32 | void const* stack_{nullptr}; 33 | stream_thread_context thread_context_{}; 34 | void const* backing_store_{nullptr}; 35 | stream_thread_name thread_name_; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /DbgHelpUtils/memory_info_list_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "memory_info_list_stream.h" 2 | 3 | #include "mini_dump.h" 4 | 5 | namespace dlg_help_utils 6 | { 7 | memory_info_list_stream::memory_info_list_stream(mini_dump const& dump, size_t const index) 8 | { 9 | index_ = index; 10 | auto const* entry = dump.find_stream_type(MemoryInfoListStream, index_); 11 | if (entry == nullptr) 12 | { 13 | return; 14 | } 15 | 16 | auto const* data = dump.rva32(entry->Location); 17 | memory_info_list_ = static_cast(data); 18 | found_ = true; 19 | 20 | if (memory_info_list_->SizeOfHeader == sizeof(MINIDUMP_MEMORY_INFO_LIST)) 21 | { 22 | if (memory_info_list_->SizeOfEntry == sizeof(MINIDUMP_MEMORY_INFO)) 23 | { 24 | list_ = reinterpret_cast(static_cast(data) + sizeof( 25 | MINIDUMP_MEMORY_INFO_LIST)); 26 | is_valid_ = true; 27 | } 28 | } 29 | } 30 | 31 | std::experimental::generator memory_info_list_stream::list() const // NOLINT(bugprone-reserved-identifier) 32 | { 33 | for (size_t index = 0; index < memory_info_list_->NumberOfEntries; ++index) 34 | { 35 | // ReSharper disable once CppAwaiterTypeIsNotClass 36 | co_yield &list_[index]; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | 4 | // ReSharper disable once CppUnusedIncludeDirective 5 | #include "windows_setup.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include "stream_thread.h" 11 | 12 | namespace dlg_help_utils 13 | { 14 | class mini_dump; 15 | 16 | class thread_list_stream 17 | { 18 | public: 19 | explicit thread_list_stream(mini_dump const& dump, size_t index = 0); 20 | 21 | [[nodiscard]] bool found() const { return found_; } 22 | [[nodiscard]] size_t index() const { return index_; } 23 | [[nodiscard]] MINIDUMP_THREAD_LIST const& thread_list() const { return *thread_list_; } 24 | 25 | [[nodiscard]] std::experimental::generator list() const; 26 | 27 | [[nodiscard]] std::optional find_thread(ULONG32 thread_id, 28 | thread_names_list_stream const& names_list, 29 | memory_list_stream const& memory_list, 30 | memory64_list_stream const& memory64_list) const; 31 | 32 | private: 33 | mini_dump const& dump_; 34 | bool found_{false}; 35 | size_t index_; 36 | MINIDUMP_THREAD_LIST const* thread_list_{nullptr}; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_handle.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_handle.h" 2 | 3 | #include "mini_dump.h" 4 | #include "string_stream.h" 5 | 6 | using namespace std::string_view_literals; 7 | 8 | namespace dlg_help_utils 9 | { 10 | stream_handle::stream_handle(mini_dump const& dump, void const* data, size_t const handle_descriptor_version) 11 | : dump_{dump} 12 | , data_{data} 13 | , handle_descriptor_version_{handle_descriptor_version} 14 | { 15 | type_name_ = string_stream::to_string(dump, descriptor().TypeNameRva); 16 | object_name_ = string_stream::to_string(dump, descriptor().ObjectNameRva); 17 | } 18 | 19 | std::experimental::generator stream_handle::list() const // NOLINT(bugprone-reserved-identifier) 20 | { 21 | if (handle_descriptor_version_ < 2) 22 | { 23 | co_return; 24 | } 25 | 26 | if (descriptor_2().ObjectInfoRva == 0) 27 | { 28 | co_return; 29 | } 30 | 31 | auto const* entry = static_cast(dump_.rva32( 32 | descriptor_2().ObjectInfoRva)); 33 | co_yield stream_handle_object_information{*entry}; 34 | 35 | while (entry->NextInfoRva != 0) 36 | { 37 | entry = static_cast(dump_.rva32(entry->NextInfoRva)); 38 | co_yield stream_handle_object_information{*entry}; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /DbgHelpUtils/handle_operation_list_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "handle_operation_list_stream.h" 2 | 3 | #include "mini_dump.h" 4 | 5 | namespace dlg_help_utils 6 | { 7 | handle_operation_list_stream::handle_operation_list_stream(mini_dump const& dump, size_t const index) 8 | { 9 | index_ = index; 10 | auto const* entry = dump.find_stream_type(HandleOperationListStream, index_); 11 | if (entry == nullptr) 12 | { 13 | return; 14 | } 15 | 16 | auto const* data = dump.rva32(entry->Location); 17 | handle_operation_list_ = static_cast(data); 18 | found_ = true; 19 | 20 | if (handle_operation_list_->SizeOfHeader == sizeof(MINIDUMP_HANDLE_OPERATION_LIST) 21 | && handle_operation_list_->SizeOfEntry == sizeof(AVRF_HANDLE_OPERATION)) 22 | { 23 | list_ = reinterpret_cast(static_cast(data) + sizeof( 24 | MINIDUMP_HANDLE_OPERATION_LIST)); 25 | is_valid_ = true; 26 | } 27 | } 28 | 29 | std::experimental::generator handle_operation_list_stream::list() const // NOLINT(bugprone-reserved-identifier) 30 | { 31 | for (size_t index = 0; index < handle_operation_list_->NumberOfEntries; ++index) 32 | { 33 | // ReSharper disable once CppAwaiterTypeIsNotClass 34 | co_yield &list_[index]; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /DbgHelpUtils/function_table_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | #include 5 | #include 6 | 7 | #include "stream_function_descriptor.h" 8 | #include "function_table_entry_type.h" 9 | 10 | namespace dlg_help_utils 11 | { 12 | class mini_dump; 13 | 14 | class function_table_stream 15 | { 16 | public: 17 | explicit function_table_stream(mini_dump const& dump, size_t index = 0); 18 | 19 | [[nodiscard]] bool found() const { return found_; } 20 | [[nodiscard]] bool is_valid() const { return is_valid_; } 21 | [[nodiscard]] function_table_entry_type entry_type() const { return entry_type_; } 22 | [[nodiscard]] size_t index() const { return index_; } 23 | MINIDUMP_FUNCTION_TABLE_STREAM const* operator->() const { return function_table_list_; } 24 | [[nodiscard]] ULONG64 size() const { return function_table_list_->NumberOfDescriptors; } 25 | 26 | [[nodiscard]] std::experimental::generator list() const; 27 | 28 | private: 29 | bool found_{false}; 30 | bool is_valid_{false}; 31 | size_t index_; 32 | void const* end_list_{nullptr}; 33 | MINIDUMP_FUNCTION_TABLE_STREAM const* function_table_list_{nullptr}; 34 | MINIDUMP_FUNCTION_TABLE_DESCRIPTOR const* list_{nullptr}; 35 | function_table_entry_type entry_type_{function_table_entry_type::unknown}; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /DbgHelpUtils/module_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | #include 7 | 8 | #include "stream_module.h" 9 | 10 | namespace dlg_help_utils 11 | { 12 | class mini_dump; 13 | 14 | class module_list_stream 15 | { 16 | public: 17 | explicit module_list_stream(mini_dump const& dump, size_t index = 0); 18 | 19 | [[nodiscard]] bool found() const { return found_; } 20 | [[nodiscard]] size_t index() const { return index_; } 21 | [[nodiscard]] MINIDUMP_MODULE_LIST const& module_list() const { return *module_list_; } 22 | 23 | [[nodiscard]] std::vector const& list() const { return modules_; } 24 | 25 | [[nodiscard]] stream_module const* find_module(uint64_t address) const; 26 | [[nodiscard]] stream_module const* find_module(std::wstring_view const& module_name) const; 27 | 28 | private: 29 | [[nodiscard]] static MINIDUMP_MODULE_LIST const* get_module_list(mini_dump const& dump, size_t& index); 30 | [[nodiscard]] std::vector build_modules() const; 31 | 32 | private: 33 | mini_dump const& dump_; 34 | MINIDUMP_MODULE_LIST const* module_list_{nullptr}; 35 | size_t const index_; 36 | bool const found_{false}; 37 | std::vector const modules_{build_modules()}; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_function_descriptor.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_function_descriptor.h" 2 | 3 | #include 4 | 5 | namespace dlg_help_utils 6 | { 7 | stream_function_descriptor::stream_function_descriptor(MINIDUMP_FUNCTION_TABLE_DESCRIPTOR const& header, 8 | ULONG32 const size_of_native_descriptor, 9 | ULONG32 const size_of_function_entry, 10 | function_table_entry_type const entry_type) 11 | : header_(header) 12 | , size_of_native_descriptor_(size_of_native_descriptor) 13 | , size_of_function_entry_(size_of_function_entry) 14 | , entry_type_{entry_type} 15 | { 16 | auto const* data = reinterpret_cast(&header_) + sizeof(header_); 17 | 18 | native_descriptor_ = data; 19 | function_entry_table_ = data + size_of_native_descriptor; 20 | } 21 | 22 | std::experimental::generator stream_function_descriptor::list() const // NOLINT(bugprone-reserved-identifier) 23 | { 24 | for (size_t index = 0; index < header_.EntryCount; ++index) 25 | { 26 | // ReSharper disable once CppAwaiterTypeIsNotClass 27 | co_yield stream_function_entry{ 28 | index, function_entry_table_ + (index * size_of_function_entry_), size_of_function_entry_, entry_type_ 29 | }; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /DbgHelpUtils/chrono_unit_convert_to_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils::chrono_unit_utilities 6 | { 7 | template 8 | void convert_to_string(std::wostream& os, Us1 us1, Us2 us2, std::wstring const& us1_name, std::wstring const& us1_plural_name) 9 | { 10 | os << us1.count(); 11 | 12 | if (us2.count() > 0) 13 | { 14 | if (const auto partial = static_cast((static_cast(us2.count()) / static_cast( 15 | std::chrono::duration_cast(Us1{1}).count())) * 100.0); partial > 0) 16 | { 17 | os << L"." << partial << L" " << us1_plural_name; 18 | return; 19 | } 20 | } 21 | 22 | os << L" " << (us1.count() <= 1 ? us1_name : us1_plural_name); 23 | } 24 | 25 | template 26 | void convert_to_compact_string(std::wostream& os, Us1 us1, Us2 us2, std::wstring const& us_name) 27 | { 28 | os << us1.count(); 29 | 30 | if (us2.count() > 0) 31 | { 32 | if (const auto partial = static_cast((static_cast(us2.count()) / static_cast( 33 | std::chrono::duration_cast(Us1{1}).count())) * 100.0); partial > 0) 34 | { 35 | os << L"." << partial << us_name; 36 | return; 37 | } 38 | } 39 | 40 | os << us_name; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_function_entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows_setup.h" 3 | 4 | #include 5 | 6 | #include "function_table_entry_type.h" 7 | 8 | namespace dlg_help_utils 9 | { 10 | class stream_function_entry 11 | { 12 | public: 13 | stream_function_entry(size_t index, void const* function_entry, uint32_t size_of_function_entry, 14 | function_table_entry_type entry_type); 15 | 16 | [[nodiscard]] size_t index() const { return index_; } 17 | [[nodiscard]] void const* data() const { return function_entry_; } 18 | [[nodiscard]] size_t size() const { return size_of_function_entry_; } 19 | [[nodiscard]] function_table_entry_type entry_type() const { return entry_type_; } 20 | [[nodiscard]] FPO_DATA const& fpo_data() const { return *fpo_data_; } 21 | [[nodiscard]] IMAGE_FUNCTION_ENTRY const& image_function_entry() const { return *image_function_entry_; } 22 | 23 | [[nodiscard]] IMAGE_FUNCTION_ENTRY64 const& image_function_entry_64() const 24 | { 25 | return *image_function_entry_64_; 26 | } 27 | 28 | private: 29 | size_t index_; 30 | uint32_t size_of_function_entry_{0}; 31 | void const* function_entry_{nullptr}; 32 | function_table_entry_type entry_type_; 33 | FPO_DATA const* fpo_data_{nullptr}; 34 | IMAGE_FUNCTION_ENTRY const* image_function_entry_{nullptr}; 35 | IMAGE_FUNCTION_ENTRY64 const* image_function_entry_64_{nullptr}; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_environment_variables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "stream_utils.h" 5 | #include "symbol_type_info.h" 6 | 7 | namespace dlg_help_utils 8 | { 9 | class cache_manager; 10 | } 11 | 12 | namespace dlg_help_utils::stream_stack_dump 13 | { 14 | class mini_dump_memory_walker; 15 | } 16 | 17 | namespace dlg_help_utils::process 18 | { 19 | 20 | class process_environment_variables 21 | { 22 | public: 23 | process_environment_variables(cache_manager& cache, stream_stack_dump::mini_dump_memory_walker const& walker, uint64_t process_parameters_address); 24 | 25 | [[nodiscard]] stream_stack_dump::mini_dump_memory_walker const& walker() const { return *walker_; } 26 | [[nodiscard]] uint64_t process_parameters_address() const { return process_parameters_address_; } 27 | 28 | [[nodiscard]] std::experimental::generator environment() const; 29 | 30 | private: 31 | struct cache_data 32 | { 33 | dbg_help::symbol_type_info process_parameters_symbol_info; 34 | 35 | stream_utils::symbol_type_and_base_type_field_offset rtl_user_process_parameters_structure_environment_field_data; 36 | }; 37 | [[nodiscard]] cache_data const& setup_globals() const; 38 | 39 | private: 40 | cache_manager* cache_manager_; 41 | cache_data const* cache_data_{&setup_globals()}; 42 | stream_stack_dump::mini_dump_memory_walker const* walker_; 43 | uint64_t process_parameters_address_; 44 | }; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /DbgHelpUtils/unit_convert_to_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "units.h" 5 | 6 | namespace dlg_help_utils::unit_utilities 7 | { 8 | template 9 | void convert_to_string(std::wostream& os, Us1 us1, Us2 us2, std::wstring const& us1_name, std::wstring const& us1_plural_name) 10 | { 11 | using namespace units; 12 | os << us1.count(); 13 | 14 | if (us2.count() > 0) 15 | { 16 | if (const auto partial = static_cast((static_cast(us2.count()) / static_cast( 17 | length_cast(Us1{1}).count())) * 100.0); partial > 0) 18 | { 19 | os << L"." << partial << L" " << us1_plural_name; 20 | return; 21 | } 22 | } 23 | 24 | os << L" " << (us1.count() <= 1 ? us1_name : us1_plural_name); 25 | } 26 | 27 | template 28 | void convert_to_compact_string(std::wostream& os, Us1 us1, Us2 us2, std::wstring const& us_name) 29 | { 30 | using namespace units; 31 | os << us1.count(); 32 | 33 | if (us2.count() > 0) 34 | { 35 | if (const auto partial = static_cast((static_cast(us2.count()) / static_cast( 36 | length_cast(Us1{1}).count())) * 100.0); partial > 0) 37 | { 38 | os << L"." << partial << us_name; 39 | return; 40 | } 41 | } 42 | 43 | os << us_name; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DbgHelpUtils/i_stack_walk_callback.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "enable_module_loading.h" 3 | #include "symbol_address_info.h" 4 | #include 5 | #include 6 | 7 | namespace dlg_help_utils::dbg_help 8 | { 9 | enum class thread_context_type 10 | { 11 | x86, 12 | wow64, 13 | x64 14 | }; 15 | 16 | class i_stack_walk_callback 17 | { 18 | public: 19 | i_stack_walk_callback() = default; 20 | virtual ~i_stack_walk_callback() = default; 21 | 22 | i_stack_walk_callback(i_stack_walk_callback const&) = delete; 23 | i_stack_walk_callback(i_stack_walk_callback&&) = default; 24 | 25 | i_stack_walk_callback& operator=(i_stack_walk_callback const&) = delete; 26 | i_stack_walk_callback& operator=(i_stack_walk_callback&&) = default; 27 | 28 | [[nodiscard]] virtual bool read_process_memory(DWORD64 base_address 29 | , PVOID buffer 30 | , DWORD size 31 | , LPDWORD number_of_bytes_read 32 | , enable_module_loading_t enable_module_loading = enable_module_loading_t{true}) = 0; 33 | [[nodiscard]] virtual PVOID function_table_access(DWORD64 base_address) = 0; 34 | [[nodiscard]] virtual DWORD64 get_module_base_routine(DWORD64 address) = 0; 35 | [[nodiscard]] virtual DWORD64 translate_address(HANDLE h_thread, LPADDRESS64 lp_address) = 0; 36 | 37 | [[nodiscard]] virtual std::optional find_symbol_info(thread_context_type type, STACKFRAME_EX const& frame, void const* thread_context) const = 0; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_entry_reference.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "graph_node_variable_symbol_reference_data.h" 6 | 7 | namespace dlg_help_utils::heap::allocation_graph 8 | { 9 | class process_heap_graph_node; 10 | 11 | class process_heap_entry_reference 12 | { 13 | public: 14 | process_heap_entry_reference(uint64_t to_offset, uint64_t to_pointer, uint64_t from_offset, uint64_t from_pointer, process_heap_graph_node const& heap_entry); 15 | process_heap_entry_reference(uint64_t to_offset, uint64_t to_pointer, uint64_t from_offset, uint64_t from_pointer, process_heap_graph_node const& heap_entry, graph_node_variable_symbol_reference_data const& variable_symbol_info); 16 | 17 | [[nodiscard]] uint64_t node_index() const { return node_index_; } 18 | [[nodiscard]] uint64_t to_offset() const { return to_offset_; } 19 | [[nodiscard]] uint64_t to_pointer() const { return to_pointer_; } 20 | [[nodiscard]] uint64_t from_offset() const { return from_offset_; } 21 | [[nodiscard]] uint64_t from_pointer() const { return from_pointer_; } 22 | [[nodiscard]] std::optional const& variable_symbol_info() const { return variable_symbol_info_; } 23 | 24 | private: 25 | uint64_t to_offset_; 26 | uint64_t to_pointer_; 27 | uint64_t from_offset_; 28 | uint64_t from_pointer_; 29 | uint64_t node_index_; 30 | std::optional variable_symbol_info_; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_function_descriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | #include 8 | 9 | #include "stream_function_entry.h" 10 | #include "function_table_entry_type.h" 11 | 12 | namespace dlg_help_utils 13 | { 14 | class stream_function_descriptor 15 | { 16 | public: 17 | stream_function_descriptor(MINIDUMP_FUNCTION_TABLE_DESCRIPTOR const& header, ULONG32 size_of_native_descriptor, 18 | ULONG32 size_of_function_entry, function_table_entry_type entry_type); 19 | 20 | MINIDUMP_FUNCTION_TABLE_DESCRIPTOR const* operator->() const { return &header_; } 21 | [[nodiscard]] void const* native_descriptor() const { return native_descriptor_; } 22 | [[nodiscard]] size_t native_descriptor_size() const { return size_of_native_descriptor_; } 23 | [[nodiscard]] void const* raw_function_table() const { return function_entry_table_; } 24 | 25 | [[nodiscard]] std::experimental::generator list() const; 26 | 27 | private: 28 | MINIDUMP_FUNCTION_TABLE_DESCRIPTOR const& header_; 29 | ULONG32 size_of_native_descriptor_{0}; 30 | ULONG32 size_of_function_entry_{0}; 31 | function_table_entry_type entry_type_{function_table_entry_type::unknown}; 32 | void const* native_descriptor_{nullptr}; 33 | uint8_t const* function_entry_table_{nullptr}; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /DbgHelpUtils/find_thread_stack.cpp: -------------------------------------------------------------------------------- 1 | #include "find_thread_stack.h" 2 | 3 | #include "memory64_list_stream.h" 4 | #include "memory_list_stream.h" 5 | #include "thread_ex_list_stream.h" 6 | #include "thread_list_stream.h" 7 | #include "thread_names_list_stream.h" 8 | 9 | namespace dlg_help_utils 10 | { 11 | std::optional find_thread_stack(mini_dump const& mini_dump, uint32_t const thread_id) 12 | { 13 | thread_list_stream const thread_list{mini_dump}; 14 | thread_ex_list_stream const thread_ex_list{mini_dump}; 15 | thread_names_list_stream const names_list{mini_dump}; 16 | 17 | if (thread_list.found()) 18 | { 19 | memory_list_stream const memory_list{mini_dump}; 20 | memory64_list_stream const memory64_list{mini_dump}; 21 | if (auto const thread = thread_list.find_thread(thread_id, names_list, memory_list, memory64_list); thread.has_value()) 22 | { 23 | return thread_stack{ 24 | thread->stack(), (*thread)->Stack.Memory.DataSize, (*thread)->Stack.StartOfMemoryRange 25 | }; 26 | } 27 | } 28 | 29 | if (thread_ex_list.found()) 30 | { 31 | if (auto const thread = thread_ex_list.find_thread(thread_id, names_list); thread.has_value()) 32 | { 33 | return thread_stack{ 34 | thread->stack(), (*thread)->Stack.Memory.DataSize, (*thread)->Stack.StartOfMemoryRange 35 | }; 36 | } 37 | } 38 | 39 | return std::nullopt; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /DbgHelpUtils/handle_data_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | #include 7 | #include 8 | 9 | #include "stream_handle.h" 10 | 11 | namespace dlg_help_utils 12 | { 13 | class mini_dump; 14 | 15 | class handle_data_stream 16 | { 17 | public: 18 | explicit handle_data_stream(mini_dump const& dump, size_t index = 0); 19 | 20 | [[nodiscard]] bool found() const { return found_; } 21 | [[nodiscard]] bool is_valid() const { return is_valid_; } 22 | [[nodiscard]] size_t index() const { return index_; } 23 | [[nodiscard]] size_t handle_descriptor_version() const { return handle_descriptor_version_; } 24 | [[nodiscard]] ULONG64 size() const { return handle_data_list_->NumberOfDescriptors; } 25 | 26 | [[nodiscard]] std::map const& handle_type_totals() const 27 | { 28 | return handle_type_totals_; 29 | } 30 | 31 | [[nodiscard]] std::experimental::generator list() const; 32 | 33 | private: 34 | mini_dump const& dump_; 35 | bool found_{false}; 36 | bool is_valid_{false}; 37 | size_t index_; 38 | size_t handle_descriptor_version_{0}; 39 | MINIDUMP_HANDLE_DATA_STREAM const* handle_data_list_{nullptr}; 40 | uint8_t const* list_{nullptr}; 41 | std::map handle_type_totals_; 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /DbgHelpUtils/allocation_stack_trace_helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace dlg_help_utils::dbg_help 7 | { 8 | struct symbol_address_info; 9 | } 10 | 11 | namespace dlg_help_utils::stream_stack_dump 12 | { 13 | class mini_dump_memory_walker; 14 | } 15 | 16 | namespace dlg_help_utils::heap 17 | { 18 | class process_heap_entry; 19 | class system_module_list; 20 | } 21 | 22 | namespace dlg_help_utils::heap::statistic_views 23 | { 24 | class allocation_stack_trace_helper 25 | { 26 | public: 27 | allocation_stack_trace_helper(stream_stack_dump::mini_dump_memory_walker const& walker, system_module_list const& system_module); 28 | 29 | [[nodiscard]] stream_stack_dump::mini_dump_memory_walker const& walker() const { return *walker_; } 30 | [[nodiscard]] system_module_list const& system_module() const { return *system_module_; } 31 | 32 | [[nodiscard]] std::optional find_common_allocation_callsite(process_heap_entry const& entry) const; 33 | [[nodiscard]] std::optional find_common_allocation_callsite(std::vector const& entries) const; 34 | [[nodiscard]] static std::vector find_common_allocation_stack_trace(std::optional const& common_allocation_callsite, std::vector const& entries); 35 | 36 | private: 37 | stream_stack_dump::mini_dump_memory_walker const* walker_; 38 | system_module_list const* system_module_; 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /DbgHelpUtils/system_info_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "windows_setup.h" 4 | #include 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | class mini_dump; 10 | 11 | class system_info_stream 12 | { 13 | public: 14 | explicit system_info_stream(mini_dump const& dump, size_t index = 0); 15 | 16 | [[nodiscard]] bool found() const { return found_; } 17 | [[nodiscard]] size_t index() const { return index_; } 18 | [[nodiscard]] MINIDUMP_SYSTEM_INFO const& system_info() const { return *system_info_; } 19 | [[nodiscard]] std::wstring_view const& csd_version() const { return csd_version_; } 20 | [[nodiscard]] std::wstring const& vendor_id() const { return vendor_id_; } 21 | [[nodiscard]] bool is_intel() const { return is_intel_; } 22 | [[nodiscard]] bool is_amd() const { return is_amd_; } 23 | [[nodiscard]] bool is_x86() const; 24 | [[nodiscard]] bool is_x64() const; 25 | [[nodiscard]] unsigned short processor_model() const { return processor_model_; } 26 | [[nodiscard]] unsigned short processor_stepping() const { return processor_stepping_; } 27 | 28 | private: 29 | bool found_{false}; 30 | size_t index_{}; 31 | MINIDUMP_SYSTEM_INFO const* system_info_{nullptr}; 32 | std::wstring_view csd_version_; 33 | std::wstring vendor_id_; 34 | bool is_intel_{}; 35 | bool is_amd_{}; 36 | unsigned short processor_model_{}; 37 | unsigned short processor_stepping_{}; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_streams.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "DbgHelpUtils/windows_setup.h" 4 | 5 | #include 6 | #include 7 | 8 | class dump_file_options; 9 | 10 | namespace dlg_help_utils 11 | { 12 | namespace dbg_help 13 | { 14 | class symbol_engine; 15 | } 16 | 17 | class mini_dump; 18 | } 19 | 20 | void dump_mini_dump_streams(std::wostream& log, dlg_help_utils::mini_dump const& dump_file); 21 | void dump_mini_dump_stream_index(std::wostream& log, dlg_help_utils::mini_dump const& dump_file, size_t index, 22 | dump_file_options const& options, 23 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 24 | void dump_mini_dump_stream_type(std::wostream& log, dlg_help_utils::mini_dump const& dump_file, MINIDUMP_STREAM_TYPE type, 25 | dump_file_options const& options, 26 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 27 | void dump_mini_dump_all_stream_indexes(std::wostream& log, dlg_help_utils::mini_dump const& dump_file, 28 | dump_file_options const& options, 29 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 30 | void dump_mini_dump_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index, 31 | MINIDUMP_DIRECTORY const& entry, dump_file_options const& options, 32 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 33 | -------------------------------------------------------------------------------- /DbgHelpUtils/misc_info_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | namespace dlg_help_utils 8 | { 9 | class mini_dump; 10 | 11 | class misc_info_stream 12 | { 13 | public: 14 | explicit misc_info_stream(mini_dump const& dump, size_t index = 0); 15 | 16 | [[nodiscard]] bool found() const { return found_; } 17 | [[nodiscard]] bool is_valid() const { return is_valid_; } 18 | [[nodiscard]] size_t index() const { return index_; } 19 | [[nodiscard]] size_t misc_info_version() const { return misc_info_version_; } 20 | [[nodiscard]] MINIDUMP_MISC_INFO const& misc_info() const { return *misc_info_; } 21 | [[nodiscard]] MINIDUMP_MISC_INFO_2 const& misc_info_2() const { return *misc_info_2_; } 22 | [[nodiscard]] MINIDUMP_MISC_INFO_3 const& misc_info_3() const { return *misc_info_3_; } 23 | [[nodiscard]] MINIDUMP_MISC_INFO_4 const& misc_info_4() const { return *misc_info_4_; } 24 | [[nodiscard]] MINIDUMP_MISC_INFO_5 const& misc_info_5() const { return *misc_info_5_; } 25 | 26 | private: 27 | bool found_{false}; 28 | bool is_valid_{false}; 29 | size_t index_{}; 30 | size_t misc_info_version_{}; 31 | MINIDUMP_MISC_INFO const* misc_info_{nullptr}; 32 | MINIDUMP_MISC_INFO_2 const* misc_info_2_{nullptr}; 33 | MINIDUMP_MISC_INFO_3 const* misc_info_3_{nullptr}; 34 | MINIDUMP_MISC_INFO_4 const* misc_info_4_{nullptr}; 35 | MINIDUMP_MISC_INFO_5 const* misc_info_5_{nullptr}; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_info_list_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "thread_info_list_stream.h" 2 | 3 | #include "mini_dump.h" 4 | #include "thread_names_list_stream.h" 5 | 6 | namespace dlg_help_utils 7 | { 8 | thread_info_list_stream::thread_info_list_stream(mini_dump const& dump, size_t const index) 9 | : dump_{dump} 10 | , index_{index} 11 | { 12 | auto const* entry = dump.find_stream_type(ThreadInfoListStream, index_); 13 | if (entry == nullptr) 14 | { 15 | return; 16 | } 17 | 18 | auto const* data = dump.rva32(entry->Location); 19 | thread_info_list_ = static_cast(data); 20 | found_ = true; 21 | 22 | if (thread_info_list_->SizeOfHeader == sizeof(MINIDUMP_THREAD_INFO_LIST)) 23 | { 24 | if (thread_info_list_->SizeOfEntry == sizeof(MINIDUMP_THREAD_INFO)) 25 | { 26 | list_ = reinterpret_cast(static_cast(data) + sizeof( 27 | MINIDUMP_THREAD_INFO_LIST)); 28 | is_valid_ = true; 29 | } 30 | } 31 | } 32 | 33 | std::experimental::generator thread_info_list_stream::list() const // NOLINT(bugprone-reserved-identifier) 34 | { 35 | thread_names_list_stream const names_list{dump_}; 36 | for (size_t index = 0; index < thread_info_list_->NumberOfEntries; ++index) 37 | { 38 | // ReSharper disable once CppAwaiterTypeIsNotClass 39 | co_yield stream_thread_info{list_[index], names_list}; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /MiniDumper/MiniDumper.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | MiniDumper 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 33 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_ex_list_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "thread_ex_list_stream.h" 2 | 3 | #include "mini_dump.h" 4 | #include "thread_names_list_stream.h" 5 | 6 | namespace dlg_help_utils 7 | { 8 | thread_ex_list_stream::thread_ex_list_stream(mini_dump const& dump, size_t const index) 9 | : dump_{dump} 10 | , index_{index} 11 | { 12 | auto const* entry = dump.find_stream_type(ThreadListStream, index_); 13 | if (entry == nullptr) 14 | { 15 | return; 16 | } 17 | 18 | thread_list_ = static_cast(dump.rva32(entry->Location)); 19 | found_ = true; 20 | } 21 | 22 | std::experimental::generator thread_ex_list_stream::list() const // NOLINT(bugprone-reserved-identifier) 23 | { 24 | thread_names_list_stream const names_list{dump_}; 25 | for (size_t index = 0; index < thread_list_->NumberOfThreads; ++index) 26 | { 27 | co_yield stream_thread_ex{dump_, thread_list_->Threads[index], names_list}; 28 | } 29 | } 30 | 31 | std::optional thread_ex_list_stream::find_thread(ULONG32 const thread_id, 32 | thread_names_list_stream const& names_list) const 33 | { 34 | for (size_t index = 0; index < thread_list_->NumberOfThreads; ++index) 35 | { 36 | if (thread_list_->Threads[index].ThreadId == thread_id) 37 | { 38 | return stream_thread_ex{dump_, thread_list_->Threads[index], names_list}; 39 | } 40 | } 41 | 42 | return std::nullopt; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_handle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | 7 | // ReSharper disable once CppUnusedIncludeDirective 8 | #include 9 | #include 10 | 11 | #include "stream_handle_object_information.h" 12 | 13 | namespace dlg_help_utils 14 | { 15 | class mini_dump; 16 | 17 | class stream_handle 18 | { 19 | public: 20 | explicit stream_handle(mini_dump const& dump, void const* data, size_t handle_descriptor_version); 21 | 22 | [[nodiscard]] size_t handle_descriptor_version() const { return handle_descriptor_version_; } 23 | 24 | [[nodiscard]] MINIDUMP_HANDLE_DESCRIPTOR const& descriptor() const 25 | { 26 | return *static_cast(data_); 27 | } 28 | 29 | [[nodiscard]] MINIDUMP_HANDLE_DESCRIPTOR_2 const& descriptor_2() const 30 | { 31 | return *static_cast(data_); 32 | } 33 | 34 | [[nodiscard]] std::wstring_view const& type_name() const { return type_name_; } 35 | [[nodiscard]] std::wstring_view const& object_name() const { return object_name_; } 36 | 37 | [[nodiscard]] std::experimental::generator list() const; 38 | 39 | private: 40 | mini_dump const& dump_; 41 | void const* data_; 42 | size_t handle_descriptor_version_; 43 | std::wstring_view type_name_; 44 | std::wstring_view object_name_; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /DbgHelpUtils/by_size_frequency_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "interface_process_heaps_statistic_view_impl.h" 6 | #include "process_heaps_statistic_view.h" 7 | 8 | namespace dlg_help_utils::heap::statistic_views 9 | { 10 | class by_size_frequency_view 11 | : public process_heaps_statistic_view::interface_process_heaps_statistic_view_impl 12 | { 13 | public: 14 | using view_type = process_heaps_statistic_view::view_type; 15 | 16 | by_size_frequency_view(view_type view, allocation_stack_trace_helper const& helper, statistic_view_options const& statistic_view_options, process_heaps const& process, std::map const& allocated_entries, std::map const& free_entries); 17 | 18 | [[nodiscard]] bool is_range_single_value() const override { return true; } 19 | [[nodiscard]] std::experimental::generator buckets() const override; 20 | 21 | private: 22 | struct bucket_entries 23 | { 24 | std::vector entries; 25 | std::vector free_entries; 26 | }; 27 | 28 | [[nodiscard]] static bucket_entries& get_bucket(std::map& buckets, process_heap_entry const& entry); 29 | [[nodiscard]] static double calculate_bucket_range_count_percent(bucket_entries const& bucket, size_t max_entries); 30 | [[nodiscard]] static double calculate_bucket_range_size_percent(std::map const& buckets, uint64_t key); 31 | [[nodiscard]] static uint64_t sum_entries(std::vector const& entries); 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /DbgHelpUtils/windows_error.cpp: -------------------------------------------------------------------------------- 1 | #include "windows_error.h" 2 | 3 | #include 4 | 5 | #include "handles.h" 6 | #include "stream_hex_dump.h" 7 | #include "wide_runtime_error.h" 8 | 9 | using namespace std; 10 | 11 | namespace dlg_help_utils::windows_error 12 | { 13 | using namespace handles; 14 | 15 | void throw_windows_api_error(std::wstring_view const& api, DWORD const ec) 16 | { 17 | throw exceptions::wide_runtime_error{std::format(L"{0} failed. Error: {1} - {2}", api, stream_hex_dump::to_hex(ec), get_windows_error_string(ec))}; 18 | } 19 | 20 | void throw_windows_api_error(std::wstring_view const& api, std::wstring_view const& optional_data, DWORD const ec) 21 | { 22 | throw exceptions::wide_runtime_error{std::format(L"{0} failed ({1}). Error: {2} - {3}", api, optional_data, stream_hex_dump::to_hex(ec), get_windows_error_string(ec))}; 23 | } 24 | 25 | std::wstring get_windows_error_string(DWORD const ec, std::wstring const& dll_source_path) 26 | { 27 | auto const source_module = load_library(dll_source_path); 28 | LPVOID buffer{nullptr}; 29 | FormatMessageW( 30 | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | ( 31 | source_module ? FORMAT_MESSAGE_FROM_HMODULE : 0), 32 | source_module.get(), 33 | ec, 34 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 35 | reinterpret_cast(&buffer), 36 | 0, 37 | nullptr); 38 | if (!buffer) 39 | { 40 | return {}; 41 | } 42 | 43 | auto buffer_handle = make_local_memory_handle(buffer); 44 | return wstring{static_cast(buffer)}; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /MiniDumper/common_symbol_lookup_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace dlg_help_utils 7 | { 8 | namespace stream_utils 9 | { 10 | struct symbol_type_and_value; 11 | } 12 | namespace dbg_help 13 | { 14 | class symbol_type_info; 15 | } 16 | } 17 | 18 | namespace dlg_help_utils 19 | { 20 | namespace stream_stack_dump 21 | { 22 | class mini_dump_memory_walker; 23 | } 24 | } 25 | 26 | std::optional get_type_info(std::wostream& log, dlg_help_utils::stream_stack_dump::mini_dump_memory_walker const& walker, std::wstring const& symbol_type_name); 27 | std::optional find_field_pointer_and_type(std::wostream& log, dlg_help_utils::stream_stack_dump::mini_dump_memory_walker const& walker, dlg_help_utils::dbg_help::symbol_type_info const& type_symbol_info, std::wstring const& symbol_type_name, uint64_t address, std::wstring_view field_name); 28 | std::optional find_field_pointer(std::wostream& log, dlg_help_utils::stream_stack_dump::mini_dump_memory_walker const& walker, dlg_help_utils::dbg_help::symbol_type_info const& type_symbol_info, std::wstring const& symbol_type_name, uint64_t address, std::wstring_view field_name); 29 | std::optional find_field_pointer(std::wostream& log, dlg_help_utils::stream_stack_dump::mini_dump_memory_walker const& walker, std::wstring const& symbol_type_name, uint64_t address, std::wstring_view field_name); 30 | std::optional dump_field(std::wostream& log, dlg_help_utils::stream_stack_dump::mini_dump_memory_walker const& walker, std::wstring const& symbol_type_name, uint64_t address); 31 | -------------------------------------------------------------------------------- /DbgHelpUtils/segment_heap_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "size_units.h" 5 | 6 | namespace dlg_help_utils::process 7 | { 8 | class process_environment_block; 9 | } 10 | 11 | namespace dlg_help_utils::heap 12 | { 13 | class ust_address_stack_trace; 14 | 15 | struct segment_heap_entry_extra_data 16 | { 17 | uint64_t unused_bytes; 18 | uint64_t ust_address; 19 | }; 20 | 21 | class segment_heap_utils 22 | { 23 | public: 24 | static segment_heap_entry_extra_data read_extra_data(process::process_environment_block const& peb, ust_address_stack_trace const& stack_trace, uint64_t block_address, uint64_t block_size); 25 | static uint64_t read_ust_address(process::process_environment_block const& peb, ust_address_stack_trace const& stack_trace, uint64_t block_address, uint64_t block_size, uint64_t unused_bytes); 26 | 27 | static std::optional read_front_padding_size(process::process_environment_block const& peb, uint64_t block_address, uint64_t block_size, uint16_t windows10_min_version, uint16_t windows10_max_version); 28 | static std::optional read_front_padding_size_large(process::process_environment_block const& peb, uint64_t block_address, uint64_t block_size, uint16_t windows10_min_version, uint16_t windows10_max_version); 29 | 30 | static bool may_have_front_padding(process::process_environment_block const& peb, uint16_t windows10_min_version, uint16_t windows10_max_version); 31 | 32 | private: 33 | template 34 | static std::optional get_read_front_padding_size(process::process_environment_block const& peb, uint64_t block_address, uint64_t block_size, std::array front_padding_sizes); 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /DbgHelpUtils/list_entry_walker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "stream_utils.h" 7 | #include "symbol_type_info.h" 8 | 9 | namespace dlg_help_utils 10 | { 11 | class cache_manager; 12 | } 13 | 14 | namespace dlg_help_utils::stream_stack_dump 15 | { 16 | class mini_dump_memory_walker; 17 | } 18 | 19 | namespace dlg_help_utils::ntdll_utilities 20 | { 21 | 22 | class list_entry_walker 23 | { 24 | public: 25 | list_entry_walker(cache_manager& cache, stream_stack_dump::mini_dump_memory_walker const& walker, uint64_t start_address, std::wstring const& entry_symbol_name, std::wstring const& entry_field_name, std::function address_decoder = {}); 26 | 27 | [[nodiscard]] cache_manager& cache() const { return *cache_manager_; } 28 | [[nodiscard]] stream_stack_dump::mini_dump_memory_walker const& walker() const { return *walker_; } 29 | 30 | [[nodiscard]] std::experimental::generator entries() const; 31 | 32 | static std::wstring const& symbol_name; 33 | 34 | private: 35 | struct cache_data 36 | { 37 | dbg_help::symbol_type_info list_entry_symbol_type; 38 | stream_utils::symbol_type_and_base_type_field_offset flink_field_data; 39 | }; 40 | 41 | [[nodiscard]] cache_data const& setup_globals() const; 42 | 43 | private: 44 | cache_manager* cache_manager_; 45 | stream_stack_dump::mini_dump_memory_walker const* walker_; 46 | uint64_t start_address_; 47 | std::function address_decoder_; 48 | uint64_t list_entry_entry_offset_; 49 | cache_data const* cache_data_{&setup_globals()}; 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /DbgHelpUtils/range_units.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifdef max 5 | #undef max 6 | #endif 7 | 8 | namespace dlg_help_utils::range_utils 9 | { 10 | template 11 | void limit_range(T start_range, T end_range, Tl& length) 12 | { 13 | if (start_range > end_range - length) 14 | { 15 | length = end_range - start_range; 16 | } 17 | } 18 | 19 | template 20 | void limit_range(T start_range, Tl& length) 21 | { 22 | limit_range(start_range, std::numeric_limits::max(), length); 23 | } 24 | 25 | template 26 | bool range_contains(T start_range, uint64_t range_length, T start, uint64_t length) 27 | { 28 | return start >= start_range && start + length <= start_range + range_length; 29 | } 30 | 31 | template 32 | bool range_union(T start_range, uint64_t range_length, T start, uint64_t& length) 33 | { 34 | if (!range_contains(start_range, range_length, start, 1)) 35 | { 36 | return false; 37 | } 38 | 39 | if (start + length >= start_range + range_length) 40 | { 41 | length = (start_range + range_length) - start; 42 | } 43 | 44 | return true; 45 | } 46 | 47 | template 48 | bool validate_range(T start_range, T end_range, Tl length) 49 | { 50 | if (start_range > end_range - length) 51 | { 52 | return false; 53 | } 54 | return true; 55 | } 56 | 57 | template 58 | bool validate_range(T start_range, Tl length) 59 | { 60 | return validate_range(start_range, std::numeric_limits::max(), length); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /DbgHelpUtils/by_size_ranges_frequency_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "interface_process_heaps_statistic_view_impl.h" 6 | #include "process_heaps_statistic_view.h" 7 | 8 | namespace dlg_help_utils::heap::statistic_views 9 | { 10 | class by_size_ranges_frequency_view 11 | : public process_heaps_statistic_view::interface_process_heaps_statistic_view_impl 12 | { 13 | public: 14 | using view_type = process_heaps_statistic_view::view_type; 15 | 16 | by_size_ranges_frequency_view(view_type view, allocation_stack_trace_helper const& helper, statistic_view_options const& statistic_view_options, process_heaps const& process, std::map const& allocated_entries, std::map const& free_entries); 17 | 18 | [[nodiscard]] bool is_range_single_value() const override { return false; } 19 | [[nodiscard]] std::experimental::generator buckets() const override; 20 | 21 | private: 22 | struct bucket_entries 23 | { 24 | std::vector entries; 25 | std::vector free_entries; 26 | }; 27 | 28 | [[nodiscard]] bucket_entries& get_bucket(std::map& buckets, process_heap_entry const& entry) const; 29 | [[nodiscard]] static double calculate_bucket_range_count_percent(bucket_entries const& bucket, size_t max_entries); 30 | [[nodiscard]] static double calculate_bucket_range_size_percent(std::map const& buckets, uint64_t key); 31 | [[nodiscard]] static uint64_t sum_entries(std::vector const& entries); 32 | 33 | private: 34 | size_units::base_16::bytes range_size_; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /DbgHelpUtils/call_convention.h: -------------------------------------------------------------------------------- 1 | // ReSharper disable IdentifierTypo 2 | #pragma once 3 | 4 | namespace dlg_help_utils::dbg_help 5 | { 6 | enum class calling_convention 7 | { 8 | near_c = 0x00, // near right to left push, caller pops stack 9 | far_c = 0x01, // far right to left push, caller pops stack 10 | near_pascal = 0x02, // near left to right push, callee pops stack 11 | far_pascal = 0x03, // far left to right push, callee pops stack 12 | near_fast = 0x04, // near left to right push with regs, callee pops stack 13 | far_fast = 0x05, // far left to right push with regs, callee pops stack 14 | skipped = 0x06, // skipped (unused) call index 15 | near_std = 0x07, // near standard call 16 | far_std = 0x08, // far standard call 17 | near_sys = 0x09, // near sys call 18 | far_sys = 0x0a, // far sys call 19 | thiscall = 0x0b, // this call (this passed in register) 20 | mipscall = 0x0c, // Mips call 21 | generic = 0x0d, // Generic call sequence 22 | alphacall = 0x0e, // Alpha call 23 | ppccall = 0x0f, // PPC call 24 | shcall = 0x10, // Hitachi SuperH call 25 | armcall = 0x11, // ARM call 26 | am33call = 0x12, // AM33 call 27 | tricall = 0x13, // TriCore Call 28 | sh5_call = 0x14, // Hitachi SuperH-5 call 29 | m32rcall = 0x15, // M32R Call 30 | clrcall = 0x16, // clr call 31 | inlinecall = 0x17, // Marker for routines always inlined and thus lacking a convention 32 | near_vector = 0x18, // near left to right push with regs, callee pops stack 33 | swift = 0x19, // Swift calling convention 34 | reserved = 0x20 // first unused call enumeration 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /DbgHelpUtils/heap_ucr_descriptor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "size_units.h" 5 | #include "stream_utils.h" 6 | #include "symbol_type_info.h" 7 | 8 | namespace dlg_help_utils::process 9 | { 10 | class process_environment_block; 11 | } 12 | 13 | namespace dlg_help_utils::stream_stack_dump 14 | { 15 | class mini_dump_memory_walker; 16 | } 17 | 18 | namespace dlg_help_utils::heap 19 | { 20 | class nt_heap; 21 | 22 | class heap_ucr_descriptor 23 | { 24 | public: 25 | heap_ucr_descriptor(nt_heap const& heap, uint64_t heap_ucr_descriptor_address); 26 | 27 | [[nodiscard]] nt_heap const& heap() const { return *heap_; } 28 | [[nodiscard]] stream_stack_dump::mini_dump_memory_walker const& walker() const; 29 | [[nodiscard]] process::process_environment_block const& peb() const; 30 | 31 | [[nodiscard]] uint64_t address() const; 32 | [[nodiscard]] size_units::base_16::bytes size() const; 33 | 34 | [[nodiscard]] uint64_t symbol_address() const { return heap_ucr_descriptor_address_; } 35 | [[nodiscard]] dbg_help::symbol_type_info const& symbol_type() const { return cache_data_->heap_ucr_descriptor_symbol_type; } 36 | 37 | static std::wstring const& symbol_name; 38 | static void setup_globals(nt_heap const& heap); 39 | 40 | private: 41 | struct cache_data 42 | { 43 | dbg_help::symbol_type_info heap_ucr_descriptor_symbol_type; 44 | stream_utils::symbol_type_and_base_type_field_offset heap_ucr_descriptor_address_field_data; 45 | stream_utils::symbol_type_and_base_type_field_offset heap_ucr_descriptor_size_field_data; 46 | }; 47 | 48 | cache_data const* cache_data_; 49 | nt_heap const* heap_; 50 | uint64_t heap_ucr_descriptor_address_; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /DbgHelpUtils/misc_info_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "misc_info_stream.h" 2 | 3 | #include "mini_dump.h" 4 | #include "string_stream.h" 5 | 6 | using namespace std::string_view_literals; 7 | 8 | namespace dlg_help_utils 9 | { 10 | misc_info_stream::misc_info_stream(mini_dump const& dump, size_t const index) 11 | { 12 | index_ = index; 13 | auto const* entry = dump.find_stream_type(MiscInfoStream, index_); 14 | if (entry == nullptr) 15 | { 16 | return; 17 | } 18 | 19 | auto const* data = dump.rva32(entry->Location); 20 | found_ = true; 21 | 22 | if (entry->Location.DataSize >= sizeof(MINIDUMP_MISC_INFO)) 23 | { 24 | misc_info_version_ = 1; 25 | misc_info_ = static_cast(data); 26 | is_valid_ = true; 27 | } 28 | else 29 | { 30 | return; 31 | } 32 | 33 | if (entry->Location.DataSize >= sizeof(MINIDUMP_MISC_INFO_2)) 34 | { 35 | misc_info_version_ = 2; 36 | misc_info_2_ = static_cast(data); 37 | } 38 | 39 | if (entry->Location.DataSize >= sizeof(MINIDUMP_MISC_INFO_3)) 40 | { 41 | misc_info_version_ = 3; 42 | misc_info_3_ = static_cast(data); 43 | } 44 | 45 | if (entry->Location.DataSize >= sizeof(MINIDUMP_MISC_INFO_4)) 46 | { 47 | misc_info_version_ = 4; 48 | misc_info_4_ = static_cast(data); 49 | } 50 | 51 | if (entry->Location.DataSize >= sizeof(MINIDUMP_MISC_INFO_5)) 52 | { 53 | misc_info_version_ = 5; 54 | misc_info_5_ = static_cast(data); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /DbgHelpUtils/lfh_heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "nt_heap.h" 6 | #include "symbol_type_info.h" 7 | 8 | namespace dlg_help_utils::process 9 | { 10 | class process_environment_block; 11 | } 12 | 13 | namespace dlg_help_utils::stream_stack_dump 14 | { 15 | class mini_dump_memory_walker; 16 | } 17 | 18 | namespace dlg_help_utils::heap 19 | { 20 | class lfh_segment; 21 | 22 | class lfh_heap 23 | { 24 | public: 25 | lfh_heap(nt_heap const& heap, uint64_t lfh_heap_address); 26 | 27 | [[nodiscard]] nt_heap const& heap() const { return *heap_; } 28 | [[nodiscard]] stream_stack_dump::mini_dump_memory_walker const& walker() const; 29 | [[nodiscard]] process::process_environment_block const& peb() const; 30 | 31 | [[nodiscard]] uint64_t address() const { return lfh_heap_address_; } 32 | 33 | [[nodiscard]] std::optional const& lfh_key() const { return cache_data_->lfh_key; } 34 | [[nodiscard]] std::experimental::generator lfh_segments() const; 35 | 36 | [[nodiscard]] uint64_t symbol_address() const { return address(); } 37 | [[nodiscard]] dbg_help::symbol_type_info const& symbol_type() const { return cache_data_->lfh_heap_symbol_type; } 38 | 39 | static std::wstring const& symbol_name; 40 | static void setup_globals(nt_heap const& heap); 41 | 42 | private: 43 | struct cache_data 44 | { 45 | dbg_help::symbol_type_info lfh_heap_symbol_type; 46 | std::optional lfh_key; 47 | dbg_help::symbol_type_and_field_offset lfh_heap_sub_segment_zones_field_data; 48 | }; 49 | 50 | cache_data const* cache_data_; 51 | nt_heap const* heap_; 52 | uint64_t lfh_heap_address_; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heaps_statistics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | #include 4 | #include 5 | 6 | #include "allocation_stack_trace_helper.h" 7 | 8 | namespace dlg_help_utils::heap 9 | { 10 | namespace statistic_views 11 | { 12 | class statistic_view_options; 13 | } 14 | 15 | class process_heaps; 16 | class process_heap_entry; 17 | class process_heaps_statistic_view; 18 | 19 | class process_heaps_statistics 20 | { 21 | public: 22 | process_heaps_statistics(process_heaps const& process, system_module_list const& system_module_list, statistic_views::statistic_view_options const& statistic_view_options); 23 | 24 | [[nodiscard]] process_heaps_statistic_view view_by_size_frequency() const; 25 | [[nodiscard]] process_heaps_statistic_view view_by_size_ranges_frequency() const; 26 | [[nodiscard]] process_heaps_statistic_view view_by_stacktrace_frequency() const; 27 | [[nodiscard]] process_heaps_statistic_view view_by_application_callsite_frequency() const; 28 | 29 | private: 30 | [[nodiscard]] std::map get_allocated_entries() const; 31 | [[nodiscard]] std::map get_free_entries() const; 32 | [[nodiscard]] static std::map get_all_entries(std::experimental::generator entries); 33 | 34 | private: 35 | process_heaps const& process_; 36 | statistic_views::statistic_view_options const& statistic_view_options_; 37 | statistic_views::allocation_stack_trace_helper const helper_; 38 | std::map const allocated_entries_; 39 | std::map const free_entries_; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /DbgHelpUtils/by_stacktrace_frequency_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "interface_process_heaps_statistic_view_impl.h" 6 | #include "process_heaps_statistic_view.h" 7 | 8 | namespace dlg_help_utils::heap::statistic_views 9 | { 10 | class by_stacktrace_frequency_view 11 | : public process_heaps_statistic_view::interface_process_heaps_statistic_view_impl 12 | { 13 | public: 14 | using view_type = process_heaps_statistic_view::view_type; 15 | 16 | by_stacktrace_frequency_view(view_type view, allocation_stack_trace_helper const& helper, statistic_view_options const& statistic_view_options, process_heaps const& process, std::map const& allocated_entries, std::map const& free_entries); 17 | 18 | [[nodiscard]] bool is_range_single_value() const override { return false; } 19 | [[nodiscard]] std::experimental::generator buckets() const override; 20 | 21 | private: 22 | struct bucket_entries 23 | { 24 | size_units::base_16::bytes start_range{0}; 25 | size_units::base_16::bytes end_range{0}; 26 | std::vector entries; 27 | std::vector free_entries; 28 | }; 29 | 30 | [[nodiscard]] static bucket_entries& get_bucket(std::map& buckets, process_heap_entry const& entry); 31 | [[nodiscard]] static double calculate_bucket_range_count_percent(bucket_entries const& bucket, size_t max_entries); 32 | [[nodiscard]] static double calculate_bucket_range_size_percent(std::map const& buckets, uint64_t key); 33 | [[nodiscard]] static uint64_t sum_entries(std::vector const& entries); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /DbgHelpUtils/unloaded_module_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | 4 | // ReSharper disable once CppUnusedIncludeDirective 5 | #include "windows_setup.h" 6 | #include 7 | #include 8 | 9 | #include "stream_unloaded_module.h" 10 | 11 | namespace dlg_help_utils 12 | { 13 | class mini_dump; 14 | 15 | class unloaded_module_list_stream 16 | { 17 | public: 18 | explicit unloaded_module_list_stream(mini_dump const& dump, size_t index = 0); 19 | 20 | [[nodiscard]] bool found() const { return found_; } 21 | [[nodiscard]] bool is_valid() const { return is_valid_; } 22 | [[nodiscard]] size_t index() const { return index_; } 23 | [[nodiscard]] ULONG32 size() const { return module_list_->NumberOfEntries; } 24 | 25 | [[nodiscard]] std::vector const& list() const { return modules_; } 26 | 27 | [[nodiscard]] stream_unloaded_module const* find_module(uint64_t address) const; 28 | [[nodiscard]] stream_unloaded_module const* find_module(std::wstring_view const& module_name) const; 29 | 30 | private: 31 | [[nodiscard]] static MINIDUMP_UNLOADED_MODULE_LIST const* get_unloaded_module_list(mini_dump const& dump, size_t& index); 32 | [[nodiscard]] MINIDUMP_UNLOADED_MODULE const* get_unloaded_module() const; 33 | [[nodiscard]] std::vector build_modules() const; 34 | 35 | private: 36 | mini_dump const& dump_; 37 | MINIDUMP_UNLOADED_MODULE_LIST const* module_list_; 38 | size_t const index_; 39 | bool const found_; 40 | bool const is_valid_; 41 | MINIDUMP_UNLOADED_MODULE const* list_{get_unloaded_module()}; 42 | std::vector const modules_{build_modules()}; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /DbgHelpUtils/memory_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dlg_help_utils 10 | { 11 | struct memory_range; 12 | class mini_dump; 13 | 14 | class memory_list_stream 15 | { 16 | public: 17 | explicit memory_list_stream(mini_dump const& dump, size_t index = 0); 18 | 19 | [[nodiscard]] bool found() const { return found_; } 20 | [[nodiscard]] size_t index() const { return index_; } 21 | [[nodiscard]] MINIDUMP_MEMORY_LIST const& memory_list() const { return *memory_list_; } 22 | 23 | [[nodiscard]] std::vector const& list() const { return memory_address_ranges_; } 24 | 25 | [[nodiscard]] void const* find_address_range(uint64_t address, uint64_t length) const; 26 | [[nodiscard]] void const* find_any_address_range(uint64_t address, uint64_t& length) const; 27 | [[nodiscard]] std::experimental::generator memory_ranges() const; 28 | 29 | private: 30 | [[nodiscard]] std::vector::const_iterator memory_address_ranges_upper_bound(uint64_t address) const; 31 | [[nodiscard]] static MINIDUMP_MEMORY_LIST const* get_memory_list(mini_dump const& dump, size_t& index); 32 | [[nodiscard]] std::vector build_memory_address_ranges() const; 33 | 34 | private: 35 | mini_dump const& dump_; 36 | MINIDUMP_MEMORY_LIST const* memory_list_; 37 | size_t const index_; 38 | std::vector memory_address_ranges_{build_memory_address_ranges()}; 39 | bool const found_; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /DbgHelpUtils/process_heap_entry_symbol_address_reference.cpp: -------------------------------------------------------------------------------- 1 | #include "process_heap_entry_symbol_address_reference.h" 2 | 3 | namespace dlg_help_utils::heap::allocation_graph 4 | { 5 | process_heap_entry_symbol_address_reference::process_heap_entry_symbol_address_reference(is_root_symbol_t const is_root_symbol, is_metadata_symbol_t const is_metadata_symbol, uint64_t const address, uint64_t const node_index, dbg_help::symbol_type_info symbol_type, uint32_t const thread_id, std::wstring thread_name) 6 | : address_{address} 7 | , node_index_{node_index} 8 | , is_root_symbol_{is_root_symbol} 9 | , is_metadata_symbol_{is_metadata_symbol} 10 | , symbol_type_{std::move(symbol_type)} 11 | , thread_id_{thread_id} 12 | , thread_name_{std::move(thread_name)} 13 | { 14 | } 15 | 16 | process_heap_entry_symbol_address_reference::process_heap_entry_symbol_address_reference(is_root_symbol_t const is_root_symbol, is_metadata_symbol_t const is_metadata_symbol, uint64_t const address, uint64_t const node_index, dbg_help::symbol_type_info symbol_type) 17 | : address_{address} 18 | , node_index_{node_index} 19 | , is_root_symbol_{is_root_symbol} 20 | , is_metadata_symbol_{is_metadata_symbol} 21 | , symbol_type_{std::move(symbol_type)} 22 | { 23 | } 24 | 25 | void process_heap_entry_symbol_address_reference::add_variable_symbol_reference(uint64_t const variable_address, uint64_t const variable_address_offset, size_t const pointer_size, dbg_help::symbol_type_info pointer_symbol_type, std::wstring name) 26 | { 27 | auto const end_variable_address = variable_address + pointer_size - 1; 28 | variable_symbol_references_.insert(std::make_pair(end_variable_address, variable_symbol_data{variable_address_offset, variable_address, std::move(pointer_symbol_type), std::move(name)})); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DbgHelpUtils/rtl_balanced_links_walker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "stream_utils.h" 6 | #include "symbol_type_info.h" 7 | 8 | namespace dlg_help_utils 9 | { 10 | class cache_manager; 11 | } 12 | 13 | namespace dlg_help_utils::stream_stack_dump 14 | { 15 | class mini_dump_memory_walker; 16 | } 17 | 18 | namespace dlg_help_utils::ntdll_utilities 19 | { 20 | 21 | class rtl_balanced_links_walker 22 | { 23 | public: 24 | rtl_balanced_links_walker(cache_manager& cache, stream_stack_dump::mini_dump_memory_walker const& walker, uint64_t head_node_address, std::wstring const& entry_symbol_name, std::wstring const& entry_field_name); 25 | rtl_balanced_links_walker(cache_manager& cache, stream_stack_dump::mini_dump_memory_walker const& walker, uint64_t head_node_address); 26 | 27 | [[nodiscard]] cache_manager& cache() const { return *cache_manager_; } 28 | [[nodiscard]] stream_stack_dump::mini_dump_memory_walker const& walker() const { return *walker_; } 29 | 30 | [[nodiscard]] std::experimental::generator entries() const; 31 | 32 | static std::wstring const& symbol_name; 33 | 34 | private: 35 | struct cache_data 36 | { 37 | dbg_help::symbol_type_info rtl_balanced_links_symbol_type; 38 | stream_utils::symbol_type_and_base_type_field_offset right_field_data; 39 | stream_utils::symbol_type_and_base_type_field_offset left_field_data; 40 | }; 41 | 42 | [[nodiscard]] cache_data const& setup_globals() const; 43 | 44 | private: 45 | cache_manager* cache_manager_; 46 | stream_stack_dump::mini_dump_memory_walker const* walker_; 47 | uint64_t head_node_address_; 48 | uint64_t rtl_balanced_link_entry_offset_; 49 | cache_data const* cache_data_{&setup_globals()}; 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /DbgHelpUtils/rtl_rb_tree_walker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "stream_utils.h" 6 | #include "symbol_type_info.h" 7 | 8 | namespace dlg_help_utils 9 | { 10 | class cache_manager; 11 | } 12 | 13 | namespace dlg_help_utils::stream_stack_dump 14 | { 15 | class mini_dump_memory_walker; 16 | } 17 | 18 | namespace dlg_help_utils::ntdll_utilities 19 | { 20 | 21 | class rtl_rb_tree_walker 22 | { 23 | public: 24 | rtl_rb_tree_walker(cache_manager& cache, stream_stack_dump::mini_dump_memory_walker const& walker, uint64_t rb_tree_address, std::wstring const& entry_symbol_name, std::wstring const& entry_field_name); 25 | 26 | [[nodiscard]] cache_manager& cache() const { return *cache_manager_; } 27 | [[nodiscard]] stream_stack_dump::mini_dump_memory_walker const& walker() const { return *walker_; } 28 | 29 | [[nodiscard]] std::experimental::generator entries() const; 30 | 31 | static std::wstring const& symbol_name; 32 | static std::wstring const& node_symbol_name; 33 | 34 | private: 35 | struct cache_data 36 | { 37 | dbg_help::symbol_type_info rtl_rb_tree_symbol_type; 38 | dbg_help::symbol_type_info rtl_rb_balanced_node_symbol_type; 39 | stream_utils::symbol_type_and_base_type_field_offset root_field_data; 40 | stream_utils::symbol_type_and_base_type_field_offset right_field_data; 41 | stream_utils::symbol_type_and_base_type_field_offset left_field_data; 42 | }; 43 | 44 | [[nodiscard]] cache_data const& setup_globals() const; 45 | 46 | private: 47 | cache_manager* cache_manager_; 48 | stream_stack_dump::mini_dump_memory_walker const* walker_; 49 | uint64_t rb_tree_address_; 50 | uint64_t rtl_balanced_node_entry_offset_; 51 | cache_data const* cache_data_{&setup_globals()}; 52 | }; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /DbgHelpUtils/handles.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows_setup.h" 3 | #include 4 | #include 5 | 6 | namespace dlg_help_utils::handles 7 | { 8 | template 9 | std::unique_ptr make_handle(T* handle, D deleter) 10 | { 11 | return std::unique_ptr{handle, deleter}; 12 | } 13 | 14 | // ReSharper disable once CppParameterMayBeConst 15 | inline auto make_windows_handle(HANDLE handle) 16 | { 17 | return make_handle(handle == INVALID_HANDLE_VALUE ? nullptr : handle, CloseHandle); 18 | } 19 | 20 | inline auto make_empty_windows_handle() 21 | { 22 | return make_windows_handle(nullptr); 23 | } 24 | 25 | using windows_handle = decltype(make_windows_handle(HANDLE{})); 26 | 27 | // ReSharper disable once CppParameterMayBeConst 28 | inline auto make_windows_library_handle(HMODULE handle) 29 | { 30 | return make_handle(handle, FreeLibrary); 31 | } 32 | 33 | using windows_library_handle = decltype(make_windows_library_handle(HMODULE{})); 34 | 35 | inline auto load_library(std::wstring const& dll_source_path) 36 | { 37 | return make_windows_library_handle(dll_source_path.empty() ? nullptr : LoadLibraryW(dll_source_path.c_str())); 38 | } 39 | 40 | // ReSharper disable once CppParameterMayBeConst 41 | inline auto make_local_memory_handle(LPVOID ptr) 42 | { 43 | return make_handle(ptr, LocalFree); 44 | } 45 | 46 | using local_memory_handle = decltype(make_local_memory_handle(LPVOID{})); 47 | 48 | // ReSharper disable once CppParameterMayBeConst 49 | inline auto make_map_view_handle(LPVOID ptr) 50 | { 51 | return make_handle(ptr, UnmapViewOfFile); 52 | } 53 | 54 | using map_view_handle = decltype(make_map_view_handle(LPVOID{})); 55 | 56 | inline auto make_empty_map_view_handle() 57 | { 58 | return make_map_view_handle(nullptr); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /DbgHelpUtils/by_application_callsite_frequency_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "interface_process_heaps_statistic_view_impl.h" 6 | #include "process_heaps_statistic_view.h" 7 | 8 | namespace dlg_help_utils::heap::statistic_views 9 | { 10 | class by_application_callsite_frequency_view 11 | : public process_heaps_statistic_view::interface_process_heaps_statistic_view_impl 12 | { 13 | public: 14 | using view_type = process_heaps_statistic_view::view_type; 15 | 16 | by_application_callsite_frequency_view(view_type view, allocation_stack_trace_helper const& helper, statistic_view_options const& statistic_view_options, process_heaps const& process, std::map const& allocated_entries, std::map const& free_entries); 17 | 18 | [[nodiscard]] bool is_range_single_value() const override { return false; } 19 | [[nodiscard]] std::experimental::generator buckets() const override; 20 | 21 | private: 22 | struct bucket_entries 23 | { 24 | std::optional common_allocation_callsite; 25 | size_units::base_16::bytes start_range{0}; 26 | size_units::base_16::bytes end_range{0}; 27 | std::vector entries; 28 | std::vector free_entries; 29 | }; 30 | 31 | [[nodiscard]] bucket_entries& get_bucket(std::map& buckets, process_heap_entry const& entry) const; 32 | [[nodiscard]] static double calculate_bucket_range_count_percent(bucket_entries const& bucket, size_t max_entries); 33 | [[nodiscard]] static double calculate_bucket_range_size_percent(std::map const& buckets, uint64_t key); 34 | [[nodiscard]] static uint64_t sum_entries(std::vector const& entries); 35 | }; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /DbgHelpUtils/memory64_list_stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable CppClangTidyCppcoreguidelinesAvoidConstOrRefDataMembers 3 | // ReSharper disable once CppUnusedIncludeDirective 4 | #include "windows_setup.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dlg_help_utils 10 | { 11 | struct memory_range; 12 | class mini_dump; 13 | 14 | struct memory64_entry 15 | { 16 | ULONG64 start_of_memory_range; 17 | ULONG64 end_of_memory_range; 18 | MINIDUMP_LOCATION_DESCRIPTOR64 location; 19 | }; 20 | 21 | class memory64_list_stream 22 | { 23 | public: 24 | explicit memory64_list_stream(mini_dump const& dump, size_t index = 0); 25 | 26 | [[nodiscard]] bool found() const { return found_; } 27 | [[nodiscard]] size_t index() const { return index_; } 28 | [[nodiscard]] MINIDUMP_MEMORY64_LIST const& memory_list() const { return *memory_list_; } 29 | 30 | [[nodiscard]] std::vector const& list() const { return memory_address_ranges_; } 31 | 32 | [[nodiscard]] void const* find_address_range(uint64_t address, uint64_t length) const; 33 | [[nodiscard]] void const* find_any_address_range(uint64_t address, uint64_t& length) const; 34 | [[nodiscard]] std::experimental::generator memory_ranges() const; 35 | 36 | private: 37 | [[nodiscard]] std::vector::const_iterator memory_address_ranges_upper_bound(uint64_t address) const; 38 | [[nodiscard]] static MINIDUMP_MEMORY64_LIST const* get_memory_list(mini_dump const& dump, size_t& index); 39 | [[nodiscard]] std::vector build_memory_address_ranges() const; 40 | 41 | private: 42 | mini_dump const& dump_; 43 | MINIDUMP_MEMORY64_LIST const* memory_list_; 44 | size_t const index_; 45 | std::vector const memory_address_ranges_{build_memory_address_ranges()}; 46 | bool const found_; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /ValidateHeapEntries/symbol_engine_ui.cpp: -------------------------------------------------------------------------------- 1 | #include "symbol_engine_ui.h" 2 | 3 | #include 4 | #include 5 | 6 | symbol_engine_ui::symbol_engine_ui(bool const no_output) 7 | : no_output_{no_output} 8 | { 9 | } 10 | 11 | bool symbol_engine_ui::deferred_symbol_load_cancel([[maybe_unused]] std::wstring_view const& module_name) 12 | { 13 | return false; 14 | } 15 | 16 | void symbol_engine_ui::deferred_symbol_load_partial([[maybe_unused]] std::wstring_view const& module_name) 17 | { 18 | } 19 | 20 | void symbol_engine_ui::start_download(std::wstring_view const& module_name) 21 | { 22 | std::wstringstream ss; 23 | ss << L"downloading " << module_name << L": "; 24 | module_ = std::move(ss).str(); 25 | if(!no_output_) 26 | { 27 | std::wcerr << module_; 28 | } 29 | last_percent_.clear(); 30 | } 31 | 32 | void symbol_engine_ui::download_percent(unsigned const percent) 33 | { 34 | if (!last_percent_.empty()) 35 | { 36 | std::wcerr << std::wstring(last_percent_.size(), L'\b'); 37 | } 38 | 39 | std::wstringstream ss; 40 | ss << percent << L"%"; 41 | if(!no_output_) 42 | { 43 | std::wcerr << ss.str(); 44 | } 45 | last_percent_ = std::move(ss).str(); 46 | } 47 | 48 | void symbol_engine_ui::download_complete() 49 | { 50 | if (!no_output_ && (!last_percent_.empty() || !module_.empty())) 51 | { 52 | std::wstring const clear(last_percent_.size() + module_.size(), L'\b'); 53 | std::wcerr << clear << std::wstring(last_percent_.size() + module_.size(), L' ') << clear; 54 | } 55 | last_percent_.clear(); 56 | module_.clear(); 57 | } 58 | 59 | std::wostream& symbol_engine_ui::log_stream() const 60 | { 61 | if(!no_output_) 62 | { 63 | return std::wcerr; 64 | } 65 | 66 | return null_stream_; 67 | } 68 | 69 | bool symbol_engine_ui::symbol_load_debug() const 70 | { 71 | return false; 72 | } 73 | 74 | bool symbol_engine_ui::symbol_load_debug_memory() const 75 | { 76 | return false; 77 | } 78 | -------------------------------------------------------------------------------- /DbgHelpUtils/handle_data_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "handle_data_stream.h" 2 | 3 | #include "mini_dump.h" 4 | 5 | namespace dlg_help_utils 6 | { 7 | handle_data_stream::handle_data_stream(mini_dump const& dump, size_t const index) 8 | : dump_{dump} 9 | , index_{index} 10 | { 11 | auto const* entry = dump.find_stream_type(HandleDataStream, index_); 12 | if (entry == nullptr) 13 | { 14 | return; 15 | } 16 | 17 | auto const* data = dump.rva32(entry->Location); 18 | handle_data_list_ = static_cast(data); 19 | found_ = true; 20 | 21 | if (handle_data_list_->SizeOfHeader == sizeof(MINIDUMP_HANDLE_DATA_STREAM)) 22 | { 23 | if (handle_data_list_->SizeOfDescriptor == sizeof(MINIDUMP_HANDLE_DESCRIPTOR)) 24 | { 25 | handle_descriptor_version_ = 1; 26 | } 27 | else if (handle_data_list_->SizeOfDescriptor == sizeof(MINIDUMP_HANDLE_DESCRIPTOR_2)) 28 | { 29 | handle_descriptor_version_ = 2; 30 | } 31 | else 32 | { 33 | return; 34 | } 35 | 36 | list_ = static_cast(data) + sizeof(MINIDUMP_HANDLE_OPERATION_LIST); 37 | is_valid_ = true; 38 | 39 | for (auto const& handle : list()) 40 | { 41 | ++handle_type_totals_[handle.type_name()]; 42 | } 43 | } 44 | } 45 | 46 | std::experimental::generator handle_data_stream::list() const // NOLINT(bugprone-reserved-identifier) 47 | { 48 | if (!is_valid()) co_return; 49 | 50 | for (size_t index = 0; index < handle_data_list_->NumberOfDescriptors; ++index) 51 | { 52 | // ReSharper disable once CppAwaiterTypeIsNotClass 53 | co_yield stream_handle{ 54 | dump_, list_ + (index * handle_data_list_->SizeOfDescriptor), handle_descriptor_version_ 55 | }; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /DbgHelpUtils/stream_thread_context.cpp: -------------------------------------------------------------------------------- 1 | #include "stream_thread_context.h" 2 | 3 | #include "mini_dump.h" 4 | #include "system_info_stream.h" 5 | 6 | #ifndef CONTEXT_i386 7 | // ReSharper disable once CppInconsistentNaming 8 | #define CONTEXT_i386 0x10000 // NOLINT(cppcoreguidelines-macro-usage) 9 | #define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x20L) // NOLINT(cppcoreguidelines-macro-usage) 10 | #endif 11 | 12 | namespace dlg_help_utils 13 | { 14 | stream_thread_context::stream_thread_context(mini_dump const& dump, MINIDUMP_LOCATION_DESCRIPTOR const& location) 15 | : context_{dump.rva32(location)} 16 | , size_{location.DataSize} 17 | { 18 | if (system_info_stream const system_info{dump}; system_info.found()) 19 | { 20 | switch (system_info.system_info().ProcessorArchitecture) 21 | { 22 | case PROCESSOR_ARCHITECTURE_INTEL: 23 | x86_thread_context_available_ = true; 24 | x86_thread_context_ = static_cast(context_); 25 | x86_thread_context_has_extended_registers_ = (x86_thread_context_->ContextFlags & 26 | CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS; 27 | break; 28 | 29 | case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: 30 | case PROCESSOR_ARCHITECTURE_IA32_ON_ARM64: 31 | wow64_thread_context_available_ = true; 32 | wow64_thread_context_ = static_cast(context_); 33 | wow64_thread_context_has_extended_registers_ = (wow64_thread_context_->ContextFlags & 34 | CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS; 35 | break; 36 | 37 | case PROCESSOR_ARCHITECTURE_AMD64: 38 | x64_thread_context_available_ = true; 39 | x64_thread_context_ = static_cast(context_); 40 | break; 41 | 42 | default: 43 | break; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_symbols.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class dump_file_options; 6 | 7 | namespace dlg_help_utils 8 | { 9 | class module_list_stream; 10 | class cache_manager; 11 | 12 | namespace dbg_help 13 | { 14 | class symbol_type_info; 15 | class symbol_engine; 16 | } 17 | 18 | class mini_dump; 19 | } 20 | 21 | void dump_mini_dump_symbol_type(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, std::wstring const& type_name, dump_file_options const& options, 22 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 23 | void dump_mini_dump_symbol_name(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, std::wstring const& symbol_name, dump_file_options const& options, 24 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 25 | void dump_mini_dump_module_symbol_types(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, std::wstring const& module_name, dump_file_options const& options, 26 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 27 | void dump_mini_dump_address(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, std::wstring const& address, dump_file_options const& options, 28 | dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 29 | void dump_symbol_type(std::wostream& log, dlg_help_utils::dbg_help::symbol_type_info const& type, dlg_help_utils::module_list_stream const& module_list, dump_file_options const& options, size_t base_offset = 0, size_t indent = 0); 30 | void dump_mini_dump_peb(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, dlg_help_utils::cache_manager& cache, dump_file_options const& options, dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 31 | void dump_mini_dump_stack_trace_database(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, dlg_help_utils::cache_manager& cache, dump_file_options const& options, dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 32 | -------------------------------------------------------------------------------- /DbgHelpUtils/thread_list_stream.cpp: -------------------------------------------------------------------------------- 1 | #include "thread_list_stream.h" 2 | 3 | 4 | #include "memory64_list_stream.h" 5 | #include "memory_list_stream.h" 6 | #include "mini_dump.h" 7 | #include "thread_names_list_stream.h" 8 | 9 | namespace dlg_help_utils 10 | { 11 | thread_list_stream::thread_list_stream(mini_dump const& dump, size_t const index) 12 | : dump_{dump} 13 | , index_{index} 14 | { 15 | auto const* entry = dump.find_stream_type(ThreadListStream, index_); 16 | if (entry == nullptr) 17 | { 18 | return; 19 | } 20 | 21 | thread_list_ = static_cast(dump.rva32(entry->Location)); 22 | found_ = true; 23 | } 24 | 25 | std::experimental::generator thread_list_stream::list() const // NOLINT(bugprone-reserved-identifier) 26 | { 27 | thread_names_list_stream const names_list{dump_}; 28 | memory_list_stream const memory_list{dump_}; 29 | memory64_list_stream const memory64_list{dump_}; 30 | for (size_t index = 0; index < thread_list_->NumberOfThreads; ++index) 31 | { 32 | co_yield stream_thread{dump_, thread_list_->Threads[index], names_list, memory_list, memory64_list}; 33 | } 34 | } 35 | 36 | std::optional thread_list_stream::find_thread(ULONG32 const thread_id, 37 | thread_names_list_stream const& names_list, 38 | memory_list_stream const& memory_list, 39 | memory64_list_stream const& memory64_list) const 40 | { 41 | for (size_t index = 0; index < thread_list_->NumberOfThreads; ++index) 42 | { 43 | if (thread_list_->Threads[index].ThreadId == thread_id) 44 | { 45 | return stream_thread{dump_, thread_list_->Threads[index], names_list, memory_list, memory64_list}; 46 | } 47 | } 48 | 49 | return std::nullopt; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /DbgHelpUtils/crc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace dlg_help_utils::crc 6 | { 7 | namespace details 8 | { 9 | constexpr auto make_crc_table() 10 | { 11 | std::array crc_table{}; 12 | 13 | // terms of polynomial defining this crc (except x^32): 14 | const uint8_t p[] = {0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26}; 15 | 16 | // ReSharper disable once CommentTypo 17 | // make exclusive-or pattern from polynomial (0xedb88320L) 18 | uint32_t poly = 0L; 19 | 20 | for (auto const n : p) 21 | { 22 | poly |= 1L << (31 - n); 23 | } 24 | 25 | for (uint32_t n = 0; n < crc_table.size(); n++) 26 | { 27 | auto c = n; 28 | for (uint32_t k = 0; k < 8; k++) 29 | { 30 | c = c & 1 ? poly ^ (c >> 1) : c >> 1; 31 | } 32 | #pragma warning(push) 33 | #pragma warning(disable : 28020) 34 | crc_table[n] = c; //NOLINT 35 | #pragma warning(pop) 36 | } 37 | 38 | return crc_table; 39 | } 40 | 41 | static auto constexpr crc_table = make_crc_table(); 42 | } 43 | 44 | constexpr uint32_t crc32(void const* data, size_t const length, uint32_t crc = ~0UL) 45 | { 46 | auto const* p = static_cast(data); 47 | for (size_t i = 0; i < length; ++i) 48 | { 49 | crc = details::crc_table[(crc ^ p[i]) & 0xFF] ^ (crc >> 8); 50 | } 51 | 52 | return crc; 53 | } 54 | 55 | template 56 | constexpr uint32_t crc32(std::array const& data, uint32_t const crc = ~0UL) 57 | { 58 | return crc32(static_cast(data.data()), data.size() * sizeof(T), crc); 59 | } 60 | 61 | template 62 | constexpr uint32_t crc32(T data[N], uint32_t const crc = ~0UL) 63 | { 64 | return crc32(static_cast(data), N * sizeof(T), crc); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /MiniDumper/dump_mini_dump_thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // ReSharper disable once CppUnusedIncludeDirective 3 | #include "DbgHelpUtils/stream_thread_context.h" 4 | #include "DbgHelpUtils/tagged_bool.h" 5 | #include "DbgHelpUtils/windows_setup.h" 6 | 7 | #include 8 | 9 | class dump_file_options; 10 | 11 | namespace dlg_help_utils 12 | { 13 | namespace dbg_help 14 | { 15 | class symbol_engine; 16 | } 17 | 18 | class mini_dump; 19 | } 20 | 21 | void dump_mini_dump_thread_context(std::wostream& log, dlg_help_utils::stream_thread_context const& thread_context, dump_file_options const& options); 22 | void dump_mini_dump_x64_thread_context(std::wostream& log, dlg_help_utils::stream_thread_context::context_x64 const& context); 23 | 24 | using has_extended_registers_t = dlg_help_utils::tagged_bool; 25 | void dump_mini_dump_wow64_thread_context(std::wostream& log, WOW64_CONTEXT const& context, has_extended_registers_t has_extended_registers); 26 | void dump_mini_dump_x86_thread_context(std::wostream& log, dlg_help_utils::stream_thread_context::context_x86 const& context, has_extended_registers_t has_extended_registers); 27 | void dump_mini_dump_thread_names_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 28 | void dump_mini_dump_thread_list_stream_data(std::wostream& log 29 | , dlg_help_utils::mini_dump const& mini_dump 30 | , size_t index 31 | , dump_file_options const& options 32 | , dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 33 | void dump_mini_dump_thread_list_ex_stream_data(std::wostream& log 34 | , dlg_help_utils::mini_dump const& mini_dump 35 | , size_t index 36 | , dump_file_options const& options 37 | , dlg_help_utils::dbg_help::symbol_engine& symbol_engine); 38 | void dump_mini_dump_thread_info_list_stream_data(std::wostream& log, dlg_help_utils::mini_dump const& mini_dump, size_t index); 39 | void load_and_dump_teb(std::wostream& log 40 | , dlg_help_utils::mini_dump const& mini_dump 41 | , dlg_help_utils::dbg_help::symbol_engine& symbol_engine 42 | , ULONG64 teb_address); 43 | -------------------------------------------------------------------------------- /DbgHelpUtils/flags_string_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "stream_hex_dump.h" 7 | 8 | namespace dlg_help_utils::flags_string_utils 9 | { 10 | template 11 | std::wstring generate_flags_string(T dump_flags, std::map const& flag_masks) 12 | { 13 | std::wostringstream ss; 14 | auto first{true}; 15 | 16 | for (auto const& [option, title] : flag_masks) 17 | { 18 | if (first && option == 0 && dump_flags == option) 19 | { 20 | first = false; 21 | ss << title; 22 | } 23 | else if ((dump_flags & option) == option) 24 | { 25 | dump_flags &= ~option; 26 | if (first) 27 | { 28 | first = false; 29 | } 30 | else 31 | { 32 | ss << L", "; 33 | } 34 | 35 | ss << title; 36 | } 37 | } 38 | 39 | if (dump_flags > 0) 40 | { 41 | if (!first) 42 | { 43 | ss << L", "; 44 | } 45 | 46 | ss << L"unknown options [" << stream_hex_dump::to_hex(dump_flags) << L"]"; 47 | } 48 | else if (first) 49 | { 50 | ss << L"none"; 51 | } 52 | 53 | return std::move(ss).str(); 54 | } 55 | 56 | template 57 | std::vector generate_flags_strings(T dump_flags, std::map const& flag_masks) 58 | { 59 | std::vector rv; 60 | 61 | for (auto const& [option, title] : flag_masks) 62 | { 63 | if (option == 0 && dump_flags == option) 64 | { 65 | rv.emplace_back(title); 66 | } 67 | else if ((dump_flags & option) == option) 68 | { 69 | dump_flags &= ~option; 70 | rv.emplace_back(title); 71 | } 72 | } 73 | 74 | return rv; 75 | } 76 | } 77 | --------------------------------------------------------------------------------