From 2a8a1a57413ac678d87aed7c300b1e29ab77f631 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Sun, 22 Feb 2026 20:16:54 -0800 Subject: [PATCH] test all LNCT encoding in the file table, test line instruction encoder, test special opcode encoding --- src/dwarf/dwarf_parse.c | 66 ++-- src/dwarf/dwarf_parse.h | 8 +- src/dwarf/dwarf_writer.c | 103 ++++-- src/dwarf/dwarf_writer.h | 16 +- src/rdi_from_dwarf/rdi_from_dwarf.c | 20 +- src/torture/torture_dwarf.c | 502 +++++++++++++++++++++++----- 6 files changed, 549 insertions(+), 166 deletions(-) diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index c56c2ec4..628099fa 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -2276,7 +2276,7 @@ dw_read_line_vm_header(Arena *arena, // compile unit name is always first in the file table { DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1); - node->file.file_name = cu_name; + node->file.path = cu_name; SLLQueuePush(file_list.first, file_list.last, node); file_list.node_count += 1; } @@ -2288,10 +2288,10 @@ dw_read_line_vm_header(Arena *arena, if (first_byte == 0) { break; } DW_LineFile file = {0}; - TryRead(str8_deserial_read_cstr (data, cursor, &file.file_name), cursor, exit); - TryRead(str8_deserial_read_uleb128(data, cursor, &file.dir_idx), cursor, exit); - TryRead(str8_deserial_read_uleb128(data, cursor, &file.modify_time), cursor, exit); - TryRead(str8_deserial_read_uleb128(data, cursor, &file.file_size), cursor, exit); + TryRead(str8_deserial_read_cstr (data, cursor, &file.path), cursor, exit); + TryRead(str8_deserial_read_uleb128(data, cursor, &file.dir_idx), cursor, exit); + TryRead(str8_deserial_read_uleb128(data, cursor, &file.time_stamp), cursor, exit); + TryRead(str8_deserial_read_uleb128(data, cursor, &file.size), cursor, exit); DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1); node->file = file; @@ -2309,10 +2309,10 @@ dw_read_line_vm_header(Arena *arena, file_table.v = push_array(arena, DW_LineFile, file_list.node_count); for EachNode(n, DW_LineFileNode, file_list.first) { DW_LineFile *dst = &file_table.v[file_table.count++]; - dst->file_name = push_str8_copy(arena, n->file.file_name); + dst->path = push_str8_copy(arena, n->file.path); dst->dir_idx = n->file.dir_idx; - dst->modify_time = n->file.modify_time; - dst->file_size = n->file.file_size; + dst->time_stamp = n->file.time_stamp; + dst->size = n->file.size; } } // DWARF5 @@ -2379,12 +2379,12 @@ dw_read_line_vm_header(Arena *arena, cursor += form_size; switch (lnct) { - case DW_LNCT_Path: { file->file_name = dw_interp_string(input, format, cu_str_offsets, form); } break; - case DW_LNCT_DirectoryIndex: { file->dir_idx = dw_interp_const_u64(form); } break; - case DW_LNCT_TimeStamp: { file->modify_time = dw_interp_const_u64(form); } break; - case DW_LNCT_Size: { file->file_size = dw_interp_const_u64(form); } break; - case DW_LNCT_MD5: { file->md5_digest = dw_interp_const_u128(form); } break; - case DW_LNCT_LLVM_Source: { file->source = dw_interp_string(input, format, cu_str_offsets, form); } break; + case DW_LNCT_Path: { file->path = dw_interp_string(input, format, cu_str_offsets, form); } break; + case DW_LNCT_DirectoryIndex: { file->dir_idx = dw_interp_const_u64(form); } break; + case DW_LNCT_TimeStamp: { file->time_stamp = dw_interp_const_u64(form); } break; + case DW_LNCT_Size: { file->size = dw_interp_const_u64(form); } break; + case DW_LNCT_MD5: { file->md5 = dw_interp_const_u128(form); } break; + case DW_LNCT_LLVM_Source: { file->source = dw_interp_string(input, format, cu_str_offsets, form); } break; default: { Assert(!"unexpected LNTC encoding"); } break; @@ -2565,7 +2565,9 @@ dw_line_vm_step(DW_LineVM *vm) } break; case DW_StdOpcode_FixedAdvancePc: { - TryRead(str8_deserial_read_struct(vm->program, vm->cursor, &vm->operands[0].u64), vm->cursor, exit); + U16 fixed_advance = 0; + TryRead(str8_deserial_read_struct(vm->program, vm->cursor, &fixed_advance), vm->cursor, exit); + vm->operands[0].u64 = fixed_advance; vm->state.address += vm->operands[0].u64; vm->state.op_index = 0; } break; @@ -2590,7 +2592,7 @@ dw_line_vm_step(DW_LineVM *vm) vm->cursor += vm->ext_length; U64 ext_cursor = 0; - TryRead(str8_deserial_read_struct(ext_data, ext_cursor, &vm->ext_opcode), vm->cursor, exit); + TryRead(str8_deserial_read_struct(ext_data, ext_cursor, &vm->ext_opcode), ext_cursor, exit); switch (vm->ext_opcode) { case DW_ExtOpcode_EndSequence: { @@ -2600,26 +2602,26 @@ dw_line_vm_step(DW_LineVM *vm) } break; case DW_ExtOpcode_SetAddress: { - TryRead(str8_deserial_read(ext_data, ext_cursor, &vm->operands[0].u64, vm->header.address_size, vm->header.address_size), vm->cursor, exit); + TryRead(str8_deserial_read(ext_data, ext_cursor, &vm->operands[0].u64, vm->header.address_size, vm->header.address_size), ext_cursor, exit); vm->state.address = vm->operands[0].u64; vm->state.op_index = 0; } break; case DW_ExtOpcode_DefineFile: { - TryRead(str8_deserial_read_cstr (ext_data, ext_cursor, &vm->operands[0].string), vm->cursor, exit); // file name - TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[1].u64), vm->cursor, exit); // dir index - TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[2].u64), vm->cursor, exit); // modify time - TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[3].u64), vm->cursor, exit); // file size + TryRead(str8_deserial_read_cstr (ext_data, ext_cursor, &vm->operands[0].string), ext_cursor, exit); // file name + TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[1].u64), ext_cursor, exit); // dir index + TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[2].u64), ext_cursor, exit); // modify time + TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[3].u64), ext_cursor, exit); // file size if (vm->ext_file_ht == 0) { vm->ext_file_ht = hash_table_init(vm->arena, 512); } DW_LineFile *file = push_array(vm->arena, DW_LineFile, 1); - file->file_name = vm->operands[0].string; - file->dir_idx = vm->operands[1].u64; - file->modify_time = vm->operands[2].u64; - file->file_size = vm->operands[3].u64; + file->path = vm->operands[0].string; + file->dir_idx = vm->operands[1].u64; + file->time_stamp = vm->operands[2].u64; + file->size = vm->operands[3].u64; if (hash_table_search_u64_raw(vm->ext_file_ht, vm->state.file_index) == 0) { vm->error = push_str8f(vm->arena, "file with index %I64d was already defined", vm->state.file_index); @@ -2630,7 +2632,7 @@ dw_line_vm_step(DW_LineVM *vm) } break; case DW_ExtOpcode_SetDiscriminator: { - TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[0].u64), vm->cursor, exit); + TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[0].u64), ext_cursor, exit); vm->state.discriminator = vm->operands[0].u64; } break; @@ -2675,13 +2677,13 @@ dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file) Assert(dir_table.count > 0); // find directory and file name associated with the file index - String8 dir = dir_table.v[file->dir_idx]; - String8 file_name = file->file_name; + String8 dir = dir_table.v[file->dir_idx]; + String8 path = file->path; // infer path style if directory is empty use file name PathStyle style = path_style_from_str8(dir); if (style == PathStyle_Null || style == PathStyle_Relative) { - style = path_style_from_str8(file->file_name); + style = path_style_from_str8(file->path); } String8List path_list = {0}; @@ -2697,17 +2699,17 @@ dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file) str8_list_concat_in_place(&path_list, &dir_list); // push file name - str8_list_push(scratch.arena, &path_list, file->file_name); + str8_list_push(scratch.arena, &path_list, file->path); // resolve dots in the path str8_path_list_resolve_dots_in_place(&path_list, style); } // join path - String8 path = str8_path_list_join_by_style(arena, &path_list, style); + String8 result = str8_path_list_join_by_style(arena, &path_list, style); scratch_end(scratch); - return path; + return result; } internal DW_PubStringsTable diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index be823410..25efb799 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -173,11 +173,11 @@ typedef struct DW_TagTree typedef struct DW_LineFile { - String8 file_name; + String8 path; U64 dir_idx; - U64 modify_time; - U64 file_size; - U128 md5_digest; + U64 time_stamp; + U64 size; + U128 md5; String8 source; } DW_LineFile; diff --git a/src/dwarf/dwarf_writer.c b/src/dwarf/dwarf_writer.c index 6fbf357e..e534d1d9 100644 --- a/src/dwarf/dwarf_writer.c +++ b/src/dwarf/dwarf_writer.c @@ -117,6 +117,7 @@ dw_writer_begin(DW_Format format, DW_Version version, DW_CompUnitKind cu_kind, A writer->line.line_range = 14; writer->line.opcode_base = DW_StdOpcode_Count; writer->line.ln = 1; + Assert(writer->line.line_base < writer->line.line_range); for EachElement(i, writer->sections) { str8_serial_begin(arena, &writer->sections[i].srl); } @@ -179,6 +180,10 @@ dw_serial_push_form(Arena *arena, String8List *srl, DW_Version version, DW_Forma case DW_Form_String: { str8_serial_push_cstr(arena, srl, form.reader.string); } break; + case DW_Form_Block: { + dw_serial_push_uleb128(arena, srl, form.reader.block.size); + str8_serial_push_string(arena, srl, form.reader.block); + } break; case DW_Form_Flag: { str8_serial_push_u8(arena, srl, form.reader.flag); } break; @@ -537,7 +542,9 @@ dw_data_from_line_insts(Arena *arena, U8 address_size, DW_LineInstList insts) } break; case DW_StdOpcode_SetPrologueEnd: {} break; case DW_StdOpcode_SetEpilogueBegin: {} break; - case DW_StdOpcode_SetIsa: {} break; + case DW_StdOpcode_SetIsa: { + dw_serial_push_uleb128(arena, &srl, inst->set_isa); + } break; case DW_StdOpcode_ExtendedOpcode: { // get ext size U64 ext_size = 0; @@ -562,7 +569,7 @@ dw_data_from_line_insts(Arena *arena, U8 address_size, DW_LineInstList insts) switch (inst->ext) { case DW_ExtOpcode_EndSequence: {} break; case DW_ExtOpcode_SetAddress: { - dw_serial_push_uleb128(arena, &srl, inst->set_address); + str8_serial_push_string(arena, &srl, str8_copy(arena, str8((U8 *)&inst->set_address, address_size))); } break; case DW_ExtOpcode_DefineFile: { NotImplemented; @@ -590,23 +597,29 @@ dw_writer_line_emit(DW_Writer *writer, DW_WriterFile *file, U64 ln, U64 col, U64 dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_file(file)); } + S64 col_delta = (S64)col - (S64)writer->line.col; + if (col_delta != 0) { dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_column(col_delta)); } + Assert(addr <= max_S64); S64 addr_delta = (S64)addr - (S64)writer->line.addr; S64 ln_delta = (S64)ln - (S64)writer->line.ln; - S64 col_delta = (S64)col - (S64)writer->line.col; - if (col_delta == 0 && (ln_delta > 0 || addr_delta > 0) && - writer->line.line_base <= ln_delta && ln_delta < writer->line.line_range+writer->line.line_base && - addr_delta < max_U8 - writer->line.opcode_base) { - U8 opcode = (ln_delta - writer->line.line_base) + (writer->line.line_range * addr_delta) + writer->line.opcode_base; + S64 max_ln_delta = writer->line.line_range + writer->line.line_base; + S64 max_addr_delta = (max_U8 - writer->line.opcode_base - (ln_delta - writer->line.line_base)) / writer->line.line_range; + if ((ln_delta != 0 || addr_delta != 0) && + writer->line.line_base <= ln_delta && ln_delta < max_ln_delta && // check line number window + 0 <= addr_delta && addr_delta <= max_addr_delta) { // check address window + U8 opcode = (ln_delta - writer->line.line_base) + (addr_delta * writer->line.line_range) + writer->line.opcode_base; dw_line_inst_list_push(writer->arena, &writer->line.line_insts, (DW_LineInst){ .opcode = opcode }); } else { if (addr_delta != 0) { dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_pc(addr_delta)); } if (ln_delta != 0) { dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_line(ln_delta)); } - if (col_delta != 0) { dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_column(col_delta)); } - dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_copy()); + if (addr_delta != 0 || ln_delta != 0 || col_delta != 0) { + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_copy()); + } } + // update registers writer->line.file = file; writer->line.ln = ln; writer->line.col = col; @@ -619,6 +632,22 @@ dw_writer_line_set_address(DW_Writer *writer, U64 address) dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_set_address(address)); } +internal void +dw_writer_line_set_discriminator(DW_Writer *writer, U64 d) +{ + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_set_discriminator(d)); +} + +internal void +dw_writer_line_end_sequence(DW_Writer *writer) +{ + writer->line.file = 0; + writer->line.ln = 1; + writer->line.addr = 0; + writer->line.col = 0; + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_end_sequence()); +} + internal void dw_writer_line_set_prologue_end(DW_Writer *writer) { @@ -641,8 +670,7 @@ internal DW_WriterFile * dw_writer_new_file(DW_Writer *writer, String8 path) { DW_WriterFile *file = push_array(writer->arena, DW_WriterFile, 1); - file->path = path; - file->file_idx = writer->line.file_count; + file->path = path; SLLQueuePush(writer->line.first_file, writer->line.last_file, file); writer->line.file_count += 1; @@ -936,7 +964,7 @@ dw_writer_emit(DW_Writer *writer) // line { // push line table terminator - dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_end_sequence()); + dw_writer_line_end_sequence(writer); // find comp dir in the compile unit tag String8 comp_dir = {0}; @@ -945,7 +973,7 @@ dw_writer_emit(DW_Writer *writer) for EachNode(attrib, DW_WriterAttrib, writer->root->first_attrib) { if (attrib->kind == DW_AttribKind_CompDir) { AssertAlways(attrib->form.writer.kind == DW_WriterFormKind_String); - comp_dir = attrib->form.writer.string; + comp_dir = str8_chop_last_slash(attrib->form.writer.string); } else if (attrib->kind == DW_AttribKind_Name) { AssertAlways(attrib->form.writer.kind == DW_WriterFormKind_String); comp_name = attrib->form.writer.string; @@ -964,31 +992,38 @@ dw_writer_emit(DW_Writer *writer) dw_serial_push_uleb128(writer->arena, srl, DW_LNCT_Path); dw_serial_push_uleb128(writer->arena, srl, DW_Form_String); - - // dedup directories String8List dirs = {0}; HashTable *dir_ht = hash_table_init(scratch.arena, writer->line.file_count + 1); // first entry must be compile unit directory hash_table_push_string_u64(scratch.arena, dir_ht, comp_dir, dir_ht->count); - str8_list_push(scratch.arena, &dirs, comp_dir); + if (comp_dir.size == 2 && char_is_alpha(comp_dir.str[0]) && comp_dir.str[1] == ':') { + str8_list_pushf(scratch.arena, &dirs, "%S/", comp_dir); + } else { + str8_list_push(scratch.arena, &dirs, comp_dir); + } for EachNode(file, DW_WriterFile, writer->line.first_file) { String8 path = str8_chop_last_slash(file->path); + if (path.size == 0) { + continue; + } if ( ! hash_table_search_string_u64(dir_ht, path, &file->dir_idx)) { + // @dir_idx file->dir_idx = hash_table_push_string_u64(scratch.arena, dir_ht, path, dir_ht->count)->v.value_u64; - str8_list_push(scratch.arena, &dirs, path); + if (path.size == 2 && char_is_alpha(path.str[0]) && path.str[1] == ':') { + str8_list_pushf(scratch.arena, &dirs, "%S/", path); + } else { + str8_list_push(scratch.arena, &dirs, path); + } } } - KeyValuePair *dirs_kv = key_value_pairs_from_hash_table(scratch.arena, dir_ht); - //sort_key_value_pairs_as_string_sensitive(dirs_kv, dir_ht->count); // (15) directories_count - dw_serial_push_uleb128(writer->arena, srl, dir_ht->count); + dw_serial_push_uleb128(writer->arena, srl, dirs.node_count); // (16) directories - for (U64 i = 0; i < dir_ht->count; i += 1) { - String8 dir = dirs_kv[i].key_string; - dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, (DW_WriterXForm) { .reader = { .kind = DW_Form_String, .string = dir } }); + for EachNode(dir_n, String8Node, dirs.first) { + dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, (DW_WriterXForm) { .reader = { .kind = DW_Form_String, .string = dir_n->string } }); } scratch_end(scratch); @@ -1014,10 +1049,10 @@ dw_writer_emit(DW_Writer *writer) // enable encodings in use for EachNode(file, DW_WriterFile, writer->line.first_file) { - if (file->time_stamp != 0) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_TimeStamp ) = DW_Form_UData; } - if (file->size != 0) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_Size ) = DW_Form_UData; } - if (file->md5.size != 0) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_MD5 ) = DW_Form_Block; } - if (file->source.size != 0) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_LLVM_Source) = DW_Form_String; } + if (file->time_stamp != 0) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_TimeStamp ) = DW_Form_UData; } + if (file->size != 0) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_Size ) = DW_Form_UData; } + if ( ! u128_match(file->md5, u128_zero())) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_MD5 ) = DW_Form_Block; } + if (file->source.size != 0) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_LLVM_Source) = DW_Form_String; } } // count needed encodings @@ -1057,11 +1092,15 @@ dw_writer_emit(DW_Writer *writer) } } } + U64 file_idx = 0; for EachNode(file, DW_WriterFile, writer->line.first_file) { static DW_WriterXForm null_form_udata = { .reader = { .kind = DW_Form_UData } }; static DW_WriterXForm null_form_string = { .reader = { .kind = DW_Form_String } }; static DW_WriterXForm null_form_block = { .reader = { .kind = DW_Form_Block } }; + // @file_idx + file->file_idx = file_idx++; + // path Assert(*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_Path) == DW_Form_String); String8 file_name = str8_skip_last_slash(file->path); @@ -1095,8 +1134,8 @@ dw_writer_emit(DW_Writer *writer) // MD5 if (*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_MD5) == DW_Form_Block) { - if (file->md5.size) { - DW_WriterXForm md5_form = { .reader = { .kind = DW_Form_Block, .block = file->md5 } }; + if ( ! u128_match(file->md5, u128_zero())) { + DW_WriterXForm md5_form = { .reader = { .kind = DW_Form_Block, .block = str8_struct(&file->md5) } }; dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, md5_form); } else { dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, null_form_block); @@ -1143,9 +1182,9 @@ dw_writer_emit(DW_Writer *writer) // (11) opcode_base str8_serial_push_struct(writer->arena, srl, &writer->line.opcode_base); // (12) standard_opcode_lengths - U8 *std_op_lens = push_array(writer->arena, U8, DW_StdOpcode_Count - 1); - for (U64 i = 1; i < DW_StdOpcode_Count; i += 1) { std_op_lens[i-1] = dw_length_from_std_opcode(i); } - str8_serial_push_string(writer->arena, srl, str8(std_op_lens, DW_StdOpcode_Count - 1)); + U8 *std_op_lens = push_array(writer->arena, U8, writer->line.opcode_base - 1); + for (U64 i = 1; i < writer->line.opcode_base; i += 1) { std_op_lens[i-1] = dw_length_from_std_opcode(i); } + str8_serial_push_string(writer->arena, srl, str8(std_op_lens, writer->line.opcode_base - 1)); // directory table str8_list_concat_in_place(srl, &dir_table_srl); // file table diff --git a/src/dwarf/dwarf_writer.h b/src/dwarf/dwarf_writer.h index 466ad5d5..bff6a141 100644 --- a/src/dwarf/dwarf_writer.h +++ b/src/dwarf/dwarf_writer.h @@ -135,7 +135,7 @@ typedef struct DW_WriterFile String8 path; U64 time_stamp; U64 size; - String8 md5; + U128 md5; String8 source; // computed during line table emit step U64 file_idx; @@ -306,12 +306,14 @@ internal DW_LineInstNode * dw_line_inst_list_push (Arena *arena, DW_LineInst #define DW_LNE_set_address(a) (DW_LineInst){ .opcode = DW_StdOpcode_ExtendedOpcode, .ext = DW_ExtOpcode_SetAddress, .set_address = a } #define DW_LNE_set_discriminator(d) (DW_LineInst){ .opcode = DW_StdOpcode_ExtendedOpcode, .ext = DW_ExtOpcode_SetDiscriminator, .set_discriminator = d } -internal void dw_writer_line_emit (DW_Writer *writer, DW_WriterFile *file, U64 ln, U64 col, U64 addr); -internal void dw_writer_line_set_address (DW_Writer *writer, U64 address); -internal void dw_writer_line_set_prologue_end(DW_Writer *writer); -internal void dw_writer_line_epilogue_begin (DW_Writer *writer); -internal void dw_writer_line_set_isa (DW_Writer *writer, U64 isa); -internal DW_WriterFile * dw_writer_new_file (DW_Writer *writer, String8 path); +internal void dw_writer_line_emit (DW_Writer *writer, DW_WriterFile *file, U64 ln, U64 col, U64 addr); +internal void dw_writer_line_set_address (DW_Writer *writer, U64 address); +internal void dw_writer_line_set_discriminator(DW_Writer *writer, U64 d); +internal void dw_writer_line_end_sequence (DW_Writer *writer); +internal void dw_writer_line_set_prologue_end (DW_Writer *writer); +internal void dw_writer_line_epilogue_begin (DW_Writer *writer); +internal void dw_writer_line_set_isa (DW_Writer *writer, U64 isa); +internal DW_WriterFile * dw_writer_new_file (DW_Writer *writer, String8 path); //////////////////////////////// // Emit diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index c548091b..22529068 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -2564,7 +2564,7 @@ d2r_src_file_lookup_compar(void *raw_a, void *raw_b) String8 dir_path_b = b->vm->header.dir_table.v[file_b->dir_idx]; int cmp = str8_compar(dir_path_a, dir_path_b, 0); if (cmp == 0) { - cmp = str8_compar(file_a->file_name, file_b->file_name, 0); + cmp = str8_compar(file_a->path, file_b->path, 0); } return cmp; } @@ -2587,9 +2587,9 @@ d2r_hash_line_file(String8 dir_path, DW_LineFile *file) XXH3_state_t hasher = {0}; XXH3_64bits_reset(&hasher); XXH3_64bits_update(&hasher, dir_path.str, dir_path.size); - XXH3_64bits_update(&hasher, file->file_name.str, file->file_name.size); - XXH3_64bits_update(&hasher, &file->modify_time, sizeof(file->modify_time)); - XXH3_64bits_update(&hasher, &file->md5_digest, sizeof(file->md5_digest)); + XXH3_64bits_update(&hasher, file->path.str, file->path.size); + XXH3_64bits_update(&hasher, &file->time_stamp, sizeof(file->time_stamp)); + XXH3_64bits_update(&hasher, &file->md5, sizeof(file->md5)); XXH64_hash_t hash = XXH3_64bits_digest(&hasher); return hash; } @@ -2841,18 +2841,18 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) { String8List path_list = {0}; str8_list_push_node(&path_list, &(String8Node){ .string = lookup->vm->header.dir_table.v[src->dir_idx] }); - str8_list_push_node(&path_list, &(String8Node){ .string = src->file_name }); + str8_list_push_node(&path_list, &(String8Node){ .string = src->path }); path = str8_path_list_join_by_style(arena, &path_list, path_style); } // fill out source file dst->path = path; - if ( ! u128_match(src->md5_digest, u128_zero())) { + if ( ! u128_match(src->md5, u128_zero())) { dst->checksum_kind = RDI_ChecksumKind_MD5; - dst->checksum = str8_copy(arena, str8_struct(&src->md5_digest)); - } else if (src->modify_time != 0) { + dst->checksum = str8_copy(arena, str8_struct(&src->md5)); + } else if (src->time_stamp != 0) { dst->checksum_kind = RDI_ChecksumKind_Timestamp; - dst->checksum = str8_copy(arena, str8_struct(&src->modify_time)); + dst->checksum = str8_copy(arena, str8_struct(&src->time_stamp)); } lookup->src_file = dst; @@ -2891,7 +2891,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params) (line_buffer_size >= D2R_LineBufferMax || line_buffer->file_index != vm->state.file_index)) && line_buffer_size > 0) { // lookup source file - DW_LineFile *file = &vm->header.file_table.v[vm->state.file_index]; + DW_LineFile *file = &vm->header.file_table.v[line_buffer->file_index]; U64 hash = d2r_hash_line_file(vm->header.dir_table.v[file->dir_idx], file); D2R_SrcFileLookup *lookup = lfht_search(src_file_lfht, hash, &(D2R_SrcFileLookup){ .file = file, .vm = vm }, d2r_src_file_lookup_is_equal, 0); RDIM_SrcFile *src_file = lookup->src_file; diff --git a/src/torture/torture_dwarf.c b/src/torture/torture_dwarf.c index 2641aefd..820cdfd3 100644 --- a/src/torture/torture_dwarf.c +++ b/src/torture/torture_dwarf.c @@ -34,7 +34,7 @@ t_dw_test_sleb128(U64 v, U64 expected_length) String8 e = dw_write_sleb128(scratch.arena, v0); if (!(expected_length == e.size)) { goto exit; } - U64 v1; + S64 v1; U64 bytes_read = str8_deserial_read_sleb128(e, 0, &v1); if (!(bytes_read == e.size)) { goto exit; } if (!(v0 == v1)) { goto exit; } @@ -55,6 +55,8 @@ T_BeginTest(test_leb128) T_Ok(t_dw_test_sleb128(min_S64, 10)); T_Ok(t_dw_test_sleb128(max_S64, 10)); + T_Ok(t_dw_test_uleb128(0xDEADBEEFCAFEBABE, 10)); + for EachIndex(i, 64) { T_Ok(t_dw_test_uleb128((1ull << i), 1 + (i / 7))); } @@ -102,45 +104,419 @@ exit:; return is_match; } -internal DW_Writer * -dwt_make_writer(void) +internal DW_Input +dw_input_from_writer(Arena *arena, DW_Writer *writer) { - Temp scratch = scratch_begin(0, 0); + Temp scratch = scratch_begin(&arena, 1); - String8 comp_dir = t_make_file_path(scratch.arena, str8_lit("")); - String8 comp_name = str8_lit("test_code.txt"); - String8 test_text = str8_lit("nop\nnop\nret\n"); - String8 test_path = t_make_file_path(scratch.arena, comp_name); - t_write_file(comp_name, test_text); + OBJ *obj = obj_alloc(0, Arch_x64); + OBJ_Section *text_section = obj_push_section(obj, str8_lit(".text"), OBJ_SectionFlag_Read|OBJ_SectionFlag_Exec|OBJ_SectionFlag_Load); + str8_serial_push_u8(obj->arena, &text_section->data, 0x90); + str8_serial_push_u8(obj->arena, &text_section->data, 0x90); + str8_serial_push_u8(obj->arena, &text_section->data, 0x90); + str8_serial_push_u8(obj->arena, &text_section->data, 0xc3); + obj_push_symbol(obj, str8_lit("entry"), OBJ_SymbolScope_Global, OBJ_RefKind_Section, text_section); + + dw_writer_emit_to_obj(writer, obj); + String8 raw_coff = coff_from_obj(scratch.arena, obj); + + t_write_file(str8_lit("dwarf.obj"), raw_coff); + t_invoke(str8_lit("radlink"), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full dwarf.obj"), max_U64); + os_delete_file_at_path(t_make_file_path(scratch.arena, str8_lit("a.pdb"))); + + String8 exe = t_read_file(arena, str8_lit("a.exe")); + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)(exe.str + pe.section_table_range.min); + String8 string_table = str8_substr(exe, pe.string_table_range); + DW_Input input = dw_input_from_coff_section_table(arena, exe, string_table, pe.section_count, section_table); + + obj_release(&obj); + scratch_end(scratch); + return input; +} + +T_BeginTest(dwarf_line_opcodes) +{ + DW_Writer *writer = dw_writer_begin(DW_Format_32Bit, DW_Version_5, DW_CompUnitKind_Compile, Arch_x64); + String8 comp_dir = str8_lit("c:/devel/"); + String8 comp_name = str8_lit("test.c"); + U64 address = 0xDEADBEEFCAFEBABE; + dw_writer_tag_begin(writer, DW_TagKind_CompileUnit); + dw_writer_push_attrib_string(writer, DW_AttribKind_Producer, str8_lit("RAD DWARF WRITER")); + dw_writer_push_attrib_string(writer, DW_AttribKind_CompDir, comp_dir); + dw_writer_push_attrib_string(writer, DW_AttribKind_Name, comp_name); + dw_writer_push_attrib_line_ptr(writer, DW_AttribKind_StmtList, 0); + dw_writer_tag_end(writer); + + // test directory table and file table + DW_WriterFile *file2 = dw_writer_new_file(writer, str8_lit("d:/foobar/qwe.c")); + file2->time_stamp = 123; + file2->size = max_U64; + file2->md5 = *(U128 *)&((U8[sizeof(U128)]) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }); + file2->source = str8_lit("a quick brown fox jumps over the lazy dog\n"); + DW_WriterFile *file = dw_writer_new_file(writer, comp_name); + file->time_stamp = max_U64; + file->size = 314; + file->md5 = *(U128 *)&((U8[sizeof(U128)]) { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, }); + file->source = str8_lit("int main() { return 057; }\n"); + + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_copy()); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_pc(7)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_pc(-7)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_line(4)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_line(-4)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_file(file)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_column(max_U64)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_column(0)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_negate_stmt()); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_negate_stmt()); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_basic_block()); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_const_add_pc()); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_fixed_advance_pc(max_U16)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_prologue_end()); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_epilogue_begin()); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_isa(max_U64)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_set_address(address)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_set_discriminator(2)); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_end_sequence()); + + DW_Input input = dw_input_from_writer(scratch.arena, writer); + Rng1U64Array cu_ranges = dw_unit_ranges_from_data_arr(scratch.arena, input.sec[DW_Section_Info].data); + DW_CompUnit cu = dw_cu_from_info_off(scratch.arena, &input, (DW_ListUnitInput){0}, cu_ranges.v[0].min, 0); + DW_LineVM *line_vm = dw_line_vm_init(&input, &cu); + + T_Ok(line_vm->header.dir_table.count == 2); + T_Ok(line_vm->header.file_table.count == 2); + + T_Ok(str8_match(line_vm->header.dir_table.v[0], str8_lit("c:/devel"), 0)); + T_Ok(str8_match(line_vm->header.dir_table.v[1], str8_lit("d:/foobar"), 0)); + + DW_LineFile *file_reader = &line_vm->header.file_table.v[0]; + T_Ok(str8_match(file_reader->path, comp_name, 0)); + T_Ok(file_reader->dir_idx == 0); + T_Ok(file_reader->time_stamp == file->time_stamp); + T_Ok(u128_match(file_reader->md5, file->md5)); + T_Ok(str8_match(file_reader->source, file->source, 0)); + + DW_LineFile *file2_reader = &line_vm->header.file_table.v[1]; + T_Ok(str8_match(file2_reader->path, str8_lit("qwe.c"), 0)); + T_Ok(file2_reader->dir_idx == 1); + T_Ok(file2_reader->time_stamp == file2->time_stamp); + T_Ok(u128_match(file2_reader->md5, file2->md5)); + T_Ok(str8_match(file2_reader->source, file2->source, 0)); + + T_Ok(line_vm->new_line == 0); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_Copy); + T_Ok(line_vm->new_line == 1); + T_Ok(line_vm->state.discriminator == 0); + T_Ok(line_vm->state.basic_block == 0); + T_Ok(line_vm->state.prologue_end == 0); + T_Ok(line_vm->state.epilogue_begin == 0); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvancePc); + T_Ok(line_vm->state.address == 7); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvancePc); + T_Ok(line_vm->state.address == 0); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 5); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 1); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_SetFile); + T_Ok(line_vm->state.file_index == 0); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_SetColumn); + T_Ok(line_vm->state.column == max_U64); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_SetColumn); + T_Ok(line_vm->state.column == 0); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_NegateStmt); + T_Ok(line_vm->state.is_stmt == 0); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_NegateStmt); + T_Ok(line_vm->state.is_stmt == 1); + + T_Ok(line_vm->state.basic_block == 0); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_SetBasicBlock); + T_Ok(line_vm->state.basic_block == 1); - DW_Writer *writer = dw_writer_begin(DW_Format_32Bit, DW_Version_Last, DW_CompUnitKind_Compile, Arch_x64); - // line { - DW_WriterFile *a_file = dw_writer_new_file(writer, test_path); - dw_writer_line_set_prologue_end(writer); - dw_writer_line_emit(writer, a_file, 1, 0, 0x140001000); - dw_writer_line_emit(writer, a_file, 2, 0, 0x140001001); - dw_writer_line_emit(writer, a_file, 3, 0, 0x140001002); - - //DW_WriterFile *b_file = dw_writer_new_file(writer, str8_lit("~/devel/projects/b/b.c")); - //DW_WriterFile *a_file = dw_writer_new_file(writer, str8_lit("~/devel/projects/a.c")); - //dw_writer_line_set_prologue_end(writer); - //dw_writer_line_emit(writer, b_file, 10, 0, 0x140001000); - //dw_writer_line_emit(writer, b_file, 11, 0, 0x140001010); - //dw_writer_line_emit(writer, a_file, 1, 0, 0x140001016); - //dw_writer_line_emit(writer, a_file, 2, 0, 0x140001020); + U64 addr_before = line_vm->state.address; + U64 const_advance = (0xffu - line_vm->header.opcode_base) / line_vm->header.line_range; + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(!line_vm->new_line); + T_Ok(line_vm->state.address == addr_before + const_advance); } + + T_Ok(line_vm->state.address == 0x11); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_FixedAdvancePc); + T_Ok(line_vm->state.address == max_U16 + 0x11); + + T_Ok(line_vm->state.prologue_end == 0); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_SetPrologueEnd); + T_Ok(line_vm->state.prologue_end == 1); + + T_Ok(line_vm->state.epilogue_begin == 0); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_SetEpilogueBegin); + T_Ok(line_vm->state.epilogue_begin == 1); + + T_Ok(line_vm->state.isa == 0); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_SetIsa); + T_Ok(line_vm->state.isa == max_U64); + + T_Ok(line_vm->state.address != address); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_ExtendedOpcode); + T_Ok(line_vm->ext_opcode == DW_ExtOpcode_SetAddress); + T_Ok(line_vm->state.address == address); + + T_Ok(line_vm->state.discriminator == 0); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_ExtendedOpcode); + T_Ok(line_vm->ext_opcode == DW_ExtOpcode_SetDiscriminator); + T_Ok(line_vm->state.discriminator == 2); + + T_Ok(!line_vm->state.end_sequence); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_ExtendedOpcode); + T_Ok(line_vm->ext_opcode == DW_ExtOpcode_EndSequence); + T_Ok(line_vm->state.end_sequence); + + dw_writer_end(&writer); +} +T_EndTest; + +T_BeginTest(dwarf_line_emit) +{ + DW_Writer *writer = dw_writer_begin(DW_Format_32Bit, DW_Version_5, DW_CompUnitKind_Compile, Arch_x64); + String8 comp_dir = str8_lit("c:/devel/"); + String8 comp_name = str8_lit("test.c"); + dw_writer_tag_begin(writer, DW_TagKind_CompileUnit); + dw_writer_push_attrib_string(writer, DW_AttribKind_Producer, str8_lit("RAD DWARF WRITER")); + dw_writer_push_attrib_string(writer, DW_AttribKind_CompDir, comp_dir); + dw_writer_push_attrib_string(writer, DW_AttribKind_Name, comp_name); + dw_writer_push_attrib_line_ptr(writer, DW_AttribKind_StmtList, 0); + dw_writer_tag_end(writer); + + // test special opcode writer and reader + DW_WriterFile *file = dw_writer_new_file(writer, comp_name); + + // init sequence + dw_writer_line_emit(writer, file, 10000, 0, 1000); + + for EachIndex(i, abs_s64(writer->line.line_base) + 1) { + dw_writer_line_emit(writer, file, writer->line.ln-i, 0, writer->line.addr+1); + + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_line(i)); + writer->line.ln += i; + } + + // special opcode line window underflow, must emit three instructions to advance + dw_writer_line_emit(writer, file, (writer->line.ln + writer->line.line_base) - 1, 0, writer->line.addr + 1); + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_line(-(writer->line.line_base - 1))); + + for EachIndex(i, (writer->line.line_range + writer->line.line_base) + 1) { + dw_writer_line_emit(writer, file, writer->line.ln+i, 0, writer->line.addr+1); + + dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_line(-i)); + writer->line.ln -= i; + } + + dw_writer_line_end_sequence(writer); + dw_writer_line_emit(writer, file, 1000, 0, writer->line.addr+1); + + // test address window + S64 c = writer->line.line_range + writer->line.line_base; + U64 line_addr_count = 0; + for (S64 i = 0; i < c; ++i) { + U64 ln_delta = i + writer->line.line_base; + S64 max_ln_delta = writer->line.line_range + writer->line.line_base; + S64 max_addr_delta = (max_U8 - writer->line.opcode_base - (ln_delta - writer->line.line_base)) / writer->line.line_range; + for EachIndex(k, max_addr_delta) { + dw_writer_line_emit(writer, file, writer->line.ln + i, 0, writer->line.addr + k); + line_addr_count += 1; + } + } + + DW_Input input = dw_input_from_writer(scratch.arena, writer); + Rng1U64Array cu_ranges = dw_unit_ranges_from_data_arr(scratch.arena, input.sec[DW_Section_Info].data); + DW_CompUnit cu = dw_cu_from_info_off(scratch.arena, &input, (DW_ListUnitInput){0}, cu_ranges.v[0].min, 0); + DW_LineVM *line_vm = dw_line_vm_init(&input, &cu); + + // check init sequence + { + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_SetFile); + T_Ok(line_vm->state.file_index == 0); + T_Ok(line_vm->new_line == 0); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvancePc); + T_Ok(line_vm->state.address == 1000); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->new_line == 0); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_Copy); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->state.address == 1000); + T_Ok(line_vm->new_line == 1); + } + + { + U64 pc = line_vm->state.address; + for EachIndex(i, abs_s64(writer->line.line_base) + 1) { + pc += 1; + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == 0x20 - i); + T_Ok(line_vm->state.line == 10000 - i); + T_Ok(line_vm->state.address == pc); + T_Ok(line_vm->new_line == 1); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->state.address == pc); + } + + // line window underflow check + { + pc += 1; + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvancePc); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->state.address == pc); + T_Ok(!line_vm->new_line); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 9994); + T_Ok(line_vm->state.address == pc); + T_Ok(!line_vm->new_line); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_Copy); + T_Ok(line_vm->state.line == 9994); + T_Ok(line_vm->state.address == pc); + T_Ok(line_vm->new_line); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->state.address == pc); + T_Ok(!line_vm->new_line); + } + + for EachIndex(i, writer->line.line_range + writer->line.line_base) { + pc += 1; + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == 0x20 + i); + T_Ok(line_vm->state.line == 10000 + i); + T_Ok(line_vm->state.address == pc); + T_Ok(line_vm->new_line); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->state.address == pc); + T_Ok(!line_vm->new_line); + } + + // line window overflow check + { + pc += 1; + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvancePc); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->state.address == pc); + T_Ok(!line_vm->new_line); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 10009); + T_Ok(line_vm->state.address == pc); + T_Ok(!line_vm->new_line); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_Copy); + T_Ok(line_vm->state.address == pc); + T_Ok(line_vm->state.line == 10009); + T_Ok(line_vm->new_line); + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_AdvanceLine); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->state.address == pc); + T_Ok(!line_vm->new_line); + } + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_ExtendedOpcode); + T_Ok(line_vm->ext_opcode == DW_ExtOpcode_EndSequence); + T_Ok(line_vm->state.line == 10000); + T_Ok(line_vm->state.address == pc); + T_Ok(line_vm->new_line); + } + + { + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(dw_line_vm_step(line_vm)); + + for EachIndex(i, line_addr_count/*first line is a noop*/-1) { + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->header.opcode_base < line_vm->opcode); + T_Ok(line_vm->new_line); + } + + T_Ok(dw_line_vm_step(line_vm)); + T_Ok(line_vm->opcode == DW_StdOpcode_ExtendedOpcode); + T_Ok(line_vm->ext_opcode == DW_ExtOpcode_EndSequence); + T_Ok(line_vm->state.line == 1586); + T_Ok(line_vm->state.address == 1161); + T_Ok(line_vm->new_line); + } +} +T_EndTest; + +T_BeginTest(dwarf_writer) +{ + DW_Writer *writer = dw_writer_begin(DW_Format_32Bit, DW_Version_5, DW_CompUnitKind_Compile, Arch_x64); // info { dw_writer_tag_begin(writer, DW_TagKind_CompileUnit); dw_writer_push_attrib_string(writer, DW_AttribKind_Producer, str8_lit("RAD DWARF WRITER")); - dw_writer_push_attrib_string(writer, DW_AttribKind_CompDir, comp_dir); - dw_writer_push_attrib_string(writer, DW_AttribKind_Name, comp_name); dw_writer_push_attrib_enum(writer, DW_AttribKind_Language, DW_Language_C99); dw_writer_push_attrib_flag(writer, DW_AttribKind_UseUtf8, 1); - dw_writer_push_attrib_line_ptr(writer, DW_AttribKind_StmtList, 0); dw_writer_push_attrib_address(writer, DW_AttribKind_LowPc, 0x140001000); - dw_writer_push_attrib_address(writer, DW_AttribKind_HighPc, 0x140001003); + dw_writer_push_attrib_address(writer, DW_AttribKind_HighPc, 0x140001004); { DW_WriterTag *char_type = dw_writer_tag_begin(writer, DW_TagKind_BaseType); dw_writer_push_attrib_sint(writer, DW_AttribKind_ByteSize, 1); @@ -183,7 +559,7 @@ dwt_make_writer(void) dw_writer_push_attrib_flag(writer, DW_AttribKind_External, 1); dw_writer_push_attrib_flag(writer, DW_AttribKind_Prototyped, 1); dw_writer_push_attrib_address(writer, DW_AttribKind_LowPc, 0x140001000); - dw_writer_push_attrib_address(writer, DW_AttribKind_HighPc, 0x140001003); + dw_writer_push_attrib_address(writer, DW_AttribKind_HighPc, 0x140001004); dw_writer_push_attrib_string(writer, DW_AttribKind_Name, str8_lit("main")); dw_writer_push_attrib_ref(writer, DW_AttribKind_Type, simple_struct_tag); dw_writer_push_attrib_expression(writer, DW_AttribKind_FrameBase, &(DW_ExprEnc)DW_ExprEnc_Op(Reg7), 1); @@ -192,47 +568,12 @@ dwt_make_writer(void) dw_writer_tag_end(writer); } - { - DW_Input input; - { - OBJ *obj = obj_alloc(0, Arch_x64); - OBJ_Section *text_section = obj_push_section(obj, str8_lit(".text"), OBJ_SectionFlag_Read|OBJ_SectionFlag_Exec|OBJ_SectionFlag_Load); - str8_serial_push_u8(obj->arena, &text_section->data, 0x90); - str8_serial_push_u8(obj->arena, &text_section->data, 0x90); - str8_serial_push_u8(obj->arena, &text_section->data, 0xc3); - obj_push_symbol(obj, str8_lit("entry"), OBJ_SymbolScope_Global, OBJ_RefKind_Section, text_section); + DW_Input input = dw_input_from_writer(scratch.arena, writer); + DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); + DW_CompUnit cu = dw_cu_from_info_off(scratch.arena, &input, lu_input, 0, 1); + DW_TagTree tag_tree = dw_tag_tree_from_cu(scratch.arena, &input, &cu); + AssertAlways(dwt_tags_must_match(writer->root, tag_tree.root)); - dw_writer_emit_to_obj(writer, obj); - - String8 raw_coff = coff_from_obj(scratch.arena, obj); - COFF_FileHeaderInfo obj_coff_header = coff_file_header_info_from_data(raw_coff); - String8 raw_sections = str8_substr(raw_coff, obj_coff_header.section_table_range); - U64 section_count = raw_sections.size / sizeof(COFF_SectionHeader); - COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_sections.str; - String8 string_table = str8_substr(raw_coff, obj_coff_header.string_table_range); - input = dw_input_from_coff_section_table(scratch.arena, raw_coff, string_table, section_count, section_table); - - t_write_file(str8_lit("dwarf.obj"), raw_coff); - - t_invoke(str8_lit("radlink"), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full dwarf.obj"), max_U64); - - obj_release(&obj); - } - - DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); - DW_CompUnit cu = dw_cu_from_info_off(scratch.arena, &input, lu_input, 0, 1); - DW_TagTree tag_tree = dw_tag_tree_from_cu(scratch.arena, &input, &cu); - AssertAlways(dwt_tags_must_match(writer->root, tag_tree.root)); - - } - - scratch_end(scratch); - return writer; -} - -T_BeginTest(dwarf_writer) -{ - DW_Writer *writer = dwt_make_writer(); // validate the writer @@ -250,7 +591,7 @@ T_BeginTest(dwarf_writer) T_Ok(comp_unit_tag->kind == DW_TagKind_CompileUnit); T_Ok(comp_unit_tag->next == 0); T_Ok(comp_unit_tag->parent == 0); - T_Ok(comp_unit_tag->attrib_count == 3); + T_Ok(comp_unit_tag->attrib_count == 5); T_Ok(comp_unit_tag->abbrev_id == 1); T_Ok(comp_unit_tag->info_off == 0xc); @@ -278,7 +619,7 @@ T_BeginTest(dwarf_writer) T_Ok(char_type_tag->parent == comp_unit_tag); T_Ok(char_type_tag->attrib_count == 3); T_Ok(char_type_tag->abbrev_id == 2); - T_Ok(char_type_tag->info_off == 0x20); + T_Ok(char_type_tag->info_off == 0x30); T_Ok(char_type_tag->first_attrib != char_type_tag->last_attrib); DW_WriterAttrib *byte_size_attrib = char_type_tag->first_attrib; @@ -306,7 +647,7 @@ T_BeginTest(dwarf_writer) T_Ok(const_type_tag->parent == comp_unit_tag); T_Ok(const_type_tag->attrib_count == 1); T_Ok(const_type_tag->abbrev_id == 3); - T_Ok(const_type_tag->info_off == 0x28); + T_Ok(const_type_tag->info_off == 0x38); T_Ok(const_type_tag->first_attrib && const_type_tag->first_attrib == const_type_tag->last_attrib); DW_WriterAttrib *type_attrib = const_type_tag->first_attrib; @@ -322,7 +663,7 @@ T_BeginTest(dwarf_writer) T_Ok(dup_char_type_tag->parent == comp_unit_tag); T_Ok(dup_char_type_tag->attrib_count == 3); T_Ok(dup_char_type_tag->abbrev_id == 2); - T_Ok(dup_char_type_tag->info_off == 0x2a); + T_Ok(dup_char_type_tag->info_off == 0x3a); T_Ok(dup_char_type_tag->first_attrib != dup_char_type_tag->last_attrib); DW_WriterAttrib *byte_size_attrib = dup_char_type_tag->first_attrib; @@ -350,7 +691,7 @@ T_BeginTest(dwarf_writer) T_Ok(simple_struct_tag->parent == comp_unit_tag); T_Ok(simple_struct_tag->attrib_count == 2); T_Ok(simple_struct_tag->abbrev_id == 4); - T_Ok(simple_struct_tag->info_off == 0x32); + T_Ok(simple_struct_tag->info_off == 0x42); DW_WriterAttrib *simple_struct_name = simple_struct_tag->first_attrib; T_Ok(simple_struct_name->kind == DW_AttribKind_Name); @@ -362,7 +703,7 @@ T_BeginTest(dwarf_writer) T_Ok(m0_tag->kind == DW_TagKind_Member); T_Ok(m0_tag->parent == simple_struct_tag); T_Ok(m0_tag->attrib_count == 3); - T_Ok(m0_tag->info_off == 0x3b); + T_Ok(m0_tag->info_off == 0x4b); T_Ok(m0_tag->abbrev_id == 5); DW_WriterAttrib *name = m0_tag->first_attrib; @@ -373,7 +714,7 @@ T_BeginTest(dwarf_writer) DW_WriterAttrib *type = name->next; T_Ok(type->kind == DW_AttribKind_Type); T_Ok(type->form.reader.kind == DW_Form_Ref1); - T_Ok(type->form.reader.ref == 0x20); + T_Ok(type->form.reader.ref == 0x30); DW_WriterAttrib *data_loc = type->next; T_Ok(data_loc->kind == DW_AttribKind_DataMemberLocation); @@ -387,7 +728,7 @@ T_BeginTest(dwarf_writer) T_Ok(m1_tag->kind == DW_TagKind_Member); T_Ok(m1_tag->parent == simple_struct_tag); T_Ok(m1_tag->attrib_count == 4); - T_Ok(m1_tag->info_off == 0x41); + T_Ok(m1_tag->info_off == 0x51); T_Ok(m1_tag->abbrev_id == 6); DW_WriterAttrib *name = m1_tag->first_attrib; @@ -398,7 +739,7 @@ T_BeginTest(dwarf_writer) DW_WriterAttrib *type = name->next; T_Ok(type->kind == DW_AttribKind_Type); T_Ok(type->form.reader.kind == DW_Form_Ref1); - T_Ok(type->form.reader.ref == 0x20); + T_Ok(type->form.reader.ref == 0x30); DW_WriterAttrib *data_loc = type->next; T_Ok(data_loc->kind == DW_AttribKind_DataMemberLocation); @@ -433,13 +774,13 @@ T_BeginTest(dwarf_writer) T_Ok(low_pc->kind == DW_AttribKind_LowPc); T_Ok(low_pc->form.reader.kind == DW_Form_Addr); T_Ok(low_pc->form.reader.addr.size == sizeof(U64)); - T_Ok(*(U64 *)low_pc->form.reader.addr.str == 0x14012f2f0); + T_Ok(*(U64 *)low_pc->form.reader.addr.str == 0x140001000); DW_WriterAttrib *high_pc = low_pc->next; T_Ok(high_pc->kind == DW_AttribKind_HighPc); T_Ok(high_pc->form.reader.kind == DW_Form_Addr); T_Ok(high_pc->form.reader.addr.size == sizeof(U64)); - T_Ok(*(U64 *)high_pc->form.reader.addr.str == 0x14012f405); + T_Ok(*(U64 *)high_pc->form.reader.addr.str == 0x140001004); DW_WriterAttrib *name = high_pc->next; T_Ok(name->kind == DW_AttribKind_Name); @@ -651,4 +992,3 @@ T_EndTest; #endif #undef T_Group -