diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h
index 960202a3..5de439be 100644
--- a/src/dwarf/dwarf.h
+++ b/src/dwarf/dwarf.h
@@ -166,6 +166,7 @@ typedef enum DW_StdOpcodeEnum
#define X(_N,_ID) DW_StdOpcode_##_N = _ID,
DW_StdOpcode_XList
#undef X
+ DW_StdOpcode_Count,
} DW_StdOpcodeEnum;
#define DW_ExtOpcode_XList \
diff --git a/src/dwarf/dwarf_writer.c b/src/dwarf/dwarf_writer.c
index 420704f5..c76d0c2e 100644
--- a/src/dwarf/dwarf_writer.c
+++ b/src/dwarf/dwarf_writer.c
@@ -49,14 +49,6 @@ dw_size_from_uint(U64 v)
return 0;
}
-internal void
-dw_lower_form(DW_WriterFormKind form_kind,
- DW_WriterForm form,
- DW_FormKind *form_kind_out,
- DW_Form *form_out)
-{
-}
-
internal DW_WriterFixupNode *
dw_writer_fixup_list_push(Arena *arena, DW_WriterFixupList *list, DW_WriterFixup v)
{
@@ -110,19 +102,22 @@ dw_writer_begin(DW_Format format, DW_Version version, DW_CompUnitKind cu_kind, A
{
Arena *arena = arena_alloc();
DW_Writer *writer = push_array(arena, DW_Writer, 1);
- writer->arena = arena;
- writer->arch = arch;
- writer->format = format;
- writer->version = version;
- writer->cu_kind = cu_kind;
- writer->address_size = byte_size_from_arch(arch);
- writer->current = 0;
- writer->abbrev_id_map = hash_table_init(arena, 0x2000);
+ writer->arena = arena;
+ writer->arch = arch;
+ writer->format = format;
+ writer->version = version;
+ writer->cu_kind = cu_kind;
+ writer->address_size = byte_size_from_arch(arch);
+ writer->current = 0;
+ writer->abbrev_id_map = hash_table_init(arena, 0x2000);
+ writer->line.opcode_base = DW_StdOpcode_Count;
+ writer->line.line_base = -5;
+ writer->line.line_range = 14;
for EachElement(i, writer->sections) {
str8_serial_begin(arena, &writer->sections[i].srl);
}
- // write .debug_info header
+ // write info header
{
String8List *srl = &writer->sections[DW_Section_Info].srl;
@@ -158,6 +153,137 @@ dw_writer_end(DW_Writer **writer_ptr)
*writer_ptr = 0;
}
+internal U64
+dw_serial_push_form(Arena *arena, String8List *srl, DW_Version version, DW_Format format, U8 address_size, DW_WriterFixupList *fixups, DW_WriterXForm form)
+{
+ U64 start_off = srl->total_size;
+ switch (form.reader.kind) {
+ case DW_Form_Addr: {
+ str8_serial_push_string(arena, srl, form.reader.addr);
+ } break;
+ case DW_Form_Block1:
+ case DW_Form_Block2:
+ case DW_Form_Block4: {
+ str8_serial_push_string(arena, srl, form.reader.block);
+ } break;
+ case DW_Form_Data1:
+ case DW_Form_Data2:
+ case DW_Form_Data4:
+ case DW_Form_Data8: {
+ str8_serial_push_string(arena, srl, form.reader.data);
+ } break;
+ case DW_Form_String: {
+ str8_serial_push_cstr(arena, srl, form.reader.string);
+ } break;
+ case DW_Form_Flag: {
+ str8_serial_push_u8(arena, srl, form.reader.flag);
+ } break;
+ case DW_Form_SData: {
+ dw_serial_push_sleb128(arena, srl, form.reader.sdata);
+ } break;
+ case DW_Form_Strp: {
+ dw_serial_push_uint(arena, srl, format, form.reader.sec_offset);
+ } break;
+ case DW_Form_UData: {
+ dw_serial_push_uleb128(arena, srl, form.reader.udata);
+ } break;
+ case DW_Form_RefAddr: {
+ if (version < DW_Version_3) {
+ Assert(address_size <= sizeof(form.reader.ref));
+ str8_serial_push_string(arena, srl, str8((U8 *)&form.reader.ref, address_size));
+ } else {
+ dw_serial_push_uint(arena, srl, format, form.reader.ref);
+ }
+ } break;
+ case DW_Form_Ref1: {
+ str8_serial_push_u8(arena, srl, (U8)form.reader.ref);
+ } break;
+ case DW_Form_Ref2: {
+ str8_serial_push_u16(arena, srl, (U16)form.reader.ref);
+ } break;
+ case DW_Form_Ref4: {
+ str8_serial_push_u32(arena, srl, (U32)form.reader.ref);
+ } break;
+ case DW_Form_Ref8: {
+ if (form.writer.ref->info_off == 0) {
+ // reserve 8 bytes
+ void *value = str8_serial_push_u64(arena, srl, 0);
+
+ // push fixup
+ dw_writer_fixup_list_push(arena, fixups, (DW_WriterFixup){ .ptr = value, .tag = form.writer.ref });
+ }
+ } break;
+ case DW_Form_RefUData: {
+ dw_serial_push_uleb128(arena, srl, form.reader.ref);
+ } break;
+ case DW_Form_Indirect: {
+ NotImplemented;
+ } break;
+ case DW_Form_SecOffset: {
+ dw_serial_push_uint(arena, srl, format, form.reader.sec_offset);
+ } break;
+ case DW_Form_ExprLoc: {
+ dw_serial_push_uleb128(arena, srl, form.reader.exprloc.size);
+ str8_serial_push_string(arena, srl, form.reader.exprloc);
+ } break;
+ case DW_Form_FlagPresent: {
+ } break;
+ case DW_Form_RefSig8: {
+ NotImplemented;
+ } break;
+ case DW_Form_Strx:
+ case DW_Form_Addrx:
+ case DW_Form_RngListx:
+ case DW_Form_LocListx: {
+ dw_serial_push_uleb128(arena, srl, form.reader.xval);
+ } break;
+ case DW_Form_RefSup4: {
+ NotImplemented;
+ } break;
+ case DW_Form_StrpSup: {
+ dw_serial_push_uint(arena, srl, format, form.reader.strp_sup);
+ } break;
+ case DW_Form_Data16: {
+ str8_serial_push_string(arena, srl, form.reader.data);
+ } break;
+ case DW_Form_LineStrp: {
+ dw_serial_push_uint(arena, srl, format, form.reader.sec_offset);
+ } break;
+ case DW_Form_ImplicitConst: {
+ // value is stored in the abbrev entry
+ } break;
+ case DW_Form_RefSup8: {
+ NotImplemented;
+ } break;
+ case DW_Form_Strx1:
+ case DW_Form_Addrx1: {
+ str8_serial_push_u8(arena, srl, (U8)form.reader.xval);
+ } break;
+ case DW_Form_Strx2:
+ case DW_Form_Addrx2: {
+ str8_serial_push_u16(arena, srl, (U16)form.reader.xval);
+ } break;
+ case DW_Form_Strx3:
+ case DW_Form_Addrx3: {
+ str8_serial_push_string(arena, srl, str8((U8 *)&form.reader.xval, 3));
+ } break;
+ case DW_Form_Strx4:
+ case DW_Form_Addrx4: {
+ str8_serial_push_u32(arena, srl, (U32)form.reader.xval);
+ } break;
+
+ case DW_Form_GNU_StrpAlt: {
+ dw_serial_push_uint(arena, srl, format, form.reader.sec_offset);
+ } break;
+ case DW_Form_GNU_RefAlt: {
+ dw_serial_push_uint(arena, srl, format, form.reader.ref);
+ } break;
+
+ default: InvalidPath; break;
+ }
+ return srl->total_size - start_off;
+}
+
internal String8
dw_make_abbrev_entry(Arena *arena, DW_WriterTag *tag)
{
@@ -174,9 +300,9 @@ dw_make_abbrev_entry(Arena *arena, DW_WriterTag *tag)
// attrib abbrev
for EachNode(attrib, DW_WriterAttrib, tag->first_attrib) {
dw_serial_push_uleb128(scratch.arena, &srl, attrib->kind);
- dw_serial_push_uleb128(scratch.arena, &srl, attrib->reader.form.kind);
- if (attrib->reader.form.kind == DW_Form_ImplicitConst) {
- dw_serial_push_sleb128(scratch.arena, &srl, attrib->reader.form.implicit_const);
+ dw_serial_push_uleb128(scratch.arena, &srl, attrib->form.reader.kind);
+ if (attrib->form.reader.kind == DW_Form_ImplicitConst) {
+ dw_serial_push_sleb128(scratch.arena, &srl, attrib->form.reader.implicit_const);
}
}
@@ -251,7 +377,7 @@ dw_writer_push_attrib(DW_Writer *writer, DW_AttribKind kind, DW_WriterForm form)
DW_WriterAttrib *attrib = dw_writer_attrib_chunk_list_push(writer->arena, &writer->attrib_chunk_list, 512);
attrib->kind = kind;
- attrib->writer.form = form;
+ attrib->form.writer = form;
SLLQueuePush(writer->current->first_attrib, writer->current->last_attrib, attrib);
writer->current->attrib_count += 1;
return attrib;
@@ -358,68 +484,230 @@ dw_writer_push_attrib_implicit(DW_Writer *writer, DW_AttribKind kind, S64 implic
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_Implicit, .implicit = implicit });
}
+internal void
+dw_line_inst_list_push_node(DW_LineInstList *list, DW_LineInstNode *node)
+{
+ SLLQueuePush(list->first, list->last, node);
+ list->count += 1;
+}
+
+internal DW_LineInstNode *
+dw_line_inst_list_push(Arena *arena, DW_LineInstList *list, DW_LineInst v)
+{
+ DW_LineInstNode *node = push_array(arena, DW_LineInstNode, 1);
+ node->v = v;
+ dw_line_inst_list_push_node(list, node);
+ return node;
+}
+
+internal String8
+dw_data_from_line_insts(Arena *arena, U8 address_size, DW_LineInstList insts)
+{
+ Temp scratch = scratch_begin(&arena, 1);
+ String8List srl = {0};
+ str8_serial_begin(scratch.arena, &srl);
+
+ for EachNode(inst_n, DW_LineInstNode, insts.first) {
+ DW_LineInst *inst = &inst_n->v;
+
+ str8_serial_push_struct(scratch.arena, &srl, &inst->opcode);
+ switch (inst->opcode) {
+ case DW_StdOpcode_Copy: {} break;
+ case DW_StdOpcode_AdvancePc: {
+ dw_serial_push_uleb128(arena, &srl, inst->advance_pc);
+ } break;
+ case DW_StdOpcode_AdvanceLine: {
+ dw_serial_push_sleb128(arena, &srl, inst->advance_line);
+ } break;
+ case DW_StdOpcode_SetFile: {
+ dw_serial_push_uleb128(arena, &srl, inst->set_file->file_idx);
+ } break;
+ case DW_StdOpcode_SetColumn: {
+ dw_serial_push_uleb128(arena, &srl, inst->set_column);
+ } break;
+ case DW_StdOpcode_NegateStmt: {} break;
+ case DW_StdOpcode_SetBasicBlock: {} break;
+ case DW_StdOpcode_ConstAddPc: {} break;
+ case DW_StdOpcode_FixedAdvancePc: {
+ str8_serial_push_u16(arena, &srl, inst->fixed_advance_pc);
+ } break;
+ case DW_StdOpcode_SetPrologueEnd: {} break;
+ case DW_StdOpcode_SetEpilogueBegin: {} break;
+ case DW_StdOpcode_SetIsa: {} break;
+ case DW_StdOpcode_ExtendedOpcode: {
+ // get ext size
+ U64 ext_size = 0;
+ switch (inst->ext) {
+ case DW_ExtOpcode_EndSequence: { ext_size = 0; } break;
+ case DW_ExtOpcode_SetAddress: { ext_size = address_size; } break;
+ case DW_ExtOpcode_DefineFile: {
+ NotImplemented;
+ } break;
+ case DW_ExtOpcode_SetDiscriminator: {
+ ext_size = dw_size_from_uleb128(inst->set_discriminator);
+ } break;
+ default: { InvalidPath; } break;
+ }
+
+ // write ext header
+ dw_serial_push_uleb128(arena, &srl, ext_size);
+ str8_serial_push_struct(arena, &srl, &inst->ext);
+
+ // write ext operands
+ switch (inst->ext) {
+ case DW_ExtOpcode_EndSequence: {} break;
+ case DW_ExtOpcode_SetAddress: {
+ dw_serial_push_uleb128(arena, &srl, inst->set_address);
+ } break;
+ case DW_ExtOpcode_DefineFile: {
+ NotImplemented;
+ } break;
+ case DW_ExtOpcode_SetDiscriminator: {
+ dw_serial_push_uleb128(arena, &srl, inst->set_discriminator);
+ } break;
+ default: { InvalidPath; } break;
+ }
+ } break;
+ // special opcode
+ default: {} break;
+ }
+ }
+
+ String8 data = str8_serial_end(arena, &srl);
+ scratch_end(scratch);
+ return data;
+}
+
+internal void
+dw_writer_line_emit(DW_Writer *writer, DW_WriterFile *file, U64 ln, U64 col, U64 addr)
+{
+ if (writer->line.last_file != file) {
+ dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_file(file));
+ }
+
+ Assert(addr <= max_S64);
+ S64 addr_delta = (S64)addr - (S64)writer->line.addr;
+ if (addr_delta != 0) {
+ dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_pc(addr_delta));
+ }
+
+ S64 ln_delta = (S64)ln - (S64)writer->line.ln;
+ if (ln_delta != 0) {
+ dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_advance_line(ln_delta));
+ }
+
+ 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));
+ }
+
+ // append row
+ dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_copy());
+
+ writer->line.file = file;
+ writer->line.ln = ln;
+ writer->line.col = col;
+ writer->line.addr = addr;
+}
+
+internal void
+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_prologue_end(DW_Writer *writer)
+{
+ dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_prologue_end());
+}
+
+internal void
+dw_writer_line_epilogue_begin(DW_Writer *writer)
+{
+ dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_epilogue_begin());
+}
+
+internal void
+dw_writer_line_set_isa(DW_Writer *writer, U64 isa)
+{
+ dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNS_set_isa(isa));
+}
+
+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;
+
+ SLLQueuePush(writer->line.first_file, writer->line.last_file, file);
+ writer->line.file_count += 1;
+ return file;
+}
+
internal void
dw_lower_attrib_forms(DW_Writer *writer, DW_WriterTag *tag)
{
for EachNode(attrib, DW_WriterAttrib, tag->first_attrib) {
- switch (attrib->writer.form.kind) {
+ switch (attrib->form.writer.kind) {
case DW_WriterFormKind_Null: {} break;
case DW_WriterFormKind_Flag: {
- attrib->reader.form.kind = DW_Form_Flag;
- attrib->reader.form.flag = attrib->writer.form.flag;
+ attrib->form.reader.kind = DW_Form_Flag;
+ attrib->form.reader.flag = attrib->form.writer.flag;
} break;
case DW_WriterFormKind_SInt: {
- switch (dw_int_enc_from_sint(attrib->writer.form.sint)) {
- case DW_IntEnc_Null: attrib->reader.form.kind = 0; break;
+ switch (dw_int_enc_from_sint(attrib->form.writer.sint)) {
+ case DW_IntEnc_Null: attrib->form.reader.kind = 0; break;
case DW_IntEnc_1Byte: {
- attrib->reader.form.kind = DW_Form_Data1;
- attrib->reader.form.data = str8((U8 *)&attrib->writer.form.sint, sizeof(S8));
+ attrib->form.reader.kind = DW_Form_Data1;
+ attrib->form.reader.data = str8((U8 *)&attrib->form.writer.sint, sizeof(S8));
} break;
case DW_IntEnc_2Byte: {
- attrib->reader.form.kind = DW_Form_Data2;
- attrib->reader.form.data = str8((U8 *)&attrib->writer.form.sint, sizeof(S16));
+ attrib->form.reader.kind = DW_Form_Data2;
+ attrib->form.reader.data = str8((U8 *)&attrib->form.writer.sint, sizeof(S16));
} break;
case DW_IntEnc_4Byte: {
- attrib->reader.form.kind = DW_Form_Data4;
- attrib->reader.form.data = str8((U8 *)&attrib->writer.form.sint, sizeof(U32));
+ attrib->form.reader.kind = DW_Form_Data4;
+ attrib->form.reader.data = str8((U8 *)&attrib->form.writer.sint, sizeof(U32));
} break;
case DW_IntEnc_LEB128: {
- attrib->reader.form.kind = DW_Form_SData;
- attrib->reader.form.sdata = attrib->writer.form.sint;
+ attrib->form.reader.kind = DW_Form_SData;
+ attrib->form.reader.sdata = attrib->form.writer.sint;
} break;
default: InvalidPath; break;
}
} break;
case DW_WriterFormKind_UInt: {
- attrib->reader.form.kind = DW_Form_UData;
- attrib->reader.form.udata = attrib->writer.form.uint;
+ attrib->form.reader.kind = DW_Form_UData;
+ attrib->form.reader.udata = attrib->form.writer.uint;
} break;
case DW_WriterFormKind_Address: {
- Assert(writer->address_size <= sizeof(attrib->writer.form.address));
- attrib->reader.form.kind = DW_Form_Addr;
- attrib->reader.form.addr = push_str8_copy(writer->arena, str8((U8 *)&attrib->writer.form.address, writer->address_size));
+ Assert(writer->address_size <= sizeof(attrib->form.writer.address));
+ attrib->form.reader.kind = DW_Form_Addr;
+ attrib->form.reader.addr = push_str8_copy(writer->arena, str8((U8 *)&attrib->form.writer.address, writer->address_size));
} break;
case DW_WriterFormKind_Ref: {
- if (attrib->writer.form.ref->info_off == 0) {
- attrib->reader.form.kind = DW_Form_Ref8;
+ if (attrib->form.writer.ref->info_off == 0) {
+ attrib->form.reader.kind = DW_Form_Ref8;
} else {
- switch (dw_int_enc_from_uint(attrib->writer.form.ref->info_off)) {
+ switch (dw_int_enc_from_uint(attrib->form.writer.ref->info_off)) {
case DW_IntEnc_Null: break;
case DW_IntEnc_1Byte: {
- attrib->reader.form.kind = DW_Form_Ref1;
- attrib->reader.form.ref = (U8)attrib->writer.form.ref->info_off;
+ attrib->form.reader.kind = DW_Form_Ref1;
+ attrib->form.reader.ref = (U8)attrib->form.writer.ref->info_off;
} break;
case DW_IntEnc_2Byte: {
- attrib->reader.form.kind = DW_Form_Ref2;
- attrib->reader.form.ref = (U16)attrib->writer.form.ref->info_off;
+ attrib->form.reader.kind = DW_Form_Ref2;
+ attrib->form.reader.ref = (U16)attrib->form.writer.ref->info_off;
} break;
case DW_IntEnc_4Byte: {
- attrib->reader.form.kind = DW_Form_Ref4;
- attrib->reader.form.ref = (U32)attrib->writer.form.ref->info_off;
+ attrib->form.reader.kind = DW_Form_Ref4;
+ attrib->form.reader.ref = (U32)attrib->form.writer.ref->info_off;
} break;
case DW_IntEnc_LEB128: {
- attrib->reader.form.kind = DW_Form_RefUData;
- attrib->reader.form.ref = attrib->writer.form.ref->info_off;
+ attrib->form.reader.kind = DW_Form_RefUData;
+ attrib->form.reader.ref = attrib->form.writer.ref->info_off;
} break;
default: InvalidPath; break;
}
@@ -438,26 +726,26 @@ dw_lower_attrib_forms(DW_Writer *writer, DW_WriterTag *tag)
NotImplemented;
} break;
case DW_WriterFormKind_Block: {
- attrib->reader.form.block = attrib->writer.form.block;
- switch (attrib->writer.form.block.size) {
+ attrib->form.reader.block = attrib->form.writer.block;
+ switch (attrib->form.writer.block.size) {
case 0 : break;
- case 1 : attrib->reader.form.kind = DW_Form_Block1; break;
- case 2 : attrib->reader.form.kind = DW_Form_Block2; break;
- case 4 : attrib->reader.form.kind = DW_Form_Block4; break;
- default: attrib->reader.form.kind = DW_Form_Block; break;
+ case 1 : attrib->form.reader.kind = DW_Form_Block1; break;
+ case 2 : attrib->form.reader.kind = DW_Form_Block2; break;
+ case 4 : attrib->form.reader.kind = DW_Form_Block4; break;
+ default: attrib->form.reader.kind = DW_Form_Block; break;
}
} break;
case DW_WriterFormKind_String: {
- attrib->reader.form.kind = DW_Form_String;
- attrib->reader.form.string = attrib->writer.form.string;
+ attrib->form.reader.kind = DW_Form_String;
+ attrib->form.reader.string = attrib->form.writer.string;
} break;
case DW_WriterFormKind_ExprLoc: {
- attrib->reader.form.kind = DW_Form_ExprLoc;
- attrib->reader.form.exprloc = attrib->writer.form.exprloc;
+ attrib->form.reader.kind = DW_Form_ExprLoc;
+ attrib->form.reader.exprloc = attrib->form.writer.exprloc;
} break;
case DW_WriterFormKind_Implicit: {
- attrib->reader.form.kind = DW_Form_ImplicitConst;
- attrib->reader.form.implicit_const = attrib->writer.form.implicit;
+ attrib->form.reader.kind = DW_Form_ImplicitConst;
+ attrib->form.reader.implicit_const = attrib->form.writer.implicit;
} break;
default: { InvalidPath; } break;
}
@@ -500,74 +788,74 @@ dw_writer_emit_tag(DW_Writer *writer, DW_WriterTag *tag)
{
String8List *debug_info = &writer->sections[DW_Section_Info].srl;
for EachNode(attrib, DW_WriterAttrib, tag->first_attrib) {
- switch (attrib->reader.form.kind) {
+ switch (attrib->form.reader.kind) {
case DW_Form_Addr: {
- str8_serial_push_string(writer->arena, debug_info, attrib->reader.form.addr);
+ str8_serial_push_string(writer->arena, debug_info, attrib->form.reader.addr);
} break;
case DW_Form_Block1:
case DW_Form_Block2:
case DW_Form_Block4: {
- str8_serial_push_string(writer->arena, debug_info, attrib->reader.form.block);
+ str8_serial_push_string(writer->arena, debug_info, attrib->form.reader.block);
} break;
case DW_Form_Data1:
case DW_Form_Data2:
case DW_Form_Data4:
case DW_Form_Data8: {
- str8_serial_push_string(writer->arena, debug_info, attrib->reader.form.data);
+ str8_serial_push_string(writer->arena, debug_info, attrib->form.reader.data);
} break;
case DW_Form_String: {
- str8_serial_push_cstr(writer->arena, debug_info, attrib->reader.form.string);
+ str8_serial_push_cstr(writer->arena, debug_info, attrib->form.reader.string);
} break;
case DW_Form_Flag: {
- str8_serial_push_u8(writer->arena, debug_info, attrib->reader.form.flag);
+ str8_serial_push_u8(writer->arena, debug_info, attrib->form.reader.flag);
} break;
case DW_Form_SData: {
- dw_serial_push_sleb128(writer->arena, debug_info, attrib->reader.form.sdata);
+ dw_serial_push_sleb128(writer->arena, debug_info, attrib->form.reader.sdata);
} break;
case DW_Form_Strp: {
- dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.sec_offset);
+ dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->form.reader.sec_offset);
} break;
case DW_Form_UData: {
- dw_serial_push_uleb128(writer->arena, debug_info, attrib->reader.form.udata);
+ dw_serial_push_uleb128(writer->arena, debug_info, attrib->form.reader.udata);
} break;
case DW_Form_RefAddr: {
if (writer->version < DW_Version_3) {
- Assert(writer->address_size <= sizeof(attrib->reader.form.ref));
- str8_serial_push_string(writer->arena, debug_info, str8((U8 *)&attrib->reader.form.ref, writer->address_size));
+ Assert(writer->address_size <= sizeof(attrib->form.reader.ref));
+ str8_serial_push_string(writer->arena, debug_info, str8((U8 *)&attrib->form.reader.ref, writer->address_size));
} else {
- dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.ref);
+ dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->form.reader.ref);
}
} break;
case DW_Form_Ref1: {
- str8_serial_push_u8(writer->arena, debug_info, (U8)attrib->reader.form.ref);
+ str8_serial_push_u8(writer->arena, debug_info, (U8)attrib->form.reader.ref);
} break;
case DW_Form_Ref2: {
- str8_serial_push_u16(writer->arena, debug_info, (U16)attrib->reader.form.ref);
+ str8_serial_push_u16(writer->arena, debug_info, (U16)attrib->form.reader.ref);
} break;
case DW_Form_Ref4: {
- str8_serial_push_u32(writer->arena, debug_info, (U32)attrib->reader.form.ref);
+ str8_serial_push_u32(writer->arena, debug_info, (U32)attrib->form.reader.ref);
} break;
case DW_Form_Ref8: {
- if (attrib->writer.form.ref->info_off == 0) {
+ if (attrib->form.writer.ref->info_off == 0) {
// reserve 8 bytes
void *value = str8_serial_push_u64(writer->arena, debug_info, 0);
// push fixup
- dw_writer_fixup_list_push(writer->arena, &writer->fixups, (DW_WriterFixup){ .value = value, .attrib = attrib });
+ dw_writer_fixup_list_push(writer->arena, &writer->fixups, (DW_WriterFixup){ .tag = attrib->form.writer.ref, .ptr = value });
}
} break;
case DW_Form_RefUData: {
- dw_serial_push_uleb128(writer->arena, debug_info, attrib->reader.form.ref);
+ dw_serial_push_uleb128(writer->arena, debug_info, attrib->form.reader.ref);
} break;
case DW_Form_Indirect: {
NotImplemented;
} break;
case DW_Form_SecOffset: {
- dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.sec_offset);
+ dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->form.reader.sec_offset);
} break;
case DW_Form_ExprLoc: {
- dw_serial_push_uleb128(writer->arena, debug_info, attrib->reader.form.exprloc.size);
- str8_serial_push_string(writer->arena, debug_info, attrib->reader.form.exprloc);
+ dw_serial_push_uleb128(writer->arena, debug_info, attrib->form.reader.exprloc.size);
+ str8_serial_push_string(writer->arena, debug_info, attrib->form.reader.exprloc);
} break;
case DW_Form_FlagPresent: {
} break;
@@ -578,19 +866,19 @@ dw_writer_emit_tag(DW_Writer *writer, DW_WriterTag *tag)
case DW_Form_Addrx:
case DW_Form_RngListx:
case DW_Form_LocListx: {
- dw_serial_push_uleb128(writer->arena, debug_info, attrib->reader.form.xval);
+ dw_serial_push_uleb128(writer->arena, debug_info, attrib->form.reader.xval);
} break;
case DW_Form_RefSup4: {
NotImplemented;
} break;
case DW_Form_StrpSup: {
- dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.strp_sup);
+ dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->form.reader.strp_sup);
} break;
case DW_Form_Data16: {
- str8_serial_push_string(writer->arena, debug_info, attrib->reader.form.data);
+ str8_serial_push_string(writer->arena, debug_info, attrib->form.reader.data);
} break;
case DW_Form_LineStrp: {
- dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.sec_offset);
+ dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->form.reader.sec_offset);
} break;
case DW_Form_ImplicitConst: {
// value is stored in the abbrev entry
@@ -600,26 +888,26 @@ dw_writer_emit_tag(DW_Writer *writer, DW_WriterTag *tag)
} break;
case DW_Form_Strx1:
case DW_Form_Addrx1: {
- str8_serial_push_u8(writer->arena, debug_info, (U8)attrib->reader.form.xval);
+ str8_serial_push_u8(writer->arena, debug_info, (U8)attrib->form.reader.xval);
} break;
case DW_Form_Strx2:
case DW_Form_Addrx2: {
- str8_serial_push_u16(writer->arena, debug_info, (U16)attrib->reader.form.xval);
+ str8_serial_push_u16(writer->arena, debug_info, (U16)attrib->form.reader.xval);
} break;
case DW_Form_Strx3:
case DW_Form_Addrx3: {
- str8_serial_push_string(writer->arena, debug_info, str8((U8 *)&attrib->reader.form.xval, 3));
+ str8_serial_push_string(writer->arena, debug_info, str8((U8 *)&attrib->form.reader.xval, 3));
} break;
case DW_Form_Strx4:
case DW_Form_Addrx4: {
- str8_serial_push_u32(writer->arena, debug_info, (U32)attrib->reader.form.xval);
+ str8_serial_push_u32(writer->arena, debug_info, (U32)attrib->form.reader.xval);
} break;
case DW_Form_GNU_StrpAlt: {
- dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.sec_offset);
+ dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->form.reader.sec_offset);
} break;
case DW_Form_GNU_RefAlt: {
- dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.ref);
+ dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->form.reader.ref);
} break;
default: InvalidPath; break;
@@ -641,36 +929,245 @@ dw_writer_emit_tag(DW_Writer *writer, DW_WriterTag *tag)
internal void
dw_writer_emit(DW_Writer *writer)
{
- dw_writer_emit_tag(writer, writer->root);
+ // line
+ {
+ // push line table terminator
+ dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_end_sequence());
- // null terminate .debug_abbrev
- dw_serial_push_uleb128(writer->arena, &writer->sections[DW_Section_Abbrev].srl, 0);
- dw_serial_push_uleb128(writer->arena, &writer->sections[DW_Section_Abbrev].srl, 0);
-
- // fixup units lengths
- for EachElement(i, writer->sections) {
- if (writer->sections[i].length) {
- if (writer->format == DW_Format_64Bit) {
- U64 *length = writer->sections[i].length;
- U64 length_size = sizeof(U64) + sizeof(U32);
- Assert(writer->sections[i].srl.total_size >= length_size);
- *length = writer->sections[i].srl.total_size - length_size;
- } else {
- U32 *length = writer->sections[i].length;
- U32 length_size = sizeof(U32);
- Assert(writer->sections[i].srl.total_size >= length_size);
- *length = safe_cast_u32(writer->sections[i].srl.total_size - length_size);
+ // find comp dir in the compile unit tag
+ String8 comp_dir = {0};
+ String8 comp_name = {0};
+ Assert(writer->root->kind == DW_TagKind_CompileUnit);
+ 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;
+ } else if (attrib->kind == DW_AttribKind_Name) {
+ AssertAlways(attrib->form.writer.kind == DW_WriterFormKind_String);
+ comp_name = attrib->form.writer.string;
}
}
+
+ String8List dir_table_srl = {0};
+ str8_serial_begin(writer->arena, &dir_table_srl);
+ {
+ Temp scratch = scratch_begin(0, 0);
+ String8List *srl = &dir_table_srl;
+
+ // (13) directory_entry_format_count
+ str8_serial_push_u8(writer->arena, srl, 1);
+ // (14) directory_entry_format
+ dw_serial_push_uleb128(writer->arena, srl, DW_LNCT_Path);
+ dw_serial_push_uleb128(writer->arena, srl, DW_Form_String);
+
+ // dedup directories
+ 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);
+ for EachNode(file, DW_WriterFile, writer->line.first_file) {
+ String8 path = str8_chop_last_slash(file->path);
+ if ( ! hash_table_search_string_u64(dir_ht, path, &file->dir_idx)) {
+ file->dir_idx = hash_table_push_string_u64(scratch.arena, dir_ht, path, dir_ht->count)->v.value_u64;
+ }
+ }
+ 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);
+ // (16) directories
+ for (U64 i = 1; 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 } });
+ }
+
+ scratch_end(scratch);
+ }
+
+ String8List file_table_srl = {0};
+ {
+ Temp scratch = scratch_begin(0, 0);
+ String8List *srl = &file_table_srl;
+
+ struct { DW_LNCT lnct; DW_FormKind form_kind; } encs[] = {
+ { DW_LNCT_Path, DW_Form_String },
+ { DW_LNCT_DirectoryIndex, DW_Form_UData },
+ { DW_LNCT_TimeStamp, DW_Form_Null }, // DW_Form_UData
+ { DW_LNCT_Size, DW_Form_Null }, // DW_Form_UData
+ { DW_LNCT_MD5, DW_Form_Null }, // DW_Form_Block
+ { DW_LNCT_LLVM_Source, DW_Form_Null } // DW_Form_String
+ };
+
+ HashTable *encs_ht = hash_table_init(scratch.arena, ArrayCount(encs) * 2);
+ for EachElement(i, encs) { hash_table_push_u64_raw(scratch.arena, encs_ht, encs[i].lnct, &encs[i].form_kind); }
+
+ // 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; }
+ }
+
+ // count needed encodings
+ U64 enc_count = 0;
+ for EachElement(i, encs) { if (encs[i].form_kind != DW_Form_Null) { enc_count += 1; } }
+
+ // (17) file_name_entry_format_count
+ str8_serial_push_u16(writer->arena, srl, enc_count);
+
+ // (18) file_name_entry_format
+ for EachElement(i, encs) {
+ if (encs[i].form_kind == DW_Form_Null) { continue; }
+ dw_serial_push_uleb128(writer->arena, srl, encs[i].lnct );
+ dw_serial_push_uleb128(writer->arena, srl, encs[i].form_kind);
+ }
+
+ // (19) file_names_count
+ dw_serial_push_uleb128(writer->arena, srl, writer->line.file_count);
+
+ // (20) file_names
+ if (comp_name.size) {
+ for (DW_WriterFile *n = writer->line.first_file, *p = 0; n != 0; p = n, n = n->next) {
+ String8 file_name = str8_skip_last_slash(n->path);
+ if (str8_match(file_name, comp_name, 0)) {
+ if (p == 0) {
+ // file is already first
+ } else {
+ // move compile unit file to be first entry in the table
+ p->next = n->next;
+ n->next = writer->line.first_file;
+ writer->line.first_file = n;
+ }
+ break;
+ }
+ }
+ }
+ 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 } };
+
+ // path
+ Assert(*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_Path) == DW_Form_String);
+ DW_WriterXForm path_form = { .reader = { .kind = DW_Form_String, .string = file->path } };
+ dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, path_form);
+
+ // directory index
+ Assert(*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_DirectoryIndex) == DW_Form_UData);
+ DW_WriterXForm dir_idx_form = { .reader = { .kind = DW_Form_UData, .udata = file->time_stamp } };
+ dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, dir_idx_form);
+
+ // time stamp
+ if (*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_TimeStamp) == DW_Form_UData) {
+ if (file->time_stamp) {
+ DW_WriterXForm time_stamp_form = { .reader = { .kind = DW_Form_UData, .udata = file->time_stamp } };
+ dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, time_stamp_form);
+ } else {
+ dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, null_form_udata);
+ }
+ }
+
+ // size
+ if (*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_Size) == DW_Form_UData) {
+ if (file->size) {
+ DW_WriterXForm size_form = { .reader = { .kind = DW_Form_UData, .udata = file->size } };
+ dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, size_form);
+ } else {
+ dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, null_form_udata);
+ }
+ }
+
+ // 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 } };
+ 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);
+ }
+ }
+
+ // LLVM Source
+ if (*(DW_FormKind *)hash_table_search_u64_raw(encs_ht, DW_LNCT_LLVM_Source) == DW_Form_String) {
+ if (file->source.size) {
+ DW_WriterXForm source_form = { .reader = { .kind = DW_Form_String, .string = file->source } };
+ dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, source_form);
+ } else {
+ dw_serial_push_form(writer->arena, srl, writer->version, writer->format, writer->address_size, 0, null_form_string);
+ }
+ }
+ }
+
+ scratch_end(scratch);
+ }
+
+ {
+ String8List *srl = &writer->sections[DW_Section_Line].srl;
+ // (1) unit_length
+ writer->sections[DW_Section_Line].length = dw_serial_push_length(writer->arena, srl, writer->format, 0);
+ // (2) version
+ str8_serial_push_struct(writer->arena, srl, &writer->version);
+ // (3) address_size
+ str8_serial_push_struct(writer->arena, srl, &writer->address_size);
+ // (4) segment_selector_size
+ str8_serial_push_struct(writer->arena, srl, &writer->segsel_size);
+ // (5) header_length
+ U64 header_size = srl->total_size + dir_table_srl.total_size + file_table_srl.total_size;
+ dw_serial_push_uint(writer->arena, srl, writer->format, header_size);
+ // (6) minimum_instruction_length
+ str8_serial_push_struct(writer->arena, srl, &writer->line.min_inst_len);
+ // (7) maximum_operations_per_instruction
+ str8_serial_push_struct(writer->arena, srl, &writer->line.max_ops_per_inst);
+ // (8) default_is_stmt
+ str8_serial_push_struct(writer->arena, srl, &writer->line.default_is_stmt);
+ // (9) line_base
+ str8_serial_push_struct(writer->arena, srl, &writer->line.line_base);
+ // (10) line_range
+ str8_serial_push_struct(writer->arena, srl, &writer->line.line_range);
+ // (11) opcode_base
+ str8_serial_push_struct(writer->arena, srl, &writer->line.opcode_base);
+ // (12) standard_opcode_lengths
+ str8_serial_push_struct(writer->arena, srl, &writer->line.std_op_lens);
+ // directory table
+ str8_list_concat_in_place(srl, &dir_table_srl);
+ // file table
+ str8_list_concat_in_place(srl, &file_table_srl);
+ // line program
+ String8 line_program_data = dw_data_from_line_insts(writer->arena, writer->address_size, writer->line.line_insts);
+ str8_serial_push_string(writer->arena, srl, line_program_data);
+ }
}
- // fixup forward references in .debug_info
- for EachNode(fixup_n, DW_WriterFixupNode, writer->fixups.first) {
- DW_WriterFixup *fixup = &fixup_n->v;
- if (fixup->attrib->reader.form.kind == DW_Form_Ref8) {
- Assert(fixup->attrib->writer.form.ref->info_off != 0);
- MemoryCopy(fixup->value, &fixup->attrib->writer.form.ref->info_off, sizeof(U64));
- fixup->attrib->reader.form.ref = fixup->attrib->writer.form.ref->info_off;
+ // info
+ {
+ dw_writer_emit_tag(writer, writer->root);
+
+ // null terminate .debug_abbrev
+ dw_serial_push_uleb128(writer->arena, &writer->sections[DW_Section_Abbrev].srl, 0);
+
+ // fixup units lengths
+ for EachElement(i, writer->sections) {
+ if (writer->sections[i].length) {
+ if (writer->format == DW_Format_64Bit) {
+ U64 *length = writer->sections[i].length;
+ U64 length_size = sizeof(U64) + sizeof(U32);
+ Assert(writer->sections[i].srl.total_size >= length_size);
+ *length = writer->sections[i].srl.total_size - length_size;
+ } else {
+ U32 *length = writer->sections[i].length;
+ U32 length_size = sizeof(U32);
+ Assert(writer->sections[i].srl.total_size >= length_size);
+ *length = safe_cast_u32(writer->sections[i].srl.total_size - length_size);
+ }
+ }
+ }
+
+ // fixup forward references in .debug_info
+ for EachNode(fixup_n, DW_WriterFixupNode, writer->fixups.first) {
+ DW_WriterFixup *fixup = &fixup_n->v;
+ Assert(fixup->tag->info_off != 0);
+ MemoryCopy(fixup->ptr, &fixup->tag->info_off, sizeof(U64));
}
}
}
diff --git a/src/dwarf/dwarf_writer.h b/src/dwarf/dwarf_writer.h
index 821c98fd..95b2f913 100644
--- a/src/dwarf/dwarf_writer.h
+++ b/src/dwarf/dwarf_writer.h
@@ -65,15 +65,16 @@ typedef struct DW_WriterForm
};
} DW_WriterForm;
+typedef struct DW_WriterXForm
+{
+ DW_WriterForm writer;
+ DW_Form reader;
+} DW_WriterXForm;
+
typedef struct DW_WriterAttrib
{
DW_AttribKindEnum kind;
- struct {
- DW_WriterForm form;
- } writer;
- struct {
- DW_Form form;
- } reader;
+ DW_WriterXForm form;
struct DW_WriterAttrib *next;
} DW_WriterAttrib;
@@ -123,10 +124,58 @@ typedef struct DW_WriterAttribChunkList
DW_WriterAttribChunk *last;
} DW_WriterAttribChunkList;
+typedef struct DW_WriterLine
+{
+ struct DW_WriterLine *next;
+} DW_WriterLine;
+
+typedef struct DW_WriterFile
+{
+ struct DW_WriterFile *next;
+ String8 path;
+ U64 time_stamp;
+ U64 size;
+ String8 md5;
+ String8 source;
+ U64 file_idx;
+ U64 dir_idx;
+} DW_WriterFile;
+
+typedef struct DW_LineInst
+{
+ DW_StdOpcode opcode;
+ union {
+ U64 advance_pc;
+ S64 advance_line;
+ DW_WriterFile *set_file;
+ U64 set_column;
+ U16 fixed_advance_pc;
+ U64 set_isa;
+ struct {
+ DW_ExtOpcode ext;
+ U64 set_address;
+ U64 set_discriminator;
+ };
+ };
+} DW_LineInst;
+
+typedef struct DW_LineInstNode
+{
+ DW_LineInst v;
+ struct DW_LineInstNode *next;
+} DW_LineInstNode;
+
+typedef struct DW_LineInstList
+{
+ U64 count;
+ DW_LineInstNode *first;
+ DW_LineInstNode *last;
+} DW_LineInstList;
+
typedef struct DW_WriterFixup
{
- struct DW_WriterAttrib *attrib;
- U8 *value;
+ DW_WriterTag *tag;
+ U8 *ptr;
} DW_WriterFixup;
typedef struct DW_WriterFixupNode
@@ -151,38 +200,67 @@ typedef struct DW_WriterSection
typedef struct DW_Writer
{
Arena *arena;
+
+ // Compile Unit
+ Arch arch;
+ DW_Version version;
+ DW_Format format;
+ DW_CompUnitKind cu_kind;
+ U8 address_size;
+ U8 segsel_size;
+
+ // Abbrev
+ U64 abbrev_base_info_off;
+ HashTable *abbrev_id_map;
+
+ // Info
DW_WriterTag *root;
DW_WriterTag *current;
- Arch arch;
- DW_Format format;
- DW_Version version;
- DW_CompUnitKind cu_kind;
- U64 address_size;
- U64 abbrev_base_info_off;
+
+ // Line
+ struct {
+ U8 min_inst_len;
+ U8 max_ops_per_inst;
+ U8 default_is_stmt;
+ S8 line_base;
+ U8 line_range;
+ U8 opcode_base;
+ U8 *std_op_lens;
+ DW_LineInstList line_insts;
+
+ DW_WriterFile *file;
+ U64 ln;
+ U64 col;
+ U64 addr;
+
+ U64 file_count;
+ DW_WriterFile *first_file;
+ DW_WriterFile *last_file;
+ } line;
+
+ // Emit
DW_WriterFixupList fixups;
- HashTable *abbrev_id_map;
DW_WriterSection sections[DW_Section_Count];
DW_WriterAttribChunkList attrib_chunk_list;
DW_WriterTagChunkList tag_chunk_list;
} DW_Writer;
////////////////////////////////
-
-internal DW_IntEnc dw_int_enc_from_sint(S64 v);
-internal DW_IntEnc dw_int_enc_from_uint(U64 v);
-
-internal U64 dw_size_from_sint(S64 v);
-internal U64 dw_size_from_uint(U64 v);
-
-internal void dw_serial_push_form(Arena *arena, String8List *srl, DW_Format format, DW_Version version, U8 address_size, DW_FormKind form_kind, DW_Form form);
-
-////////////////////////////////
+// Writer
internal DW_Writer * dw_writer_begin(DW_Format format, DW_Version version, DW_CompUnitKind cu_kind, Arch arch);
-internal void dw_writer_end(DW_Writer **writer_ptr);
+internal void dw_writer_end (DW_Writer **writer_ptr);
+
+////////////////////////////////
+// Form
+
+internal U64 dw_serial_push_form(Arena *arena, String8List *srl, DW_Version version, DW_Format format, U8 address_size, DW_WriterFixupList *fixups, DW_WriterXForm form);
+
+////////////////////////////////
+// Info
internal DW_WriterTag * dw_writer_tag_begin(DW_Writer *writer, DW_TagKind kind);
-internal void dw_writer_tag_end(DW_Writer *writer);
+internal void dw_writer_tag_end (DW_Writer *writer);
internal DW_WriterAttrib * dw_writer_push_attrib (DW_Writer *writer, DW_AttribKind kind, DW_WriterForm form );
internal DW_WriterAttrib * dw_writer_push_attrib_address (DW_Writer *writer, DW_AttribKind kind, U64 address );
@@ -201,13 +279,56 @@ internal DW_WriterAttrib * dw_writer_push_attrib_line_ptr (DW_Writer *writer,
internal DW_WriterAttrib * dw_writer_push_attrib_mac_ptr (DW_Writer *writer, DW_AttribKind kind, void * mac_ptr );
internal DW_WriterAttrib * dw_writer_push_attrib_rng_list_ptr(DW_Writer *writer, DW_AttribKind kind, void * rng_list_ptr);
internal DW_WriterAttrib * dw_writer_push_attrib_implicit (DW_Writer *writer, DW_AttribKind kind, S64 implicit );
-
#define dw_writer_push_attrib_expressionv(w, k, ...) dw_writer_push_attrib_expression(w, k, (DW_ExprEnc[]){ __VA_ARGS__ }, ArrayCount(((DW_ExprEnc[]){ __VA_ARGS__ })) )
+////////////////////////////////
+// Line
+
+internal void dw_line_inst_list_push_node(DW_LineInstList *list, DW_LineInstNode *node);
+internal DW_LineInstNode * dw_line_inst_list_push (Arena *arena, DW_LineInstList *list, DW_LineInst op);
+
+// std opcodes
+#define DW_LNS_copy() (DW_LineInst){ .opcode = DW_StdOpcode_Copy }
+#define DW_LNS_advance_pc(d) (DW_LineInst){ .opcode = DW_StdOpcode_AdvancePc, .advance_pc = d }
+#define DW_LNS_advance_line(s) (DW_LineInst){ .opcode = DW_StdOpcode_AdvanceLine, .advance_line = s }
+#define DW_LNS_set_file(f) (DW_LineInst){ .opcode = DW_StdOpcode_SetFile, .set_file = f }
+#define DW_LNS_set_column(c) (DW_LineInst){ .opcode = DW_StdOpcode_SetColumn, .set_column = c }
+#define DW_LNS_negate_stmt() (DW_LineInst){ .opcode = DW_StdOpcode_NegateStmt }
+#define DW_LNS_set_basic_block() (DW_LineInst){ .opcode = DW_StdOpcode_SetBasicBlock }
+#define DW_LNS_const_add_pc(a) (DW_LineInst){ .opcode = DW_StdOpcode_ConstAddPc }
+#define DW_LNS_fixed_advance_pc(a) (DW_LineInst){ .opcode = DW_StdOpcode_FixedAdvancePc, .fixed_advance_pc = a }
+#define DW_LNS_set_prologue_end() (DW_LineInst){ .opcode = DW_StdOpcode_SetPrologueEnd }
+#define DW_LNS_set_epilogue_begin() (DW_LineInst){ .opcode = DW_StdOpcode_SetEpilogueBegin }
+#define DW_LNS_set_isa(i) (DW_LineInst){ .opcode = DW_StdOpcode_SetIsa, .set_isa = i }
+
+// ext opcodes
+#define DW_LNE_end_sequence() (DW_LineInst){ .opcode = DW_StdOpcode_ExtendedOpcode, .ext = DW_ExtOpcode_EndSequence }
+#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);
+
+////////////////////////////////
+// Emit
+
internal void dw_writer_emit(DW_Writer *writer);
#ifdef OBJ_H
internal void dw_writer_emit_to_obj(DW_Writer *writer, OBJ *obj);
#endif
+////////////////////////////////
+// Format Helpers
+
+internal DW_IntEnc dw_int_enc_from_sint(S64 v);
+internal DW_IntEnc dw_int_enc_from_uint(U64 v);
+
+internal U64 dw_size_from_sint(S64 v);
+internal U64 dw_size_from_uint(U64 v);
+
#endif // DWARF_WRITER_H
diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c
index 25cc5c9f..7cdbbcb7 100644
--- a/src/linker/hash_table.c
+++ b/src/linker/hash_table.c
@@ -519,3 +519,12 @@ remove_duplicates_str8_list(Arena *arena, String8List list)
return result;
}
+internal String8 **
+str8_from_key_value_pairs(Arena *arena, KeyValuePair *v, U64 count)
+{
+ String8 **result = push_array(arena, String8 *, count);
+ for EachIndex(i, count) {
+ result[i] = &v[i].value_string;
+ }
+ return result;
+}
diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h
index 80f0ea30..326c0b1b 100644
--- a/src/linker/hash_table.h
+++ b/src/linker/hash_table.h
@@ -94,14 +94,16 @@ internal U32 * keys_from_hash_table_u32 (Arena *arena, HashTable
internal U64 * keys_from_hash_table_u64 (Arena *arena, HashTable *ht);
internal String8 keys_from_hash_table_str8 (Arena *arena, HashTable *ht);
internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht);
+internal void * keys_from_hash_table_raw (Arena *arena, HashTable *ht);
-internal void * keys_from_hash_table_raw (Arena *arena, HashTable *ht);
-internal void * values_from_hash_table_raw(Arena *arena, HashTable *ht);
+internal U64 * values_from_hash_table_u64(Arena *arena, HashTable *ht);
internal void sort_key_value_pairs_as_u32 (KeyValuePair *pairs, U64 count);
internal void sort_key_value_pairs_as_u64 (KeyValuePair *pairs, U64 count);
internal void sort_key_value_pairs_as_string_sensitive(KeyValuePair *pairs, U64 count);
+internal String8 ** str8_from_key_value_pairs(Arena *arena, KeyValuePair *v, U64 count);
+
// --- Misc --------------------------------------------------------------------
internal U64Array remove_duplicates_u64_array(Arena *arena, U64Array arr);
diff --git a/src/natvis/base.natvis b/src/natvis/base.natvis
index 59a43987..4db4ce56 100644
--- a/src/natvis/base.natvis
+++ b/src/natvis/base.natvis
@@ -154,6 +154,7 @@
+
{{ count={count} first={first} }}
- count
diff --git a/src/torture/torture_dwarf.c b/src/torture/torture_dwarf.c
index 567364e4..095b76b9 100644
--- a/src/torture/torture_dwarf.c
+++ b/src/torture/torture_dwarf.c
@@ -82,8 +82,8 @@ dwt_tags_must_match(DW_WriterTag *writer_tag, DW_TagNode *reader_tag)
DW_AttribNode *reader_attrib = reader_tag->tag.attribs.first;
while (writer_attrib) {
if (writer_attrib->kind != reader_attrib->v.attrib_kind) { goto exit; }
- if (writer_attrib->reader.form.kind != reader_attrib->v.form.kind) { goto exit; }
- if ( ! dw_form_match(writer_attrib->reader.form, reader_attrib->v.form)) { goto exit; }
+ if (writer_attrib->form.reader.kind != reader_attrib->v.form.kind) { goto exit; }
+ if ( ! dw_form_match(writer_attrib->form.reader, reader_attrib->v.form)) { goto exit; }
writer_attrib = writer_attrib->next;
reader_attrib = reader_attrib->next;
}
@@ -107,11 +107,23 @@ dwt_make_writer(void)
{
Temp scratch = scratch_begin(0, 0);
- // define debug info layout
DW_Writer *writer = dw_writer_begin(DW_Format_32Bit, DW_Version_Last, DW_CompUnitKind_Compile, Arch_x64);
+ // line
+ {
+ 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);
+ }
+ // 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, str8_lit("~/devel/projects"));
+ dw_writer_push_attrib_string(writer, DW_AttribKind_Name, str8_lit("a.c"));
dw_writer_push_attrib_enum(writer, DW_AttribKind_Language, DW_Language_C99);
dw_writer_push_attrib_flag(writer, DW_AttribKind_UseUtf8, 1);
{
@@ -223,19 +235,19 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *producer_attrib = comp_unit_tag->first_attrib;
T_Ok(producer_attrib->kind == DW_AttribKind_Producer);
- T_Ok(producer_attrib->reader.form.kind == DW_Form_String);
- T_Ok(str8_match(producer_attrib->writer.form.string, str8_lit("RAD DWARF WRITER"), 0));
+ T_Ok(producer_attrib->form.reader.kind == DW_Form_String);
+ T_Ok(str8_match(producer_attrib->form.writer.string, str8_lit("RAD DWARF WRITER"), 0));
DW_WriterAttrib *language_attrib = producer_attrib->next;
T_Ok(language_attrib->kind == DW_AttribKind_Language);
- T_Ok(language_attrib->reader.form.kind == DW_Form_Data1);
- T_Ok(language_attrib->reader.form.data.size == 1);
- T_Ok(*(U8 *)language_attrib->reader.form.data.str == DW_Language_C99);
+ T_Ok(language_attrib->form.reader.kind == DW_Form_Data1);
+ T_Ok(language_attrib->form.reader.data.size == 1);
+ T_Ok(*(U8 *)language_attrib->form.reader.data.str == DW_Language_C99);
DW_WriterAttrib *use_utf8_attrib = language_attrib->next;
T_Ok(use_utf8_attrib->kind == DW_AttribKind_UseUtf8);
- T_Ok(use_utf8_attrib->reader.form.kind == DW_Form_Flag);
- T_Ok(use_utf8_attrib->reader.form.flag == 1);
+ T_Ok(use_utf8_attrib->form.reader.kind == DW_Form_Flag);
+ T_Ok(use_utf8_attrib->form.reader.flag == 1);
}
DW_WriterTag *char_type_tag = comp_unit_tag->first_child;
@@ -250,20 +262,20 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *byte_size_attrib = char_type_tag->first_attrib;
T_Ok(byte_size_attrib->kind == DW_AttribKind_ByteSize);
- T_Ok(byte_size_attrib->reader.form.kind == DW_Form_Data1);
- T_Ok(byte_size_attrib->reader.form.data.size == 1);
- T_Ok(*(U8 *)byte_size_attrib->reader.form.data.str == 1);
+ T_Ok(byte_size_attrib->form.reader.kind == DW_Form_Data1);
+ T_Ok(byte_size_attrib->form.reader.data.size == 1);
+ T_Ok(*(U8 *)byte_size_attrib->form.reader.data.str == 1);
DW_WriterAttrib *encoding_attrib = byte_size_attrib->next;
T_Ok(encoding_attrib->kind == DW_AttribKind_Encoding);
- T_Ok(encoding_attrib->reader.form.kind == DW_Form_Data1);
- T_Ok(encoding_attrib->reader.form.data.size == 1);
- T_Ok(*(U8 *)encoding_attrib->reader.form.data.str == DW_ATE_SignedChar);
+ T_Ok(encoding_attrib->form.reader.kind == DW_Form_Data1);
+ T_Ok(encoding_attrib->form.reader.data.size == 1);
+ T_Ok(*(U8 *)encoding_attrib->form.reader.data.str == DW_ATE_SignedChar);
DW_WriterAttrib *name_attrib = encoding_attrib->next;
T_Ok(name_attrib->kind == DW_AttribKind_Name);
- T_Ok(name_attrib->reader.form.kind == DW_Form_String);
- T_Ok(str8_match(name_attrib->reader.form.string, str8_lit("char"), 0));
+ T_Ok(name_attrib->form.reader.kind == DW_Form_String);
+ T_Ok(str8_match(name_attrib->form.reader.string, str8_lit("char"), 0));
}
DW_WriterTag *const_type_tag = char_type_tag->next;
@@ -278,8 +290,8 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *type_attrib = const_type_tag->first_attrib;
T_Ok(type_attrib->kind == DW_AttribKind_Type);
- T_Ok(type_attrib->writer.form.kind == DW_WriterFormKind_Ref);
- T_Ok(type_attrib->writer.form.ref == char_type_tag);
+ T_Ok(type_attrib->form.writer.kind == DW_WriterFormKind_Ref);
+ T_Ok(type_attrib->form.writer.ref == char_type_tag);
}
DW_WriterTag *dup_char_type_tag = const_type_tag->next;
@@ -294,20 +306,20 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *byte_size_attrib = dup_char_type_tag->first_attrib;
T_Ok(byte_size_attrib->kind == DW_AttribKind_ByteSize);
- T_Ok(byte_size_attrib->reader.form.kind == DW_Form_Data1);
- T_Ok(byte_size_attrib->reader.form.data.size == 1);
- T_Ok(*(U8 *)byte_size_attrib->reader.form.data.str == 1);
+ T_Ok(byte_size_attrib->form.reader.kind == DW_Form_Data1);
+ T_Ok(byte_size_attrib->form.reader.data.size == 1);
+ T_Ok(*(U8 *)byte_size_attrib->form.reader.data.str == 1);
DW_WriterAttrib *encoding_attrib = byte_size_attrib->next;
T_Ok(encoding_attrib->kind == DW_AttribKind_Encoding);
- T_Ok(encoding_attrib->reader.form.kind == DW_Form_Data1);
- T_Ok(encoding_attrib->reader.form.data.size == 1);
- T_Ok(*(U8 *)encoding_attrib->reader.form.data.str == DW_ATE_SignedChar);
+ T_Ok(encoding_attrib->form.reader.kind == DW_Form_Data1);
+ T_Ok(encoding_attrib->form.reader.data.size == 1);
+ T_Ok(*(U8 *)encoding_attrib->form.reader.data.str == DW_ATE_SignedChar);
DW_WriterAttrib *name_attrib = encoding_attrib->next;
T_Ok(name_attrib->kind == DW_AttribKind_Name);
- T_Ok(name_attrib->reader.form.kind == DW_Form_String);
- T_Ok(str8_match(name_attrib->reader.form.string, str8_lit("char"), 0));
+ T_Ok(name_attrib->form.reader.kind == DW_Form_String);
+ T_Ok(str8_match(name_attrib->form.reader.string, str8_lit("char"), 0));
}
DW_WriterTag *simple_struct_tag = dup_char_type_tag->next;
@@ -321,8 +333,8 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *simple_struct_name = simple_struct_tag->first_attrib;
T_Ok(simple_struct_name->kind == DW_AttribKind_Name);
- T_Ok(simple_struct_name->reader.form.kind == DW_Form_String);
- T_Ok(str8_match(simple_struct_name->reader.form.string, str8_lit("FooBar"), 0));
+ T_Ok(simple_struct_name->form.reader.kind == DW_Form_String);
+ T_Ok(str8_match(simple_struct_name->form.reader.string, str8_lit("FooBar"), 0));
DW_WriterTag *m0_tag = simple_struct_tag->first_child;
{
@@ -334,19 +346,19 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *name = m0_tag->first_attrib;
T_Ok(name->kind == DW_AttribKind_Name);
- T_Ok(name->reader.form.kind == DW_Form_String);
- T_Ok(str8_match(name->reader.form.string, str8_lit("m0"), 0));
+ T_Ok(name->form.reader.kind == DW_Form_String);
+ T_Ok(str8_match(name->form.reader.string, str8_lit("m0"), 0));
DW_WriterAttrib *type = name->next;
T_Ok(type->kind == DW_AttribKind_Type);
- T_Ok(type->reader.form.kind == DW_Form_Ref1);
- T_Ok(type->reader.form.ref == 0x20);
+ T_Ok(type->form.reader.kind == DW_Form_Ref1);
+ T_Ok(type->form.reader.ref == 0x20);
DW_WriterAttrib *data_loc = type->next;
T_Ok(data_loc->kind == DW_AttribKind_DataMemberLocation);
- T_Ok(data_loc->reader.form.kind == DW_Form_Data1);
- T_Ok(data_loc->reader.form.data.size == 1);
- T_Ok(*(U8 *)data_loc->reader.form.data.str == 0);
+ T_Ok(data_loc->form.reader.kind == DW_Form_Data1);
+ T_Ok(data_loc->form.reader.data.size == 1);
+ T_Ok(*(U8 *)data_loc->form.reader.data.str == 0);
}
DW_WriterTag *m1_tag = m0_tag->next;
@@ -359,24 +371,24 @@ T_BeginTest(dwarf_writer)
DW_WriterAttrib *name = m1_tag->first_attrib;
T_Ok(name->kind == DW_AttribKind_Name);
- T_Ok(name->reader.form.kind == DW_Form_String);
- T_Ok(str8_match(name->reader.form.string, str8_lit("m1"), 0));
+ T_Ok(name->form.reader.kind == DW_Form_String);
+ T_Ok(str8_match(name->form.reader.string, str8_lit("m1"), 0));
DW_WriterAttrib *type = name->next;
T_Ok(type->kind == DW_AttribKind_Type);
- T_Ok(type->reader.form.kind == DW_Form_Ref1);
- T_Ok(type->reader.form.ref == 0x20);
+ T_Ok(type->form.reader.kind == DW_Form_Ref1);
+ T_Ok(type->form.reader.ref == 0x20);
DW_WriterAttrib *data_loc = type->next;
T_Ok(data_loc->kind == DW_AttribKind_DataMemberLocation);
- T_Ok(data_loc->reader.form.kind == DW_Form_Data1);
- T_Ok(data_loc->reader.form.data.size == 1);
- T_Ok(*(U8 *)data_loc->reader.form.data.str == 10);
+ T_Ok(data_loc->form.reader.kind == DW_Form_Data1);
+ T_Ok(data_loc->form.reader.data.size == 1);
+ T_Ok(*(U8 *)data_loc->form.reader.data.str == 10);
DW_WriterAttrib *byte_size = data_loc->next;
T_Ok(byte_size->kind == DW_AttribKind_ByteSize);
- T_Ok(byte_size->reader.form.kind == DW_Form_ImplicitConst);
- T_Ok(byte_size->reader.form.implicit_const == 123);
+ T_Ok(byte_size->form.reader.kind == DW_Form_ImplicitConst);
+ T_Ok(byte_size->form.reader.implicit_const == 123);
}
}
@@ -388,40 +400,40 @@ T_BeginTest(dwarf_writer)
{
DW_WriterAttrib *external = main_tag->first_attrib;
T_Ok(external->kind == DW_AttribKind_External);
- T_Ok(external->reader.form.kind == DW_Form_Flag);
- T_Ok(external->reader.form.flag);
+ T_Ok(external->form.reader.kind == DW_Form_Flag);
+ T_Ok(external->form.reader.flag);
DW_WriterAttrib *prototyped = external->next;
T_Ok(prototyped->kind == DW_AttribKind_Prototyped);
- T_Ok(prototyped->reader.form.kind == DW_Form_Flag);
- T_Ok(prototyped->reader.form.flag);
+ T_Ok(prototyped->form.reader.kind == DW_Form_Flag);
+ T_Ok(prototyped->form.reader.flag);
DW_WriterAttrib *low_pc = prototyped->next;
T_Ok(low_pc->kind == DW_AttribKind_LowPc);
- T_Ok(low_pc->reader.form.kind == DW_Form_Addr);
- T_Ok(low_pc->reader.form.addr.size == sizeof(U64));
- T_Ok(*(U64 *)low_pc->reader.form.addr.str == 0x14012f2f0);
+ 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);
DW_WriterAttrib *high_pc = low_pc->next;
T_Ok(high_pc->kind == DW_AttribKind_HighPc);
- T_Ok(high_pc->reader.form.kind == DW_Form_Addr);
- T_Ok(high_pc->reader.form.addr.size == sizeof(U64));
- T_Ok(*(U64 *)high_pc->reader.form.addr.str == 0x14012f405);
+ 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);
DW_WriterAttrib *name = high_pc->next;
T_Ok(name->kind == DW_AttribKind_Name);
- T_Ok(name->reader.form.kind == DW_Form_String);
- T_Ok(str8_match(name->reader.form.string, str8_lit("main"), 0));
+ T_Ok(name->form.reader.kind == DW_Form_String);
+ T_Ok(str8_match(name->form.reader.string, str8_lit("main"), 0));
DW_WriterAttrib *type = name->next;
T_Ok(type->kind == DW_AttribKind_Type);
- T_Ok(type->reader.form.kind == DW_Form_Ref1);
- T_Ok(type->reader.form.ref == simple_struct_tag->info_off);
+ T_Ok(type->form.reader.kind == DW_Form_Ref1);
+ T_Ok(type->form.reader.ref == simple_struct_tag->info_off);
DW_WriterAttrib *frame_base = type->next;
T_Ok(frame_base->kind == DW_AttribKind_FrameBase);
- T_Ok(frame_base->reader.form.kind == DW_Form_ExprLoc);
- DW_Expr frame_base_expr = dw_expr_from_data(scratch.arena, writer->format, writer->address_size, frame_base->reader.form.exprloc);
+ T_Ok(frame_base->form.reader.kind == DW_Form_ExprLoc);
+ DW_Expr frame_base_expr = dw_expr_from_data(scratch.arena, writer->format, writer->address_size, frame_base->form.reader.exprloc);
T_Ok(frame_base_expr.count == 1);
T_Ok(frame_base_expr.first->opcode == DW_ExprOp_Reg7);
T_Ok(frame_base_expr.first->operands == 0);