mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 17:28:07 +00:00
WIP DWARF writer
This commit is contained in:
+1
-2
@@ -961,6 +961,7 @@ dw_form_match(DW_Form a, DW_Form b)
|
|||||||
|
|
||||||
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
@@ -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 {
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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, §ions[i]->data, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// zero out writer sections
|
||||||
|
MemoryZeroArray(writer->sections);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user