WIP DWARF writer

This commit is contained in:
Nikita Smith
2026-02-10 23:57:43 -08:00
parent ff82d9843c
commit 69434278bd
10 changed files with 1439 additions and 5 deletions
+3 -4
View File
@@ -959,8 +959,9 @@ dw_form_match(DW_Form a, DW_Form b)
switch (a.kind) {
case DW_Form_Null: {} break;
case DW_Form_Addr: { is_match = str8_match(a.addr, b.addr, 0); } break;
case DW_Form_String: { is_match = str8_match(a.string, b.string, 0); } break;
case DW_Form_Addr: { is_match = str8_match(a.addr, b.addr, 0); } break;
case DW_Form_String: { is_match = str8_match(a.string, b.string, 0); } break;
case DW_Form_ExprLoc: { is_match = str8_match(a.exprloc, b.exprloc, 0); } break;
case DW_Form_Block:
case DW_Form_Block1:
@@ -1026,7 +1027,5 @@ dw_form_match(DW_Form a, DW_Form b)
}
return is_match;
return is_match;
}
+1 -1
View File
@@ -494,7 +494,7 @@ typedef enum DW_FormEnum
#undef X
} DW_FormEnum;
typedef union DW_Form
typedef struct DW_Form
{
DW_FormKind kind;
union {
+1
View File
@@ -9,5 +9,6 @@
#include "dwarf/dwarf_unwind.c"
#include "dwarf/dwarf_dump.c"
#include "dwarf/dwarf_help.c"
#include "dwarf/dwarf_writer.c"
#include "dwarf/eh_frame.c"
#include "dwarf/eh_dump.c"
+1
View File
@@ -12,6 +12,7 @@
#include "dwarf/dwarf_unwind.h"
#include "dwarf/dwarf_dump.h"
#include "dwarf/dwarf_help.h"
#include "dwarf/dwarf_writer.h"
#include "dwarf/eh_frame.h"
#include "dwarf/eh_dump.h"
+667
View File
@@ -0,0 +1,667 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal DW_IntEnc
dw_int_enc_from_sint(S64 v)
{
if ((S8)v == v) return DW_IntEnc_1Byte;
if ((S16)v == v) return DW_IntEnc_2Byte;
if ((S32)v == v) return DW_IntEnc_4Byte;
return DW_IntEnc_LEB128;
}
internal DW_IntEnc
dw_int_enc_from_uint(U64 v)
{
if ((U8)v == v) return DW_IntEnc_1Byte;
if ((U16)v == v) return DW_IntEnc_2Byte;
if ((U32)v == v) return DW_IntEnc_4Byte;
return DW_IntEnc_LEB128;
}
internal U64
dw_size_from_sint(S64 v)
{
DW_IntEnc enc = dw_int_enc_from_sint(v);
switch (enc) {
case DW_IntEnc_Null: break;
case DW_IntEnc_1Byte: return 1;
case DW_IntEnc_2Byte: return 2;
case DW_IntEnc_4Byte: return 4;
case DW_IntEnc_LEB128: return dw_size_from_sleb128(v);
default: InvalidPath; break;
}
return 0;
}
internal U64
dw_size_from_uint(U64 v)
{
DW_IntEnc enc = dw_int_enc_from_uint(v);
switch (enc) {
case DW_IntEnc_Null: break;
case DW_IntEnc_1Byte: return 1;
case DW_IntEnc_2Byte: return 2;
case DW_IntEnc_4Byte: return 4;
case DW_IntEnc_LEB128: return dw_size_from_uleb128(v);
default: InvalidPath; break;
}
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)
{
DW_WriterFixupNode *n = push_array(arena, DW_WriterFixupNode, 1);
n->v = v;
SLLQueuePush(list->first, list->last, n);
list->count += 1;
return n;
}
internal DW_WriterAttrib *
dw_writer_attrib_chunk_list_push(Arena *arena, DW_WriterAttribChunkList *list, U64 cap)
{
if (list->last == 0 || list->last->count >= list->last->max) {
DW_WriterAttribChunk *n = push_array(arena, DW_WriterAttribChunk, 1);
n->v = push_array_no_zero(arena, DW_WriterAttrib, cap);
n->max = cap;
SLLQueuePush(list->first, list->last, n);
list->chunk_count += 1;
}
DW_WriterAttrib *result = &list->last->v[list->last->count++];
MemoryZeroStruct(result);
list->total_count += 1;
return result;
}
internal DW_WriterTag *
dw_writer_tag_chunk_list_push(Arena *arena, DW_WriterTagChunkList *list, U64 cap)
{
if (list->last == 0 || list->last->count >= list->last->max) {
DW_WriterTagChunk *n = push_array(arena, DW_WriterTagChunk, 1);
n->v = push_array_no_zero(arena, DW_WriterTag, cap);
n->max = cap;
SLLQueuePush(list->first, list->last, n);
list->chunk_count += 1;
}
DW_WriterTag *result = &list->last->v[list->last->count++];
MemoryZeroStruct(result);
list->total_count += 1;
return result;
}
internal DW_Writer *
dw_writer_begin(DW_Format format, DW_Version version, DW_CompUnitKind cu_kind, Arch arch)
{
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);
for EachElement(i, writer->sections) {
str8_serial_begin(arena, &writer->sections[i].srl);
}
// write .debug_info header
{
String8List *srl = &writer->sections[DW_Section_Info].srl;
// length
writer->sections[DW_Section_Info].length = dw_serial_push_length(writer->arena, srl, writer->format, 0);
// version
str8_serial_push_struct(writer->arena, srl, &writer->version);
// compile unit kind
str8_serial_push_struct(writer->arena, srl, &writer->cu_kind);
// address size
str8_serial_push_u8(writer->arena, srl, (U8)writer->address_size);
// reserve 'abbrev_base'
writer->abbrev_base_info_off = srl->total_size;
dw_serial_push_uint(writer->arena, srl, writer->format, 0);
if (writer->cu_kind == DW_CompUnitKind_Skeleton) {
// TODO: write skeleton id
NotImplemented;
}
}
return writer;
}
internal void
dw_writer_end(DW_Writer **writer_ptr)
{
arena_release((*writer_ptr)->arena);
*writer_ptr = 0;
}
internal String8
dw_make_abbrev_entry(Arena *arena, DW_WriterTag *tag)
{
Temp scratch = scratch_begin(&arena, 1);
String8List srl = {0};
str8_serial_begin(scratch.arena, &srl);
// tag abbrev
B8 has_children = tag->first_child != 0;
dw_serial_push_uleb128(scratch.arena, &srl, tag->kind);
str8_serial_push_string(scratch.arena, &srl, str8_struct(&has_children));
// 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);
}
}
// closing entry
dw_serial_push_uleb128(scratch.arena, &srl, 0);
dw_serial_push_uleb128(scratch.arena, &srl, 0);
String8 tag_abbrev = str8_serial_end(arena, &srl);
scratch_end(scratch);
return tag_abbrev;
}
internal DW_WriterTag *
dw_writer_tag_begin(DW_Writer *writer, DW_TagKind kind)
{
DW_WriterTag *tag = dw_writer_tag_chunk_list_push(writer->arena, &writer->tag_chunk_list, 512);
tag->kind = kind;
tag->parent = writer->current;
// add tag to the tree
if (writer->current) {
SLLQueuePush(writer->current->first_child, writer->current->last_child, tag);
} else {
writer->root = tag;
}
writer->current = tag;
return tag;
}
internal void
dw_writer_tag_end(DW_Writer *writer)
{
// pop to parent
writer->current = writer->current->parent;
}
internal DW_WriterAttrib *
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;
SLLQueuePush(writer->current->first_attrib, writer->current->last_attrib, attrib);
writer->current->attrib_count += 1;
return attrib;
}
internal DW_WriterAttrib *
dw_writer_push_attrib_address(DW_Writer *writer, DW_AttribKind kind, U64 address)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_Address, .address = address });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_block(DW_Writer *writer, DW_AttribKind kind, String8 block)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_Block, .block = str8_copy(writer->arena, block) });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_data(DW_Writer *writer, DW_AttribKind kind, String8 data)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_Data, .data = str8_copy(writer->arena, data) });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_string(DW_Writer *writer, DW_AttribKind kind, String8 string)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_String, .string = string });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_flag(DW_Writer *writer, DW_AttribKind kind, B8 flag)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_Flag, .flag = flag });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_sint(DW_Writer *writer, DW_AttribKind kind, S64 sint)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_SInt, .sint = sint});
}
internal DW_WriterAttrib *
dw_writer_push_attrib_uint(DW_Writer *writer, DW_AttribKind kind, U64 uint)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_UInt, .uint = uint });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_enum(DW_Writer *writer, DW_AttribKind kind, S64 e)
{
return dw_writer_push_attrib_sint(writer, kind, e);
}
internal DW_WriterAttrib *
dw_writer_push_attrib_ref(DW_Writer *writer, DW_AttribKind kind, DW_WriterTag *ref)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_Ref, .ref = ref });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_exprloc(DW_Writer *writer, DW_AttribKind kind, String8 exprloc)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_ExprLoc, .exprloc = str8_copy(writer->arena, exprloc) });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_expression(DW_Writer *writer, DW_AttribKind kind, DW_ExprEnc *encs, U64 encs_count)
{
String8 exprloc = dw_encode_expr(writer->arena, writer->arch, writer->format, encs, encs_count);
return dw_writer_push_attrib_exprloc(writer, kind, exprloc);
}
internal DW_WriterAttrib *
dw_writer_push_attrib_line_ptr(DW_Writer *writer, DW_AttribKind kind, void *line_ptr)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_LinePtr, .line_ptr = line_ptr });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_mac_ptr(DW_Writer *writer, DW_AttribKind kind, void *mac_ptr)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_MacPtr, .mac_ptr = mac_ptr });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_rng_list_ptr(DW_Writer *writer, DW_AttribKind kind, void *rng_list_ptr)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_RngListPtr, .rng_list_ptr = rng_list_ptr });
}
internal DW_WriterAttrib *
dw_writer_push_attrib_implicit(DW_Writer *writer, DW_AttribKind kind, S64 implicit)
{
return dw_writer_push_attrib(writer, kind, (DW_WriterForm){ .kind = DW_WriterFormKind_Implicit, .implicit = implicit });
}
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) {
case DW_WriterFormKind_Null: {} break;
case DW_WriterFormKind_Flag: {
attrib->reader.form.kind = DW_Form_Flag;
attrib->reader.form.flag = attrib->writer.form.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;
case DW_IntEnc_1Byte: {
attrib->reader.form.kind = DW_Form_Data1;
attrib->reader.form.data = str8((U8 *)&attrib->writer.form.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));
} break;
case DW_IntEnc_4Byte: {
attrib->reader.form.kind = DW_Form_Data4;
attrib->reader.form.data = str8((U8 *)&attrib->writer.form.sint, sizeof(U32));
} break;
case DW_IntEnc_LEB128: {
attrib->reader.form.kind = DW_Form_SData;
attrib->reader.form.sdata = attrib->writer.form.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;
} 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));
} break;
case DW_WriterFormKind_Ref: {
if (attrib->writer.form.ref->info_off == 0) {
attrib->reader.form.kind = DW_Form_Ref8;
} else {
switch (dw_int_enc_from_uint(attrib->writer.form.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;
} break;
case DW_IntEnc_2Byte: {
attrib->reader.form.kind = DW_Form_Ref2;
attrib->reader.form.ref = (U16)attrib->writer.form.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;
} break;
case DW_IntEnc_LEB128: {
attrib->reader.form.kind = DW_Form_RefUData;
attrib->reader.form.ref = attrib->writer.form.ref->info_off;
} break;
default: InvalidPath; break;
}
}
} break;
case DW_WriterFormKind_LinePtr: {
NotImplemented;
} break;
case DW_WriterFormKind_MacPtr: {
NotImplemented;
} break;
case DW_WriterFormKind_RngListPtr: {
NotImplemented;
} break;
case DW_WriterFormKind_Data: {
NotImplemented;
} break;
case DW_WriterFormKind_Block: {
attrib->reader.form.block = attrib->writer.form.block;
switch (attrib->writer.form.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;
}
} break;
case DW_WriterFormKind_String: {
attrib->reader.form.kind = DW_Form_String;
attrib->reader.form.string = attrib->writer.form.string;
} break;
case DW_WriterFormKind_ExprLoc: {
attrib->reader.form.kind = DW_Form_ExprLoc;
attrib->reader.form.exprloc = attrib->writer.form.exprloc;
} break;
case DW_WriterFormKind_Implicit: {
attrib->reader.form.kind = DW_Form_ImplicitConst;
attrib->reader.form.implicit_const = attrib->writer.form.implicit;
} break;
default: { InvalidPath; } break;
}
}
}
internal void
dw_writer_emit_tag(DW_Writer *writer, DW_WriterTag *tag)
{
Assert(tag->info_off == 0);
dw_lower_attrib_forms(writer, tag);
// make abbrev id for the tag
U64 abbrev_id;
{
Temp temp = temp_begin(writer->arena);
String8 abbrev_entry = dw_make_abbrev_entry(temp.arena, tag);
if ( ! hash_table_search_string_u64(writer->abbrev_id_map, abbrev_entry, &abbrev_id)) {
abbrev_id = writer->abbrev_id_map->count + 1;
hash_table_push_string_u64(writer->arena, writer->abbrev_id_map, abbrev_entry, abbrev_id);
// push abbrev entry
dw_serial_push_uleb128(writer->arena, &writer->sections[DW_Section_Abbrev].srl, abbrev_id);
str8_serial_push_string(writer->arena, &writer->sections[DW_Section_Abbrev].srl, abbrev_entry);
} else {
temp_end(temp);
}
}
tag->abbrev_id = abbrev_id;
tag->info_off = writer->sections[DW_Section_Info].srl.total_size;
// emit tag abbrev id
dw_serial_push_uleb128(writer->arena, &writer->sections[DW_Section_Info].srl, tag->abbrev_id);
// emit attribs
{
String8List *debug_info = &writer->sections[DW_Section_Info].srl;
for EachNode(attrib, DW_WriterAttrib, tag->first_attrib) {
switch (attrib->reader.form.kind) {
case DW_Form_Addr: {
str8_serial_push_string(writer->arena, debug_info, attrib->reader.form.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);
} 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);
} break;
case DW_Form_String: {
str8_serial_push_cstr(writer->arena, debug_info, attrib->reader.form.string);
} break;
case DW_Form_Flag: {
str8_serial_push_u8(writer->arena, debug_info, attrib->reader.form.flag);
} break;
case DW_Form_SData: {
dw_serial_push_sleb128(writer->arena, debug_info, attrib->reader.form.sdata);
} break;
case DW_Form_Strp: {
dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.sec_offset);
} break;
case DW_Form_UData: {
dw_serial_push_uleb128(writer->arena, debug_info, attrib->reader.form.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));
} else {
dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.ref);
}
} break;
case DW_Form_Ref1: {
str8_serial_push_u8(writer->arena, debug_info, (U8)attrib->reader.form.ref);
} break;
case DW_Form_Ref2: {
str8_serial_push_u16(writer->arena, debug_info, (U16)attrib->reader.form.ref);
} break;
case DW_Form_Ref4: {
str8_serial_push_u32(writer->arena, debug_info, (U32)attrib->reader.form.ref);
} break;
case DW_Form_Ref8: {
if (attrib->writer.form.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 });
}
} break;
case DW_Form_RefUData: {
dw_serial_push_uleb128(writer->arena, debug_info, attrib->reader.form.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);
} 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);
} 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(writer->arena, debug_info, attrib->reader.form.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);
} break;
case DW_Form_Data16: {
str8_serial_push_string(writer->arena, debug_info, attrib->reader.form.data);
} break;
case DW_Form_LineStrp: {
dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.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(writer->arena, debug_info, (U8)attrib->reader.form.xval);
} break;
case DW_Form_Strx2:
case DW_Form_Addrx2: {
str8_serial_push_u16(writer->arena, debug_info, (U16)attrib->reader.form.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));
} break;
case DW_Form_Strx4:
case DW_Form_Addrx4: {
str8_serial_push_u32(writer->arena, debug_info, (U32)attrib->reader.form.xval);
} break;
case DW_Form_GNU_StrpAlt: {
dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.sec_offset);
} break;
case DW_Form_GNU_RefAlt: {
dw_serial_push_uint(writer->arena, debug_info, writer->format, attrib->reader.form.ref);
} break;
default: InvalidPath; break;
}
}
}
// write children
for EachNode(child, DW_WriterTag, tag->first_child) {
dw_writer_emit_tag(writer, child);
}
// close tag
if (tag->first_child) {
dw_serial_push_uleb128(writer->arena, &writer->sections[DW_Section_Info].srl, 0);
}
}
internal void
dw_writer_emit(DW_Writer *writer)
{
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) {
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;
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;
}
}
}
#ifdef OBJ_H
internal void
dw_writer_emit_to_obj(DW_Writer *writer, OBJ *obj)
{
dw_writer_emit(writer);
// push obj sections
OBJ_Section *sections[DW_Section_Count] = {0};
for EachElement(i, writer->sections) {
if (writer->sections[i].srl.total_size) {
sections[i] = obj_push_section(obj, dw_name_string_from_section_kind(i), OBJ_SectionFlag_Read|OBJ_SectionFlag_Write);
}
}
// push OBJ relocation for 'abbrev base'
OBJ_Section *debug_info = sections[DW_Section_Info];
obj_push_reloc(obj, debug_info, OBJ_RelocKind_SecRel, writer->abbrev_base_info_off, sections[DW_Section_Abbrev]->symbol);
// copy section data from writer to obj
for EachElement(i, writer->sections) {
if (writer->sections[i].srl.total_size > 0) {
String8 data = str8_serial_end(obj->arena, &writer->sections[i].srl);
str8_list_push(obj->arena, &sections[i]->data, data);
}
}
// zero out writer sections
MemoryZeroArray(writer->sections);
}
#endif
+209
View File
@@ -0,0 +1,209 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_WRITER_H
#define DWARF_WRITER_H
////////////////////////////////
typedef enum
{
DW_IntEnc_Null,
DW_IntEnc_1Byte,
DW_IntEnc_2Byte,
DW_IntEnc_4Byte,
DW_IntEnc_LEB128,
} DW_IntEnc;
////////////////////////////////
typedef enum
{
DW_WriterFormKind_Null,
DW_WriterFormKind_Flag,
DW_WriterFormKind_SInt,
DW_WriterFormKind_UInt,
DW_WriterFormKind_Address,
DW_WriterFormKind_Ref,
DW_WriterFormKind_LinePtr,
DW_WriterFormKind_MacPtr,
DW_WriterFormKind_RngListPtr,
DW_WriterFormKind_Data,
DW_WriterFormKind_Block,
DW_WriterFormKind_String,
DW_WriterFormKind_ExprLoc,
DW_WriterFormKind_Implicit,
} DW_WriterFormKind;
typedef struct DW_WriterForm
{
DW_WriterFormKind kind;
union {
B8 flag;
S64 sint;
U64 uint;
U64 address;
S64 implicit;
union {
struct {
struct DW_WriterTag *ref;
void *line_ptr;
void *mac_ptr;
void *rng_list_ptr;
};
struct {
U64 ref_offset;
U64 line_offset;
U64 mac_ptr_offset;
U64 rng_list_offset;
};
};
String8 data;
String8 block;
String8 string;
String8 exprloc;
};
} DW_WriterForm;
typedef struct DW_WriterAttrib
{
DW_AttribKindEnum kind;
struct {
DW_WriterForm form;
} writer;
struct {
DW_Form form;
} reader;
struct DW_WriterAttrib *next;
} DW_WriterAttrib;
typedef struct DW_WriterTag
{
DW_TagKindEnum kind;
struct DW_WriterTag *next;
struct DW_WriterTag *parent;
struct DW_WriterTag *first_child;
struct DW_WriterTag *last_child;
U64 attrib_count;
U64 abbrev_id;
U64 info_off;
DW_WriterAttrib *first_attrib;
DW_WriterAttrib *last_attrib;
} DW_WriterTag;
typedef struct DW_WriterTagChunk
{
U64 count;
U64 max;
DW_WriterTag *v;
struct DW_WriterTagChunk *next;
} DW_WriterTagChunk;
typedef struct DW_WriterTagChunkList
{
U64 chunk_count;
U64 total_count;
DW_WriterTagChunk *first;
DW_WriterTagChunk *last;
} DW_WriterTagChunkList;
typedef struct DW_WriterAttribChunk
{
U64 count;
U64 max;
DW_WriterAttrib *v;
struct DW_WriterAttribChunk *next;
} DW_WriterAttribChunk;
typedef struct DW_WriterAttribChunkList
{
U64 chunk_count;
U64 total_count;
DW_WriterAttribChunk *first;
DW_WriterAttribChunk *last;
} DW_WriterAttribChunkList;
typedef struct DW_WriterFixup
{
struct DW_WriterAttrib *attrib;
U8 *value;
} DW_WriterFixup;
typedef struct DW_WriterFixupNode
{
DW_WriterFixup v;
struct DW_WriterFixupNode *next;
} DW_WriterFixupNode;
typedef struct DW_WriterFixupList
{
U64 count;
DW_WriterFixupNode *first;
DW_WriterFixupNode *last;
} DW_WriterFixupList;
typedef struct DW_WriterSection
{
void *length;
String8List srl;
} DW_WriterSection;
typedef struct DW_Writer
{
Arena *arena;
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;
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);
////////////////////////////////
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 DW_WriterTag * dw_writer_tag_begin(DW_Writer *writer, DW_TagKind kind);
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 );
internal DW_WriterAttrib * dw_writer_push_attrib_block (DW_Writer *writer, DW_AttribKind kind, String8 block );
internal DW_WriterAttrib * dw_writer_push_attrib_data (DW_Writer *writer, DW_AttribKind kind, String8 data );
internal DW_WriterAttrib * dw_writer_push_attrib_string (DW_Writer *writer, DW_AttribKind kind, String8 string );
internal DW_WriterAttrib * dw_writer_push_attrib_flag (DW_Writer *writer, DW_AttribKind kind, B8 flag );
internal DW_WriterAttrib * dw_writer_push_attrib_sint (DW_Writer *writer, DW_AttribKind kind, S64 sint );
internal DW_WriterAttrib * dw_writer_push_attrib_uint (DW_Writer *writer, DW_AttribKind kind, U64 uint );
internal DW_WriterAttrib * dw_writer_push_attrib_enum (DW_Writer *writer, DW_AttribKind kind, S64 e );
internal DW_WriterAttrib * dw_writer_push_attrib_ref (DW_Writer *writer, DW_AttribKind kind, DW_WriterTag *ref );
internal DW_WriterAttrib * dw_writer_push_attrib_exprloc (DW_Writer *writer, DW_AttribKind kind, String8 exprloc );
internal DW_WriterAttrib * dw_writer_push_attrib_line_ptr (DW_Writer *writer, DW_AttribKind kind, void * line_ptr );
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 );
internal void dw_writer_emit(DW_Writer *writer);
#ifdef OBJ_H
internal void dw_writer_emit_to_obj(DW_Writer *writer, OBJ *obj);
#endif
#endif // DWARF_WRITER_H