checkpoint: basic line emission

This commit is contained in:
Nikita Smith
2026-02-20 11:17:12 -08:00
parent a6dd529dd5
commit cfe3cde396
7 changed files with 853 additions and 210 deletions
+1
View File
@@ -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 \
+587 -90
View File
@@ -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)
{
@@ -118,11 +110,14 @@ dw_writer_begin(DW_Format format, DW_Version version, DW_CompUnitKind cu_kind, A
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;
@@ -640,12 +928,223 @@ dw_writer_emit_tag(DW_Writer *writer, DW_WriterTag *tag)
internal void
dw_writer_emit(DW_Writer *writer)
{
// line
{
// push line table terminator
dw_line_inst_list_push(writer->arena, &writer->line.line_insts, DW_LNE_end_sequence());
// 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);
}
}
// 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);
dw_serial_push_uleb128(writer->arena, &writer->sections[DW_Section_Abbrev].srl, 0);
// fixup units lengths
for EachElement(i, writer->sections) {
@@ -667,10 +1166,8 @@ dw_writer_emit(DW_Writer *writer)
// 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;
Assert(fixup->tag->info_off != 0);
MemoryCopy(fixup->ptr, &fixup->tag->info_off, sizeof(U64));
}
}
}
+147 -26
View File
@@ -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,36 +200,65 @@ 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);
////////////////////////////////
// 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);
@@ -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
+9
View File
@@ -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;
}
+4 -2
View File
@@ -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 * 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);
+1
View File
@@ -154,6 +154,7 @@
<AlternativeType Name="COFF_LibWriterMemberList"/>
<AlternativeType Name="PE_BaseRelocBlockList"/>
<AlternativeType Name="DW_Expr"/>
<AlternativeType Name="DW_LineInstList"/>
<DisplayString>{{ count={count} first={first} }} </DisplayString>
<Expand>
<Item Name="[count]">count</Item>
+74 -62
View File
@@ -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);