test all LNCT encoding in the file table,

test line instruction encoder,
test special opcode encoding
This commit is contained in:
Nikita Smith
2026-02-22 20:17:00 -08:00
parent a7e64c3928
commit 2a8a1a5741
6 changed files with 549 additions and 166 deletions
+29 -27
View File
@@ -2276,7 +2276,7 @@ dw_read_line_vm_header(Arena *arena,
// compile unit name is always first in the file table // compile unit name is always first in the file table
{ {
DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1); 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); SLLQueuePush(file_list.first, file_list.last, node);
file_list.node_count += 1; file_list.node_count += 1;
} }
@@ -2288,10 +2288,10 @@ dw_read_line_vm_header(Arena *arena,
if (first_byte == 0) { break; } if (first_byte == 0) { break; }
DW_LineFile file = {0}; DW_LineFile file = {0};
TryRead(str8_deserial_read_cstr (data, cursor, &file.file_name), 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.dir_idx), cursor, exit);
TryRead(str8_deserial_read_uleb128(data, cursor, &file.modify_time), cursor, exit); TryRead(str8_deserial_read_uleb128(data, cursor, &file.time_stamp), cursor, exit);
TryRead(str8_deserial_read_uleb128(data, cursor, &file.file_size), cursor, exit); TryRead(str8_deserial_read_uleb128(data, cursor, &file.size), cursor, exit);
DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1); DW_LineFileNode *node = push_array(scratch.arena, DW_LineFileNode, 1);
node->file = file; 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); file_table.v = push_array(arena, DW_LineFile, file_list.node_count);
for EachNode(n, DW_LineFileNode, file_list.first) { for EachNode(n, DW_LineFileNode, file_list.first) {
DW_LineFile *dst = &file_table.v[file_table.count++]; 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->dir_idx = n->file.dir_idx;
dst->modify_time = n->file.modify_time; dst->time_stamp = n->file.time_stamp;
dst->file_size = n->file.file_size; dst->size = n->file.size;
} }
} }
// DWARF5 // DWARF5
@@ -2379,11 +2379,11 @@ dw_read_line_vm_header(Arena *arena,
cursor += form_size; cursor += form_size;
switch (lnct) { switch (lnct) {
case DW_LNCT_Path: { file->file_name = 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_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_TimeStamp: { file->time_stamp = dw_interp_const_u64(form); } break;
case DW_LNCT_Size: { file->file_size = dw_interp_const_u64(form); } break; case DW_LNCT_Size: { file->size = dw_interp_const_u64(form); } break;
case DW_LNCT_MD5: { file->md5_digest = dw_interp_const_u128(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; case DW_LNCT_LLVM_Source: { file->source = dw_interp_string(input, format, cu_str_offsets, form); } break;
default: { default: {
Assert(!"unexpected LNTC encoding"); Assert(!"unexpected LNTC encoding");
@@ -2565,7 +2565,9 @@ dw_line_vm_step(DW_LineVM *vm)
} break; } break;
case DW_StdOpcode_FixedAdvancePc: { 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.address += vm->operands[0].u64;
vm->state.op_index = 0; vm->state.op_index = 0;
} break; } break;
@@ -2590,7 +2592,7 @@ dw_line_vm_step(DW_LineVM *vm)
vm->cursor += vm->ext_length; vm->cursor += vm->ext_length;
U64 ext_cursor = 0; 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) { switch (vm->ext_opcode) {
case DW_ExtOpcode_EndSequence: { case DW_ExtOpcode_EndSequence: {
@@ -2600,26 +2602,26 @@ dw_line_vm_step(DW_LineVM *vm)
} break; } break;
case DW_ExtOpcode_SetAddress: { 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.address = vm->operands[0].u64;
vm->state.op_index = 0; vm->state.op_index = 0;
} break; } break;
case DW_ExtOpcode_DefineFile: { 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_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), vm->cursor, exit); // dir index 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), vm->cursor, exit); // modify time 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), vm->cursor, exit); // file size TryRead(str8_deserial_read_uleb128(ext_data, ext_cursor, &vm->operands[3].u64), ext_cursor, exit); // file size
if (vm->ext_file_ht == 0) { if (vm->ext_file_ht == 0) {
vm->ext_file_ht = hash_table_init(vm->arena, 512); vm->ext_file_ht = hash_table_init(vm->arena, 512);
} }
DW_LineFile *file = push_array(vm->arena, DW_LineFile, 1); DW_LineFile *file = push_array(vm->arena, DW_LineFile, 1);
file->file_name = vm->operands[0].string; file->path = vm->operands[0].string;
file->dir_idx = vm->operands[1].u64; file->dir_idx = vm->operands[1].u64;
file->modify_time = vm->operands[2].u64; file->time_stamp = vm->operands[2].u64;
file->file_size = vm->operands[3].u64; file->size = vm->operands[3].u64;
if (hash_table_search_u64_raw(vm->ext_file_ht, vm->state.file_index) == 0) { 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); 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; } break;
case DW_ExtOpcode_SetDiscriminator: { 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; vm->state.discriminator = vm->operands[0].u64;
} break; } break;
@@ -2676,12 +2678,12 @@ dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file)
// find directory and file name associated with the file index // find directory and file name associated with the file index
String8 dir = dir_table.v[file->dir_idx]; String8 dir = dir_table.v[file->dir_idx];
String8 file_name = file->file_name; String8 path = file->path;
// infer path style if directory is empty use file name // infer path style if directory is empty use file name
PathStyle style = path_style_from_str8(dir); PathStyle style = path_style_from_str8(dir);
if (style == PathStyle_Null || style == PathStyle_Relative) { 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}; 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); str8_list_concat_in_place(&path_list, &dir_list);
// push file name // 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 // resolve dots in the path
str8_path_list_resolve_dots_in_place(&path_list, style); str8_path_list_resolve_dots_in_place(&path_list, style);
} }
// join path // 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); scratch_end(scratch);
return path; return result;
} }
internal DW_PubStringsTable internal DW_PubStringsTable
+4 -4
View File
@@ -173,11 +173,11 @@ typedef struct DW_TagTree
typedef struct DW_LineFile typedef struct DW_LineFile
{ {
String8 file_name; String8 path;
U64 dir_idx; U64 dir_idx;
U64 modify_time; U64 time_stamp;
U64 file_size; U64 size;
U128 md5_digest; U128 md5;
String8 source; String8 source;
} DW_LineFile; } DW_LineFile;
+64 -25
View File
@@ -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.line_range = 14;
writer->line.opcode_base = DW_StdOpcode_Count; writer->line.opcode_base = DW_StdOpcode_Count;
writer->line.ln = 1; writer->line.ln = 1;
Assert(writer->line.line_base < writer->line.line_range);
for EachElement(i, writer->sections) { for EachElement(i, writer->sections) {
str8_serial_begin(arena, &writer->sections[i].srl); 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: { case DW_Form_String: {
str8_serial_push_cstr(arena, srl, form.reader.string); str8_serial_push_cstr(arena, srl, form.reader.string);
} break; } 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: { case DW_Form_Flag: {
str8_serial_push_u8(arena, srl, form.reader.flag); str8_serial_push_u8(arena, srl, form.reader.flag);
} break; } break;
@@ -537,7 +542,9 @@ dw_data_from_line_insts(Arena *arena, U8 address_size, DW_LineInstList insts)
} break; } break;
case DW_StdOpcode_SetPrologueEnd: {} break; case DW_StdOpcode_SetPrologueEnd: {} break;
case DW_StdOpcode_SetEpilogueBegin: {} 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: { case DW_StdOpcode_ExtendedOpcode: {
// get ext size // get ext size
U64 ext_size = 0; U64 ext_size = 0;
@@ -562,7 +569,7 @@ dw_data_from_line_insts(Arena *arena, U8 address_size, DW_LineInstList insts)
switch (inst->ext) { switch (inst->ext) {
case DW_ExtOpcode_EndSequence: {} break; case DW_ExtOpcode_EndSequence: {} break;
case DW_ExtOpcode_SetAddress: { 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; } break;
case DW_ExtOpcode_DefineFile: { case DW_ExtOpcode_DefineFile: {
NotImplemented; 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)); 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); Assert(addr <= max_S64);
S64 addr_delta = (S64)addr - (S64)writer->line.addr; S64 addr_delta = (S64)addr - (S64)writer->line.addr;
S64 ln_delta = (S64)ln - (S64)writer->line.ln; 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) && S64 max_ln_delta = writer->line.line_range + writer->line.line_base;
writer->line.line_base <= ln_delta && 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;
addr_delta < max_U8 - writer->line.opcode_base) { if ((ln_delta != 0 || addr_delta != 0) &&
U8 opcode = (ln_delta - writer->line.line_base) + (writer->line.line_range * addr_delta) + writer->line.opcode_base; 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 }); dw_line_inst_list_push(writer->arena, &writer->line.line_insts, (DW_LineInst){ .opcode = opcode });
} else { } else {
if (addr_delta != 0) { dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_pc(addr_delta)); } 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 (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)); } if (addr_delta != 0 || ln_delta != 0 || col_delta != 0) {
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_copy());
} }
}
// update registers
writer->line.file = file; writer->line.file = file;
writer->line.ln = ln; writer->line.ln = ln;
writer->line.col = col; 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)); 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 internal void
dw_writer_line_set_prologue_end(DW_Writer *writer) dw_writer_line_set_prologue_end(DW_Writer *writer)
{ {
@@ -642,7 +671,6 @@ dw_writer_new_file(DW_Writer *writer, String8 path)
{ {
DW_WriterFile *file = push_array(writer->arena, DW_WriterFile, 1); DW_WriterFile *file = push_array(writer->arena, DW_WriterFile, 1);
file->path = path; file->path = path;
file->file_idx = writer->line.file_count;
SLLQueuePush(writer->line.first_file, writer->line.last_file, file); SLLQueuePush(writer->line.first_file, writer->line.last_file, file);
writer->line.file_count += 1; writer->line.file_count += 1;
@@ -936,7 +964,7 @@ dw_writer_emit(DW_Writer *writer)
// line // line
{ {
// push line table terminator // 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 // find comp dir in the compile unit tag
String8 comp_dir = {0}; String8 comp_dir = {0};
@@ -945,7 +973,7 @@ dw_writer_emit(DW_Writer *writer)
for EachNode(attrib, DW_WriterAttrib, writer->root->first_attrib) { for EachNode(attrib, DW_WriterAttrib, writer->root->first_attrib) {
if (attrib->kind == DW_AttribKind_CompDir) { if (attrib->kind == DW_AttribKind_CompDir) {
AssertAlways(attrib->form.writer.kind == DW_WriterFormKind_String); 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) { } else if (attrib->kind == DW_AttribKind_Name) {
AssertAlways(attrib->form.writer.kind == DW_WriterFormKind_String); AssertAlways(attrib->form.writer.kind == DW_WriterFormKind_String);
comp_name = attrib->form.writer.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_LNCT_Path);
dw_serial_push_uleb128(writer->arena, srl, DW_Form_String); dw_serial_push_uleb128(writer->arena, srl, DW_Form_String);
// dedup directories // dedup directories
String8List dirs = {0}; String8List dirs = {0};
HashTable *dir_ht = hash_table_init(scratch.arena, writer->line.file_count + 1); HashTable *dir_ht = hash_table_init(scratch.arena, writer->line.file_count + 1);
// first entry must be compile unit directory // first entry must be compile unit directory
hash_table_push_string_u64(scratch.arena, dir_ht, comp_dir, dir_ht->count); hash_table_push_string_u64(scratch.arena, dir_ht, comp_dir, dir_ht->count);
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); str8_list_push(scratch.arena, &dirs, comp_dir);
}
for EachNode(file, DW_WriterFile, writer->line.first_file) { for EachNode(file, DW_WriterFile, writer->line.first_file) {
String8 path = str8_chop_last_slash(file->path); 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)) { 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; file->dir_idx = hash_table_push_string_u64(scratch.arena, dir_ht, path, dir_ht->count)->v.value_u64;
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); 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 // (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 // (16) directories
for (U64 i = 0; i < dir_ht->count; i += 1) { for EachNode(dir_n, String8Node, dirs.first) {
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_n->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 } });
} }
scratch_end(scratch); scratch_end(scratch);
@@ -1016,7 +1051,7 @@ dw_writer_emit(DW_Writer *writer)
for EachNode(file, DW_WriterFile, writer->line.first_file) { 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->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->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 ( ! 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; } if (file->source.size != 0) { *(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_LLVM_Source) = DW_Form_String; }
} }
@@ -1057,11 +1092,15 @@ dw_writer_emit(DW_Writer *writer)
} }
} }
} }
U64 file_idx = 0;
for EachNode(file, DW_WriterFile, writer->line.first_file) { 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_udata = { .reader = { .kind = DW_Form_UData } };
static DW_WriterXForm null_form_string = { .reader = { .kind = DW_Form_String } }; static DW_WriterXForm null_form_string = { .reader = { .kind = DW_Form_String } };
static DW_WriterXForm null_form_block = { .reader = { .kind = DW_Form_Block } }; static DW_WriterXForm null_form_block = { .reader = { .kind = DW_Form_Block } };
// @file_idx
file->file_idx = file_idx++;
// path // path
Assert(*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_Path) == DW_Form_String); 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); String8 file_name = str8_skip_last_slash(file->path);
@@ -1095,8 +1134,8 @@ dw_writer_emit(DW_Writer *writer)
// MD5 // MD5
if (*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_MD5) == DW_Form_Block) { if (*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_MD5) == DW_Form_Block) {
if (file->md5.size) { if ( ! u128_match(file->md5, u128_zero())) {
DW_WriterXForm md5_form = { .reader = { .kind = DW_Form_Block, .block = file->md5 } }; 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); dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, md5_form);
} else { } else {
dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, null_form_block); 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 // (11) opcode_base
str8_serial_push_struct(writer->arena, srl, &writer->line.opcode_base); str8_serial_push_struct(writer->arena, srl, &writer->line.opcode_base);
// (12) standard_opcode_lengths // (12) standard_opcode_lengths
U8 *std_op_lens = push_array(writer->arena, U8, DW_StdOpcode_Count - 1); U8 *std_op_lens = push_array(writer->arena, U8, writer->line.opcode_base - 1);
for (U64 i = 1; i < DW_StdOpcode_Count; i += 1) { std_op_lens[i-1] = dw_length_from_std_opcode(i); } 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, DW_StdOpcode_Count - 1)); str8_serial_push_string(writer->arena, srl, str8(std_op_lens, writer->line.opcode_base - 1));
// directory table // directory table
str8_list_concat_in_place(srl, &dir_table_srl); str8_list_concat_in_place(srl, &dir_table_srl);
// file table // file table
+3 -1
View File
@@ -135,7 +135,7 @@ typedef struct DW_WriterFile
String8 path; String8 path;
U64 time_stamp; U64 time_stamp;
U64 size; U64 size;
String8 md5; U128 md5;
String8 source; String8 source;
// computed during line table emit step // computed during line table emit step
U64 file_idx; U64 file_idx;
@@ -308,6 +308,8 @@ internal DW_LineInstNode * dw_line_inst_list_push (Arena *arena, DW_LineInst
internal void dw_writer_line_emit (DW_Writer *writer, DW_WriterFile *file, U64 ln, U64 col, U64 addr); 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_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_set_prologue_end (DW_Writer *writer);
internal void dw_writer_line_epilogue_begin (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 void dw_writer_line_set_isa (DW_Writer *writer, U64 isa);
+10 -10
View File
@@ -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]; 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); int cmp = str8_compar(dir_path_a, dir_path_b, 0);
if (cmp == 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; return cmp;
} }
@@ -2587,9 +2587,9 @@ d2r_hash_line_file(String8 dir_path, DW_LineFile *file)
XXH3_state_t hasher = {0}; XXH3_state_t hasher = {0};
XXH3_64bits_reset(&hasher); XXH3_64bits_reset(&hasher);
XXH3_64bits_update(&hasher, dir_path.str, dir_path.size); 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->path.str, file->path.size);
XXH3_64bits_update(&hasher, &file->modify_time, sizeof(file->modify_time)); XXH3_64bits_update(&hasher, &file->time_stamp, sizeof(file->time_stamp));
XXH3_64bits_update(&hasher, &file->md5_digest, sizeof(file->md5_digest)); XXH3_64bits_update(&hasher, &file->md5, sizeof(file->md5));
XXH64_hash_t hash = XXH3_64bits_digest(&hasher); XXH64_hash_t hash = XXH3_64bits_digest(&hasher);
return hash; return hash;
} }
@@ -2841,18 +2841,18 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
{ {
String8List path_list = {0}; 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 = 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); path = str8_path_list_join_by_style(arena, &path_list, path_style);
} }
// fill out source file // fill out source file
dst->path = path; 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_kind = RDI_ChecksumKind_MD5;
dst->checksum = str8_copy(arena, str8_struct(&src->md5_digest)); dst->checksum = str8_copy(arena, str8_struct(&src->md5));
} else if (src->modify_time != 0) { } else if (src->time_stamp != 0) {
dst->checksum_kind = RDI_ChecksumKind_Timestamp; 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; 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 >= D2R_LineBufferMax || line_buffer->file_index != vm->state.file_index))
&& line_buffer_size > 0) { && line_buffer_size > 0) {
// lookup source file // 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); 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); 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; RDIM_SrcFile *src_file = lookup->src_file;
+416 -76
View File
@@ -34,7 +34,7 @@ t_dw_test_sleb128(U64 v, U64 expected_length)
String8 e = dw_write_sleb128(scratch.arena, v0); String8 e = dw_write_sleb128(scratch.arena, v0);
if (!(expected_length == e.size)) { goto exit; } if (!(expected_length == e.size)) { goto exit; }
U64 v1; S64 v1;
U64 bytes_read = str8_deserial_read_sleb128(e, 0, &v1); U64 bytes_read = str8_deserial_read_sleb128(e, 0, &v1);
if (!(bytes_read == e.size)) { goto exit; } if (!(bytes_read == e.size)) { goto exit; }
if (!(v0 == v1)) { 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(min_S64, 10));
T_Ok(t_dw_test_sleb128(max_S64, 10)); T_Ok(t_dw_test_sleb128(max_S64, 10));
T_Ok(t_dw_test_uleb128(0xDEADBEEFCAFEBABE, 10));
for EachIndex(i, 64) { for EachIndex(i, 64) {
T_Ok(t_dw_test_uleb128((1ull << i), 1 + (i / 7))); T_Ok(t_dw_test_uleb128((1ull << i), 1 + (i / 7)));
} }
@@ -102,45 +104,419 @@ exit:;
return is_match; return is_match;
} }
internal DW_Writer * internal DW_Input
dwt_make_writer(void) 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("")); OBJ *obj = obj_alloc(0, Arch_x64);
String8 comp_name = str8_lit("test_code.txt"); OBJ_Section *text_section = obj_push_section(obj, str8_lit(".text"), OBJ_SectionFlag_Read|OBJ_SectionFlag_Exec|OBJ_SectionFlag_Load);
String8 test_text = str8_lit("nop\nnop\nret\n"); str8_serial_push_u8(obj->arena, &text_section->data, 0x90);
String8 test_path = t_make_file_path(scratch.arena, comp_name); str8_serial_push_u8(obj->arena, &text_section->data, 0x90);
t_write_file(comp_name, test_text); 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 *writer = dw_writer_begin(DW_Format_32Bit, DW_Version_Last, DW_CompUnitKind_Compile, Arch_x64); dw_writer_emit_to_obj(writer, obj);
// line String8 raw_coff = coff_from_obj(scratch.arena, obj);
{
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")); t_write_file(str8_lit("dwarf.obj"), raw_coff);
//DW_WriterFile *a_file = dw_writer_new_file(writer, str8_lit("~/devel/projects/a.c")); t_invoke(str8_lit("radlink"), str8_lit("/subsystem:console /entry:entry /out:a.exe /debug:full dwarf.obj"), max_U64);
//dw_writer_line_set_prologue_end(writer); os_delete_file_at_path(t_make_file_path(scratch.arena, str8_lit("a.pdb")));
//dw_writer_line_emit(writer, b_file, 10, 0, 0x140001000);
//dw_writer_line_emit(writer, b_file, 11, 0, 0x140001010); String8 exe = t_read_file(arena, str8_lit("a.exe"));
//dw_writer_line_emit(writer, a_file, 1, 0, 0x140001016); PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, exe);
//dw_writer_line_emit(writer, a_file, 2, 0, 0x140001020); 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;
} }
// info
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_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_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_CompDir, comp_dir);
dw_writer_push_attrib_string(writer, DW_AttribKind_Name, comp_name); 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);
{
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_enum(writer, DW_AttribKind_Language, DW_Language_C99); 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_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_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_WriterTag *char_type = dw_writer_tag_begin(writer, DW_TagKind_BaseType);
dw_writer_push_attrib_sint(writer, DW_AttribKind_ByteSize, 1); 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_External, 1);
dw_writer_push_attrib_flag(writer, DW_AttribKind_Prototyped, 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_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_string(writer, DW_AttribKind_Name, str8_lit("main"));
dw_writer_push_attrib_ref(writer, DW_AttribKind_Type, simple_struct_tag); 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); 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_writer_tag_end(writer);
} }
{ DW_Input input = dw_input_from_writer(scratch.arena, 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_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_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_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); DW_TagTree tag_tree = dw_tag_tree_from_cu(scratch.arena, &input, &cu);
AssertAlways(dwt_tags_must_match(writer->root, tag_tree.root)); 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 // 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->kind == DW_TagKind_CompileUnit);
T_Ok(comp_unit_tag->next == 0); T_Ok(comp_unit_tag->next == 0);
T_Ok(comp_unit_tag->parent == 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->abbrev_id == 1);
T_Ok(comp_unit_tag->info_off == 0xc); 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->parent == comp_unit_tag);
T_Ok(char_type_tag->attrib_count == 3); T_Ok(char_type_tag->attrib_count == 3);
T_Ok(char_type_tag->abbrev_id == 2); 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); T_Ok(char_type_tag->first_attrib != char_type_tag->last_attrib);
DW_WriterAttrib *byte_size_attrib = char_type_tag->first_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->parent == comp_unit_tag);
T_Ok(const_type_tag->attrib_count == 1); T_Ok(const_type_tag->attrib_count == 1);
T_Ok(const_type_tag->abbrev_id == 3); 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); 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; 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->parent == comp_unit_tag);
T_Ok(dup_char_type_tag->attrib_count == 3); T_Ok(dup_char_type_tag->attrib_count == 3);
T_Ok(dup_char_type_tag->abbrev_id == 2); 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); 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; 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->parent == comp_unit_tag);
T_Ok(simple_struct_tag->attrib_count == 2); T_Ok(simple_struct_tag->attrib_count == 2);
T_Ok(simple_struct_tag->abbrev_id == 4); 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; DW_WriterAttrib *simple_struct_name = simple_struct_tag->first_attrib;
T_Ok(simple_struct_name->kind == DW_AttribKind_Name); 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->kind == DW_TagKind_Member);
T_Ok(m0_tag->parent == simple_struct_tag); T_Ok(m0_tag->parent == simple_struct_tag);
T_Ok(m0_tag->attrib_count == 3); 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); T_Ok(m0_tag->abbrev_id == 5);
DW_WriterAttrib *name = m0_tag->first_attrib; DW_WriterAttrib *name = m0_tag->first_attrib;
@@ -373,7 +714,7 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *type = name->next; DW_WriterAttrib *type = name->next;
T_Ok(type->kind == DW_AttribKind_Type); T_Ok(type->kind == DW_AttribKind_Type);
T_Ok(type->form.reader.kind == DW_Form_Ref1); 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; DW_WriterAttrib *data_loc = type->next;
T_Ok(data_loc->kind == DW_AttribKind_DataMemberLocation); 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->kind == DW_TagKind_Member);
T_Ok(m1_tag->parent == simple_struct_tag); T_Ok(m1_tag->parent == simple_struct_tag);
T_Ok(m1_tag->attrib_count == 4); 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); T_Ok(m1_tag->abbrev_id == 6);
DW_WriterAttrib *name = m1_tag->first_attrib; DW_WriterAttrib *name = m1_tag->first_attrib;
@@ -398,7 +739,7 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *type = name->next; DW_WriterAttrib *type = name->next;
T_Ok(type->kind == DW_AttribKind_Type); T_Ok(type->kind == DW_AttribKind_Type);
T_Ok(type->form.reader.kind == DW_Form_Ref1); 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; DW_WriterAttrib *data_loc = type->next;
T_Ok(data_loc->kind == DW_AttribKind_DataMemberLocation); 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->kind == DW_AttribKind_LowPc);
T_Ok(low_pc->form.reader.kind == DW_Form_Addr); T_Ok(low_pc->form.reader.kind == DW_Form_Addr);
T_Ok(low_pc->form.reader.addr.size == sizeof(U64)); 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; DW_WriterAttrib *high_pc = low_pc->next;
T_Ok(high_pc->kind == DW_AttribKind_HighPc); T_Ok(high_pc->kind == DW_AttribKind_HighPc);
T_Ok(high_pc->form.reader.kind == DW_Form_Addr); T_Ok(high_pc->form.reader.kind == DW_Form_Addr);
T_Ok(high_pc->form.reader.addr.size == sizeof(U64)); 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; DW_WriterAttrib *name = high_pc->next;
T_Ok(name->kind == DW_AttribKind_Name); T_Ok(name->kind == DW_AttribKind_Name);
@@ -651,4 +992,3 @@ T_EndTest;
#endif #endif
#undef T_Group #undef T_Group