diff --git a/src/dnmd/bytes.c b/src/dnmd/bytes.c index a82ae87b..a9c3a9f4 100644 --- a/src/dnmd/bytes.c +++ b/src/dnmd/bytes.c @@ -257,28 +257,27 @@ bool decompress_i32(uint8_t const** data, size_t* data_len, int32_t* o) uint32_t unsigned_value; size_t original_data_len = *data_len; if (!decompress_u32(data, data_len, &unsigned_value)) - { return false; - } + bool is_signed = (unsigned_value & 1) != 0; unsigned_value >>= 1; if (is_signed) { - switch (*data_len - original_data_len) + switch (original_data_len - *data_len) { // Sign extend the value based on the number of bytes used. case 1: - { unsigned_value |= SIGN_MASK_ONEBYTE; - } + break; case 2: - { unsigned_value |= SIGN_MASK_TWOBYTE; - } - default: - { + break; + case 4: unsigned_value |= SIGN_MASK_FOURBYTE; - } + break; + default: + assert(false); + return false; } } *o = (int32_t)unsigned_value; diff --git a/src/dnmd/entry.c b/src/dnmd/entry.c index 275dcc74..427660ca 100644 --- a/src/dnmd/entry.c +++ b/src/dnmd/entry.c @@ -432,16 +432,16 @@ static bool dump_table_rows(mdtable_t* table) } else if (sequence_points->records[k].kind == mdsp_HiddenSequencePointRecord) { - printf("hidden-sequence-point-record: %u", sequence_points->records[k].hidden_sequence_point.il_offset); + printf("hidden-sequence-point-record: %u", sequence_points->records[k].hidden_sequence_point.rolling_il_offset); } else if (sequence_points->records[k].kind == mdsp_SequencePointRecord) { printf("sequence-point-record: (%u, %u, %" PRId64 ", %" PRId64 ", %" PRId64 ")", - sequence_points->records[k].sequence_point.il_offset, - sequence_points->records[k].sequence_point.num_lines, + sequence_points->records[k].sequence_point.rolling_il_offset, + sequence_points->records[k].sequence_point.delta_lines, sequence_points->records[k].sequence_point.delta_columns, - sequence_points->records[k].sequence_point.start_line, - sequence_points->records[k].sequence_point.start_column); + sequence_points->records[k].sequence_point.rolling_start_line, + sequence_points->records[k].sequence_point.rolling_start_column); } else { diff --git a/src/dnmd/pdb_blobs.c b/src/dnmd/pdb_blobs.c index 550ab196..2f210849 100644 --- a/src/dnmd/pdb_blobs.c +++ b/src/dnmd/pdb_blobs.c @@ -14,10 +14,10 @@ md_blob_parse_result_t md_parse_document_name(mdhandle_t handle, uint8_t const* uint8_t separator; if (!read_u8(&blob, &blob_len, &separator)) return mdbpr_InvalidBlob; - + if (separator > 0x7f) return mdbpr_InvalidBlob; - + uint8_t* name_current = (uint8_t*)name; size_t remaining_name_len = *name_len; size_t required_len = 0; @@ -45,13 +45,13 @@ md_blob_parse_result_t md_parse_document_name(mdhandle_t handle, uint8_t const* uint32_t part_offset; if (!decompress_u32(&blob, &blob_len, &part_offset)) return mdbpr_InvalidBlob; - + // The part blob is a UTF-8 string that is not null-terminated. const uint8_t* part; uint32_t part_len; if (!try_get_blob(cxt, part_offset, &part, &part_len)) return mdbpr_InvalidBlob; - + // Add the required space for the part. // If there is space in the buffer, write the part. required_len += part_len; @@ -91,7 +91,7 @@ static uint32_t get_num_sequence_points(mdcursor_t method_debug_information, uin uint32_t ignored; if (!decompress_u32(&blob, &blob_len, &ignored)) // header LocalSignature return UINT32_MAX; - + mdcursor_t document; if (1 != md_get_column_value_as_cursor(method_debug_information, mdtMethodDebugInformation_Document, 1, &document)) return UINT32_MAX; @@ -108,7 +108,7 @@ static uint32_t get_num_sequence_points(mdcursor_t method_debug_information, uin uint32_t il_offset; if (!decompress_u32(&blob, &blob_len, &il_offset)) // ILOffset return UINT32_MAX; - + // The first record cannot be a document record if (!first_record && il_offset == 0) { @@ -124,7 +124,7 @@ static uint32_t get_num_sequence_points(mdcursor_t method_debug_information, uin uint32_t delta_lines; if (!decompress_u32(&blob, &blob_len, &delta_lines)) // DeltaLines return UINT32_MAX; - + uint32_t delta_columns; if (!decompress_u32(&blob, &blob_len, &delta_columns)) // DeltaColumns return UINT32_MAX; @@ -145,11 +145,16 @@ static uint32_t get_num_sequence_points(mdcursor_t method_debug_information, uin return num_records; } -md_blob_parse_result_t md_parse_sequence_points(mdcursor_t method_debug_information, uint8_t const* blob, size_t blob_len, md_sequence_points_t* sequence_points, size_t* buffer_len) +md_blob_parse_result_t md_parse_sequence_points( + mdcursor_t method_debug_information, + uint8_t const* blob, + size_t blob_len, + md_sequence_points_t* sequence_points, + size_t* buffer_len) { if (CursorNull(&method_debug_information) || CursorEnd(&method_debug_information)) return mdbpr_InvalidArgument; - + if (blob == NULL || buffer_len == NULL) return mdbpr_InvalidArgument; @@ -157,7 +162,7 @@ md_blob_parse_result_t md_parse_sequence_points(mdcursor_t method_debug_informat if (num_records == UINT32_MAX) return mdbpr_InvalidBlob; - + size_t required_size = sizeof(md_sequence_points_t) + num_records * sizeof(sequence_points->records[0]); if (sequence_points == NULL || *buffer_len < required_size) { @@ -168,7 +173,7 @@ md_blob_parse_result_t md_parse_sequence_points(mdcursor_t method_debug_informat // header LocalSignature if (!decompress_u32(&blob, &blob_len, &sequence_points->signature)) return mdbpr_InvalidBlob; - + mdcursor_t document; if (1 != md_get_column_value_as_cursor(method_debug_information, mdtMethodDebugInformation_Document, 1, &document)) return mdbpr_InvalidBlob; @@ -176,15 +181,20 @@ md_blob_parse_result_t md_parse_sequence_points(mdcursor_t method_debug_informat // Create a "null" cursor to default-initialize the document field. mdcxt_t* cxt = extract_mdcxt(md_extract_handle_from_cursor(method_debug_information)); sequence_points->document = create_cursor(&cxt->tables[mdtid_Document], 0); - + // header InitialDocument uint32_t document_rid = 0; - if (CursorNull(&document) && !decompress_u32(&blob, &blob_len, &document_rid)) + if (CursorNull(&document) + && !decompress_u32(&blob, &blob_len, &document_rid)) + { return mdbpr_InvalidBlob; - + } + if (document_rid != 0 && !md_token_to_cursor(cxt, CreateTokenType(mdtid_Document) | document_rid, &sequence_points->document)) + { return mdbpr_InvalidBlob; + } bool seen_non_hidden_sequence_point = false; for (uint32_t i = 0; blob_len > 0 && i < num_records; ++i) @@ -192,85 +202,90 @@ md_blob_parse_result_t md_parse_sequence_points(mdcursor_t method_debug_informat uint32_t il_offset; if (!decompress_u32(&blob, &blob_len, &il_offset)) // ILOffset return mdbpr_InvalidBlob; + + // Check if the method transitioned + // into a new source file. if (i != 0 && il_offset == 0) { uint32_t document_row_id; if (!decompress_u32(&blob, &blob_len, &document_row_id)) // Document return mdbpr_InvalidBlob; - + sequence_points->records[i].kind = mdsp_DocumentRecord; if (!md_token_to_cursor(cxt, CreateTokenType(mdtid_Document) | document_row_id, &sequence_points->records[i].document.document)) return mdbpr_InvalidBlob; + + continue; + } + + uint32_t delta_lines; + if (!decompress_u32(&blob, &blob_len, &delta_lines)) // DeltaLines + return mdbpr_InvalidBlob; + + int64_t delta_columns; + if (delta_lines == 0) + { + uint32_t raw_delta_columns; + if (!decompress_u32(&blob, &blob_len, &raw_delta_columns)) // DeltaColumns + return mdbpr_InvalidBlob; + delta_columns = raw_delta_columns; } else { - uint32_t delta_lines; - if (!decompress_u32(&blob, &blob_len, &delta_lines)) // DeltaLines + int32_t raw_delta_columns; + if (!decompress_i32(&blob, &blob_len, &raw_delta_columns)) // DeltaColumns return mdbpr_InvalidBlob; + delta_columns = raw_delta_columns; + } - int64_t delta_columns; - if (delta_lines == 0) - { - uint32_t raw_delta_columns; - if (!decompress_u32(&blob, &blob_len, &raw_delta_columns)) // DeltaColumns - return mdbpr_InvalidBlob; - delta_columns = raw_delta_columns; - } - else - { - int32_t raw_delta_columns; - if (!decompress_i32(&blob, &blob_len, &raw_delta_columns)) // DeltaColumns - return mdbpr_InvalidBlob; - delta_columns = raw_delta_columns; - } - - if (delta_columns == 0) - { - sequence_points->records[i].kind = mdsp_HiddenSequencePointRecord; - sequence_points->records[i].hidden_sequence_point.il_offset = il_offset; - } - else if (!seen_non_hidden_sequence_point) - { - seen_non_hidden_sequence_point = true; - uint32_t start_line; - if (!decompress_u32(&blob, &blob_len, &start_line)) // StartLine - return mdbpr_InvalidBlob; - uint32_t start_column; - if (!decompress_u32(&blob, &blob_len, &start_column)) // StartColumn - return mdbpr_InvalidBlob; - - sequence_points->records[i].kind = mdsp_SequencePointRecord; - sequence_points->records[i].sequence_point.il_offset = il_offset; - sequence_points->records[i].sequence_point.num_lines = delta_lines; - sequence_points->records[i].sequence_point.delta_columns = delta_columns; - sequence_points->records[i].sequence_point.start_line = start_line; - sequence_points->records[i].sequence_point.start_column = start_column; - } - else - { - // If we've seen a non-hidden sequence point, - // then the values are compressed signed integers instead of - // unsigned integers. - int32_t start_line; - if (!decompress_i32(&blob, &blob_len, &start_line)) // StartLine - return mdbpr_InvalidBlob; - int32_t start_column; - if (!decompress_i32(&blob, &blob_len, &start_column)) // StartColumn - return mdbpr_InvalidBlob; + // Check for hidden point + if (delta_lines == 0 && delta_columns == 0) + { + sequence_points->records[i].kind = mdsp_HiddenSequencePointRecord; + sequence_points->records[i].hidden_sequence_point.rolling_il_offset = il_offset; + continue; + } - sequence_points->records[i].kind = mdsp_SequencePointRecord; - sequence_points->records[i].sequence_point.il_offset = il_offset; - sequence_points->records[i].sequence_point.num_lines = delta_lines; - sequence_points->records[i].sequence_point.delta_columns = delta_columns; - sequence_points->records[i].sequence_point.start_line = start_line; - sequence_points->records[i].sequence_point.start_column = start_column; - } + int64_t start_line; + int64_t start_column; + if (!seen_non_hidden_sequence_point) + { + seen_non_hidden_sequence_point = true; + uint32_t start_line_raw; + if (!decompress_u32(&blob, &blob_len, &start_line_raw)) // StartLine + return mdbpr_InvalidBlob; + uint32_t start_column_raw; + if (!decompress_u32(&blob, &blob_len, &start_column_raw)) // StartColumn + return mdbpr_InvalidBlob; + start_line = start_line_raw; + start_column = start_column_raw; } + else + { + // If we've seen a non-hidden sequence point, + // then the values are compressed signed integers instead of + // unsigned integers. + int32_t start_line_raw; + if (!decompress_i32(&blob, &blob_len, &start_line_raw)) // StartLine + return mdbpr_InvalidBlob; + int32_t start_column_raw; + if (!decompress_i32(&blob, &blob_len, &start_column_raw)) // StartColumn + return mdbpr_InvalidBlob; + start_line = start_line_raw; + start_column = start_column_raw; + } + + sequence_points->records[i].kind = mdsp_SequencePointRecord; + sequence_points->records[i].sequence_point.rolling_il_offset = il_offset; + sequence_points->records[i].sequence_point.delta_lines = delta_lines; + sequence_points->records[i].sequence_point.delta_columns = delta_columns; + sequence_points->records[i].sequence_point.rolling_start_line = start_line; + sequence_points->records[i].sequence_point.rolling_start_column = start_column; } if (blob_len != 0) return mdbpr_InvalidBlob; - + sequence_points->record_count = num_records; return mdbpr_Success; } @@ -289,7 +304,7 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co uint32_t element_type; if (!decompress_u32(&custom_modifiers_blob, &custom_modifiers_blob_len, &element_type)) return mdbpr_InvalidBlob; - + if (element_type != ELEMENT_TYPE_CMOD_OPT && element_type != ELEMENT_TYPE_CMOD_REQD) break; @@ -299,7 +314,6 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co } size_t required_size = sizeof(md_local_constant_sig_t) + num_custom_modifiers * sizeof(local_constant_sig->custom_modifiers[0]); - if (local_constant_sig == NULL || *buffer_len < required_size) { *buffer_len = required_size; @@ -308,12 +322,12 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co local_constant_sig->custom_modifier_count = num_custom_modifiers; - for (uint8_t i = 0; i < num_custom_modifiers; ++i) + for (uint32_t i = 0; i < num_custom_modifiers; ++i) { uint32_t element_type; if (!decompress_u32(&custom_modifiers_blob, &custom_modifiers_blob_len, &element_type)) return mdbpr_InvalidBlob; - + if (element_type != ELEMENT_TYPE_CMOD_OPT && element_type != ELEMENT_TYPE_CMOD_REQD) break; @@ -322,7 +336,7 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co uint32_t cindex; if (!decompress_u32(&custom_modifiers_blob, &custom_modifiers_blob_len, &cindex)) return mdbpr_InvalidBlob; - + mdtable_id_t table; uint32_t row_id; // Technically the spec defines this as a TypeDefOrRefOrSpecEncoded token, @@ -330,14 +344,14 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co // TypeDefOrRefOrSpec encoding. if (!decompose_coded_index(cindex, mdtc_idx_coded | InsertCodedIndex(mdci_TypeDefOrRef), &table, &row_id)) return mdbpr_InvalidBlob; - + local_constant_sig->custom_modifiers[i].type = CreateTokenType(table) | row_id; } uint32_t type_code; if (!decompress_u32(&blob, &blob_len, &type_code)) return mdbpr_InvalidBlob; - + uint32_t constant_type_index; mdtable_id_t constant_type_table; uint32_t constant_type_row; @@ -380,6 +394,7 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co local_constant_sig->primitive.type_code = (uint8_t)type_code; local_constant_sig->value_blob = blob; local_constant_sig->value_len = blob_len; + break; case ELEMENT_TYPE_R8: if (blob_len != 8) return mdbpr_InvalidBlob; @@ -387,6 +402,7 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co local_constant_sig->primitive.type_code = (uint8_t)type_code; local_constant_sig->value_blob = blob; local_constant_sig->value_len = blob_len; + break; case ELEMENT_TYPE_STRING: local_constant_sig->constant_kind = mdck_PrimitiveConstant; local_constant_sig->primitive.type_code = (uint8_t)type_code; @@ -405,6 +421,7 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co case ELEMENT_TYPE_U4: case ELEMENT_TYPE_I8: case ELEMENT_TYPE_U8: + // Save off the value. local_constant_sig->value_blob = blob; local_constant_sig->value_len = blob_len; switch (type_code) @@ -443,8 +460,12 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co return mdbpr_InvalidBlob; break; } + default: + assert(false); + return mdbpr_InvalidArgument; } - + + // Check if there is any remaining blob data. if (blob_len == 0) { local_constant_sig->constant_kind = mdck_PrimitiveConstant; @@ -453,18 +474,23 @@ md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t co else { // If we have data remaining, then we need to read the enum type. - // In this case, the we need to subtract off the rest of the blob length from the value blob length + // In this case, we subtract off the rest of the blob length from the value blob length // as it isn't part of the value. local_constant_sig->value_len -= blob_len; if (!decompress_u32(&blob, &blob_len, &constant_type_index) || !decompose_coded_index(constant_type_index, mdtc_idx_coded | InsertCodedIndex(mdci_TypeDefOrRef), &constant_type_table, &constant_type_row)) + { return mdbpr_InvalidBlob; + } local_constant_sig->constant_kind = mdck_EnumConstant; local_constant_sig->enum_constant.type_code = (uint8_t)type_code; local_constant_sig->enum_constant.enum_type = CreateTokenType(constant_type_table) | constant_type_row; } break; + default: + assert(false); + return mdbpr_InvalidArgument; } return mdbpr_Success; } @@ -482,7 +508,7 @@ static uint32_t get_num_imports(uint8_t const* blob, size_t blob_len) uint8_t kind; if (!read_u8(&blob, &blob_len, &kind)) return UINT32_MAX; - + uint32_t raw; switch (kind) { @@ -545,12 +571,10 @@ md_blob_parse_result_t md_parse_imports(mdhandle_t handle, uint8_t const* blob, return mdbpr_InvalidArgument; uint32_t num_imports = get_num_imports(blob, blob_len); - if (num_imports == UINT32_MAX) return mdbpr_InvalidBlob; size_t required_size = sizeof(md_imports_t) + num_imports * sizeof(imports->imports[0]); - if (imports == NULL || *buffer_len < required_size) { *buffer_len = required_size; @@ -563,10 +587,10 @@ md_blob_parse_result_t md_parse_imports(mdhandle_t handle, uint8_t const* blob, uint8_t kind; if (!read_u8(&blob, &blob_len, &kind)) return mdbpr_InvalidBlob; - + // Zero out this import entry. memset(&imports->imports[i], 0, sizeof(imports->imports[i])); - + imports->imports[i].kind = kind; uint32_t raw; switch (kind) @@ -596,10 +620,10 @@ md_blob_parse_result_t md_parse_imports(mdhandle_t handle, uint8_t const* blob, uint32_t row_id; if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + if (!decompose_coded_index(raw, mdtc_idx_coded | InsertCodedIndex(mdci_TypeDefOrRef), &table, &row_id)) return mdbpr_InvalidBlob; - + imports->imports[i].target_type = CreateTokenType(table) | row_id; break; } @@ -607,7 +631,7 @@ md_blob_parse_result_t md_parse_imports(mdhandle_t handle, uint8_t const* blob, case mdidk_ImportXmlNamespace: if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + if (!try_get_blob(cxt, raw, (uint8_t const**)&imports->imports[i].alias, &imports->imports[i].alias_len)) return mdbpr_InvalidBlob; @@ -620,34 +644,34 @@ md_blob_parse_result_t md_parse_imports(mdhandle_t handle, uint8_t const* blob, case mdidk_ImportAssemblyReferenceAlias: if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + if (!try_get_blob(cxt, raw, (uint8_t const**)&imports->imports[i].alias, &imports->imports[i].alias_len)) return mdbpr_InvalidBlob; break; case mdidk_AliasAssemblyReference: if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + if (!try_get_blob(cxt, raw, (uint8_t const**)&imports->imports[i].alias, &imports->imports[i].alias_len)) return mdbpr_InvalidBlob; if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + imports->imports[i].assembly = CreateTokenType(mdtid_AssemblyRef) | raw; break; case mdidk_AliasAssemblyNamespace: if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + if (!try_get_blob(cxt, raw, (uint8_t const**)&imports->imports[i].alias, &imports->imports[i].alias_len)) return mdbpr_InvalidBlob; if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + imports->imports[i].assembly = CreateTokenType(mdtid_AssemblyRef) | raw; - + if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; @@ -658,7 +682,7 @@ md_blob_parse_result_t md_parse_imports(mdhandle_t handle, uint8_t const* blob, { if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + if (!try_get_blob(cxt, raw, (uint8_t const**)&imports->imports[i].alias, &imports->imports[i].alias_len)) return mdbpr_InvalidBlob; @@ -666,10 +690,10 @@ md_blob_parse_result_t md_parse_imports(mdhandle_t handle, uint8_t const* blob, uint32_t row_id; if (!decompress_u32(&blob, &blob_len, &raw)) return mdbpr_InvalidBlob; - + if (!decompose_coded_index(raw, mdtc_idx_coded | InsertCodedIndex(mdci_TypeDefOrRef), &table, &row_id)) return mdbpr_InvalidBlob; - + imports->imports[i].target_type = CreateTokenType(table) | row_id; break; } diff --git a/src/inc/dnmd.hpp b/src/inc/dnmd.hpp index fa2acacb..9bcf8f4f 100644 --- a/src/inc/dnmd.hpp +++ b/src/inc/dnmd.hpp @@ -4,7 +4,7 @@ #include "dnmd.h" #include -struct mdhandle_deleter_t +struct mdhandle_deleter_t final { using pointer = mdhandle_t; void operator()(mdhandle_t handle) diff --git a/src/inc/dnmd_pdb.h b/src/inc/dnmd_pdb.h index 18146bfd..eacf55b8 100644 --- a/src/inc/dnmd_pdb.h +++ b/src/inc/dnmd_pdb.h @@ -43,15 +43,15 @@ typedef struct md_sequence_points__ } document; struct { - uint32_t il_offset; - uint32_t num_lines; + uint32_t rolling_il_offset; + uint32_t delta_lines; int64_t delta_columns; - int64_t start_line; - int64_t start_column; + int64_t rolling_start_line; + int64_t rolling_start_column; } sequence_point; struct { - uint32_t il_offset; + uint32_t rolling_il_offset; } hidden_sequence_point; }; } records[]; @@ -72,15 +72,13 @@ typedef struct md_local_constant_sig__ { struct { - uint8_t type_code; + uint8_t type_code; // ELEMENT_TYPE_* - ECMA-335 II.23.1.16 } primitive; - struct { - uint8_t type_code; - mdToken enum_type; + uint8_t type_code; // ELEMENT_TYPE_* - ECMA-335 II.23.1.16 + mdToken enum_type; // See ECMA-335 II.14.3 for Enum restrictions. } enum_constant; - struct { enum @@ -89,7 +87,7 @@ typedef struct md_local_constant_sig__ mdgc_Class, mdgc_Object } kind; - mdToken type; + mdToken type; // TypeDefOrRefOrSpecEncoded - ECMA-335 II.23.2.8 } general; }; @@ -97,11 +95,10 @@ typedef struct md_local_constant_sig__ size_t value_len; uint32_t custom_modifier_count; - struct { - bool required; - mdToken type; + bool required; // Differentiate modreq vs modopt. + mdToken type; // Custom modifier - ECMA-335 II.23.2.7 } custom_modifiers[]; } md_local_constant_sig_t; md_blob_parse_result_t md_parse_local_constant_sig(mdhandle_t handle, uint8_t const* blob, size_t blob_len, md_local_constant_sig_t* local_constant_sig, size_t* buffer_len); diff --git a/src/inc/internal/dnmd_platform.hpp b/src/inc/internal/dnmd_platform.hpp index 4709e619..767fc9ef 100644 --- a/src/inc/internal/dnmd_platform.hpp +++ b/src/inc/internal/dnmd_platform.hpp @@ -23,7 +23,7 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) template -struct malloc_deleter_t +struct malloc_deleter_t final { using pointer = T*; void operator()(T* mem) diff --git a/src/inc/internal/dnmd_tools_platform.hpp b/src/inc/internal/dnmd_tools_platform.hpp new file mode 100644 index 00000000..6b52064f --- /dev/null +++ b/src/inc/internal/dnmd_tools_platform.hpp @@ -0,0 +1,308 @@ +#ifndef _SRC_INC_INTERNAL_DNMD_TOOLS_PLATFORM_HPP_ +#define _SRC_INC_INTERNAL_DNMD_TOOLS_PLATFORM_HPP_ + +#include +#include +#include +#include + +#include "dnmd_platform.hpp" + +template +class span +{ +protected: + T* _ptr; + size_t _size; +public: + span() + : _ptr{} + , _size{} + { } + + span(T* ptr, size_t len) + : _ptr{ ptr }, _size{ len } + { } + + span(span const & other) = default; + + span& operator=(span&& other) noexcept = default; + + size_t size() const noexcept + { + return _size; + } + + operator T* () noexcept + { + return _ptr; + } + + operator T const* () const noexcept + { + return _ptr; + } + + T& operator[](size_t idx) + { + if (_ptr == nullptr) + throw std::runtime_error{ "Deref null" }; + if (idx >= _size) + throw std::out_of_range{ "Out of bounds access" }; + return _ptr[idx]; + } +}; + +template +class owning_span final : public span +{ +public: + owning_span() : span{} + { } + + owning_span(T* ptr, size_t len) + : span{ ptr, len } + { } + + owning_span(owning_span&& other) noexcept + : span{} + { + *this = std::move(other); + } + + ~owning_span() + { + Deleter{}(this->_ptr); + } + + owning_span& operator=(owning_span&& other) noexcept + { + if (this->_ptr != nullptr) + Deleter{}(this->_ptr); + + this->_ptr = other._ptr; + this->_size = other._size; + other._ptr = {}; + other._size = {}; + return *this; + } + + T* release() noexcept + { + T* tmp = this->_ptr; + this->_ptr = {}; + return tmp; + } +}; + +struct free_deleter final +{ + void operator()(void* ptr) + { + free(ptr); + } +}; + +template +using malloc_span = owning_span; + +inline bool create_mdhandle(malloc_span const& buffer, mdhandle_ptr& handle) +{ + mdhandle_t h; + if (!md_create_handle(buffer, buffer.size(), &h)) + return false; + handle.reset(h); + return true; +} + +// +// PE File functions +// + +inline uint32_t get_file_size(char const* path) +{ + uint32_t size_in_uint8_ts = 0; +#ifdef BUILD_WINDOWS + HANDLE handle = ::CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (handle != INVALID_HANDLE_VALUE) + { + size_in_uint8_ts = ::GetFileSize(handle, nullptr); + (void)::CloseHandle(handle); + } +#else + struct stat st; + int rc = stat(path, &st); + if (rc == 0) + size_in_uint8_ts = st.st_size; +#endif // !BUILD_WINDOWS + + return size_in_uint8_ts; +} + +inline PIMAGE_SECTION_HEADER find_section_header( + span section_headers, + uint32_t rva) +{ + for (size_t i = 0; i < section_headers.size(); ++i) + { + if (section_headers[i].VirtualAddress <= rva + && rva < (section_headers[i].VirtualAddress + section_headers[i].SizeOfRawData)) + { + return §ion_headers[i]; + } + } + + return nullptr; +} + +inline bool read_in_file(char const* file, malloc_span& b) +{ + // Read in the entire file + std::ifstream fd{ file, std::ios::binary | std::ios::in }; + if (!fd) + return false; + + size_t size = get_file_size(file); + if (size == 0) + return false; + + b = { (uint8_t*)std::malloc(size), size }; + fd.read((char*)(uint8_t*)b, b.size()); + return true; +} + +inline bool write_out_file(char const* file, malloc_span b) +{ + // Read in the entire file + std::ofstream fd{ file, std::ios::binary | std::ios::out }; + if (!fd) + return false; + + fd.write((char*)(uint8_t*)b, b.size()); + return true; +} + +inline bool get_metadata_from_pe(malloc_span& b) +{ + if (b.size() < sizeof(IMAGE_DOS_HEADER)) + return false; + + // [TODO] Handle endian issues with .NET generated PE images + // All integers should be read as little-endian. + auto dos_header = (PIMAGE_DOS_HEADER)(void*)b; + bool is_pe = dos_header->e_magic == IMAGE_DOS_SIGNATURE; + if (!is_pe) + return false; + + // Handle headers that are 32 or 64 + PIMAGE_SECTION_HEADER tgt_header; + PIMAGE_DATA_DIRECTORY dotnet_dir; + + // Section headers begin immediately after the NT_HEADERS. + span section_headers; + + if ((size_t)dos_header->e_lfanew > b.size()) + return false; + + size_t remaining_pe_size = b.size() - dos_header->e_lfanew; + uint16_t section_header_count; + uint8_t* section_header_begin; + auto nt_header_any = (PIMAGE_NT_HEADERS)(b + dos_header->e_lfanew); + if (nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 + || nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64) + { + auto nt_header64 = (PIMAGE_NT_HEADERS64)nt_header_any; + if (remaining_pe_size < sizeof(*nt_header64)) + return false; + remaining_pe_size -= sizeof(*nt_header64); + section_header_count = nt_header64->FileHeader.NumberOfSections; + section_header_begin = (uint8_t*)&nt_header64[1]; + dotnet_dir = &nt_header64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]; + } + else if (nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 + || nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) + { + auto nt_header32 = (PIMAGE_NT_HEADERS32)nt_header_any; + if (remaining_pe_size < sizeof(*nt_header32)) + return false; + remaining_pe_size -= sizeof(*nt_header32); + section_header_count = nt_header32->FileHeader.NumberOfSections; + section_header_begin = (uint8_t*)&nt_header32[1]; + dotnet_dir = &nt_header32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]; + } + else + { + // Unknown machine type + return false; + } + + // Doesn't contain a .NET header + bool is_dotnet = dotnet_dir->Size != 0; + if (!is_dotnet) + return false; + + // Compute the maximum space in the PE to validate section header count. + if (section_header_count > (remaining_pe_size / sizeof(IMAGE_SECTION_HEADER))) + return false; + + remaining_pe_size -= section_header_count * sizeof(IMAGE_SECTION_HEADER); + + section_headers = { (PIMAGE_SECTION_HEADER)section_header_begin, section_header_count }; + + tgt_header = find_section_header(section_headers, dotnet_dir->VirtualAddress); + if (tgt_header == nullptr) + return false; + + // Sanity check + if (dotnet_dir->VirtualAddress < tgt_header->VirtualAddress) + return false; + + DWORD cor_header_offset = (DWORD)(dotnet_dir->VirtualAddress - tgt_header->VirtualAddress) + tgt_header->PointerToRawData; + if (cor_header_offset > b.size() - sizeof(IMAGE_COR20_HEADER)) + return false; + + auto cor_header = (PIMAGE_COR20_HEADER)(b + cor_header_offset); + tgt_header = find_section_header(section_headers, cor_header->MetaData.VirtualAddress); + if (tgt_header == nullptr) + return false; + + // Sanity check + if (cor_header->MetaData.VirtualAddress < tgt_header->VirtualAddress) + return false; + + DWORD metadata_offset = (DWORD)(cor_header->MetaData.VirtualAddress - tgt_header->VirtualAddress) + tgt_header->PointerToRawData; + if (metadata_offset > b.size()) + return false; + + void* ptr = (void*)(b + metadata_offset); + + size_t metadata_length = cor_header->MetaData.Size; + if (metadata_length > b.size() - metadata_offset) + return false; + + // Capture the metadata portion of the image. + malloc_span metadata = { (uint8_t*)std::malloc(metadata_length), metadata_length }; + std::memcpy(metadata, ptr, metadata.size()); + b = std::move(metadata); + return true; +} + +inline bool get_metadata_from_file(malloc_span& b) +{ + // Defined in II.24.2.1 - defined in physical uint8_t order + std::array const metadata_sig = { 0x42, 0x53, 0x4A, 0x42 }; + + if (b.size() < metadata_sig.size()) + return false; + + // If the header doesn't match, the file is unknown. + for (size_t i = 0; i < metadata_sig.size(); ++i) + { + if (b[i] != metadata_sig[i]) + return false; + } + + return true; +} + +#endif // _SRC_INC_INTERNAL_DNMD_TOOLS_PLATFORM_HPP_ diff --git a/src/interfaces/CMakeLists.txt b/src/interfaces/CMakeLists.txt index 1d030dbc..db3e666a 100644 --- a/src/interfaces/CMakeLists.txt +++ b/src/interfaces/CMakeLists.txt @@ -46,8 +46,8 @@ target_compile_definitions(dnmd_interfaces PRIVATE DNMD_BUILD_SHARED) target_link_libraries(dnmd_interfaces_static PUBLIC - dnmd::dnmd - dncp::dncp) + dncp::dncp + dnmd::dnmd) target_link_libraries(dnmd_interfaces PRIVATE diff --git a/src/interfaces/controllingiunknown.hpp b/src/interfaces/controllingiunknown.hpp index 38a8e66e..d971c6ff 100644 --- a/src/interfaces/controllingiunknown.hpp +++ b/src/interfaces/controllingiunknown.hpp @@ -10,7 +10,6 @@ class ControllingIUnknown final : public IUnknown { -private: std::atomic _refCount{ 1 }; std::vector> _tearOffs; public: @@ -69,4 +68,4 @@ class ControllingIUnknown final : public IUnknown } }; -#endif \ No newline at end of file +#endif // _SRC_INTERFACES_CONTROLLINGIUNKNOWN_HPP_ \ No newline at end of file diff --git a/src/interfaces/dispenser.cpp b/src/interfaces/dispenser.cpp index 92686b5f..08671735 100644 --- a/src/interfaces/dispenser.cpp +++ b/src/interfaces/dispenser.cpp @@ -6,7 +6,7 @@ #endif // !_MSC_VER #endif // DNMD_BUILD_SHARED -#include "internal/dnmd_platform.hpp" +#include #include "dnmd_interfaces.hpp" #include "controllingiunknown.hpp" #include "metadataimportro.hpp" diff --git a/src/interfaces/dnmdowner.hpp b/src/interfaces/dnmdowner.hpp index e0be3e26..09977882 100644 --- a/src/interfaces/dnmdowner.hpp +++ b/src/interfaces/dnmdowner.hpp @@ -1,7 +1,7 @@ #ifndef _SRC_INTERFACES_DNMDOWNER_HPP_ #define _SRC_INTERFACES_DNMDOWNER_HPP_ -#include "internal/dnmd_platform.hpp" +#include #include "tearoffbase.hpp" #include "controllingiunknown.hpp" @@ -22,54 +22,47 @@ struct IDNMDOwner : IUnknown // We use a reference wrapper around the handle to allow the handle to be swapped out. // We plan to use swapping to implement table sorting as DNMD itself does not support // sorting tables or remapping tokens. -// This is explitly a non-owning view as this view will be passed to other tear-offs of the same object, +// This is explicitly a non-owning view as this view will be passed to other tear-offs of the same object, // which would otherwise lead to memory leaks. class mdhandle_view final { private: IDNMDOwner* _owner; public: - mdhandle_view(IDNMDOwner* owner) + explicit mdhandle_view(IDNMDOwner* owner) : _owner{ owner } { } - mdhandle_view(mdhandle_view const& other) - : _owner{ other._owner } - { - } + mdhandle_view(mdhandle_view const& other) = default; mdhandle_view(mdhandle_view&& other) = default; - mdhandle_view& operator=(mdhandle_view const& other) - { - _owner = other._owner; - return *this; - } + mdhandle_view& operator=(mdhandle_view const& other) = default; mdhandle_view& operator=(mdhandle_view&& other) = default; - mdhandle_t get() + mdhandle_t get() const { return _owner->MetaData(); } - bool operator==(std::nullptr_t) + bool operator==(std::nullptr_t) const { return get() == nullptr; } - bool operator!=(std::nullptr_t) + bool operator!=(std::nullptr_t) const { return get() != nullptr; } }; -inline bool operator==(std::nullptr_t, mdhandle_view& view) +inline bool operator==(std::nullptr_t, mdhandle_view const& view) { return view == nullptr; } -inline bool operator!=(std::nullptr_t, mdhandle_view& view) +inline bool operator!=(std::nullptr_t, mdhandle_view const& view) { return view != nullptr; } @@ -101,7 +94,7 @@ class DNMDOwner final : public TearOffBase , _cotaskmem_to_free{ std::move(cotaskmemMem) } { } - virtual ~DNMDOwner() = default; + virtual ~DNMDOwner() noexcept = default; public: // IDNMDOwner mdhandle_t MetaData() override diff --git a/src/interfaces/hcorenum.hpp b/src/interfaces/hcorenum.hpp index d5824f4b..a5b312f9 100644 --- a/src/interfaces/hcorenum.hpp +++ b/src/interfaces/hcorenum.hpp @@ -1,7 +1,7 @@ #ifndef _SRC_INTERFACES_HCORENUM_HPP_ #define _SRC_INTERFACES_HCORENUM_HPP_ -#include "internal/dnmd_platform.hpp" +#include enum class HCORENUMType : uint32_t { @@ -87,7 +87,7 @@ class HCORENUMImpl final HRESULT ResetDynamicEnum(_In_ uint32_t position) noexcept; }; -struct HCORENUMImplDeleter +struct HCORENUMImplDeleter final { using pointer = HCORENUMImpl*; void operator()(HCORENUMImpl* mem) diff --git a/src/interfaces/metadataimport.cpp b/src/interfaces/metadataimport.cpp index c68c95e5..584a9558 100644 --- a/src/interfaces/metadataimport.cpp +++ b/src/interfaces/metadataimport.cpp @@ -71,7 +71,7 @@ namespace return S_OK; } - struct TokenRangeFilter + struct TokenRangeFilter final { col_index_t FilterColumn; LPCWSTR Value; diff --git a/src/interfaces/metadataimportro.hpp b/src/interfaces/metadataimportro.hpp index 9f55920a..cb55a07d 100644 --- a/src/interfaces/metadataimportro.hpp +++ b/src/interfaces/metadataimportro.hpp @@ -1,7 +1,7 @@ #ifndef _SRC_INTERFACES_METADATAIMPORTRO_HPP_ #define _SRC_INTERFACES_METADATAIMPORTRO_HPP_ -#include "internal/dnmd_platform.hpp" +#include #include "tearoffbase.hpp" #include "controllingiunknown.hpp" #include "dnmdowner.hpp" @@ -610,4 +610,4 @@ class MetadataImportRO final : public TearOffBase::ConvertWorker(char const* c, WCHAR* buf int strcat_s(char* dest, rsize_t destsz, char const* src) { assert(dest != nullptr && src != nullptr); - ::strcat(dest, src); + (void)::strcat(dest, src); return 0; } #endif // !defined(__STDC_LIB_EXT1__) && !defined(BUILD_WINDOWS) diff --git a/src/interfaces/pal.hpp b/src/interfaces/pal.hpp index 707dbafd..6e47273d 100644 --- a/src/interfaces/pal.hpp +++ b/src/interfaces/pal.hpp @@ -70,7 +70,7 @@ namespace pal } } - StringConvert(A const* c) noexcept + explicit StringConvert(A const* c) noexcept : StringConvert(c, nullptr, 0) { } diff --git a/src/interfaces/tearoffbase.hpp b/src/interfaces/tearoffbase.hpp index cc3b2c8b..ddb5abff 100644 --- a/src/interfaces/tearoffbase.hpp +++ b/src/interfaces/tearoffbase.hpp @@ -1,13 +1,11 @@ #ifndef _SRC_INTERFACES_TEAROFFBASE_HPP_ #define _SRC_INTERFACES_TEAROFFBASE_HPP_ -#include "internal/dnmd_platform.hpp" +#include #include #include #include -class ControllingIUnknown; - class TearOffUnknown : public IUnknown { friend class ControllingIUnknown; @@ -18,7 +16,7 @@ class TearOffUnknown : public IUnknown virtual bool TryGetInterfaceOnThis(REFIID riid, void** ppvObject) PURE; public: - TearOffUnknown(IUnknown* outer) + explicit TearOffUnknown(IUnknown* outer) : _pUnkOuter{ outer } { assert(outer != nullptr); @@ -84,4 +82,4 @@ class TearOffBase : public TearOffUnknown, public T... } }; -#endif +#endif // _SRC_INTERFACES_TEAROFFBASE_HPP_ diff --git a/src/mddump/main.cpp b/src/mddump/main.cpp index e4fd1556..f4d948f3 100644 --- a/src/mddump/main.cpp +++ b/src/mddump/main.cpp @@ -1,126 +1,10 @@ #include #include -#include #include -#include -#include -#include #include -#include #include -#include - -template -class span -{ -protected: - T* _ptr; - size_t _size; -public: - span() - : _ptr{} - , _size{} - { } - - span(T* ptr, size_t len) - : _ptr{ ptr }, _size{ len } - { } - - span(span const & other) = default; - - span& operator=(span&& other) noexcept = default; - - size_t size() const noexcept - { - return _size; - } - - operator T* () noexcept - { - return _ptr; - } - - operator T const* () const noexcept - { - return _ptr; - } - - T& operator[](size_t idx) - { - if (_ptr == nullptr) - throw std::runtime_error{ "Deref null" }; - if (idx >= _size) - throw std::out_of_range{ "Out of bounds access" }; - return _ptr[idx]; - } -}; - -template -class owning_span : public span -{ -public: - owning_span() : span{} - { } - - owning_span(T* ptr, size_t len) - : span{ ptr, len } - { } - - owning_span(owning_span&& other) noexcept - : span{} - { - *this = std::move(other); - } - - ~owning_span() - { - Deleter{}(this->_ptr); - } - - owning_span& operator=(owning_span&& other) noexcept - { - if (this->_ptr != nullptr) - Deleter{}(this->_ptr); - - this->_ptr = other._ptr; - this->_size = other._size; - other._ptr = {}; - other._size = {}; - return *this; - } - - T* release() noexcept - { - T* tmp = this->_ptr; - this->_ptr = {}; - return tmp; - } -}; - -struct free_deleter -{ - void operator()(void* ptr) - { - free(ptr); - } -}; - -template -using malloc_span = owning_span; - -bool read_in_file(char const* file, malloc_span& b); -bool get_metadata_from_pe(malloc_span& b); -bool get_metadata_from_file(malloc_span& b); - -bool create_mdhandle(malloc_span const& buffer, mdhandle_ptr& handle) -{ - mdhandle_t h; - if (!md_create_handle(buffer, buffer.size(), &h)) - return false; - handle.reset(h); - return true; -} +#include bool apply_deltas(mdhandle_t handle, std::vector& deltas, std::vector>& data) { @@ -143,7 +27,7 @@ bool apply_deltas(mdhandle_t handle, std::vector& deltas, std::vect return true; } -struct dump_config_t +struct dump_config_t final { dump_config_t() : path{} @@ -263,178 +147,3 @@ int main(int ac, char** av) return EXIT_SUCCESS; } - -uint32_t get_file_size(char const* path) -{ - uint32_t size_in_uint8_ts = 0; -#ifdef BUILD_WINDOWS - HANDLE handle = ::CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); - if (handle != INVALID_HANDLE_VALUE) - { - size_in_uint8_ts = ::GetFileSize(handle, nullptr); - (void)::CloseHandle(handle); - } -#else - struct stat st; - int rc = stat(path, &st); - if (rc == 0) - size_in_uint8_ts = st.st_size; -#endif // !BUILD_WINDOWS - - return size_in_uint8_ts; -} - -PIMAGE_SECTION_HEADER find_section_header( - span section_headers, - uint32_t rva) -{ - for (size_t i = 0; i < section_headers.size(); ++i) - { - if (section_headers[i].VirtualAddress <= rva - && rva < (section_headers[i].VirtualAddress + section_headers[i].SizeOfRawData)) - { - return §ion_headers[i]; - } - } - - return nullptr; -} - -bool read_in_file(char const* file, malloc_span& b) -{ - // Read in the entire file - std::ifstream fd{ file, std::ios::binary | std::ios::in }; - if (!fd) - return false; - - size_t size = get_file_size(file); - if (size == 0) - return false; - - b = { (uint8_t*)std::malloc(size), size }; - fd.read((char*)(uint8_t*)b, b.size()); - return true; -} - -bool get_metadata_from_pe(malloc_span& b) -{ - if (b.size() < sizeof(IMAGE_DOS_HEADER)) - return false; - - // [TODO] Handle endian issues with .NET generated PE images - // All integers should be read as little-endian. - auto dos_header = (PIMAGE_DOS_HEADER)(void*)b; - bool is_pe = dos_header->e_magic == IMAGE_DOS_SIGNATURE; - if (!is_pe) - return false; - - // Handle headers that are 32 or 64 - PIMAGE_SECTION_HEADER tgt_header; - PIMAGE_DATA_DIRECTORY dotnet_dir; - - // Section headers begin immediately after the NT_HEADERS. - span section_headers; - - if ((size_t)dos_header->e_lfanew > b.size()) - return false; - - size_t remaining_pe_size = b.size() - dos_header->e_lfanew; - uint16_t section_header_count; - uint8_t* section_header_begin; - auto nt_header_any = (PIMAGE_NT_HEADERS)(b + dos_header->e_lfanew); - if (nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 - || nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64) - { - auto nt_header64 = (PIMAGE_NT_HEADERS64)nt_header_any; - if (remaining_pe_size < sizeof(*nt_header64)) - return false; - remaining_pe_size -= sizeof(*nt_header64); - section_header_count = nt_header64->FileHeader.NumberOfSections; - section_header_begin = (uint8_t*)&nt_header64[1]; - dotnet_dir = &nt_header64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]; - } - else if (nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 - || nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) - { - auto nt_header32 = (PIMAGE_NT_HEADERS32)nt_header_any; - if (remaining_pe_size < sizeof(*nt_header32)) - return false; - remaining_pe_size -= sizeof(*nt_header32); - section_header_count = nt_header32->FileHeader.NumberOfSections; - section_header_begin = (uint8_t*)&nt_header32[1]; - dotnet_dir = &nt_header32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]; - } - else - { - // Unknown machine type - return false; - } - - // Doesn't contain a .NET header - bool is_dotnet = dotnet_dir->Size != 0; - if (!is_dotnet) - return false; - - // Compute the maximum space in the PE to validate section header count. - if (section_header_count > (remaining_pe_size / sizeof(IMAGE_SECTION_HEADER))) - return false; - - remaining_pe_size -= section_header_count * sizeof(IMAGE_SECTION_HEADER); - - section_headers = { (PIMAGE_SECTION_HEADER)section_header_begin, section_header_count }; - - tgt_header = find_section_header(section_headers, dotnet_dir->VirtualAddress); - if (tgt_header == nullptr) - return false; - - // Sanity check - if (dotnet_dir->VirtualAddress < tgt_header->VirtualAddress) - return false; - - DWORD cor_header_offset = (DWORD)(dotnet_dir->VirtualAddress - tgt_header->VirtualAddress) + tgt_header->PointerToRawData; - if (cor_header_offset > b.size() - sizeof(IMAGE_COR20_HEADER)) - return false; - - auto cor_header = (PIMAGE_COR20_HEADER)(b + cor_header_offset); - tgt_header = find_section_header(section_headers, cor_header->MetaData.VirtualAddress); - if (tgt_header == nullptr) - return false; - - // Sanity check - if (cor_header->MetaData.VirtualAddress < tgt_header->VirtualAddress) - return false; - - DWORD metadata_offset = (DWORD)(cor_header->MetaData.VirtualAddress - tgt_header->VirtualAddress) + tgt_header->PointerToRawData; - if (metadata_offset > b.size()) - return false; - - void* ptr = (void*)(b + metadata_offset); - - size_t metadata_length = cor_header->MetaData.Size; - if (metadata_length > b.size() - metadata_offset) - return false; - - // Capture the metadata portion of the image. - malloc_span metadata = { (uint8_t*)std::malloc(metadata_length), metadata_length }; - std::memcpy(metadata, ptr, metadata.size()); - b = std::move(metadata); - return true; -} - -bool get_metadata_from_file(malloc_span& b) -{ - // Defined in II.24.2.1 - defined in physical uint8_t order - std::array const metadata_sig = { 0x42, 0x53, 0x4A, 0x42 }; - - if (b.size() < metadata_sig.size()) - return false; - - // If the header doesn't match, the file is unknown. - for (size_t i = 0; i < metadata_sig.size(); ++i) - { - if (b[i] != metadata_sig[i]) - return false; - } - - return true; -} diff --git a/src/mdmerge/main.cpp b/src/mdmerge/main.cpp index 135cdb50..39e1c8dc 100644 --- a/src/mdmerge/main.cpp +++ b/src/mdmerge/main.cpp @@ -1,127 +1,10 @@ #include #include -#include #include -#include -#include -#include #include -#include #include -#include - -template -class span -{ -protected: - T* _ptr; - size_t _size; -public: - span() - : _ptr{} - , _size{} - { } - - span(T* ptr, size_t len) - : _ptr{ ptr }, _size{ len } - { } - - span(span const & other) = default; - - span& operator=(span&& other) noexcept = default; - - size_t size() const noexcept - { - return _size; - } - - operator T* () noexcept - { - return _ptr; - } - - operator T const* () const noexcept - { - return _ptr; - } - - T& operator[](size_t idx) - { - if (_ptr == nullptr) - throw std::runtime_error{ "Deref null" }; - if (idx >= _size) - throw std::out_of_range{ "Out of bounds access" }; - return _ptr[idx]; - } -}; - -template -class owning_span : public span -{ -public: - owning_span() : span{} - { } - - owning_span(T* ptr, size_t len) - : span{ ptr, len } - { } - - owning_span(owning_span&& other) noexcept - : span{} - { - *this = std::move(other); - } - - ~owning_span() - { - Deleter{}(this->_ptr); - } - - owning_span& operator=(owning_span&& other) noexcept - { - if (this->_ptr != nullptr) - Deleter{}(this->_ptr); - - this->_ptr = other._ptr; - this->_size = other._size; - other._ptr = {}; - other._size = {}; - return *this; - } - - T* release() noexcept - { - T* tmp = this->_ptr; - this->_ptr = {}; - return tmp; - } -}; - -struct free_deleter -{ - void operator()(void* ptr) - { - free(ptr); - } -}; - -template -using malloc_span = owning_span; - -bool read_in_file(char const* file, malloc_span& b); -bool write_out_file(char const* file, malloc_span b); -bool get_metadata_from_pe(malloc_span& b); -bool get_metadata_from_file(malloc_span& b); - -bool create_mdhandle(malloc_span const& buffer, mdhandle_ptr& handle) -{ - mdhandle_t h; - if (!md_create_handle(buffer, buffer.size(), &h)) - return false; - handle.reset(h); - return true; -} +#include bool apply_deltas(mdhandle_t handle, std::vector& deltas, std::vector>& data) { @@ -145,10 +28,11 @@ bool apply_deltas(mdhandle_t handle, std::vector& deltas, std::vect return true; } -struct merge_config_t +struct merge_config_t final { merge_config_t() : path{} + , output_path{} , delta_paths{} , data{} { } @@ -270,189 +154,3 @@ int main(int ac, char** av) return EXIT_SUCCESS; } - -uint32_t get_file_size(char const* path) -{ - uint32_t size_in_uint8_ts = 0; -#ifdef BUILD_WINDOWS - HANDLE handle = ::CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); - if (handle != INVALID_HANDLE_VALUE) - { - size_in_uint8_ts = ::GetFileSize(handle, nullptr); - (void)::CloseHandle(handle); - } -#else - struct stat st; - int rc = stat(path, &st); - if (rc == 0) - size_in_uint8_ts = st.st_size; -#endif // !BUILD_WINDOWS - - return size_in_uint8_ts; -} - -PIMAGE_SECTION_HEADER find_section_header( - span section_headers, - uint32_t rva) -{ - for (size_t i = 0; i < section_headers.size(); ++i) - { - if (section_headers[i].VirtualAddress <= rva - && rva < (section_headers[i].VirtualAddress + section_headers[i].SizeOfRawData)) - { - return §ion_headers[i]; - } - } - - return nullptr; -} - -bool read_in_file(char const* file, malloc_span& b) -{ - // Read in the entire file - std::ifstream fd{ file, std::ios::binary | std::ios::in }; - if (!fd) - return false; - - size_t size = get_file_size(file); - if (size == 0) - return false; - - b = { (uint8_t*)std::malloc(size), size }; - fd.read((char*)(uint8_t*)b, b.size()); - return true; -} - -bool write_out_file(char const* file, malloc_span b) -{ - // Read in the entire file - std::ofstream fd{ file, std::ios::binary | std::ios::out }; - if (!fd) - return false; - - fd.write((char*)(uint8_t*)b, b.size()); - return true; -} - -bool get_metadata_from_pe(malloc_span& b) -{ - if (b.size() < sizeof(IMAGE_DOS_HEADER)) - return false; - - // [TODO] Handle endian issues with .NET generated PE images - // All integers should be read as little-endian. - auto dos_header = (PIMAGE_DOS_HEADER)(void*)b; - bool is_pe = dos_header->e_magic == IMAGE_DOS_SIGNATURE; - if (!is_pe) - return false; - - // Handle headers that are 32 or 64 - PIMAGE_SECTION_HEADER tgt_header; - PIMAGE_DATA_DIRECTORY dotnet_dir; - - // Section headers begin immediately after the NT_HEADERS. - span section_headers; - - if ((size_t)dos_header->e_lfanew > b.size()) - return false; - - size_t remaining_pe_size = b.size() - dos_header->e_lfanew; - uint16_t section_header_count; - uint8_t* section_header_begin; - auto nt_header_any = (PIMAGE_NT_HEADERS)(b + dos_header->e_lfanew); - if (nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 - || nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64) - { - auto nt_header64 = (PIMAGE_NT_HEADERS64)nt_header_any; - if (remaining_pe_size < sizeof(*nt_header64)) - return false; - remaining_pe_size -= sizeof(*nt_header64); - section_header_count = nt_header64->FileHeader.NumberOfSections; - section_header_begin = (uint8_t*)&nt_header64[1]; - dotnet_dir = &nt_header64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]; - } - else if (nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 - || nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM) - { - auto nt_header32 = (PIMAGE_NT_HEADERS32)nt_header_any; - if (remaining_pe_size < sizeof(*nt_header32)) - return false; - remaining_pe_size -= sizeof(*nt_header32); - section_header_count = nt_header32->FileHeader.NumberOfSections; - section_header_begin = (uint8_t*)&nt_header32[1]; - dotnet_dir = &nt_header32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]; - } - else - { - // Unknown machine type - return false; - } - - // Doesn't contain a .NET header - bool is_dotnet = dotnet_dir->Size != 0; - if (!is_dotnet) - return false; - - // Compute the maximum space in the PE to validate section header count. - if (section_header_count > (remaining_pe_size / sizeof(IMAGE_SECTION_HEADER))) - return false; - - remaining_pe_size -= section_header_count * sizeof(IMAGE_SECTION_HEADER); - - section_headers = { (PIMAGE_SECTION_HEADER)section_header_begin, section_header_count }; - - tgt_header = find_section_header(section_headers, dotnet_dir->VirtualAddress); - if (tgt_header == nullptr) - return false; - - // Sanity check - if (dotnet_dir->VirtualAddress < tgt_header->VirtualAddress) - return false; - - DWORD cor_header_offset = (DWORD)(dotnet_dir->VirtualAddress - tgt_header->VirtualAddress) + tgt_header->PointerToRawData; - if (cor_header_offset > b.size() - sizeof(IMAGE_COR20_HEADER)) - return false; - - auto cor_header = (PIMAGE_COR20_HEADER)(b + cor_header_offset); - tgt_header = find_section_header(section_headers, cor_header->MetaData.VirtualAddress); - if (tgt_header == nullptr) - return false; - - // Sanity check - if (cor_header->MetaData.VirtualAddress < tgt_header->VirtualAddress) - return false; - - DWORD metadata_offset = (DWORD)(cor_header->MetaData.VirtualAddress - tgt_header->VirtualAddress) + tgt_header->PointerToRawData; - if (metadata_offset > b.size()) - return false; - - void* ptr = (void*)(b + metadata_offset); - - size_t metadata_length = cor_header->MetaData.Size; - if (metadata_length > b.size() - metadata_offset) - return false; - - // Capture the metadata portion of the image. - malloc_span metadata = { (uint8_t*)std::malloc(metadata_length), metadata_length }; - std::memcpy(metadata, ptr, metadata.size()); - b = std::move(metadata); - return true; -} - -bool get_metadata_from_file(malloc_span& b) -{ - // Defined in II.24.2.1 - defined in physical uint8_t order - std::array const metadata_sig = { 0x42, 0x53, 0x4A, 0x42 }; - - if (b.size() < metadata_sig.size()) - return false; - - // If the header doesn't match, the file is unknown. - for (size_t i = 0; i < metadata_sig.size(); ++i) - { - if (b[i] != metadata_sig[i]) - return false; - } - - return true; -}