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) { switch (a.kind) {
case DW_Form_Null: {} break; case DW_Form_Null: {} break;
case DW_Form_Addr: { is_match = str8_match(a.addr, b.addr, 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_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_Block:
case DW_Form_Block1: case DW_Form_Block1:
@@ -1026,7 +1027,5 @@ dw_form_match(DW_Form a, DW_Form b)
} }
return is_match; return is_match;
return is_match;
} }
+1 -1
View File
@@ -494,7 +494,7 @@ typedef enum DW_FormEnum
#undef X #undef X
} DW_FormEnum; } DW_FormEnum;
typedef union DW_Form typedef struct DW_Form
{ {
DW_FormKind kind; DW_FormKind kind;
union { union {
+1
View File
@@ -9,5 +9,6 @@
#include "dwarf/dwarf_unwind.c" #include "dwarf/dwarf_unwind.c"
#include "dwarf/dwarf_dump.c" #include "dwarf/dwarf_dump.c"
#include "dwarf/dwarf_help.c" #include "dwarf/dwarf_help.c"
#include "dwarf/dwarf_writer.c"
#include "dwarf/eh_frame.c" #include "dwarf/eh_frame.c"
#include "dwarf/eh_dump.c" #include "dwarf/eh_dump.c"
+1
View File
@@ -12,6 +12,7 @@
#include "dwarf/dwarf_unwind.h" #include "dwarf/dwarf_unwind.h"
#include "dwarf/dwarf_dump.h" #include "dwarf/dwarf_dump.h"
#include "dwarf/dwarf_help.h" #include "dwarf/dwarf_help.h"
#include "dwarf/dwarf_writer.h"
#include "dwarf/eh_frame.h" #include "dwarf/eh_frame.h"
#include "dwarf/eh_dump.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
+68
View File
@@ -0,0 +1,68 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal OBJ *
obj_alloc(U64 time_stamp, Arch arch)
{
Arena *arena = arena_alloc();
OBJ *obj = push_array(arena, OBJ, 1);
obj->arena = arena;
obj->time_stamp = time_stamp;
obj->arch = arch;
return obj;
}
internal void
obj_release(OBJ **obj_ptr)
{
arena_release((*obj_ptr)->arena);
*obj_ptr = 0;
}
internal OBJ_Symbol *
obj_push_symbol(OBJ *obj, String8 name, OBJ_SymbolScope scope, OBJ_RefKind ref_kind, void *ref)
{
OBJ_SymbolNode *n = push_array(obj->arena, OBJ_SymbolNode, 1);
SLLQueuePush(obj->symbols.first, obj->symbols.last, n);
obj->symbols.count += 1;
OBJ_Symbol *v = &n->v;
v->name = push_str8_copy(obj->arena, name);
v->scope = scope;
v->ref_kind = ref_kind;
v->ref = ref;
return v;
}
internal OBJ_Section *
obj_push_section(OBJ *obj, String8 name, OBJ_SectionFlags flags)
{
OBJ_SectionNode *n = push_array(obj->arena, OBJ_SectionNode, 1);
SLLQueuePush(obj->sections.first, obj->sections.last, n);
obj->sections.count += 1;
OBJ_Section *v = &n->v;
v->name = push_str8_copy(obj->arena, name);
v->flags = flags;
v->symbol = obj_push_symbol(obj, name, OBJ_SymbolScope_Local, OBJ_RefKind_Section, v);
str8_serial_begin(obj->arena, &v->data);
return v;
}
internal OBJ_Reloc *
obj_push_reloc(OBJ *obj, OBJ_Section *sec, OBJ_RelocKind kind, U64 offset, OBJ_Symbol *symbol)
{
OBJ_RelocNode *n = push_array(obj->arena, OBJ_RelocNode, 1);
SLLQueuePush(sec->relocs.first, sec->relocs.last, n);
sec->relocs.count += 1;
OBJ_Reloc *v = &n->v;
v->kind = kind;
v->offset = offset;
v->symbol = symbol;
return v;
}
+115
View File
@@ -0,0 +1,115 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef OBJ_H
#define OBJ_H
typedef enum
{
OBJ_RefKind_Null,
OBJ_RefKind_Section,
} OBJ_RefKind;
typedef enum
{
OBJ_SymbolScope_Null,
OBJ_SymbolScope_Local,
OBJ_SymbolScope_Global,
} OBJ_SymbolScope;
typedef struct OBJ_Symbol
{
String8 name;
OBJ_SymbolScope scope;
OBJ_RefKind ref_kind;
void *ref;
} OBJ_Symbol;
typedef struct OBJ_SymbolNode
{
OBJ_Symbol v;
struct OBJ_SymbolNode *next;
} OBJ_SymbolNode;
typedef struct OBJ_SymbolList
{
U64 count;
OBJ_SymbolNode *first;
OBJ_SymbolNode *last;
} OBJ_SymbolList;
typedef enum
{
OBJ_RelocKind_Null,
OBJ_RelocKind_SecRel,
} OBJ_RelocKind;
typedef struct OBJ_Reloc
{
OBJ_RelocKind kind;
U64 offset;
OBJ_Symbol *symbol;
} OBJ_Reloc;
typedef struct OBJ_RelocNode
{
OBJ_Reloc v;
struct OBJ_RelocNode *next;
} OBJ_RelocNode;
typedef struct OBJ_RelocList
{
U64 count;
OBJ_RelocNode *first;
OBJ_RelocNode *last;
} OBJ_RelocList;
typedef enum OBJ_SectionFlags
{
OBJ_SectionFlag_Read = (1 << 0),
OBJ_SectionFlag_Write = (1 << 1),
OBJ_SectionFlag_Exec = (1 << 2),
OBJ_SectionFlag_Load = (1 << 3),
} OBJ_SectionFlags;
typedef struct OBJ_Section
{
String8 name;
String8List data;
OBJ_SectionFlags flags;
OBJ_RelocList relocs;
OBJ_Symbol *symbol;
} OBJ_Section;
typedef struct OBJ_SectionNode
{
OBJ_Section v;
struct OBJ_SectionNode *next;
} OBJ_SectionNode;
typedef struct OBJ_SectionList
{
U64 count;
OBJ_SectionNode *first;
OBJ_SectionNode *last;
} OBJ_SectionList;
typedef struct OBJ
{
Arena *arena;
U64 time_stamp;
Arch arch;
OBJ_SectionList sections;
OBJ_SymbolList symbols;
} OBJ;
////////////////////////////////
internal OBJ * obj_alloc(U64 time_stamp, Arch arch);
internal void obj_release(OBJ **obj_ptr);
internal OBJ_Symbol * obj_push_symbol(OBJ *obj, String8 name, OBJ_SymbolScope scope, OBJ_RefKind ref_kind, void *ref);
internal OBJ_Section * obj_push_section(OBJ *obj, String8 name, OBJ_SectionFlags flags);
internal OBJ_Reloc * obj_push_reloc(OBJ *obj, OBJ_Section *sec, OBJ_RelocKind kind, U64 offset, OBJ_Symbol *symbol);
#endif // OBJ_H
+372
View File
@@ -64,6 +64,378 @@ T_BeginTest(test_leb128)
} }
T_EndTest; T_EndTest;
internal B32
dwt_tags_must_match(DW_WriterTag *writer_tag, DW_TagNode *reader_tag)
{
B32 is_match = 0;
// match headers
B32 writer_has_children = writer_tag->first_child != 0;
if (writer_tag->kind != reader_tag->tag.kind) { goto exit; }
if (writer_tag->abbrev_id != reader_tag->tag.abbrev_id) { goto exit; }
if (writer_tag->attrib_count != reader_tag->tag.attribs.count) { goto exit; }
if (writer_tag->info_off != reader_tag->tag.info_off) { goto exit; }
if (writer_has_children != reader_tag->tag.has_children) { goto exit; }
// match attribs
DW_WriterAttrib *writer_attrib = writer_tag->first_attrib;
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; }
writer_attrib = writer_attrib->next;
reader_attrib = reader_attrib->next;
}
// visit children
DW_WriterTag *writer_child = writer_tag->first_child;
DW_TagNode *reader_child = reader_tag->first_child;
while (writer_child) {
if ( ! dwt_tags_must_match(writer_child, reader_child)) { goto exit; }
writer_child = writer_child->next;
reader_child = reader_child->sibling;
}
is_match = 1;
exit:;
return is_match;
}
internal DW_Writer *
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);
{
dw_writer_tag_begin(writer, DW_TagKind_CompileUnit);
dw_writer_push_attrib_string(writer, DW_AttribKind_Producer, str8_lit(BUILD_TITLE_STRING_LITERAL));
dw_writer_push_attrib_enum(writer, DW_AttribKind_Language, DW_Language_C99);
dw_writer_push_attrib_flag(writer, DW_AttribKind_UseUtf8, 1);
{
DW_WriterTag *char_type = dw_writer_tag_begin(writer, DW_TagKind_BaseType);
dw_writer_push_attrib_sint(writer, DW_AttribKind_ByteSize, 1);
dw_writer_push_attrib_enum(writer, DW_AttribKind_Encoding, DW_ATE_SignedChar);
dw_writer_push_attrib_string(writer, DW_AttribKind_Name, str8_lit("char"));
dw_writer_tag_end(writer);
dw_writer_tag_begin(writer, DW_TagKind_ConstType);
dw_writer_push_attrib_ref(writer, DW_AttribKind_Type, char_type);
dw_writer_tag_end(writer);
// test abbrev dedup
DW_WriterTag *dup_char_type = dw_writer_tag_begin(writer, DW_TagKind_BaseType);
dw_writer_push_attrib_sint(writer, DW_AttribKind_ByteSize, 1);
dw_writer_push_attrib_enum(writer, DW_AttribKind_Encoding, DW_ATE_SignedChar);
dw_writer_push_attrib_string(writer, DW_AttribKind_Name, str8_lit("char"));
dw_writer_tag_end(writer);
// simple struct test
DW_WriterTag *simple_struct_tag = dw_writer_tag_begin(writer, DW_TagKind_StructureType);
dw_writer_push_attrib_string(writer, DW_AttribKind_Name, str8_lit("FooBar"));
dw_writer_push_attrib_uint(writer, DW_AttribKind_ByteSize, 90);
{
dw_writer_tag_begin(writer, DW_TagKind_Member);
dw_writer_push_attrib_string(writer, DW_AttribKind_Name, str8_lit("m0"));
dw_writer_push_attrib_ref(writer, DW_AttribKind_Type, char_type);
dw_writer_push_attrib_sint(writer, DW_AttribKind_DataMemberLocation, 0);
dw_writer_tag_end(writer);
dw_writer_tag_begin(writer, DW_TagKind_Member);
dw_writer_push_attrib_string(writer, DW_AttribKind_Name, str8_lit("m1"));
dw_writer_push_attrib_ref(writer, DW_AttribKind_Type, char_type);
dw_writer_push_attrib_sint(writer, DW_AttribKind_DataMemberLocation, 10);
dw_writer_push_attrib_implicit(writer, DW_AttribKind_ByteSize, 123);
dw_writer_tag_end(writer);
}
dw_writer_tag_end(writer);
dw_writer_tag_begin(writer, DW_TagKind_SubProgram);
dw_writer_push_attrib_flag(writer, DW_AttribKind_External, 1);
dw_writer_push_attrib_flag(writer, DW_AttribKind_Prototyped, 1);
dw_writer_push_attrib_address(writer, DW_AttribKind_LowPc, 0x14012f2f0);
dw_writer_push_attrib_address(writer, DW_AttribKind_HighPc, 0x14012f405);
dw_writer_push_attrib_string(writer, DW_AttribKind_Name, str8_lit("main"));
dw_writer_push_attrib_ref(writer, DW_AttribKind_Type, simple_struct_tag);
dw_writer_push_attrib_expression(writer, DW_AttribKind_FrameBase, &(DW_ExprEnc)DW_ExprEnc_Op(Reg7), 1);
dw_writer_tag_end(writer);
}
dw_writer_tag_end(writer);
}
{
DW_Input input;
{
OBJ *obj = obj_alloc(0, Arch_x64);
OBJ_Section *text_section = obj_push_section(obj, str8_lit(".text"), OBJ_SectionFlag_Read|OBJ_SectionFlag_Exec|OBJ_SectionFlag_Load);
str8_serial_push_u8(obj->arena, &text_section->data, 0xc3);
obj_push_symbol(obj, str8_lit("entry"), OBJ_SymbolScope_Global, OBJ_RefKind_Section, text_section);
dw_writer_emit_to_obj(writer, obj);
String8 raw_coff = coff_from_obj(scratch.arena, obj);
COFF_FileHeaderInfo obj_coff_header = coff_file_header_info_from_data(raw_coff);
String8 raw_sections = str8_substr(raw_coff, obj_coff_header.section_table_range);
U64 section_count = raw_sections.size / sizeof(COFF_SectionHeader);
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_sections.str;
String8 string_table = str8_substr(raw_coff, obj_coff_header.string_table_range);
input = dw_input_from_coff_section_table(scratch.arena, raw_coff, string_table, section_count, section_table);
t_write_file(str8_lit("dwarf.obj"), raw_coff);
obj_release(&obj);
}
DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input);
DW_CompUnit cu = dw_cu_from_info_off(scratch.arena, &input, lu_input, 0, 1);
DW_TagTree tag_tree = dw_tag_tree_from_cu(scratch.arena, &input, &cu);
AssertAlways(dwt_tags_must_match(writer->root, tag_tree.root));
}
scratch_end(scratch);
return writer;
}
T_BeginTest(dwarf_writer)
{
DW_Writer *writer = dwt_make_writer();
// validate the writer
T_Ok(writer->current == 0);
T_Ok(writer->format == DW_Format_32Bit);
T_Ok(writer->cu_kind == DW_CompUnitKind_Compile);
T_Ok(writer->version == DW_Version_5);
T_Ok(writer->address_size == 8);
T_Ok(writer->abbrev_base_info_off == 8);
T_Ok(writer->fixups.count == 0);
T_Ok(writer->abbrev_id_map->count == 7);
DW_WriterTag *comp_unit_tag = writer->root;
{
T_Ok(comp_unit_tag->kind == DW_TagKind_CompileUnit);
T_Ok(comp_unit_tag->next == 0);
T_Ok(comp_unit_tag->parent == 0);
T_Ok(comp_unit_tag->attrib_count == 3);
T_Ok(comp_unit_tag->abbrev_id == 1);
T_Ok(comp_unit_tag->info_off == 0xc);
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(BUILD_TITLE_STRING_LITERAL), 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);
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);
}
DW_WriterTag *char_type_tag = comp_unit_tag->first_child;
{
T_Ok(char_type_tag->kind == DW_TagKind_BaseType);
T_Ok(char_type_tag->next != 0);
T_Ok(char_type_tag->parent == comp_unit_tag);
T_Ok(char_type_tag->attrib_count == 3);
T_Ok(char_type_tag->abbrev_id == 2);
T_Ok(char_type_tag->info_off == 0x4d);
T_Ok(char_type_tag->first_attrib != char_type_tag->last_attrib);
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);
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);
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));
}
DW_WriterTag *const_type_tag = char_type_tag->next;
{
T_Ok(const_type_tag->kind == DW_TagKind_ConstType);
T_Ok(const_type_tag->next != 0);
T_Ok(const_type_tag->parent == comp_unit_tag);
T_Ok(const_type_tag->attrib_count == 1);
T_Ok(const_type_tag->abbrev_id == 3);
T_Ok(const_type_tag->info_off == 0x55);
T_Ok(const_type_tag->first_attrib && const_type_tag->first_attrib == const_type_tag->last_attrib);
DW_WriterAttrib *type_attrib = const_type_tag->first_attrib;
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);
}
DW_WriterTag *dup_char_type_tag = const_type_tag->next;
{
T_Ok(dup_char_type_tag->kind == DW_TagKind_BaseType);
T_Ok(dup_char_type_tag->next != 0);
T_Ok(dup_char_type_tag->parent == comp_unit_tag);
T_Ok(dup_char_type_tag->attrib_count == 3);
T_Ok(dup_char_type_tag->abbrev_id == 2);
T_Ok(dup_char_type_tag->info_off == 0x57);
T_Ok(dup_char_type_tag->first_attrib != dup_char_type_tag->last_attrib);
DW_WriterAttrib *byte_size_attrib = dup_char_type_tag->first_attrib;
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);
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);
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));
}
DW_WriterTag *simple_struct_tag = dup_char_type_tag->next;
{
T_Ok(simple_struct_tag->kind == DW_TagKind_StructureType);
T_Ok(simple_struct_tag->next != 0);
T_Ok(simple_struct_tag->parent == comp_unit_tag);
T_Ok(simple_struct_tag->attrib_count == 2);
T_Ok(simple_struct_tag->abbrev_id == 4);
T_Ok(simple_struct_tag->info_off == 0x5f);
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));
DW_WriterTag *m0_tag = simple_struct_tag->first_child;
{
T_Ok(m0_tag->kind == DW_TagKind_Member);
T_Ok(m0_tag->parent == simple_struct_tag);
T_Ok(m0_tag->attrib_count == 3);
T_Ok(m0_tag->info_off == 0x68);
T_Ok(m0_tag->abbrev_id == 5);
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));
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 == 0x4d);
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);
}
DW_WriterTag *m1_tag = m0_tag->next;
{
T_Ok(m1_tag->kind == DW_TagKind_Member);
T_Ok(m1_tag->parent == simple_struct_tag);
T_Ok(m1_tag->attrib_count == 4);
T_Ok(m1_tag->info_off == 0x6e);
T_Ok(m1_tag->abbrev_id == 6);
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));
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 == 0x4d);
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);
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);
}
}
DW_WriterTag *main_tag = simple_struct_tag->next;
T_Ok(main_tag->next == 0);
T_Ok(main_tag->kind == DW_TagKind_SubProgram);
T_Ok(main_tag->parent == main_tag->parent);
T_Ok(main_tag->abbrev_id == 7);
{
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);
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);
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);
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);
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));
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);
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_expr.count == 1);
T_Ok(frame_base_expr.first->opcode == DW_ExprOp_Reg7);
T_Ok(frame_base_expr.first->operands == 0);
T_Ok(frame_base_expr.first->size == 1);
T_Ok(frame_base_expr.first->next == 0);
T_Ok(frame_base_expr.first->prev == 0);
}
dw_writer_end(&writer);
}
T_EndTest;
T_BeginTest(value_in_register) T_BeginTest(value_in_register)
{ {
// setup register context // setup register context
+2
View File
@@ -11,6 +11,7 @@
#include "base/base_inc.h" #include "base/base_inc.h"
#include "os/os_inc.h" #include "os/os_inc.h"
#include "obj/obj.h"
#include "linker/base_ext/base_core.h" #include "linker/base_ext/base_core.h"
#include "linker/base_ext/base_arena.h" #include "linker/base_ext/base_arena.h"
#include "linker/base_ext/base_arrays.h" #include "linker/base_ext/base_arrays.h"
@@ -34,6 +35,7 @@
#include "base/base_inc.c" #include "base/base_inc.c"
#include "os/os_inc.c" #include "os/os_inc.c"
#include "obj/obj.c"
#include "linker/hash_table.c" #include "linker/hash_table.c"
#include "linker/base_ext/base_core.c" #include "linker/base_ext/base_core.c"
#include "linker/base_ext/base_arena.c" #include "linker/base_ext/base_arena.c"