dwarf parse/expr/unwind/dump 2 -> 1; move old stuff to obsolete

This commit is contained in:
Ryan Fleury
2026-06-02 12:11:14 -07:00
parent ef5fc82e9c
commit a2700de35d
27 changed files with 11634 additions and 11635 deletions
File diff suppressed because it is too large Load Diff
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_DUMP_H
#define DWARF_DUMP_H
typedef enum
{
DW_DumperCacheFlag_InfoRanges = (1 << 0),
DW_DumperCacheFlag_CuArr = (1 << 1),
DW_DumperCacheFlag_LineVmMap = (1 << 2),
DW_DumperCacheFlag_TagTrees = (1 << 3),
} DW_DumperCacheFlags;
typedef struct DW_Dumper
{
Arena *arena;
Arch arch;
B32 is_relaxed;
B32 is_verbose;
DW_Raw *input;
DW_DumperCacheFlags cache_flags;
struct {
Rng1U64Array info_ranges;
DW_CompUnit *cu_arr;
HashTable *line_vm_map;
DW_TagTree *tag_trees;
} cache;
} DW_Dumper;
#define DW_PRINTER(name) void name(Arena *arena, String8List *strings, int indent, DW_Dumper *dumper)
typedef DW_PRINTER(DW_Printer);
////////////////////////////////
// cache
internal Rng1U64Array dw_get_info_ranges(DW_Dumper *dumper);
internal DW_CompUnit * dw_get_cu_arr(DW_Dumper *dumper);
internal HashTable * dw_get_line_vm_map(DW_Dumper *dumper);
internal DW_TagTree * dw_get_tag_trees(DW_Dumper *dumper);
////////////////////////////////
//~ rjf: Stringification Helpers
internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program);
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal String8 dw_string_from_reg_off (Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off);
internal String8 dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
internal String8 dw_string_from_expression (Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal String8 dw_string_from_cfa (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa);
internal String8 dw_string_from_cfi_row (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row);
#if 0
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx);
internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges, Arch arch);
internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges);
internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Raw *input);
#endif
////////////////////////////////
//~ rjf: Dump Entry Point
internal String8List dw_dump_list_from_sections(Arena *arena, DW_Raw *input, Arch arch, DW_SectionFlags dump_sections, B32 is_verbose);
#endif // DWARF_DUMP_H
File diff suppressed because it is too large Load Diff
+233
View File
@@ -0,0 +1,233 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_EXPR_H
#define DWARF_EXPR_H
////////////////////////////////
// evaluator
#define DW_ExprValueType_IsSigned(x) ((x) == DW_ExprValueType_S8 || (x) == DW_ExprValueType_S16 || (x) == DW_ExprValueType_S32 || (x) == DW_ExprValueType_S64 || (x) == DW_ExprValueType_S128 || (x) == DW_ExprValueType_S256 || (x) == DW_ExprValueType_S512)
#define DW_ExprValueType_IsUnsigned(x) ((x) == DW_ExprValueType_U8 || (x) == DW_ExprValueType_U16 || (x) == DW_ExprValueType_U32 || (x) == DW_ExprValueType_U64 || (x) == DW_ExprValueType_U128 || (x) == DW_ExprValueType_U256 || (x) == DW_ExprValueType_U512)
#define DW_ExprValueType_IsFloat(x) ((x) == DW_ExprValueType_F32 || (x) == DW_ExprValueType_F64)
#define DW_ExprValueType_IsInt(x) (DW_ExprValueType_IsSigned(x) || DW_ExprValueType_IsUnsigned(x) || (x) == DW_ExprValueType_Addr)
typedef enum
{
DW_ExprValueType_Generic,
DW_ExprValueType_U8,
DW_ExprValueType_U16,
DW_ExprValueType_U32,
DW_ExprValueType_U64,
DW_ExprValueType_U128,
DW_ExprValueType_U256,
DW_ExprValueType_U512,
DW_ExprValueType_S8,
DW_ExprValueType_S16,
DW_ExprValueType_S32,
DW_ExprValueType_S64,
DW_ExprValueType_S128,
DW_ExprValueType_S256,
DW_ExprValueType_S512,
DW_ExprValueType_F32,
DW_ExprValueType_F64,
DW_ExprValueType_Addr,
DW_ExprValueType_Implicit,
DW_ExprValueType_Bool,
} DW_ExprValueType;
typedef S8 DW_ExprBool;
typedef struct DW_ExprValue
{
DW_ExprValueType type;
Rng1U64Array ranges;
U64 *offsets;
union {
U8 u8;
U16 u16;
U32 u32;
U64 u64;
U128 u128;
U256 u256;
U512 u512;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
F32 f32;
F64 f64;
U64 addr;
DW_ExprBool boolean;
String8 implicit;
String8 generic;
};
} DW_ExprValue;
typedef struct DW_ExprValueNode
{
DW_ExprValue v;
struct DW_ExprValueNode *next;
} DW_ExprValueNode;
typedef enum
{
DW_PieceKind_Null,
DW_PieceKind_Value,
DW_PieceKind_Undefined,
} DW_PieceKind;
typedef struct DW_Piece
{
DW_PieceKind kind;
U64 bit_size;
U8 *value;
} DW_Piece;
typedef struct DW_PieceNode
{
DW_Piece v;
struct DW_PieceNode *next;
} DW_PieceNode;
typedef struct DW_PieceList
{
U64 count;
DW_PieceNode *first;
DW_PieceNode *last;
} DW_PieceList;
typedef struct DW_ExprStack
{
U64 count;
DW_ExprValueNode *top;
} DW_ExprStack;
typedef enum
{
DW_ExprEvalResult_Fail,
DW_ExprEvalResult_Ok,
DW_ExprEvalResult_Maybe,
DW_ExprEvalResult_ExecOpLimitReached,
} DW_ExprEvalResult;
////////////////////////////////
// encoder
typedef enum
{
DW_ExprEncType_Null,
DW_ExprEncType_Op,
DW_ExprEncType_U8,
DW_ExprEncType_U16,
DW_ExprEncType_U32,
DW_ExprEncType_U64,
DW_ExprEncType_S8,
DW_ExprEncType_S16,
DW_ExprEncType_S32,
DW_ExprEncType_S64,
DW_ExprEncType_ULEB128,
DW_ExprEncType_SLEB128,
DW_ExprEncType_Addr,
DW_ExprEncType_Block,
DW_ExprEncType_DwarfUInt,
DW_ExprEncType_Label,
DW_ExprEncType_DeclLabel,
} DW_ExprEncType;
typedef struct DW_ExprEnc
{
DW_ExprEncType type;
union {
DW_ExprOp op;
U8 u8;
U16 u16;
U32 u32;
U64 u64;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
U64 addr;
String8 block;
String8 label;
};
} DW_ExprEnc;
#define DW_ExprEnc_Op(v) { .type = DW_ExprEncType_Op, .op = DW_ExprOp_##v }
#define DW_ExprEnc_U8(v) { .type = DW_ExprEncType_U8, .u8 = v }
#define DW_ExprEnc_U16(v) { .type = DW_ExprEncType_U16, .u16 = v }
#define DW_ExprEnc_U32(v) { .type = DW_ExprEncType_U32, .u32 = v }
#define DW_ExprEnc_U64(v) { .type = DW_ExprEncType_U64, .u64 = v }
#define DW_ExprEnc_S8(v) { .type = DW_ExprEncType_S8, .s8 = v }
#define DW_ExprEnc_S16(v) { .type = DW_ExprEncType_S16, .s16 = v }
#define DW_ExprEnc_S32(v) { .type = DW_ExprEncType_S32, .s32 = v }
#define DW_ExprEnc_S64(v) { .type = DW_ExprEncType_S64, .s64 = v }
#define DW_ExprEnc_ULEB128(v) { .type = DW_ExprEncType_ULEB128, .u64 = v }
#define DW_ExprEnc_SLEB128(v) { .type = DW_ExprEncType_SLEB128, .s64 = v }
#define DW_ExprEnc_Addr(v) { .type = DW_ExprEncType_Addr, .addr = v }
#define DW_ExprEnc_Block(v) { .type = DW_ExprEncType_Block, .block = v }
#define DW_ExprEnc_UInt(v) { .type = DW_ExprEncType_DwarfUInt, .u64 = v }
#define DW_ExprEnc_Label(v) { .type = DW_ExprEncType_Label, .label = str8_lit_comp(v) }
#define DW_ExprEnc_DeclLabel(v) { .type = DW_ExprEncType_DeclLabel, .label = str8_lit_comp(v) }
////////////////////////////////
// pieces
internal DW_PieceNode * dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v);
// size -> type
internal DW_ExprValueType dw_expr_unsigned_value_type_from_bit_size(U64 bit_size);
internal DW_ExprValueType dw_expr_signed_value_type_from_bit_size(U64 bit_size);
internal DW_ExprValueType dw_expr_float_type_from_bit_size(U64 bit_size);
// type -> size
internal U64 dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k);
// typer
internal DW_ExprValueType dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
internal DW_ExprValueType dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
internal DW_ExprValue dw_expr_cast(DW_ExprValue value, DW_ExprValueType type);
// arithmetic operators
internal DW_ExprValue dw_expr_add (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_mul (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_div (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_mod (DW_ExprValue rhs, DW_ExprValue lhs);
// comparison operators
internal DW_ExprValue dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs);
// bitwise operators
internal DW_ExprValue dw_expr_xor (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_and (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_or (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shl (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shr (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs);
// unary operators
internal DW_ExprValue dw_expr_abs(DW_ExprValue value);
internal DW_ExprValue dw_expr_neg(DW_ExprValue value);
internal DW_ExprValue dw_expr_not(DW_ExprValue value);
// stack
internal DW_ExprValueNode * dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value);
internal DW_ExprValueNode * dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size);
internal DW_ExprValue dw_expr_stack_pop(DW_ExprStack *stack);
internal DW_ExprValue dw_expr_stack_peek(DW_ExprStack *stack);
internal DW_ExprValueNode * dw_expr_stack_pick(DW_ExprStack *stack, U64 idx);
// value helpers
internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v);
// evaluator
internal DW_ExprEvalResult dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls_base, U64 op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out);
#endif //DWARF_EXPR_H
File diff suppressed because it is too large Load Diff
+528
View File
@@ -0,0 +1,528 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_PARSE_H
#define DWARF_PARSE_H
typedef struct DW_Section
{
String8 name;
String8 data;
B32 is_dwo;
} DW_Section;
typedef struct DW_Raw
{
DW_Section sec[DW_Section_COUNT];
DW_Section sup[DW_Section_COUNT];
} DW_Raw;
typedef struct DW_ListUnit
{
DW_Version version;
U64 address_size;
U64 segment_selector_size;
U64 entry_size;
String8 entries;
} DW_ListUnit;
typedef struct DW_ListUnitInput
{
U64 addr_count;
U64 str_offset_count;
U64 rnglist_count;
U64 loclist_count;
Rng1U64Array addr_ranges;
Rng1U64Array str_offset_ranges;
Rng1U64Array rnglist_ranges;
Rng1U64Array loclist_ranges;
DW_ListUnit *addrs;
DW_ListUnit *str_offsets;
DW_ListUnit *rnglists;
DW_ListUnit *loclists;
} DW_ListUnitInput;
typedef struct DW_AbbrevTableEntry
{
U64 id;
U64 off;
} DW_AbbrevTableEntry;
typedef struct DW_AbbrevTable DW_AbbrevTable;
struct DW_AbbrevTable
{
U64 count;
DW_AbbrevTableEntry *entries;
};
typedef enum DW_AbbrevKind
{
DW_Abbrev_Null,
DW_Abbrev_Tag,
DW_Abbrev_Attrib,
DW_Abbrev_AttribSequenceEnd,
DW_Abbrev_DIEBegin,
DW_Abbrev_DIEEnd,
} DW_AbbrevKind;
typedef U32 DW_AbbrevFlags;
enum
{
DW_AbbrevFlag_HasImplicitConst = (1 << 0),
DW_AbbrevFlag_HasChildren = (1 << 1),
};
typedef struct DW_Abbrev
{
DW_AbbrevKind kind;
U64 sub_kind;
U64 id;
S64 implicit_const;
DW_AbbrevFlags flags;
} DW_Abbrev;
typedef struct DW_Attrib
{
U64 info_off;
U64 abbrev_off;
U64 abbrev_id;
DW_AttribKind attrib_kind;
DW_Form form;
} DW_Attrib;
typedef struct DW_AttribNode
{
struct DW_AttribNode *next;
DW_Attrib v;
} DW_AttribNode;
typedef struct DW_AttribList
{
DW_AttribNode *first;
DW_AttribNode *last;
U64 count;
} DW_AttribList;
typedef U8 DW_TagSpare;
typedef struct DW_Tag
{
B32 has_children;
U64 abbrev_id;
DW_TagKind kind;
DW_AttribList attribs;
U64 info_off;
DW_TagSpare v;
} DW_Tag;
typedef struct DW_TagNode
{
DW_Tag tag;
struct DW_TagNode *sibling;
struct DW_TagNode *first_child;
struct DW_TagNode *last_child;
} DW_TagNode;
typedef struct DW_Loc
{
Rng1U64 range;
String8 expr;
} DW_Loc;
typedef struct DW_LocNode
{
DW_Loc v;
struct DW_LocNode *next;
} DW_LocNode;
typedef struct DW_LocList
{
U64 count;
DW_LocNode *first;
DW_LocNode *last;
} DW_LocList;
typedef struct DW_CompUnit
{
B32 relaxed;
DW_Ext ext;
DW_CompUnitKind kind;
DW_Version version;
DW_Format format;
U64 address_size;
U64 abbrev_off;
Rng1U64 info_range;
U64 first_tag_info_off;
DW_AbbrevTable abbrev_table;
DW_ListUnit *addr_lu;
DW_ListUnit *str_offsets_lu;
DW_ListUnit *rnglists_lu;
DW_ListUnit *loclists_lu;
U64 low_pc;
U64 dwo_id;
DW_Tag tag;
HashTable *tag_ht;
} DW_CompUnit;
typedef struct DW_TagTree
{
DW_TagNode *root;
U64 tag_count;
} DW_TagTree;
////////////////////////////////
typedef struct DW_LineFile
{
String8 path;
U64 dir_idx;
U64 time_stamp;
U64 size;
U128 md5;
String8 source;
} DW_LineFile;
typedef struct DW_LineFileNode
{
struct DW_LineFileNode *next;
DW_LineFile file;
} DW_LineFileNode;
typedef struct DW_LineFileList
{
U64 node_count;
DW_LineFileNode *first;
DW_LineFileNode *last;
} DW_LineFileList;
typedef struct DW_LineFileArray
{
U64 count;
DW_LineFile *v;
} DW_LineFileArray;
typedef struct DW_LineVMHeader
{
U64 unit_length;
DW_Version version;
U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str.
U8 segment_selector_size;
U64 header_length;
U8 min_inst_len;
U8 max_ops_for_inst;
U8 default_is_stmt;
S8 line_base;
U8 line_range;
U8 opcode_base;
U64 num_opcode_lens;
U8 *opcode_lens;
U64 line_program_off;
String8Array dir_table;
DW_LineFileArray file_table;
} DW_LineVMHeader;
typedef struct DW_LineVMState
{
U64 address; // Address of a machine instruction.
U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction.
// Line table doesn't contain full path to a file, instead
// DWARF encodes path as two indices. First index will point into a directory
// table, and second points into a file name table.
U64 file_index;
U64 line;
U64 column;
B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint.
B32 basic_block; // Indicates that the "address" is inside a basic block.
// Indicates that "address" points to place where function starts.
// Usually prologue is the place where compiler emits instructions to
// prepare stack for a function.
B32 prologue_end;
B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack.
U64 isa; // Instruction set that is used.
U64 discriminator; // Arbitrary id that indicates to which block these instructions belong.
B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows.
} DW_LineVMState;
typedef struct DW_LineVM
{
Arena *arena;
U64 cursor;
String8 program;
DW_LineVMHeader header;
B32 new_line;
B32 new_seq;
B32 skip_opcode;
DW_LineVMState state;
U64 advance;
U64 opcode_off;
DW_StdOpcode opcode;
DW_ExtOpcode ext_opcode;
U64 ext_length;
U64 line_advance;
U64 addr_advance;
HashTable *ext_file_ht;
struct {
union {
String8 string;
U64 u64;
S64 s64;
};
} operands[4];
String8 error;
} DW_LineVM;
////////////////////////////////
// .debug_pubnames and .debug_pubtypes
typedef struct DW_PubStringsBucket
{
struct DW_PubStringsBucket *next;
String8 string;
U64 info_off;
U64 cu_info_off;
} DW_PubStringsBucket;
typedef struct DW_PubStringsTable
{
U64 size;
DW_PubStringsBucket **buckets;
} DW_PubStringsTable;
typedef struct DW_Reference
{
DW_CompUnit *cu;
U64 info_off; // global .debug_info offset
} DW_Reference;
////////////////////////////////
//~ Expression
typedef union DW_ExprOperand
{
U8 u8;
U16 u16;
U32 u32;
U64 u64;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
String8 block;
} DW_ExprOperand;
typedef struct DW_ExprInst
{
DW_ExprOp opcode;
DW_ExprOperand *operands;
U64 size;
struct DW_ExprInst *next;
struct DW_ExprInst *prev;
} DW_ExprInst;
typedef struct DW_Expr
{
U64 count;
DW_ExprInst *first;
DW_ExprInst *last;
} DW_Expr;
////////////////////////////////
// .debug_frame
typedef struct DW_CIE
{
String8 insts;
String8 aug_string;
String8 aug_data;
U64 code_align_factor;
S64 data_align_factor;
U64 ret_addr_reg;
U64 ext[4];
DW_Format format;
U8 version;
U8 address_size;
U8 segment_selector_size;
} DW_CIE;
typedef struct DW_FDE
{
DW_Format format;
U64 cie_pointer;
Rng1U64 pc_range;
String8 insts;
} DW_FDE;
typedef union DW_CFA_Operand
{
U64 u64;
S64 s64;
String8 block;
} DW_CFA_Operand;
typedef enum
{
DW_CFA_ParseErrorCode_NewInst,
DW_CFA_ParseErrorCode_End,
DW_CFA_ParseErrorCode_OutOfData
} DW_CFA_ParseErrorCode;
typedef struct DW_CFA_Inst
{
DW_CFA_Opcode opcode;
DW_CFA_Operand operands[DW_CFA_OperandMax];
} DW_CFA_Inst;
typedef struct DW_CFA_InstNode
{
DW_CFA_Inst v;
struct DW_CFA_InstNode *next;
} DW_CFA_InstNode;
typedef struct DW_CFA_InstList
{
U64 count;
DW_CFA_InstNode *first;
DW_CFA_InstNode *last;
} DW_CFA_InstList;
#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out)
typedef DW_DECODE_PTR(DW_DecodePtr);
// hasher
internal U64 dw_hash_from_string(String8 string);
// deserial helpers
internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out);
internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out);
internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out);
internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out);
internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data);
internal Rng1U64Array dw_unit_ranges_from_data_arr(Arena *arena, String8 data);
// list units
internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out);
internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Raw *input);
internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index);
internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index);
// abbrev table
internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev);
internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev);
internal DW_AbbrevTable dw_read_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base);
internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id);
// form and tag
internal B32 dw_read_form (String8 data, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, S64 implicit_const, DW_Form *form_out, U64 *bytes_read_out);
internal U64 dw_read_tag (Arena *arena, DW_Raw *input, DW_AbbrevTable abbrev_table, DW_Version version, DW_Format format, U64 address_size, Rng1U64 cu_info_range, U64 tag_info_off, DW_Tag *tag_out);
internal U64 dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out);
// attrib interp
internal U64 dw_interp_sec_offset(DW_Form form);
internal String8 dw_interp_exprloc (DW_Form form);
internal U128 dw_interp_const_u128(DW_Form form);
internal U64 dw_interp_const_u64 (DW_Form form);
internal U32 dw_interp_const_u32 (DW_Form form);
internal S64 dw_interp_const_s64 (DW_Form form);
internal S32 dw_interp_const_s32 (DW_Form form);
internal B32 dw_interp_flag (DW_Form form);
internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_Form form);
internal String8 dw_interp_block (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal String8 dw_interp_string (DW_Raw *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_Form form);
internal String8 dw_interp_line_ptr (DW_Raw *input, DW_Form form);
internal DW_LineFile * dw_interp_file (DW_LineVM *line_vm, DW_Form form);
internal DW_Reference dw_interp_ref (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal DW_LocList dw_interp_loclist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal String8 dw_exprloc_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U128 dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U64 dw_const_u64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U32 dw_const_u32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal S64 dw_const_s64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal S32 dw_const_s32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal B32 dw_flag_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U64 dw_address_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_block_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_string_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_line_ptr_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
internal DW_Reference dw_ref_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_exprloc_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U128 dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U64 dw_const_u64_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U32 dw_const_u32_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal B32 dw_flag_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U64 dw_address_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_block_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_string_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind);
internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal B32 dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
// compile unit
internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed);
internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu);
internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree);
internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off);
// line VM
internal U64 dw_read_line_vm_header(Arena *arena, DW_Raw *input, String8 cu_stmt_list, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out);
internal DW_LineVM * dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu);
internal void dw_line_vm_release(DW_LineVM *vm);
internal void dw_line_vm_advance(DW_LineVM *vm, U64 advance);
internal B32 dw_line_vm_step(DW_LineVM *vm);
internal DW_LineFile * dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx);
internal String8 dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file);
// helper for .debug_pubtypes and .debug_pubnames
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind);
// expression
internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data);
// debug frame
internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n);
internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v);
internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out);
internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out);
internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out);
internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out);
internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out);
internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
#endif // DWARF_PARSE_H
+373
View File
@@ -0,0 +1,373 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal DW_CFI_Row *
dw_make_cfi_row(Arena *arena, U64 reg_count)
{
DW_CFI_Row *row = push_array(arena, DW_CFI_Row, 1);
row->regs = push_array(arena, DW_CFI_Register, reg_count);
for EachIndex(reg_idx, reg_count) {
row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue;
}
return row;
}
internal void
dw_memcpy_cfi_row(DW_CFI_Row *dst, DW_CFI_Row *src, U64 reg_count)
{
dst->cfa = src->cfa;
MemoryCopyTyped(dst->regs, src->regs, reg_count);
}
internal DW_CFI_Row *
dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count)
{
DW_CFI_Row *new_row = dw_make_cfi_row(arena, reg_count);
dw_memcpy_cfi_row(new_row, row, reg_count);
return new_row;
}
internal DW_CFI_Unwind *
dw_cfi_unwind_init(Arena *arena,
Arch arch,
DW_CIE *cie,
DW_FDE *fde,
DW_DecodePtr *decode_ptr_func,
void *decode_ptr_ud)
{
Temp scratch = scratch_begin(&arena, 1);
DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1);
uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
uw->cie = cie;
uw->fde = fde;
uw->pc = fde->pc_range.min;
uw->arch = arch;
uw->reg_count = dw_reg_count_from_arch(arch);
// setup initial register rules
DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
uw->row = dw_make_cfi_row(arena, uw->reg_count);
uw->curr_inst = initial_insts.first;
if (!dw_cfi_next_row(arena, uw)) {
AssertAlways(0 && "unable to interpret initial row instructions");
}
// make first row from initial rules
uw->initial_row = uw->row;
uw->row = dw_copy_cfi_row(arena, uw->initial_row, uw->reg_count);
uw->curr_inst = uw->insts.first;
scratch_end(scratch);
return uw;
}
internal B32
dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw)
{
B32 is_row_valid = 0;
DW_CFA_InstNode *row_inst = uw->curr_inst;
// skip leading nops
while (uw->curr_inst) {
if (uw->curr_inst->v.opcode != DW_CFA_Nop) {
break;
}
uw->curr_inst = uw->curr_inst->next;
}
while (uw->curr_inst) {
DW_CFA_Inst *inst = &uw->curr_inst->v;
// validate register operands
DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode);
U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode);
for EachIndex(operand_idx, operand_count) {
if (operand_types[operand_idx] == DW_CFA_OperandType_Register) {
if (inst->operands[operand_idx].u64 >= uw->reg_count) {
goto exit;
}
}
}
switch (inst->opcode) {
// Row Creation Instructions
case DW_CFA_SetLoc: {
uw->pc = inst->operands[0].u64;
} break;
case DW_CFA_AdvanceLoc:
case DW_CFA_AdvanceLoc1:
case DW_CFA_AdvanceLoc2:
case DW_CFA_AdvanceLoc4: {
uw->pc += inst->operands[0].u64;
} break;
// CFA Definition Instructions
case DW_CFA_DefCfa:
case DW_CFA_DefCfaSf: {
U64 reg = inst->operands[0].u64;
S64 off = inst->operands[1].s64;
uw->row->cfa.rule = DW_CFA_Rule_RegOff;
uw->row->cfa.reg = reg;
uw->row->cfa.off = off;
} break;
case DW_CFA_DefCfaRegister: {
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
U64 reg = inst->operands[0].u64;
uw->row->cfa.reg = reg;
} break;
case DW_CFA_DefCfaOffset:
case DW_CFA_DefCfaOffsetSf: {
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
uw->row->cfa.off = inst->operands[0].s64;
} break;
case DW_CFA_DefCfaExpr: {
uw->row->cfa.rule = DW_CFA_Rule_Expression;
uw->row->cfa.expr = inst->operands[0].block;
} break;
// Register Rule Instructions
case DW_CFA_Undefined: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined;
} break;
case DW_CFA_SameValue: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue;
} break;
case DW_CFA_Offset:
case DW_CFA_OffsetExt:
case DW_CFA_OffsetExtSf: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_ValOffset:
case DW_CFA_ValOffsetSf: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_Register: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_Expr: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression;
uw->row->regs[reg].expr = inst->operands[1].block;
} break;
case DW_CFA_ValExpr: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression;
uw->row->regs[reg].expr = inst->operands[1].block;
} break;
case DW_CFA_Restore:
case DW_CFA_RestoreExt: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg] = uw->initial_row->regs[reg];
} break;
// Row State Instructions
case DW_CFA_RememberState: {
DW_CFI_Row *new_row = dw_copy_cfi_row(arena, uw->row, uw->reg_count);
SLLStackPush(uw->row, new_row);
} break;
case DW_CFA_RestoreState: {
if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops
DW_CFI_Row *free_row = uw->row;
SLLStackPop(uw->row);
SLLStackPush(uw->free_rows, free_row);
} break;
case DW_CFA_Nop: {} break;
default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode
}
uw->curr_inst = uw->curr_inst->next;
if (uw->curr_inst) {
if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; }
}
}
is_row_valid = row_inst != 0;
exit:;
return is_row_valid;
}
internal DW_CFI_Row *
dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc)
{
Temp scratch = scratch_begin(&arena, 1);
B32 is_row_found = 0;
U64 reg_count = dw_reg_count_from_arch(arch);
DW_CFI_Unwind *uw = dw_cfi_unwind_init(scratch.arena, arch, cie, fde, decode_ptr_func, decode_ptr_ctx);
DW_CFI_Row *row = dw_copy_cfi_row(scratch.arena, uw->row, uw->reg_count);
U64 prev_pc = uw->pc;
while (dw_cfi_next_row(scratch.arena, uw)) {
if (prev_pc <= pc && pc < uw->pc) {
is_row_found = 1;
break;
}
dw_memcpy_cfi_row(row, uw->row, uw->reg_count);
prev_pc = uw->pc;
}
// handle last row
if (!is_row_found) {
if (contains_1u64(fde->pc_range, pc)) {
row = uw->row;
is_row_found = 1;
}
}
// copy out final row
DW_CFI_Row *result = 0;
if (is_row_found) {
result = dw_copy_cfi_row(arena, row, reg_count);
}
scratch_end(scratch);
return result;
}
internal MachineOpResult
dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out)
{
MachineOpResult unwind_status = MachineOpResult_Fail;
ARCH_Info *arch_info = arch_info_from_arch(arch);
switch(row->cfa.rule)
{
case DW_CFA_Rule_Null:{}break;
case DW_CFA_Rule_RegOff:
{
// TODO: report error (invalid register read)
U64 cfa_reg_value = 0;
U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg);
AssertAlways(reg_size <= sizeof(cfa_reg_value));
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, row->cfa.reg);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, &cfa_reg_value))
{
break;
}
*cfa_out = cfa_reg_value + row->cfa.off;
unwind_status = MachineOpResult_Ok;
}break;
case DW_CFA_Rule_Expression:
{
Temp scratch = scratch_begin(0,0);
DW_ExprValue value = {0};
DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_32Bit, byte_size_from_arch(arch), row->cfa.expr);
DW_ExprEvalResult eval_result = dw_eval_expr(scratch.arena, arch, DW_Format_32Bit, 0, 0, 0, 9999, expr, reg_block, mem_read_func, mem_read_ud, &value);
if (eval_result == DW_ExprEvalResult_Ok) {
if (DW_ExprValueType_IsInt(value.type)) {
*cfa_out = value.u64;
unwind_status = MachineOpResult_Ok;
}
} else if (eval_result == DW_ExprEvalResult_Maybe) {
unwind_status = MachineOpResult_Maybe;
}
scratch_end(scratch);
}break;
}
return unwind_status;
}
internal MachineOpResult
dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud)
{
Temp scratch = scratch_begin(0,0);
MachineOpResult unwind_status = MachineOpResult_Ok;
ARCH_Info *arch_info = arch_info_from_arch(arch);
U64 max_reg_size = dw_reg_max_size_from_arch(arch);
void *reg_buffer = push_array(scratch.arena, U8, max_reg_size);
U64 reg_count = dw_reg_count_from_arch(arch);
for EachIndex(reg_idx, reg_count)
{
DW_CFI_Register *reg = &row->regs[reg_idx];
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_idx);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
switch(reg->rule)
{
default:{}break;
case DW_CFI_RegisterRule_Undefined: {} break;
case DW_CFI_RegisterRule_SameValue: {} break;
case DW_CFI_RegisterRule_Offset:
{
// read register value from memory
U64 addr = cfa + reg->n;
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
unwind_status = mem_read_func(addr, reg_buffer, reg_size, mem_read_ud);
if (unwind_status != MachineOpResult_Ok) { goto exit; }
// write register value to the thread context
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
}break;
case DW_CFI_RegisterRule_ValOffset:
{
// compute register value
U64 reg_value = cfa + reg->n;
// write register value to the thread context
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, &reg_value))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
}break;
case DW_CFI_RegisterRule_Register:
{
// read register value from another register
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
// write register value to the thread context
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
if (unwind_status != MachineOpResult_Ok) { goto exit; }
}break;
case DW_CFI_RegisterRule_Expression:
{
// TODO: evaluate expression
NotImplemented;
}break;
case DW_CFI_RegisterRule_ValExpression:
{
// TODO: evaluate expression
NotImplemented;
}break;
case DW_CFI_RegisterRule_Architectural:
{
NotImplemented;
}break;
}
}
// update stack pointer
arch_reg_block_write_sp(arch_info, reg_block, cfa);
exit:;
scratch_end(scratch);
return unwind_status;
}
+81
View File
@@ -0,0 +1,81 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_UNWIND_H
#define DWARF_UNWIND_H
typedef enum DW_CFI_RegisterRule
{
DW_CFI_RegisterRule_Undefined,
DW_CFI_RegisterRule_SameValue,
DW_CFI_RegisterRule_Offset,
DW_CFI_RegisterRule_ValOffset,
DW_CFI_RegisterRule_Register,
DW_CFI_RegisterRule_Expression,
DW_CFI_RegisterRule_ValExpression,
DW_CFI_RegisterRule_Architectural
} DW_CFI_RegisterRule;
typedef enum DW_CFA_Rule
{
DW_CFA_Rule_Null,
DW_CFA_Rule_RegOff,
DW_CFA_Rule_Expression
} DW_CFA_Rule;
typedef struct DW_CFA
{
DW_CFA_Rule rule;
union {
struct {
DW_Reg reg;
S64 off;
};
String8 expr;
};
} DW_CFA;
typedef struct DW_CFI_Register
{
DW_CFI_RegisterRule rule;
union {
S64 n;
String8 expr;
};
} DW_CFI_Register;
typedef struct DW_CFI_Row
{
DW_CFA cfa;
DW_CFI_Register *regs;
struct DW_CFI_Row *next;
} DW_CFI_Row;
typedef struct DW_CFI_Unwind
{
DW_CFA_InstList insts;
DW_CIE *cie;
DW_FDE *fde;
DW_CFI_Row *initial_row;
DW_CFI_Row *row;
DW_CFA_InstNode *curr_inst;
DW_CFI_Row *free_rows;
U64 pc;
Arch arch;
U64 reg_count;
} DW_CFI_Unwind;
////////////////////////////////
internal DW_CFI_Row * dw_make_cfi_row(Arena *arena, U64 reg_count);
internal DW_CFI_Row * dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count);
internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw);
internal DW_CFI_Row * dw_cfi_row_from_pc(Arena *arena, Arch arch, struct DW_CIE *cie, struct DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc);
internal MachineOpResult dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out);
internal MachineOpResult dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud);
#endif // DWARF_UNWIND_H
+584 -2086
View File
File diff suppressed because it is too large Load Diff
+5 -61
View File
@@ -4,70 +4,14 @@
#ifndef DWARF_DUMP_H
#define DWARF_DUMP_H
typedef enum
{
DW_DumperCacheFlag_InfoRanges = (1 << 0),
DW_DumperCacheFlag_CuArr = (1 << 1),
DW_DumperCacheFlag_LineVmMap = (1 << 2),
DW_DumperCacheFlag_TagTrees = (1 << 3),
} DW_DumperCacheFlags;
////////////////////////////////
//~ rjf: Helpers
typedef struct DW_Dumper
{
Arena *arena;
Arch arch;
B32 is_relaxed;
B32 is_verbose;
DW_Raw *input;
DW_DumperCacheFlags cache_flags;
struct {
Rng1U64Array info_ranges;
DW_CompUnit *cu_arr;
HashTable *line_vm_map;
DW_TagTree *tag_trees;
} cache;
} DW_Dumper;
#define DW_PRINTER(name) void name(Arena *arena, String8List *strings, int indent, DW_Dumper *dumper)
typedef DW_PRINTER(DW_Printer);
internal String8List dw_dump_list_from_expr(Arena *arena, String8 data, Arch arch, DW2_ParseCtx *ctx);
////////////////////////////////
//~ rjf: Main Dump Entry Point
// cache
internal Rng1U64Array dw_get_info_ranges(DW_Dumper *dumper);
internal DW_CompUnit * dw_get_cu_arr(DW_Dumper *dumper);
internal HashTable * dw_get_line_vm_map(DW_Dumper *dumper);
internal DW_TagTree * dw_get_tag_trees(DW_Dumper *dumper);
////////////////////////////////
//~ rjf: Stringification Helpers
internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program);
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal String8 dw_string_from_reg_off (Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off);
internal String8 dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
internal String8 dw_string_from_expression (Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
internal String8 dw_string_from_cfa (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa);
internal String8 dw_string_from_cfi_row (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row);
#if 0
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx);
internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges, Arch arch);
internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges);
internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Raw *input);
#endif
////////////////////////////////
//~ rjf: Dump Entry Point
internal String8List dw_dump_list_from_sections(Arena *arena, DW_Raw *input, Arch arch, DW_SectionFlags dump_sections, B32 is_verbose);
internal String8List dw_dump_list_from_raw(Arena *arena, DW_Raw *raw, Arch arch, DW_SectionFlags subset_flags);
#endif // DWARF_DUMP_H
-718
View File
@@ -1,718 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Helpers
internal String8List
dw_dump_list_from_expr(Arena *arena, String8 data, Arch arch, DW2_ParseCtx *ctx)
{
String8List result = {0};
Temp scratch = scratch_begin(&arena, 1);
ARCH_Info *arch_info = arch_info_from_arch(arch);
for(U64 off = 0; off < data.size;)
{
U64 start_off = 0;
// rjf: read next op
U8 op = 0;
off += str8_deserial_read_struct(data, off, &op);
// rjf: unpack op / operands
String8 operand_string = {0};
U64 size_param = 0;
B32 is_signed = 0;
switch(op)
{
case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2:
case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5:
case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8:
case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11:
case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14:
case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17:
case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20:
case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23:
case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26:
case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29:
case DW_ExprOp_Lit30: case DW_ExprOp_Lit31:
{
U64 x = op - DW_ExprOp_Lit0;
operand_string = str8f(scratch.arena, "%I64u", x);
}break;
case DW_ExprOp_Const1U:size_param = 1; goto const_n;
case DW_ExprOp_Const2U:size_param = 2; goto const_n;
case DW_ExprOp_Const4U:size_param = 4; goto const_n;
case DW_ExprOp_Const8U:size_param = 8; goto const_n;
case DW_ExprOp_Const1S:size_param = 1; is_signed = 1; goto const_n;
case DW_ExprOp_Const2S:size_param = 2; is_signed = 1; goto const_n;
case DW_ExprOp_Const4S:size_param = 4; is_signed = 1; goto const_n;
case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n;
const_n:
{
if(is_signed)
{
S64 x = 0;
off += str8_deserial_read(data, off, &x, size_param, 1);
x = extend_sign64(x, size_param);
operand_string = str8f(scratch.arena, "%I64d", x);
}
else
{
U64 x = 0;
off += str8_deserial_read(data, off, &x, size_param, 1);
operand_string = str8f(scratch.arena, "%I64u", x);
}
}break;
case DW_ExprOp_Addr:
{
U64 addr = 0;
off += str8_deserial_read(data, off, &addr, ctx->addr_size, 1);
operand_string = str8f(scratch.arena, "0x%I64x", addr);
}break;
case DW_ExprOp_ConstU:
{
U64 x = 0;
off += str8_deserial_read_uleb128(data, off, &x);
operand_string = str8f(scratch.arena, "%I64u", x);
}break;
case DW_ExprOp_ConstS:
{
S64 x = 0;
off += str8_deserial_read_sleb128(data, off, &x);
operand_string = str8f(scratch.arena, "%I64d", x);
}break;
case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2:
case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5:
case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8:
case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11:
case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14:
case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17:
case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20:
case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23:
case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26:
case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29:
case DW_ExprOp_Reg30: case DW_ExprOp_Reg31:
{
U64 reg_idx = op - DW_ExprOp_Reg0;
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
operand_string = arch_info->reg_code_name_table[regcode];
}break;
case DW_ExprOp_RegX:
{
U64 reg_idx = 0;
off += str8_deserial_read_uleb128(data, off, &reg_idx);
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
operand_string = arch_info->reg_code_name_table[regcode];
}break;
case DW_ExprOp_ImplicitValue:
{
U64 value_size = 0;
off += str8_deserial_read_uleb128(data, off, &value_size);
Rng1U64 value_range = rng_1u64(off, off + value_size);
String8 value_data = str8_substr(data, value_range);
off += value_size;
String8List value_strings = numeric_str8_list_from_data(scratch.arena, 16, value_data, 1);
operand_string = str8_list_join(scratch.arena, &value_strings, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(", "), .post = str8_lit(" }")});
}break;
case DW_ExprOp_Piece:
{
U64 size = 0;
off += str8_deserial_read_uleb128(data, off, &size);
operand_string = str8f(scratch.arena, "%u", size);
}break;
case DW_ExprOp_BitPiece:
{
U64 bit_size = 0, bit_off = 0;
off += str8_deserial_read_uleb128(data, off, &bit_size);
off += str8_deserial_read_uleb128(data, off, &bit_off);
operand_string = str8f(scratch.arena, "bit size %I64u, bit offset %I64u", bit_size, bit_off);
}break;
case DW_ExprOp_Pick:
{
U8 stack_idx = 0;
off += str8_deserial_read_struct(data, off, &stack_idx);
operand_string = str8f(scratch.arena, "stack index %u", stack_idx);
}break;
case DW_ExprOp_PlusUConst:
{
U64 addend = 0;
off += str8_deserial_read_uleb128(data, off, &addend);
operand_string = str8f(arena, "addend %I64u", addend);
}break;
case DW_ExprOp_Skip:
{
S16 x = 0;
off += str8_deserial_read_struct(data, off, &x);
operand_string = str8f(scratch.arena, "%+d bytes", x);
}break;
case DW_ExprOp_Bra:
{
S16 x = 0;
off += str8_deserial_read_struct(data, off, &x);
operand_string = str8f(scratch.arena, "%+d", x);
}break;
case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2:
case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5:
case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8:
case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11:
case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14:
case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17:
case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20:
case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23:
case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26:
case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29:
case DW_ExprOp_BReg30: case DW_ExprOp_BReg31:
{
U64 reg_idx = op - DW_ExprOp_BReg0;
S64 reg_off = 0;
off += str8_deserial_read_sleb128(data, off, &reg_off);
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
operand_string = str8f(scratch.arena, "%S+%I64d", arch_info->reg_code_name_table[regcode], reg_off);
}break;
case DW_ExprOp_FBReg:
{
S64 reg_off = 0;
off += str8_deserial_read_sleb128(data, off, &reg_off);
operand_string = str8f(scratch.arena, "frame base offset %I64d", reg_off);
}break;
case DW_ExprOp_BRegX:
{
U64 reg_idx = 0;
S64 reg_off = 0;
off += str8_deserial_read_uleb128(data, off, &reg_idx);
off += str8_deserial_read_sleb128(data, off, &reg_off);
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
operand_string = str8f(scratch.arena, "%S+%I64d", arch_info->reg_code_name_table[regcode], reg_off);
}break;
case DW_ExprOp_XDerefSize:
case DW_ExprOp_DerefSize:
{
U8 x = 0;
off += str8_deserial_read_struct(data, off, &x);
operand_string = str8f(scratch.arena, "%u", x);
}break;
case DW_ExprOp_Call2:
{
U16 x = 0;
off += str8_deserial_read_struct(data, off, &x);
operand_string = str8f(scratch.arena, "%u", x);
}break;
case DW_ExprOp_Call4:
{
U32 x = 0;
off += str8_deserial_read_struct(data, off, &x);
operand_string = str8f(arena, "%u", x);
}break;
case DW_ExprOp_CallRef:
{
U64 x = 0;
off += dw2_read_fmt_u64(data, off, ctx->format, &x);
operand_string = str8f(scratch.arena, "%I64u", x);
}break;
case DW_ExprOp_ImplicitPointer:
case DW_GNU_ExprOp_ImplicitPointer:
{
U64 info_off = 0;
off += dw2_read_fmt_u64(data, off, ctx->format, &info_off);
S64 ptr = 0;
off += str8_deserial_read_sleb128(data, off, &ptr);
operand_string = str8f(scratch.arena, ".debug_info@0x%I64x, ptr %I64x", info_off, ptr);
} break;
case DW_ExprOp_Convert:
case DW_GNU_ExprOp_Convert:
{
U64 type_cu_off = 0;
off += str8_deserial_read_uleb128(data, off, &type_cu_off);
operand_string = str8f(scratch.arena, "TypeCuOff %#I64x", ctx->unit_base_info_off + type_cu_off);
}break;
case DW_GNU_ExprOp_ParameterRef:
{
// TODO: always 4 bytes?
U32 cu_off = 0;
off += str8_deserial_read_struct(data, off, &cu_off);
operand_string = str8f(scratch.arena, "CuOff %#x", ctx->unit_base_info_off + cu_off);
}break;
case DW_ExprOp_DerefType:
case DW_GNU_ExprOp_DerefType:
{
U8 deref_size = 0;
U64 type_cu_off = 0;
off += str8_deserial_read_struct(data, off, &deref_size);
off += str8_deserial_read_uleb128(data, off, &type_cu_off);
operand_string = str8f(scratch.arena, "%#x, TypeCuOff %#I64x", deref_size, ctx->unit_base_info_off + type_cu_off);
}break;
case DW_ExprOp_ConstType:
case DW_GNU_ExprOp_ConstType:
{
U64 type_cu_off = 0;
U8 const_value_size = 0;
off += str8_deserial_read_uleb128(data, off, &type_cu_off);
off += str8_deserial_read_struct(data, off, &const_value_size);
Rng1U64 const_value_range = rng_1u64(off, off + const_value_size);
String8 const_value_data = str8_substr(data, const_value_range);
String8List const_value_strings = numeric_str8_list_from_data(scratch.arena, 16, const_value_data, 1);
String8 const_value_str = str8_list_join(scratch.arena, &const_value_strings, &(StringJoin){.sep = str8_lit(", ")});
operand_string = str8f(scratch.arena, "TypeCuOff %#I64x, Const Value { %S }", ctx->unit_base_info_off + type_cu_off, const_value_str);
off += const_value_size;
}break;
case DW_ExprOp_RegvalType:
case DW_GNU_ExprOp_RegvalType:
{
U64 reg_idx = 0, type_cu_off = 0;
off += str8_deserial_read_uleb128(data, off, &reg_idx);
off += str8_deserial_read_uleb128(data, off, &type_cu_off);
ARCH_RegCode regcode = arch_reg_code_from_dw(arch, (DW_RegCode)reg_idx);
operand_string = str8f(scratch.arena, "%S, TypeCuOff %#I64x", arch_info->reg_code_name_table[regcode], ctx->unit_base_info_off + type_cu_off);
}break;
case DW_ExprOp_EntryValue:
case DW_GNU_ExprOp_EntryValue:
{
U64 block_size = 0;
off += str8_deserial_read_uleb128(data, off, &block_size);
Rng1U64 block_range = rng_1u64(off, off + block_size);
String8 block_data = str8_substr(data, block_range);
// TODO(rjf): WTF, recursive? let's not... - if we want this, let's just do the stack inside of this function
// String8List block_expr = dw_string_list_from_expression(scratch.arena, block_data, cu_base, addr_size, arch, ver, ext, format);
// operand_string = str8_list_join(scratch.arena, &block_expr, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(","), .post = str8_lit(" }")});
operand_string = s("{...}");
off += block_size;
} break;
case DW_ExprOp_Addrx:
{
U64 addr = 0;
off += str8_deserial_read_uleb128(data, off, &addr);
operand_string = str8f(scratch.arena, "%#I64x", addr);
}break;
}
// rjf: push opcode info
String8 opcode_string = dw_string_from_expr_op(ctx->version, ctx->exts, op);
if(operand_string.size == 0)
{
str8_list_pushf(arena, &result, "%S", opcode_string);
}
else
{
str8_list_pushf(arena, &result, "%S(%S)", opcode_string, operand_string);
}
}
scratch_end(scratch);
return result;
}
////////////////////////////////
//~ rjf: Main Dump Entry Point
internal String8List
dw_dump_list_from_raw(Arena *arena, DW_Raw *raw, Arch arch, DW_SectionFlags subset_flags)
{
ProfBeginFunction();
Temp scratch = scratch_begin(&arena, 1);
String8 indent = str8_lit(" ");
//////////////////////////////
//- rjf: set up
//
typedef struct DumpSubsetOutputNode DumpSubsetOutputNode;
struct DumpSubsetOutputNode
{
DumpSubsetOutputNode *next;
DW_SectionKind section_kind;
String8List *lane_strings;
};
DumpSubsetOutputNode *first_output_node = 0;
DumpSubsetOutputNode *last_output_node = 0;
String8List *strings = 0;
#define dump(str) str8_list_push(arena, strings, (str))
#define dumpf(...) str8_list_pushf(arena, strings, __VA_ARGS__)
#define DumpSubsetKind(kind) \
if(lane_idx() == 0)\
{\
DumpSubsetOutputNode *n = push_array(scratch.arena, DumpSubsetOutputNode, 1);\
SLLQueuePush(first_output_node, last_output_node, n);\
n->section_kind = (kind);\
n->lane_strings = push_array(scratch.arena, String8List, lane_count());\
}\
lane_sync_u64(&first_output_node, 0);\
lane_sync_u64(&last_output_node, 0);\
strings = &last_output_node->lane_strings[lane_idx()];\
lane_sync(); if(subset_flags & (1ull<<(kind))) ProfScope((char *)dw_regular_name_from_section_kind(kind).str)
#define DumpSubset(name) DumpSubsetKind(DW_SectionKind_##name)
//////////////////////////////
//- rjf: .debug_abbrev
//
DumpSubset(Abbrev)
{
if(lane_idx() == 0)
{
String8 data = raw->sec[DW_SectionKind_Abbrev].data;
U64 idx = 0;
dumpf("\nabbrevs:\n{\n");
for(U64 off = 0; off < data.size; idx += 1)
{
Temp scratch2 = scratch_begin(&scratch.arena, 1);
U64 start_off = off;
// rjf: read abbrev info
DW2_AbbrevHeader abbrev_header = {0};
DW2_AbbrevAttribList abbrev_attribs = {0};
off += dw2_read_abbrev(scratch2.arena, data, off, &abbrev_header, &abbrev_attribs);
// rjf: log
dumpf(" abbrev: // abbrev[%I64u], .debug_abbrev@0x%I64x\n", idx, start_off);
dumpf(" {\n");
dumpf(" id: %I64u\n", abbrev_header.id);
dumpf(" tag_kind: %S (0x%I64x)\n", dw_string_from_tag_kind(DW_Version_Last, DW_ExtFlag_All, abbrev_header.tag_kind), abbrev_header.tag_kind);
dumpf(" has_children: %s\n", abbrev_header.has_children ? "yes" : "no");
if(abbrev_attribs.count != 0)
{
dumpf(" attribs:\n {\n");
for EachNode(n, DW2_AbbrevAttribNode, abbrev_attribs.first)
{
DW2_AbbrevAttrib *attrib = &n->v;
dumpf(" {%-24S %-16S%S}\n",
dw_string_from_attrib_kind(DW_Version_Last, DW_ExtFlag_All, attrib->attrib_kind),
dw_string_from_form_kind(DW_Version_Last, DW_ExtFlag_All, attrib->form_kind),
attrib->form_kind == DW_FormKind_ImplicitConst ? str8f(scratch2.arena, " (0x%I64x, %I64u)", attrib->implicit_const, attrib->implicit_const) : s(""));
}
dumpf(" }\n");
}
dumpf(" }\n");
if(off == start_off)
{
break;
}
}
dumpf("}\n");
}
}
//////////////////////////////
//- rjf: .debug_info
//
DumpSubset(Info)
{
//- rjf: gather unit ranges from .debug_info
Rng1U64Array *unit_info_ranges = 0;
if(lane_idx() == 0)
{
unit_info_ranges = push_array(scratch.arena, Rng1U64Array, 1);
*unit_info_ranges = dw2_unit_ranges_from_data(scratch.arena, raw->sec[DW_SectionKind_Info].data);
}
lane_sync_u64(&unit_info_ranges, 0);
U64 unit_count = unit_info_ranges->count;
//- rjf: parse all .debug_info unit headers
DW2_UnitHeader *unit_headers = 0;
Rng1U64 *unit_info_tag_ranges = 0;
{
// rjf: set up
if(lane_idx() == 0)
{
unit_headers = push_array(scratch.arena, DW2_UnitHeader, unit_count);
unit_info_tag_ranges = push_array(scratch.arena, Rng1U64, unit_count);
}
lane_sync_u64(&unit_headers, 0);
lane_sync_u64(&unit_info_tag_ranges, 0);
// rjf: parse all unit headers
String8 data = raw->sec[DW_SectionKind_Info].data;
Rng1U64 range = lane_range(unit_count);
for EachInRange(idx, range)
{
Rng1U64 unit_info_range = unit_info_ranges->v[idx];
U64 bytes_read = dw2_read_unit_header(str8_substr(data, unit_info_range), 0, &unit_headers[idx]);
unit_info_tag_ranges[idx] = r1u64(unit_info_range.min + bytes_read, unit_info_range.max);
}
}
lane_sync();
Rng1U64Array unit_info_tag_ranges_array = {unit_info_tag_ranges, unit_count};
//- rjf: build all abbreviation maps, build (unit -> abbrev map)
DW2_UnitAbbrevMapMap unit_abbrev_map_map = dw2_unit_abbrev_map_map_from_data(scratch.arena, raw->sec[DW_SectionKind_Abbrev].data, unit_headers, unit_count);
//- rjf: parse all unit offsets tables
DW2_OffsetTableSet *offset_tables = 0;
if(lane_idx() == 0)
{
offset_tables = push_array(scratch.arena, DW2_OffsetTableSet, 1);
offset_tables[0] = dw2_offset_table_set_from_raw(scratch.arena, raw);
}
lane_sync_u64(&offset_tables, 0);
//- rjf: build per-unit parsing contexts
DW2_ParseCtx *unit_parse_ctxs = 0;
{
if(lane_idx() == 0)
{
unit_parse_ctxs = push_array(scratch.arena, DW2_ParseCtx, unit_count);
}
lane_sync_u64(&unit_parse_ctxs, 0);
Rng1U64 range = lane_range(unit_count);
for EachInRange(unit_idx, range)
{
DW2_UnitHeader *hdr = &unit_headers[unit_idx];
DW2_ParseCtx *ctx = &unit_parse_ctxs[unit_idx];
// rjf: equip initial bootstrapping info
dw2_parse_ctx_equip_unit_header(ctx, hdr, unit_info_ranges->v[unit_idx].min);
dw2_parse_ctx_equip_unit_abbrev_map(ctx, &unit_abbrev_map_map, unit_idx);
// rjf: do bootstrapping parse of root tag
DW2_Tag root_tag_bootstrap = {0};
dw2_read_tag(scratch.arena, raw, ctx, raw->sec[DW_SectionKind_Info].data, unit_info_tag_ranges[unit_idx].min, &root_tag_bootstrap);
// rjf: equip info extracted from bootstrapping parse
dw2_parse_ctx_equip_unit_root_tag(ctx, &root_tag_bootstrap, offset_tables);
// rjf: do non-bootstrapping parse
DW2_Tag root_tag = {0};
dw2_read_tag(scratch.arena, raw, ctx, raw->sec[DW_SectionKind_Info].data, unit_info_tag_ranges[unit_idx].min, &root_tag);
// rjf: equip info extracted from non-bootstrapping parse
dw2_parse_ctx_equip_unit_root_tag(ctx, &root_tag, offset_tables);
}
}
lane_sync();
//- rjf: dump all unit tag trees
String8List *unit_dumps = 0;
if(lane_idx() == 0)
{
unit_dumps = push_array(scratch.arena, String8List, unit_count);
}
lane_sync_u64(&unit_dumps, 0);
U64 unit_take_idx_ = 0;
U64 *unit_take_idx_ptr = &unit_take_idx_;
lane_sync_u64(&unit_take_idx_ptr, 0);
String8List *strings_restore = strings;
for(;;)
{
//- rjf: take unit
U64 unit_idx = ins_atomic_u64_inc_eval(unit_take_idx_ptr)-1;
if(unit_idx >= unit_count)
{
break;
}
//- rjf: unpack unit
strings = &unit_dumps[unit_idx];
DW2_ParseCtx *ctx = &unit_parse_ctxs[unit_idx];
//- rjf: dump
dumpf(" unit: // unit[%I64u], .debug_info@0x%I64x\n", unit_idx, ctx->unit_base_info_off);
dumpf(" {\n");
dumpf(" version: %u\n", ctx->version);
dumpf(" format: %S\n", dw_string_from_format(ctx->format));
dumpf(" abbrev_off: 0x%I64x\n", unit_headers[unit_idx].abbrev_off);
dumpf(" addr_size: %I64u\n", ctx->addr_size);
dumpf(" kind: %S\n", dw_string_from_comp_unit_kind(unit_headers[unit_idx].kind));
dumpf(" dwo_id: 0x%I64x\n", unit_headers[unit_idx].dwo_id);
dumpf(" tags:\n {\n");
{
U64 depth = 0;
for(U64 off = unit_info_tag_ranges[unit_idx].min; off < unit_info_tag_ranges[unit_idx].max;)
{
U64 start_off = off;
Temp tag_scratch = scratch_begin(&scratch.arena, 1);
// rjf: parse next tag
DW2_Tag tag = {0};
off += dw2_read_tag(tag_scratch.arena, raw, ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
// rjf: non-zero tag -> dump
if(tag.kind != DW_TagKind_Null)
{
dumpf(" %.*s%S: // .debug_info@0x%I64x\n", depth, indent.str, dw_string_from_tag_kind(ctx->version, ctx->exts, tag.kind), start_off);
dumpf(" %.*s{\n", depth, indent.str);
for EachNode(n, DW2_AttribNode, tag.attribs.first)
{
DW2_Attrib *attrib = &n->v;
String8 kind_string = dw_string_from_attrib_kind(ctx->version, ctx->exts, attrib->attrib_kind);
String8 form_kind_string = dw_string_from_form_kind(ctx->version, ctx->exts, attrib->val.kind);
String8 value_string = {0};
DW_AttribClass value_class = dw_attrib_class_from_form_kind(ctx->version, ctx->exts, attrib->val.kind);
switch(value_class)
{
default:
{
value_string = str8f(tag_scratch.arena, "0x%I64x", attrib->val.u128.u64[0]);
}break;
case DW_AttribClass_Address:
{
value_string = str8f(tag_scratch.arena, "0x%I64x", attrib->val.addr);
}break;
case DW_AttribClass_String:
{
value_string = str8f(tag_scratch.arena, "\"%S\"", attrib->val.string);
}break;
case DW_AttribClass_Flag:
{
value_string = attrib->val.u128.u64[0] ? s("true") : s("false");
}break;
case DW_AttribClass_Block:
{
String8 block = attrib->val.string;
String8List block_strs = numeric_str8_list_from_data(tag_scratch.arena, 16, block, 1);
value_string = str8_list_join(tag_scratch.arena, &block_strs, &(StringJoin){.pre = s("{ "), .sep = s(", "), .post = s(" }")});
}break;
case DW_AttribClass_ExprLoc:
{
String8 expr = attrib->val.string;
String8List expr_strs = dw_dump_list_from_expr(tag_scratch.arena, expr, arch, ctx);
value_string = str8_list_join(tag_scratch.arena, &expr_strs, &(StringJoin){.pre = s("{ "), .sep = s(", "), .post = s(" }")});
}break;
}
dumpf(" %.*s %S: %S // %S\n", depth, indent.str, kind_string, value_string, form_kind_string);
}
}
// rjf: push/pop
if(tag.has_children)
{
depth += 1;
}
else if(tag.kind == DW_TagKind_Null)
{
depth -= 1;
}
// rjf: if tag does not have children -> end info
if(!tag.has_children)
{
dumpf(" %.*s}\n", depth, indent.str);
}
scratch_end(tag_scratch);
if(off == start_off)
{
break;
}
}
}
dumpf(" }\n");
dumpf(" }\n");
}
strings = strings_restore;
//- rjf: join unit dumps in order
if(lane_idx() == 0)
{
dumpf("\nunits:\n{\n");
for EachIndex(unit_idx, unit_count)
{
str8_list_concat_in_place(strings, &unit_dumps[unit_idx]);
}
dumpf("}\n");
}
lane_sync();
}
//////////////////////////////
//- rjf: .debug_line
//
DumpSubset(Line)
{
// TODO(rjf)
}
//////////////////////////////
//- rjf: .debug_str
//
DumpSubset(Str)
{
if(lane_idx() == 0)
{
dumpf("\nstrings:\n{\n");
String8 data = raw->sec[DW_SectionKind_Str].data;
U64 idx = 0;
for(U64 off = 0; off < data.size; idx += 1)
{
U64 start_off = off;
String8 string = {0};
off += str8_deserial_read_cstr(data, off, &string);
dumpf(" {\"%S\"} // string[%I64u], .debug_str@0x%I64x\n", string, idx, start_off);
if(off == start_off)
{
break;
}
}
dumpf("}\n");
}
}
//////////////////////////////
//- rjf: .debug_frame
//
#if 0
DumpSubset(Frame)
{
// TODO(rjf)
}
#endif
//////////////////////////////
//- rjf: .debug_loc
//
#if 0
DumpSubset(Loc)
{
// TODO(rjf)
}
#endif
//////////////////////////////
//- rjf: join results
//
String8List *result_strings_ptr = push_array(scratch.arena, String8List, 1);
lane_sync();
if(lane_idx() == 0)
{
for EachNode(n, DumpSubsetOutputNode, first_output_node)
{
String8List subset_strings = {0};
for EachIndex(idx, lane_count())
{
str8_list_concat_in_place(&subset_strings, &n->lane_strings[idx]);
}
if(subset_strings.total_size != 0)
{
str8_list_pushf(arena, result_strings_ptr, "////////////////////////////////\n//~ %S\n", dw_regular_name_from_section_kind(n->section_kind));
str8_list_concat_in_place(result_strings_ptr, &subset_strings);
str8_list_pushf(arena, result_strings_ptr, "\n");
}
}
}
lane_sync();
lane_sync_u64(&result_strings_ptr, 0);
String8List result_strings = *result_strings_ptr;
lane_sync();
#undef DumpSubsetKind
#undef DumpSubset
#undef dump
#undef dumpf
scratch_end(scratch);
ProfEnd();
return result_strings;
}
-17
View File
@@ -1,17 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_DUMP_2_H
#define DWARF_DUMP_2_H
////////////////////////////////
//~ rjf: Helpers
internal String8List dw_dump_list_from_expr(Arena *arena, String8 data, Arch arch, DW2_ParseCtx *ctx);
////////////////////////////////
//~ rjf: Main Dump Entry Point
internal String8List dw_dump_list_from_raw(Arena *arena, DW_Raw *raw, Arch arch, DW_SectionFlags subset_flags);
#endif //DWARF_DUMP_2_H
+349 -1536
View File
File diff suppressed because it is too large Load Diff
+42 -209
View File
@@ -5,229 +5,62 @@
#define DWARF_EXPR_H
////////////////////////////////
// evaluator
//~ rjf: Evaluation Values
#define DW_ExprValueType_IsSigned(x) ((x) == DW_ExprValueType_S8 || (x) == DW_ExprValueType_S16 || (x) == DW_ExprValueType_S32 || (x) == DW_ExprValueType_S64 || (x) == DW_ExprValueType_S128 || (x) == DW_ExprValueType_S256 || (x) == DW_ExprValueType_S512)
#define DW_ExprValueType_IsUnsigned(x) ((x) == DW_ExprValueType_U8 || (x) == DW_ExprValueType_U16 || (x) == DW_ExprValueType_U32 || (x) == DW_ExprValueType_U64 || (x) == DW_ExprValueType_U128 || (x) == DW_ExprValueType_U256 || (x) == DW_ExprValueType_U512)
#define DW_ExprValueType_IsFloat(x) ((x) == DW_ExprValueType_F32 || (x) == DW_ExprValueType_F64)
#define DW_ExprValueType_IsInt(x) (DW_ExprValueType_IsSigned(x) || DW_ExprValueType_IsUnsigned(x) || (x) == DW_ExprValueType_Addr)
typedef enum
typedef struct DW_EvalVal DW_EvalVal;
struct DW_EvalVal
{
DW_ExprValueType_Generic,
DW_ExprValueType_U8,
DW_ExprValueType_U16,
DW_ExprValueType_U32,
DW_ExprValueType_U64,
DW_ExprValueType_U128,
DW_ExprValueType_U256,
DW_ExprValueType_U512,
DW_ExprValueType_S8,
DW_ExprValueType_S16,
DW_ExprValueType_S32,
DW_ExprValueType_S64,
DW_ExprValueType_S128,
DW_ExprValueType_S256,
DW_ExprValueType_S512,
DW_ExprValueType_F32,
DW_ExprValueType_F64,
DW_ExprValueType_Addr,
DW_ExprValueType_Implicit,
DW_ExprValueType_Bool,
} DW_ExprValueType;
typedef S8 DW_ExprBool;
typedef struct DW_ExprValue
{
DW_ExprValueType type;
Rng1U64Array ranges;
U64 *offsets;
union {
U8 u8;
U16 u16;
U32 u32;
U64 u64;
U128 u128;
U256 u256;
U512 u512;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
F32 f32;
F64 f64;
U64 addr;
DW_ExprBool boolean;
String8 implicit;
String8 generic;
union
{
U512 u512;
S64 s64;
};
} DW_ExprValue;
String8 data;
};
typedef struct DW_ExprValueNode
typedef struct DW_EvalValNode DW_EvalValNode;
struct DW_EvalValNode
{
DW_ExprValue v;
struct DW_ExprValueNode *next;
} DW_ExprValueNode;
typedef enum
{
DW_PieceKind_Null,
DW_PieceKind_Value,
DW_PieceKind_Undefined,
} DW_PieceKind;
typedef struct DW_Piece
{
DW_PieceKind kind;
U64 bit_size;
U8 *value;
} DW_Piece;
typedef struct DW_PieceNode
{
DW_Piece v;
struct DW_PieceNode *next;
} DW_PieceNode;
typedef struct DW_PieceList
{
U64 count;
DW_PieceNode *first;
DW_PieceNode *last;
} DW_PieceList;
typedef struct DW_ExprStack
{
U64 count;
DW_ExprValueNode *top;
} DW_ExprStack;
typedef enum
{
DW_ExprEvalResult_Fail,
DW_ExprEvalResult_Ok,
DW_ExprEvalResult_Maybe,
DW_ExprEvalResult_ExecOpLimitReached,
} DW_ExprEvalResult;
DW_EvalValNode *next;
DW_EvalVal v;
};
////////////////////////////////
// encoder
//~ rjf: Evaluation Results
typedef enum
typedef enum DW_EvalStatus
{
DW_ExprEncType_Null,
DW_ExprEncType_Op,
DW_ExprEncType_U8,
DW_ExprEncType_U16,
DW_ExprEncType_U32,
DW_ExprEncType_U64,
DW_ExprEncType_S8,
DW_ExprEncType_S16,
DW_ExprEncType_S32,
DW_ExprEncType_S64,
DW_ExprEncType_ULEB128,
DW_ExprEncType_SLEB128,
DW_ExprEncType_Addr,
DW_ExprEncType_Block,
DW_ExprEncType_DwarfUInt,
DW_ExprEncType_Label,
DW_ExprEncType_DeclLabel,
} DW_ExprEncType;
DW_EvalStatus_Error,
DW_EvalStatus_FailedMemoryRead,
DW_EvalStatus_ExecOpLimitReached,
DW_EvalStatus_UnsupportedOp,
DW_EvalStatus_Good,
}
DW_EvalStatus;
typedef struct DW_ExprEnc
typedef struct DW_Eval DW_Eval;
struct DW_Eval
{
DW_ExprEncType type;
union {
DW_ExprOp op;
U8 u8;
U16 u16;
U32 u32;
U64 u64;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
U64 addr;
String8 block;
String8 label;
};
} DW_ExprEnc;
#define DW_ExprEnc_Op(v) { .type = DW_ExprEncType_Op, .op = DW_ExprOp_##v }
#define DW_ExprEnc_U8(v) { .type = DW_ExprEncType_U8, .u8 = v }
#define DW_ExprEnc_U16(v) { .type = DW_ExprEncType_U16, .u16 = v }
#define DW_ExprEnc_U32(v) { .type = DW_ExprEncType_U32, .u32 = v }
#define DW_ExprEnc_U64(v) { .type = DW_ExprEncType_U64, .u64 = v }
#define DW_ExprEnc_S8(v) { .type = DW_ExprEncType_S8, .s8 = v }
#define DW_ExprEnc_S16(v) { .type = DW_ExprEncType_S16, .s16 = v }
#define DW_ExprEnc_S32(v) { .type = DW_ExprEncType_S32, .s32 = v }
#define DW_ExprEnc_S64(v) { .type = DW_ExprEncType_S64, .s64 = v }
#define DW_ExprEnc_ULEB128(v) { .type = DW_ExprEncType_ULEB128, .u64 = v }
#define DW_ExprEnc_SLEB128(v) { .type = DW_ExprEncType_SLEB128, .s64 = v }
#define DW_ExprEnc_Addr(v) { .type = DW_ExprEncType_Addr, .addr = v }
#define DW_ExprEnc_Block(v) { .type = DW_ExprEncType_Block, .block = v }
#define DW_ExprEnc_UInt(v) { .type = DW_ExprEncType_DwarfUInt, .u64 = v }
#define DW_ExprEnc_Label(v) { .type = DW_ExprEncType_Label, .label = str8_lit_comp(v) }
#define DW_ExprEnc_DeclLabel(v) { .type = DW_ExprEncType_DeclLabel, .label = str8_lit_comp(v) }
DW_EvalVal val;
DW_EvalStatus status;
Rng1U64 missed_read_vaddr_range;
};
////////////////////////////////
//~ rjf: Evaluation State Machine
// pieces
internal DW_PieceNode * dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v);
typedef struct DW_EvalState DW_EvalState;
struct DW_EvalState
{
U64 off;
U64 op_idx;
DW_EvalValNode *top_val;
DW_EvalValNode *free_val;
};
// size -> type
internal DW_ExprValueType dw_expr_unsigned_value_type_from_bit_size(U64 bit_size);
internal DW_ExprValueType dw_expr_signed_value_type_from_bit_size(U64 bit_size);
internal DW_ExprValueType dw_expr_float_type_from_bit_size(U64 bit_size);
////////////////////////////////
//~ rjf: Expression Evaluation Functions
// type -> size
internal U64 dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k);
// typer
internal DW_ExprValueType dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
internal DW_ExprValueType dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
internal DW_ExprValue dw_expr_cast(DW_ExprValue value, DW_ExprValueType type);
// arithmetic operators
internal DW_ExprValue dw_expr_add (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_mul (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_div (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_mod (DW_ExprValue rhs, DW_ExprValue lhs);
// comparison operators
internal DW_ExprValue dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs);
// bitwise operators
internal DW_ExprValue dw_expr_xor (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_and (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_or (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shl (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shr (DW_ExprValue rhs, DW_ExprValue lhs);
internal DW_ExprValue dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs);
// unary operators
internal DW_ExprValue dw_expr_abs(DW_ExprValue value);
internal DW_ExprValue dw_expr_neg(DW_ExprValue value);
internal DW_ExprValue dw_expr_not(DW_ExprValue value);
// stack
internal DW_ExprValueNode * dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value);
internal DW_ExprValueNode * dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size);
internal DW_ExprValue dw_expr_stack_pop(DW_ExprStack *stack);
internal DW_ExprValue dw_expr_stack_peek(DW_ExprStack *stack);
internal DW_ExprValueNode * dw_expr_stack_pick(DW_ExprStack *stack, U64 idx);
// value helpers
internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v);
// evaluator
internal DW_ExprEvalResult dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls_base, U64 op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out);
#endif //DWARF_EXPR_H
internal DW_Eval dw_eval(Arena *arena, DW_Format fmt, Arch arch, MemoryMap *memory_map, void *regs, U64 frame_base, U64 cfa, U64 tls, DW_EvalState *state, String8 expr, U64 op_idx_cap);
#endif // DWARF_EXPR_H
-393
View File
@@ -1,393 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Expression Evaluation Functions
internal DW_Eval
dw_eval(Arena *arena, DW_Format fmt, Arch arch, MemoryMap *memory_map, void *regs, U64 frame_base, U64 cfa, U64 tls, DW_EvalState *state, String8 expr, U64 op_idx_cap)
{
DW_Eval result = {0};
ARCH_Info *arch_info = arch_info_from_arch(arch);
B32 need_a_break = 0;
B32 done = 0;
for(;state->off < expr.size && !need_a_break && !done;)
{
U64 start_off = state->off;
U64 off = state->off;
//- rjf: too many ops? -> error
if(state->op_idx >= op_idx_cap)
{
result.status = DW_EvalStatus_ExecOpLimitReached;
break;
}
//- rjf: read next opcode
DW_ExprOp opcode = 0;
off += str8_deserial_read_struct(expr, off, &opcode);
//- rjf: unpack opcode
U8 push_count = 0;
U8 pop_count = 0;
U8 operand_count = 0;
DW_ExprOperandKind operand_kinds[2] = {DW_ExprOperandKind_Null};
{
DW_ExprOpInfo *op_info = dw_info_from_expr_op(DW_Version_5, DW_ExtFlag_All, opcode);
push_count = op_info->push_count;
pop_count = op_info->pop_count;
operand_count = op_info->operand_count;
MemoryCopy(operand_kinds, op_info->operand_kinds, sizeof(operand_kinds));
}
//- rjf: read operands
DW_EvalVal operands[2] = {0};
for(U8 operand_idx = 0; operand_idx < operand_count; operand_idx += 1)
{
U64 fixed_bytes_to_read = 0;
switch(operand_kinds[operand_idx])
{
default:{}break;
case DW_ExprOperandKind_U8: {fixed_bytes_to_read = 1;}goto fixed_read;
case DW_ExprOperandKind_U16: {fixed_bytes_to_read = 2;}goto fixed_read;
case DW_ExprOperandKind_U32: {fixed_bytes_to_read = 4;}goto fixed_read;
case DW_ExprOperandKind_U64: {fixed_bytes_to_read = 8;}goto fixed_read;
case DW_ExprOperandKind_S8: {fixed_bytes_to_read = 1;}goto fixed_read;
case DW_ExprOperandKind_S16: {fixed_bytes_to_read = 2;}goto fixed_read;
case DW_ExprOperandKind_S32: {fixed_bytes_to_read = 4;}goto fixed_read;
case DW_ExprOperandKind_S64: {fixed_bytes_to_read = 8;}goto fixed_read;
case DW_ExprOperandKind_Addr: {fixed_bytes_to_read = byte_size_from_arch(arch);}goto fixed_read;
case DW_ExprOperandKind_DwarfUInt:{fixed_bytes_to_read = dw_addr_size_from_format(fmt);}goto fixed_read;
fixed_read:;
{
off += str8_deserial_read(expr, off, &operands[operand_idx].u512.u64[0], fixed_bytes_to_read, fixed_bytes_to_read);
}break;
case DW_ExprOperandKind_ULEB128:
{
off += str8_deserial_read_uleb128(expr, off, &operands[operand_idx].u512.u64[0]);
}break;
case DW_ExprOperandKind_SLEB128:
{
off += str8_deserial_read_sleb128(expr, off, &operands[operand_idx].s64);
}break;
case DW_ExprOperandKind_Block:
{
U8 block_size = 0;
off += str8_deserial_read_struct(expr, off, &block_size);
operands[operand_idx].data = str8_prefix(str8_skip(expr, off), block_size);
}break;
}
}
//- rjf: do pops
DW_EvalVal popped_vals[3] = {0};
{
pop_count = Min(pop_count, ArrayCount(popped_vals));
for(U8 pop_idx = 0; pop_idx < pop_count; pop_idx += 1)
{
if(state->top_val != 0)
{
DW_EvalValNode *popped = state->top_val;
SLLStackPop(state->top_val);
popped_vals[pop_idx] = popped->v;
SLLStackPush(state->free_val, popped);
}
}
}
//- rjf: apply opcode
DW_EvalVal push_vals[3] = {0};
U64 pick_target_idx = 0;
U64 deref_read_size = 0;
DW_RegCode reg_code_dw = 0;
switch(opcode)
{
//- rjf: unsuported ops
case DW_ExprOp_Call2: // DWARF function calls
case DW_ExprOp_Call4: // DWARF function calls
case DW_ExprOp_CallRef: // DWARF function calls
case DW_ExprOp_Addrx: // address in .debug_addr; not currently present for us, need to find how to preserve if we care
case DW_ExprOp_Constx: // address in .debug_addr; not currently present for us, need to find how to preserve if we care
case DW_ExprOp_EntryValue: // encodes a sub-expression as a data block - need to recursively evaluate, lol
case DW_ExprOp_ConstType: // pushes a constant - but refers into DWARF debug info to specify the type. we don't have that, need to figure out how to preserve mapping from DW type ID -> RDI type, if we care
case DW_ExprOp_DerefType: // same as above - refers to DWARF debug info
case DW_ExprOp_RegvalType: // same as above - refers to DWARF debug info
case DW_ExprOp_Piece: // pieces - used to stitch multiple sub-values together
case DW_ExprOp_BitPiece: // pieces - used to stitch multiple sub-values together
case DW_ExprOp_XDeref: // two entries popped from stack - second one is 'address space identifier'. not possible in this layer right now
case DW_ExprOp_XDerefSize: // does multiple address spaces
case DW_ExprOp_XDerefType: // refers to DWARF debug info, *and* does multiple address spaces
case DW_ExprOp_PushObjectAddress: // pushes "the address of the object currently being evaluated" ???
case DW_ExprOp_ImplicitPointer: // refers to DWARF debug info
default:
{
done = 1;
result.status = DW_EvalStatus_UnsupportedOp;
}break;
//- rjf: address ops
case DW_ExprOp_Deref:{deref_read_size = byte_size_from_arch(arch);}goto deref;
case DW_ExprOp_DerefSize:{deref_read_size = operands[0].u512.u64[0];}goto deref;
deref:;
{
U64 vaddr = popped_vals[0].u512.u64[0];
U64 read_size = Min(deref_read_size, sizeof(push_vals[0].u512));
Rng1U64 read_vaddr_range = r1u64(vaddr, vaddr+read_size);
if(!memory_map_read(memory_map, read_vaddr_range, &push_vals[0].u512))
{
need_a_break = 1;
result.status = DW_EvalStatus_FailedMemoryRead;
result.missed_read_vaddr_range = read_vaddr_range;
}
}break;
//- rjf: generic constants
case DW_ExprOp_Const1U: case DW_ExprOp_Const1S:
case DW_ExprOp_Const2U: case DW_ExprOp_Const2S:
case DW_ExprOp_Const4U: case DW_ExprOp_Const4S:
case DW_ExprOp_Const8U: case DW_ExprOp_Const8S:
case DW_ExprOp_ConstU: case DW_ExprOp_ConstS:
case DW_ExprOp_Addr:
{
push_vals[0] = operands[0];
}break;
//- rjf: stack ops
case DW_ExprOp_Dup:{push_vals[0] = popped_vals[0];}break;
case DW_ExprOp_Drop:{/* NOTE(rjf): nothing to do here - just pops */}break;
case DW_ExprOp_Swap:{push_vals[0] = popped_vals[1]; push_vals[1] = popped_vals[0];}break;
case DW_ExprOp_Rot: {push_vals[0] = popped_vals[0]; push_vals[1] = popped_vals[1]; push_vals[2] = popped_vals[2];}break;
case DW_ExprOp_Over:{pick_target_idx = 1;}break;
case DW_ExprOp_Pick:{pick_target_idx = operands[0].u512.u64[0];}goto pick_stack_val;
pick_stack_val:;
{
U64 idx = 0;
for(DW_EvalValNode *n = state->top_val; n != 0; n = n->next, idx += 1)
{
if(idx == pick_target_idx)
{
push_vals[0] = n->v;
break;
}
}
}break;
//- rjf: arithmetic ops
#define UniOpU(k, op) case k:{push_vals[0].u512.u64[0] = op(popped_vals[0].u512.u64[0]);}break
#define UniOpS(k, op) case k:{push_vals[0].s64 = op(popped_vals[0].s64);}break
#define BinOpS(k, op) case k:{push_vals[0].s64 = popped_vals[1].s64 op popped_vals[0].s64;}break
#define BinOpU(k, op) case k:{push_vals[0].u512.u64[0] = popped_vals[1].u512.u64[0] op popped_vals[0].u512.u64[0];}break
#define BinOpDiv(k, op) case k:if(popped_vals[0].u512.u64[0] != 0){push_vals[0].u512.u64[0] = popped_vals[1].u512.u64[0] op popped_vals[0].u512.u64[0];}break
UniOpS(DW_ExprOp_Abs, abs_s64);
UniOpS(DW_ExprOp_Neg, -);
UniOpU(DW_ExprOp_Not, !);
BinOpU(DW_ExprOp_Minus, -);
BinOpU(DW_ExprOp_Mul, *);
BinOpU(DW_ExprOp_Plus, +);
BinOpU(DW_ExprOp_Shl, <<);
BinOpU(DW_ExprOp_Shr, >>);
BinOpU(DW_ExprOp_And, &);
BinOpU(DW_ExprOp_Or, |);
BinOpU(DW_ExprOp_Xor, ^);
BinOpS(DW_ExprOp_Shra, >>);
BinOpDiv(DW_ExprOp_Div, /);
BinOpDiv(DW_ExprOp_Mod, %);
BinOpU(DW_ExprOp_Eq, ==);
BinOpU(DW_ExprOp_Ne, !=);
BinOpS(DW_ExprOp_Ge, >=);
BinOpS(DW_ExprOp_Gt, >);
BinOpS(DW_ExprOp_Le, <=);
BinOpS(DW_ExprOp_Lt, <);
#undef UniOpU
#undef UniOpS
#undef BinOpS
#undef BinOpU
#undef BinOpDiv
case DW_ExprOp_PlusUConst:
{
push_vals[0].u512.u64[0] = popped_vals[0].u512.u64[0] + operands[0].u512.u64[0];
}break;
//- rjf: jumps/branches
case DW_ExprOp_Bra:
{
if(popped_vals[0].u512.u64[0] == 0)
{
break;
}
} // fallthrough
case DW_ExprOp_Skip:
{
S64 jump_delta = operands[0].s64;
if((jump_delta < 0 && -jump_delta > off) || (off + jump_delta >= expr.size))
{
done = 1;
result.status = DW_EvalStatus_Error;
}
else
{
off += jump_delta;
}
}break;
//- rjf: literals
case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: case DW_ExprOp_Lit3:
case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: case DW_ExprOp_Lit6: case DW_ExprOp_Lit7:
case DW_ExprOp_Lit8: case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11:
case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: case DW_ExprOp_Lit15:
case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: case DW_ExprOp_Lit18: case DW_ExprOp_Lit19:
case DW_ExprOp_Lit20: case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23:
case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: case DW_ExprOp_Lit27:
case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: case DW_ExprOp_Lit30: case DW_ExprOp_Lit31:
{
U8 val = (opcode - DW_ExprOp_Lit0);
push_vals[0].u512.u8[0] = val;
}break;
//- rjf: register reads (opcode-encoded reg)
case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: case DW_ExprOp_Reg3:
case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: case DW_ExprOp_Reg6: case DW_ExprOp_Reg7:
case DW_ExprOp_Reg8: case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11:
case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: case DW_ExprOp_Reg15:
case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: case DW_ExprOp_Reg18: case DW_ExprOp_Reg19:
case DW_ExprOp_Reg20: case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23:
case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: case DW_ExprOp_Reg27:
case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: case DW_ExprOp_Reg30: case DW_ExprOp_Reg31:
{reg_code_dw = (opcode - DW_ExprOp_Reg0);}goto reg_read;
case DW_ExprOp_RegX:
{reg_code_dw = operands[0].u512.u64[0];}goto reg_read;
reg_read:;
{
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_code_dw);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
U64 read_size = dim_1u16(reg_rng);
read_size = Min(read_size, sizeof(push_vals[0].u512));
reg_rng.max = reg_rng.min + read_size;
arch_reg_block_read_range(arch_info, regs, reg_rng, &push_vals[0].u512);
}break;
//- rjf: register reads (opcode-encoded reg + offset)
case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: case DW_ExprOp_BReg3:
case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: case DW_ExprOp_BReg6: case DW_ExprOp_BReg7:
case DW_ExprOp_BReg8: case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11:
case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: case DW_ExprOp_BReg15:
case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: case DW_ExprOp_BReg18: case DW_ExprOp_BReg19:
case DW_ExprOp_BReg20: case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23:
case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: case DW_ExprOp_BReg27:
case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: case DW_ExprOp_BReg30: case DW_ExprOp_BReg31:
{reg_code_dw = (opcode - DW_ExprOp_BReg0);}goto based_reg_read;
case DW_ExprOp_BRegX:
{reg_code_dw = operands[0].u512.u64[0];}goto based_reg_read;
based_reg_read:;
{
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_code_dw);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
U64 read_size = dim_1u16(reg_rng);
read_size = Min(read_size, sizeof(push_vals[0].u512));
reg_rng.max = reg_rng.min + read_size;
arch_reg_block_read_range(arch_info, regs, reg_rng, &push_vals[0].u512);
push_vals[0].u512.u64[0] += operands[0].s64;
}break;
//- rjf: frame base register read
case DW_ExprOp_FBReg:
{
push_vals[0].u512.u64[0] = (U64)(frame_base + operands[0].s64);
}break;
//- rjf: TLS
case DW_ExprOp_FormTlsAddress:
{
U64 tls_off = popped_vals[0].u512.u64[0];
U64 tls_addr = tls + tls_off;
push_vals[0].u512.u64[0] = tls_addr;
}break;
//- rjf: call frame CFA
case DW_ExprOp_CallFrameCfa:
{
push_vals[0].u512.u64[0] = cfa;
}break;
//- rjf: implicit location descriptions (value is known, location is not)
case DW_ExprOp_ImplicitValue:
{
push_vals[0] = operands[0];
}break;
case DW_ExprOp_StackValue:
{
// NOTE(rjf): nothing to do here - program is over, value (but not location) has
// been evaluated and exists as the top entry on the stack.
}break;
//- rjf: conversions
case DW_ExprOp_Convert:
case DW_ExprOp_Reinterpret:
{
if(operands[0].u512.u64[0] == 0)
{
push_vals[0] = popped_vals[0];
}
else
{
// NOTE(rjf): with a nonzero operand, it is expecting us to read into the
// DWARF debug info and push as that base type. we do not have access to that
// in the general case here, and we need to figure out how to preserve that info
// if we care.
done = 1;
result.status = DW_EvalStatus_UnsupportedOp;
}
}break;
}
//- rjf: do pushes
if(!done && !need_a_break)
{
push_count = Min(push_count, ArrayCount(push_vals));
for(U8 push_idx = 0; push_idx < push_count; push_idx += 1)
{
DW_EvalValNode *n = state->free_val;
if(n != 0)
{
SLLStackPop(state->free_val);
}
else
{
n = push_array(arena, DW_EvalValNode, 1);
}
n->v = push_vals[push_idx];
SLLStackPush(state->top_val, n);
}
}
//- rjf: do not need a break? advance state.
//
// (if we *do* need a break, this means we need to ask the caller for
// more info, like memory reads, and so we want to resume from the
// offset just before this opcode)
//
if(!need_a_break)
{
state->op_idx += 1;
state->off = off;
}
//- rjf: at the end of the expression? -> set success, fill result
if(off == expr.size)
{
result.status = DW_EvalStatus_Good;
if(state->top_val != 0)
{
result.val = state->top_val->v;
}
}
//- rjf: did not advance? -> error
if(off == start_off)
{
result.status = DW_EvalStatus_Error;
break;
}
}
return result;
}
-66
View File
@@ -1,66 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_EXPR_2_H
#define DWARF_EXPR_2_H
////////////////////////////////
//~ rjf: Evaluation Values
typedef struct DW_EvalVal DW_EvalVal;
struct DW_EvalVal
{
union
{
U512 u512;
S64 s64;
};
String8 data;
};
typedef struct DW_EvalValNode DW_EvalValNode;
struct DW_EvalValNode
{
DW_EvalValNode *next;
DW_EvalVal v;
};
////////////////////////////////
//~ rjf: Evaluation Results
typedef enum DW_EvalStatus
{
DW_EvalStatus_Error,
DW_EvalStatus_FailedMemoryRead,
DW_EvalStatus_ExecOpLimitReached,
DW_EvalStatus_UnsupportedOp,
DW_EvalStatus_Good,
}
DW_EvalStatus;
typedef struct DW_Eval DW_Eval;
struct DW_Eval
{
DW_EvalVal val;
DW_EvalStatus status;
Rng1U64 missed_read_vaddr_range;
};
////////////////////////////////
//~ rjf: Evaluation State Machine
typedef struct DW_EvalState DW_EvalState;
struct DW_EvalState
{
U64 off;
U64 op_idx;
DW_EvalValNode *top_val;
DW_EvalValNode *free_val;
};
////////////////////////////////
//~ rjf: Expression Evaluation Functions
internal DW_Eval dw_eval(Arena *arena, DW_Format fmt, Arch arch, MemoryMap *memory_map, void *regs, U64 frame_base, U64 cfa, U64 tls, DW_EvalState *state, String8 expr, U64 op_idx_cap);
#endif // DWARF_EXPR_2_H
+4 -4
View File
@@ -2,10 +2,10 @@
// Licensed under the MIT license (https://opensource.org/license/mit/)
#include "dwarf/dwarf.c"
#include "dwarf/dwarf_expr_2.c"
#include "dwarf/dwarf_parse_2.c"
#include "dwarf/dwarf_unwind_2.c"
#include "dwarf/dwarf_dump_2.c"
#include "dwarf/dwarf_parse.c"
#include "dwarf/dwarf_expr.c"
#include "dwarf/dwarf_unwind.c"
#include "dwarf/dwarf_dump.c"
#if defined(COFF_H)
# include "dwarf/dwarf_parse_coff.c"
#endif
+4 -4
View File
@@ -5,10 +5,10 @@
#define DWARF_INC_H
#include "dwarf/dwarf.h"
#include "dwarf/dwarf_expr_2.h"
#include "dwarf/dwarf_parse_2.h"
#include "dwarf/dwarf_unwind_2.h"
#include "dwarf/dwarf_dump_2.h"
#include "dwarf/dwarf_parse.h"
#include "dwarf/dwarf_expr.h"
#include "dwarf/dwarf_unwind.h"
#include "dwarf/dwarf_dump.h"
#if defined(COFF_H)
# include "dwarf/dwarf_parse_coff.h"
#endif
+1829 -3244
View File
File diff suppressed because it is too large Load Diff
+369 -441
View File
@@ -4,525 +4,453 @@
#ifndef DWARF_PARSE_H
#define DWARF_PARSE_H
typedef struct DW_Section
////////////////////////////////
//~ rjf: Raw Section Data
typedef struct DW_Section DW_Section;
struct DW_Section
{
String8 name;
String8 data;
B32 is_dwo;
} DW_Section;
};
typedef struct DW_Raw
typedef struct DW_Raw DW_Raw;
struct DW_Raw
{
DW_Section sec[DW_Section_COUNT];
DW_Section sup[DW_Section_COUNT];
} DW_Raw;
DW_Section sec[DW_SectionKind_COUNT];
DW_Section sup[DW_SectionKind_COUNT];
};
typedef struct DW_ListUnit
////////////////////////////////
//~ rjf: Unit Headers
typedef struct DW2_UnitHeader DW2_UnitHeader;
struct DW2_UnitHeader
{
DW_Version version;
U64 address_size;
U64 segment_selector_size;
U64 entry_size;
String8 entries;
} DW_ListUnit;
DW_Format format;
U64 abbrev_off;
U64 addr_size;
DW_CompUnitKind kind;
U64 dwo_id;
};
typedef struct DW_ListUnitInput
////////////////////////////////
//~ rjf: Abbreviation Map (ID -> .debug_abbrev Offset)
typedef struct DW2_AbbrevAttrib DW2_AbbrevAttrib;
struct DW2_AbbrevAttrib
{
U64 addr_count;
U64 str_offset_count;
U64 rnglist_count;
U64 loclist_count;
Rng1U64Array addr_ranges;
Rng1U64Array str_offset_ranges;
Rng1U64Array rnglist_ranges;
Rng1U64Array loclist_ranges;
DW_ListUnit *addrs;
DW_ListUnit *str_offsets;
DW_ListUnit *rnglists;
DW_ListUnit *loclists;
} DW_ListUnitInput;
DW_AttribKind attrib_kind;
DW_FormKind form_kind;
U64 implicit_const;
};
typedef struct DW_AbbrevTableEntry
typedef struct DW2_AbbrevAttribNode DW2_AbbrevAttribNode;
struct DW2_AbbrevAttribNode
{
DW2_AbbrevAttribNode *next;
DW2_AbbrevAttrib v;
};
typedef struct DW2_AbbrevAttribList DW2_AbbrevAttribList;
struct DW2_AbbrevAttribList
{
DW2_AbbrevAttribNode *first;
DW2_AbbrevAttribNode *last;
U64 count;
};
typedef struct DW2_AbbrevHeader DW2_AbbrevHeader;
struct DW2_AbbrevHeader
{
U64 id;
U64 off;
} DW_AbbrevTableEntry;
typedef struct DW_AbbrevTable DW_AbbrevTable;
struct DW_AbbrevTable
{
U64 count;
DW_AbbrevTableEntry *entries;
DW_TagKind tag_kind;
B8 has_children;
};
typedef enum DW_AbbrevKind
typedef struct DW2_AbbrevMapNode DW2_AbbrevMapNode;
struct DW2_AbbrevMapNode
{
DW_Abbrev_Null,
DW_Abbrev_Tag,
DW_Abbrev_Attrib,
DW_Abbrev_AttribSequenceEnd,
DW_Abbrev_DIEBegin,
DW_Abbrev_DIEEnd,
} DW_AbbrevKind;
DW2_AbbrevMapNode *next;
U64 id;
U64 off;
};
typedef U32 DW_AbbrevFlags;
typedef struct DW2_AbbrevMap DW2_AbbrevMap;
struct DW2_AbbrevMap
{
DW2_AbbrevMapNode **slots;
U64 slots_count;
};
typedef struct DW2_UnitAbbrevMapMap DW2_UnitAbbrevMapMap;
struct DW2_UnitAbbrevMapMap
{
U64 map_count;
DW2_AbbrevMap *map_from_idx_table;
DW2_AbbrevMap **map_from_unit_idx_table;
};
////////////////////////////////
//~ rjf: Offset Tables (.debug_str_offsets, .debug_rnglists)
typedef struct DW2_OffsetTable DW2_OffsetTable;
struct DW2_OffsetTable
{
DW_Format format;
DW_Version version;
U8 addr_size;
U8 segment_selector_size;
U64 entry_size;
U64 entries_count;
void *entries;
};
typedef struct DW2_OffsetTableNode DW2_OffsetTableNode;
struct DW2_OffsetTableNode
{
DW2_OffsetTableNode *next;
DW2_OffsetTable v;
Rng1U64 range;
};
typedef struct DW2_OffsetTableList DW2_OffsetTableList;
struct DW2_OffsetTableList
{
DW2_OffsetTableNode *first;
DW2_OffsetTableNode *last;
U64 count;
};
typedef struct DW2_OffsetTableSet DW2_OffsetTableSet;
struct DW2_OffsetTableSet
{
// rjf: .debug_str_offsets
U64 str_offsets_tables_count;
DW2_OffsetTable *str_offsets_tables;
Rng1U64 *str_offsets_tables_ranges;
// rjf: .debug_rnglists
U64 rnglists_tables_count;
DW2_OffsetTable *rnglists_tables;
Rng1U64 *rnglists_tables_ranges;
// rjf: .debug_addr
U64 addr_tables_count;
DW2_OffsetTable *addr_tables;
Rng1U64 *addr_tables_ranges;
// rjf: .debug_loclists
U64 loclists_tables_count;
DW2_OffsetTable *loclists_tables;
Rng1U64 *loclists_tables_ranges;
};
////////////////////////////////
//~ rjf: Parsing Context Bundle
typedef struct DW2_ParseCtx DW2_ParseCtx;
struct DW2_ParseCtx
{
DW_Version version;
DW_Format format;
DW_ExtFlags exts;
U64 addr_size;
U64 unit_base_addr;
U64 unit_base_info_off;
DW2_AbbrevMap *abbrev_map;
DW2_OffsetTable *rnglists_table;
DW2_OffsetTable *str_offsets_table;
DW2_OffsetTable *addr_table;
DW2_OffsetTable *loclists_table;
String8 unit_dir;
String8 unit_file;
DW_Language language;
};
////////////////////////////////
//~ rjf: Tag Attributes
typedef struct DW2_FormVal DW2_FormVal;
struct DW2_FormVal
{
DW_FormKind kind;
U128 u128;
String8 string;
U64 addr;
};
typedef struct DW2_Attrib DW2_Attrib;
struct DW2_Attrib
{
DW_AttribKind attrib_kind;
DW2_FormVal val;
};
typedef struct DW2_AttribNode DW2_AttribNode;
struct DW2_AttribNode
{
DW2_AttribNode *next;
DW2_Attrib v;
};
typedef struct DW2_AttribList DW2_AttribList;
struct DW2_AttribList
{
DW2_AttribNode *first;
DW2_AttribNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Tags
typedef struct DW2_Tag DW2_Tag;
struct DW2_Tag
{
DW_TagKind kind;
B32 has_children;
DW2_AttribList attribs;
};
////////////////////////////////
//~ rjf: Line Info
typedef U32 DW2_LineTableFileFlags;
enum
{
DW_AbbrevFlag_HasImplicitConst = (1 << 0),
DW_AbbrevFlag_HasChildren = (1 << 1),
DW2_LineTableFileFlag_HasMD5 = (1<<0),
DW2_LineTableFileFlag_HasModifyTime = (1<<1),
};
typedef struct DW_Abbrev
typedef struct DW2_LineTableFile DW2_LineTableFile;
struct DW2_LineTableFile
{
DW_AbbrevKind kind;
U64 sub_kind;
U64 id;
S64 implicit_const;
DW_AbbrevFlags flags;
} DW_Abbrev;
String8 file_name;
DW2_LineTableFileFlags flags;
U64 dir_idx;
U64 modify_time;
U64 file_size;
MD5 md5;
String8 source;
};
typedef struct DW_Attrib
typedef struct DW2_LineTableFileNode DW2_LineTableFileNode;
struct DW2_LineTableFileNode
{
U64 info_off;
U64 abbrev_off;
U64 abbrev_id;
DW_AttribKind attrib_kind;
DW_Form form;
} DW_Attrib;
DW2_LineTableFileNode *next;
DW2_LineTableFile v;
};
typedef struct DW_AttribNode
typedef struct DW2_LineTableFileList DW2_LineTableFileList;
struct DW2_LineTableFileList
{
struct DW_AttribNode *next;
DW_Attrib v;
} DW_AttribNode;
DW2_LineTableFileNode *first;
DW2_LineTableFileNode *last;
U64 count;
};
typedef struct DW_AttribList
typedef struct DW2_LineTableFileArray DW2_LineTableFileArray;
struct DW2_LineTableFileArray
{
DW_AttribNode *first;
DW_AttribNode *last;
U64 count;
} DW_AttribList;
DW2_LineTableFile *v;
U64 count;
};
typedef U8 DW_TagSpare;
typedef struct DW_Tag
typedef struct DW2_LineTableHeader DW2_LineTableHeader;
struct DW2_LineTableHeader
{
B32 has_children;
U64 abbrev_id;
DW_TagKind kind;
DW_AttribList attribs;
U64 info_off;
DW_TagSpare v;
} DW_Tag;
U64 unit_length;
DW_Format format;
DW_Version version;
U8 addr_size;
U8 segment_selector_size;
U64 header_length;
U8 min_inst_length;
U8 max_ops_per_inst;
U8 default_is_stmt;
S8 line_base;
U8 line_range;
U8 opcode_base;
U64 opcode_lengths_count;
U8 *opcode_lengths;
DW2_LineTableFileArray dirs;
DW2_LineTableFileArray files;
U64 line_program_off;
U64 total_unit_data_size; // NOTE(rjf): would be implied by `unit_length`, but DWARF makes that the size *past* the variable-width unit-length field itself
};
typedef struct DW_TagNode
typedef struct DW2_LineVMRegs DW2_LineVMRegs;
struct DW2_LineVMRegs
{
DW_Tag tag;
struct DW_TagNode *sibling;
struct DW_TagNode *first_child;
struct DW_TagNode *last_child;
} DW_TagNode;
U64 address;
U64 vliw_op_index;
U64 file_index;
U64 line;
U64 column;
B32 is_stmt;
B32 basic_block;
B32 end_sequence;
B32 prologue_end;
B32 epilogue_begin;
U64 isa;
U64 discriminator;
};
typedef struct DW_Loc
////////////////////////////////
//~ rjf: Location Lists
typedef struct DW2_Loc DW2_Loc;
struct DW2_Loc
{
Rng1U64 range;
String8 expr;
} DW_Loc;
};
typedef struct DW_LocNode
typedef struct DW2_LocNode DW2_LocNode;
struct DW2_LocNode
{
DW_Loc v;
struct DW_LocNode *next;
} DW_LocNode;
DW2_LocNode *next;
DW2_Loc v;
};
typedef struct DW_LocList
typedef struct DW2_LocList DW2_LocList;
struct DW2_LocList
{
U64 count;
DW_LocNode *first;
DW_LocNode *last;
} DW_LocList;
typedef struct DW_CompUnit
{
B32 relaxed;
DW_Ext ext;
DW_CompUnitKind kind;
DW_Version version;
DW_Format format;
U64 address_size;
U64 abbrev_off;
Rng1U64 info_range;
U64 first_tag_info_off;
DW_AbbrevTable abbrev_table;
DW_ListUnit *addr_lu;
DW_ListUnit *str_offsets_lu;
DW_ListUnit *rnglists_lu;
DW_ListUnit *loclists_lu;
U64 low_pc;
U64 dwo_id;
DW_Tag tag;
HashTable *tag_ht;
} DW_CompUnit;
typedef struct DW_TagTree
{
DW_TagNode *root;
U64 tag_count;
} DW_TagTree;
DW2_LocNode *first;
DW2_LocNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Unwind Info
typedef struct DW_LineFile
typedef enum DW_CFIKind
{
String8 path;
U64 dir_idx;
U64 time_stamp;
U64 size;
U128 md5;
String8 source;
} DW_LineFile;
DW_CFIKind_Null,
DW_CFIKind_CIE, // Common Information Entry
DW_CFIKind_FDE, // Frame Description Entry
DW_CFIKind_COUNT
}
DW_CFIKind;
typedef struct DW_LineFileNode
typedef struct DW_CFIHeader DW_CFIHeader;
struct DW_CFIHeader
{
struct DW_LineFileNode *next;
DW_LineFile file;
} DW_LineFileNode;
DW_CFIKind kind;
DW_Format fmt;
Rng1U64 entry_range;
U64 cie_pointer_off;
U64 cie_pointer;
};
typedef struct DW_LineFileList
typedef struct DW_CIE DW_CIE;
struct DW_CIE
{
U64 node_count;
DW_LineFileNode *first;
DW_LineFileNode *last;
} DW_LineFileList;
typedef struct DW_LineFileArray
{
U64 count;
DW_LineFile *v;
} DW_LineFileArray;
typedef struct DW_LineVMHeader
{
U64 unit_length;
DW_Version version;
U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str.
U8 segment_selector_size;
U64 header_length;
U8 min_inst_len;
U8 max_ops_for_inst;
U8 default_is_stmt;
S8 line_base;
U8 line_range;
U8 opcode_base;
U64 num_opcode_lens;
U8 *opcode_lens;
U64 line_program_off;
String8Array dir_table;
DW_LineFileArray file_table;
} DW_LineVMHeader;
typedef struct DW_LineVMState
{
U64 address; // Address of a machine instruction.
U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction.
// Line table doesn't contain full path to a file, instead
// DWARF encodes path as two indices. First index will point into a directory
// table, and second points into a file name table.
U64 file_index;
U64 line;
U64 column;
B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint.
B32 basic_block; // Indicates that the "address" is inside a basic block.
// Indicates that "address" points to place where function starts.
// Usually prologue is the place where compiler emits instructions to
// prepare stack for a function.
B32 prologue_end;
B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack.
U64 isa; // Instruction set that is used.
U64 discriminator; // Arbitrary id that indicates to which block these instructions belong.
B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows.
} DW_LineVMState;
typedef struct DW_LineVM
{
Arena *arena;
U64 cursor;
String8 program;
DW_LineVMHeader header;
B32 new_line;
B32 new_seq;
B32 skip_opcode;
DW_LineVMState state;
U64 advance;
U64 opcode_off;
DW_StdOpcode opcode;
DW_ExtOpcode ext_opcode;
U64 ext_length;
U64 line_advance;
U64 addr_advance;
HashTable *ext_file_ht;
struct {
union {
String8 string;
U64 u64;
S64 s64;
};
} operands[4];
String8 error;
} DW_LineVM;
////////////////////////////////
// .debug_pubnames and .debug_pubtypes
typedef struct DW_PubStringsBucket
{
struct DW_PubStringsBucket *next;
String8 string;
U64 info_off;
U64 cu_info_off;
} DW_PubStringsBucket;
typedef struct DW_PubStringsTable
{
U64 size;
DW_PubStringsBucket **buckets;
} DW_PubStringsTable;
typedef struct DW_Reference
{
DW_CompUnit *cu;
U64 info_off; // global .debug_info offset
} DW_Reference;
////////////////////////////////
//~ Expression
typedef union DW_ExprOperand
{
U8 u8;
U16 u16;
U32 u32;
U64 u64;
S8 s8;
S16 s16;
S32 s32;
S64 s64;
String8 block;
} DW_ExprOperand;
typedef struct DW_ExprInst
{
DW_ExprOp opcode;
DW_ExprOperand *operands;
U64 size;
struct DW_ExprInst *next;
struct DW_ExprInst *prev;
} DW_ExprInst;
typedef struct DW_Expr
{
U64 count;
DW_ExprInst *first;
DW_ExprInst *last;
} DW_Expr;
////////////////////////////////
// .debug_frame
typedef struct DW_CIE
{
String8 insts;
String8 aug_string;
String8 aug_data;
U64 code_align_factor;
S64 data_align_factor;
U64 ret_addr_reg;
U64 ext[4];
Rng1U64 aug_string_range;
Rng1U64 aug_data_range;
U64 code_align_factor;
S64 data_align_factor;
U64 ret_addr_reg;
U64 ext[4];
DW_Format format;
U8 version;
U8 address_size;
U8 segment_selector_size;
} DW_CIE;
U8 version;
U8 address_size;
U8 segment_selector_size;
};
typedef struct DW_FDE
typedef struct DW_FDE DW_FDE;
struct DW_FDE
{
DW_Format format;
U64 cie_pointer;
Rng1U64 pc_range;
String8 insts;
} DW_FDE;
U64 cie_pointer;
Rng1U64 pc_range;
};
typedef union DW_CFA_Operand
typedef struct DW_CFI DW_CFI;
struct DW_CFI
{
U64 u64;
S64 s64;
String8 block;
} DW_CFA_Operand;
DW_CIE cie;
DW_FDE fde;
};
typedef enum
{
DW_CFA_ParseErrorCode_NewInst,
DW_CFA_ParseErrorCode_End,
DW_CFA_ParseErrorCode_OutOfData
} DW_CFA_ParseErrorCode;
////////////////////////////////
//~ rjf: Globals
typedef struct DW_CFA_Inst
{
DW_CFA_Opcode opcode;
DW_CFA_Operand operands[DW_CFA_OperandMax];
} DW_CFA_Inst;
global read_only DW2_Attrib dw2_attrib_nil = {0};
typedef struct DW_CFA_InstNode
{
DW_CFA_Inst v;
struct DW_CFA_InstNode *next;
} DW_CFA_InstNode;
////////////////////////////////
//~ rjf: Basic Parsing Helpers
typedef struct DW_CFA_InstList
{
U64 count;
DW_CFA_InstNode *first;
DW_CFA_InstNode *last;
} DW_CFA_InstList;
internal U64 dw2_read_initial_length(String8 data, U64 off, U64 *out, DW_Format *fmt_out);
internal U64 dw2_read_fmt_u64(String8 data, U64 off, DW_Format format, U64 *out);
internal DW_SectionKind dw_section_kind_from_string(String8 string);
#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out)
typedef DW_DECODE_PTR(DW_DecodePtr);
////////////////////////////////
//~ rjf: Unit Range Set Parsing (Top-Level .debug_info, .debug_aranges)
// hasher
internal Rng1U64Array dw2_unit_ranges_from_data(Arena *arena, String8 data);
internal U64 dw_hash_from_string(String8 string);
////////////////////////////////
//~ rjf: Unit Header Parsing
// deserial helpers
internal U64 dw2_read_unit_header(String8 data, U64 off, DW2_UnitHeader *out);
internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out);
internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out);
internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out);
internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out);
////////////////////////////////
//~ rjf: Abbreviation Map Parsing
internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data);
internal Rng1U64Array dw_unit_ranges_from_data_arr(Arena *arena, String8 data);
internal U64 dw2_read_abbrev(Arena *arena, String8 data, U64 off, DW2_AbbrevHeader *header_out, DW2_AbbrevAttribList *attribs_out);
internal DW2_AbbrevMap dw2_abbrev_map_from_data(Arena *arena, String8 data, U64 off);
internal DW2_UnitAbbrevMapMap dw2_unit_abbrev_map_map_from_data(Arena *arena, String8 data, DW2_UnitHeader *unit_headers, U64 unit_headers_count);
// list units
////////////////////////////////
//~ rjf: Form Value Parsing
internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out);
internal U64 dw2_read_form_val(DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW_FormKind form_kind, U64 implicit_const, DW2_FormVal *out);
internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Raw *input);
////////////////////////////////
//~ rjf: Parse Context Construction
internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index);
internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index);
internal void dw2_parse_ctx_equip_unit_header(DW2_ParseCtx *ctx_out, DW2_UnitHeader *hdr, U64 unit_base_info_off);
internal void dw2_parse_ctx_equip_unit_abbrev_map(DW2_ParseCtx *ctx_out, DW2_UnitAbbrevMapMap *map, U64 unit_idx);
internal void dw2_parse_ctx_equip_unit_root_tag(DW2_ParseCtx *ctx_out, DW2_Tag *tag, DW2_OffsetTableSet *offset_tables);
// abbrev table
////////////////////////////////
//~ rjf: Tag Parsing
internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev);
internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev);
internal U64 dw2_read_tag(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out);
internal DW2_Attrib *dw2_attrib_from_kind(DW2_Tag *tag, DW_AttribKind kind);
internal U64 dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal *v);
internal DW_AbbrevTable dw_read_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base);
internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id);
////////////////////////////////
//~ rjf: Line Table Parsing
// form and tag
internal U64 dw2_read_line_table_header(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out);
internal B32 dw_read_form (String8 data, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, S64 implicit_const, DW_Form *form_out, U64 *bytes_read_out);
internal U64 dw_read_tag (Arena *arena, DW_Raw *input, DW_AbbrevTable abbrev_table, DW_Version version, DW_Format format, U64 address_size, Rng1U64 cu_info_range, U64 tag_info_off, DW_Tag *tag_out);
internal U64 dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out);
////////////////////////////////
//~ rjf: Offset Table Parsing (.debug_str_offsets, .debug_rnglists)
// attrib interp
internal U64 dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out);
internal DW2_OffsetTableList dw2_offset_table_list_from_data(Arena *arena, String8 data);
internal B32 dw2_try_offset_from_table_idx(DW2_OffsetTable *tbl, U64 idx, U64 *out);
internal DW2_OffsetTableSet dw2_offset_table_set_from_raw(Arena *arena, DW_Raw *raw);
internal U64 dw_interp_sec_offset(DW_Form form);
internal String8 dw_interp_exprloc (DW_Form form);
internal U128 dw_interp_const_u128(DW_Form form);
internal U64 dw_interp_const_u64 (DW_Form form);
internal U32 dw_interp_const_u32 (DW_Form form);
internal S64 dw_interp_const_s64 (DW_Form form);
internal S32 dw_interp_const_s32 (DW_Form form);
internal B32 dw_interp_flag (DW_Form form);
internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_Form form);
internal String8 dw_interp_block (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal String8 dw_interp_string (DW_Raw *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_Form form);
internal String8 dw_interp_line_ptr (DW_Raw *input, DW_Form form);
internal DW_LineFile * dw_interp_file (DW_LineVM *line_vm, DW_Form form);
internal DW_Reference dw_interp_ref (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal DW_LocList dw_interp_loclist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
////////////////////////////////
//~ rjf: Range List Parsing (.debug_rnglists)
internal String8 dw_exprloc_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U128 dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U64 dw_const_u64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U32 dw_const_u32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal S64 dw_const_s64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal S32 dw_const_s32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal B32 dw_flag_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal U64 dw_address_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_block_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_string_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal String8 dw_line_ptr_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
internal DW_Reference dw_ref_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal Rng1U64List dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val);
internal String8 dw_exprloc_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U128 dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U64 dw_const_u64_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U32 dw_const_u32_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal B32 dw_flag_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal U64 dw_address_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_block_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_string_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind);
internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
////////////////////////////////
//~ rjf: Location List Parsing (.debug_loclists)
internal B32 dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
internal DW2_LocList dw2_loclist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val);
// compile unit
////////////////////////////////
//~ rjf: Unwind Info Parsing (.debug_frame)
internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed);
internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu);
internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree);
internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off);
// line VM
internal U64 dw_read_line_vm_header(Arena *arena, DW_Raw *input, String8 cu_stmt_list, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out);
internal DW_LineVM * dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu);
internal void dw_line_vm_release(DW_LineVM *vm);
internal void dw_line_vm_advance(DW_LineVM *vm, U64 advance);
internal B32 dw_line_vm_step(DW_LineVM *vm);
internal DW_LineFile * dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx);
internal String8 dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file);
// helper for .debug_pubtypes and .debug_pubnames
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind);
// expression
internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data);
// debug frame
internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n);
internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v);
internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out);
internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out);
internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out);
internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out);
internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out);
internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
internal U64 dw2_read_cfi_header(String8 data, U64 off, DW_CFIHeader *cfi_header_out);
internal U64 dw2_read_cie(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie_out);
internal U64 dw2_read_fde(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie, DW_FDE *fde_out);
internal B32 dw2_try_cfi_from_data(String8 data, U64 off, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
#endif // DWARF_PARSE_H
File diff suppressed because it is too large Load Diff
-456
View File
@@ -1,456 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_PARSE_2_H
#define DWARF_PARSE_2_H
////////////////////////////////
//~ rjf: Raw Section Data
typedef struct DW_Section DW_Section;
struct DW_Section
{
String8 name;
String8 data;
};
typedef struct DW_Raw DW_Raw;
struct DW_Raw
{
DW_Section sec[DW_SectionKind_COUNT];
DW_Section sup[DW_SectionKind_COUNT];
};
////////////////////////////////
//~ rjf: Unit Headers
typedef struct DW2_UnitHeader DW2_UnitHeader;
struct DW2_UnitHeader
{
DW_Version version;
DW_Format format;
U64 abbrev_off;
U64 addr_size;
DW_CompUnitKind kind;
U64 dwo_id;
};
////////////////////////////////
//~ rjf: Abbreviation Map (ID -> .debug_abbrev Offset)
typedef struct DW2_AbbrevAttrib DW2_AbbrevAttrib;
struct DW2_AbbrevAttrib
{
DW_AttribKind attrib_kind;
DW_FormKind form_kind;
U64 implicit_const;
};
typedef struct DW2_AbbrevAttribNode DW2_AbbrevAttribNode;
struct DW2_AbbrevAttribNode
{
DW2_AbbrevAttribNode *next;
DW2_AbbrevAttrib v;
};
typedef struct DW2_AbbrevAttribList DW2_AbbrevAttribList;
struct DW2_AbbrevAttribList
{
DW2_AbbrevAttribNode *first;
DW2_AbbrevAttribNode *last;
U64 count;
};
typedef struct DW2_AbbrevHeader DW2_AbbrevHeader;
struct DW2_AbbrevHeader
{
U64 id;
DW_TagKind tag_kind;
B8 has_children;
};
typedef struct DW2_AbbrevMapNode DW2_AbbrevMapNode;
struct DW2_AbbrevMapNode
{
DW2_AbbrevMapNode *next;
U64 id;
U64 off;
};
typedef struct DW2_AbbrevMap DW2_AbbrevMap;
struct DW2_AbbrevMap
{
DW2_AbbrevMapNode **slots;
U64 slots_count;
};
typedef struct DW2_UnitAbbrevMapMap DW2_UnitAbbrevMapMap;
struct DW2_UnitAbbrevMapMap
{
U64 map_count;
DW2_AbbrevMap *map_from_idx_table;
DW2_AbbrevMap **map_from_unit_idx_table;
};
////////////////////////////////
//~ rjf: Offset Tables (.debug_str_offsets, .debug_rnglists)
typedef struct DW2_OffsetTable DW2_OffsetTable;
struct DW2_OffsetTable
{
DW_Format format;
DW_Version version;
U8 addr_size;
U8 segment_selector_size;
U64 entry_size;
U64 entries_count;
void *entries;
};
typedef struct DW2_OffsetTableNode DW2_OffsetTableNode;
struct DW2_OffsetTableNode
{
DW2_OffsetTableNode *next;
DW2_OffsetTable v;
Rng1U64 range;
};
typedef struct DW2_OffsetTableList DW2_OffsetTableList;
struct DW2_OffsetTableList
{
DW2_OffsetTableNode *first;
DW2_OffsetTableNode *last;
U64 count;
};
typedef struct DW2_OffsetTableSet DW2_OffsetTableSet;
struct DW2_OffsetTableSet
{
// rjf: .debug_str_offsets
U64 str_offsets_tables_count;
DW2_OffsetTable *str_offsets_tables;
Rng1U64 *str_offsets_tables_ranges;
// rjf: .debug_rnglists
U64 rnglists_tables_count;
DW2_OffsetTable *rnglists_tables;
Rng1U64 *rnglists_tables_ranges;
// rjf: .debug_addr
U64 addr_tables_count;
DW2_OffsetTable *addr_tables;
Rng1U64 *addr_tables_ranges;
// rjf: .debug_loclists
U64 loclists_tables_count;
DW2_OffsetTable *loclists_tables;
Rng1U64 *loclists_tables_ranges;
};
////////////////////////////////
//~ rjf: Parsing Context Bundle
typedef struct DW2_ParseCtx DW2_ParseCtx;
struct DW2_ParseCtx
{
DW_Version version;
DW_Format format;
DW_ExtFlags exts;
U64 addr_size;
U64 unit_base_addr;
U64 unit_base_info_off;
DW2_AbbrevMap *abbrev_map;
DW2_OffsetTable *rnglists_table;
DW2_OffsetTable *str_offsets_table;
DW2_OffsetTable *addr_table;
DW2_OffsetTable *loclists_table;
String8 unit_dir;
String8 unit_file;
DW_Language language;
};
////////////////////////////////
//~ rjf: Tag Attributes
typedef struct DW2_FormVal DW2_FormVal;
struct DW2_FormVal
{
DW_FormKind kind;
U128 u128;
String8 string;
U64 addr;
};
typedef struct DW2_Attrib DW2_Attrib;
struct DW2_Attrib
{
DW_AttribKind attrib_kind;
DW2_FormVal val;
};
typedef struct DW2_AttribNode DW2_AttribNode;
struct DW2_AttribNode
{
DW2_AttribNode *next;
DW2_Attrib v;
};
typedef struct DW2_AttribList DW2_AttribList;
struct DW2_AttribList
{
DW2_AttribNode *first;
DW2_AttribNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Tags
typedef struct DW2_Tag DW2_Tag;
struct DW2_Tag
{
DW_TagKind kind;
B32 has_children;
DW2_AttribList attribs;
};
////////////////////////////////
//~ rjf: Line Info
typedef U32 DW2_LineTableFileFlags;
enum
{
DW2_LineTableFileFlag_HasMD5 = (1<<0),
DW2_LineTableFileFlag_HasModifyTime = (1<<1),
};
typedef struct DW2_LineTableFile DW2_LineTableFile;
struct DW2_LineTableFile
{
String8 file_name;
DW2_LineTableFileFlags flags;
U64 dir_idx;
U64 modify_time;
U64 file_size;
MD5 md5;
String8 source;
};
typedef struct DW2_LineTableFileNode DW2_LineTableFileNode;
struct DW2_LineTableFileNode
{
DW2_LineTableFileNode *next;
DW2_LineTableFile v;
};
typedef struct DW2_LineTableFileList DW2_LineTableFileList;
struct DW2_LineTableFileList
{
DW2_LineTableFileNode *first;
DW2_LineTableFileNode *last;
U64 count;
};
typedef struct DW2_LineTableFileArray DW2_LineTableFileArray;
struct DW2_LineTableFileArray
{
DW2_LineTableFile *v;
U64 count;
};
typedef struct DW2_LineTableHeader DW2_LineTableHeader;
struct DW2_LineTableHeader
{
U64 unit_length;
DW_Format format;
DW_Version version;
U8 addr_size;
U8 segment_selector_size;
U64 header_length;
U8 min_inst_length;
U8 max_ops_per_inst;
U8 default_is_stmt;
S8 line_base;
U8 line_range;
U8 opcode_base;
U64 opcode_lengths_count;
U8 *opcode_lengths;
DW2_LineTableFileArray dirs;
DW2_LineTableFileArray files;
U64 line_program_off;
U64 total_unit_data_size; // NOTE(rjf): would be implied by `unit_length`, but DWARF makes that the size *past* the variable-width unit-length field itself
};
typedef struct DW2_LineVMRegs DW2_LineVMRegs;
struct DW2_LineVMRegs
{
U64 address;
U64 vliw_op_index;
U64 file_index;
U64 line;
U64 column;
B32 is_stmt;
B32 basic_block;
B32 end_sequence;
B32 prologue_end;
B32 epilogue_begin;
U64 isa;
U64 discriminator;
};
////////////////////////////////
//~ rjf: Location Lists
typedef struct DW2_Loc DW2_Loc;
struct DW2_Loc
{
Rng1U64 range;
String8 expr;
};
typedef struct DW2_LocNode DW2_LocNode;
struct DW2_LocNode
{
DW2_LocNode *next;
DW2_Loc v;
};
typedef struct DW2_LocList DW2_LocList;
struct DW2_LocList
{
DW2_LocNode *first;
DW2_LocNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Unwind Info
typedef enum DW_CFIKind
{
DW_CFIKind_Null,
DW_CFIKind_CIE, // Common Information Entry
DW_CFIKind_FDE, // Frame Description Entry
DW_CFIKind_COUNT
}
DW_CFIKind;
typedef struct DW_CFIHeader DW_CFIHeader;
struct DW_CFIHeader
{
DW_CFIKind kind;
DW_Format fmt;
Rng1U64 entry_range;
U64 cie_pointer_off;
U64 cie_pointer;
};
typedef struct DW_CIE DW_CIE;
struct DW_CIE
{
Rng1U64 aug_string_range;
Rng1U64 aug_data_range;
U64 code_align_factor;
S64 data_align_factor;
U64 ret_addr_reg;
U64 ext[4];
DW_Format format;
U8 version;
U8 address_size;
U8 segment_selector_size;
};
typedef struct DW_FDE DW_FDE;
struct DW_FDE
{
U64 cie_pointer;
Rng1U64 pc_range;
};
typedef struct DW_CFI DW_CFI;
struct DW_CFI
{
DW_CIE cie;
DW_FDE fde;
};
////////////////////////////////
//~ rjf: Globals
global read_only DW2_Attrib dw2_attrib_nil = {0};
////////////////////////////////
//~ rjf: Basic Parsing Helpers
internal U64 dw2_read_initial_length(String8 data, U64 off, U64 *out, DW_Format *fmt_out);
internal U64 dw2_read_fmt_u64(String8 data, U64 off, DW_Format format, U64 *out);
internal DW_SectionKind dw_section_kind_from_string(String8 string);
////////////////////////////////
//~ rjf: Unit Range Set Parsing (Top-Level .debug_info, .debug_aranges)
internal Rng1U64Array dw2_unit_ranges_from_data(Arena *arena, String8 data);
////////////////////////////////
//~ rjf: Unit Header Parsing
internal U64 dw2_read_unit_header(String8 data, U64 off, DW2_UnitHeader *out);
////////////////////////////////
//~ rjf: Abbreviation Map Parsing
internal U64 dw2_read_abbrev(Arena *arena, String8 data, U64 off, DW2_AbbrevHeader *header_out, DW2_AbbrevAttribList *attribs_out);
internal DW2_AbbrevMap dw2_abbrev_map_from_data(Arena *arena, String8 data, U64 off);
internal DW2_UnitAbbrevMapMap dw2_unit_abbrev_map_map_from_data(Arena *arena, String8 data, DW2_UnitHeader *unit_headers, U64 unit_headers_count);
////////////////////////////////
//~ rjf: Form Value Parsing
internal U64 dw2_read_form_val(DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW_FormKind form_kind, U64 implicit_const, DW2_FormVal *out);
////////////////////////////////
//~ rjf: Parse Context Construction
internal void dw2_parse_ctx_equip_unit_header(DW2_ParseCtx *ctx_out, DW2_UnitHeader *hdr, U64 unit_base_info_off);
internal void dw2_parse_ctx_equip_unit_abbrev_map(DW2_ParseCtx *ctx_out, DW2_UnitAbbrevMapMap *map, U64 unit_idx);
internal void dw2_parse_ctx_equip_unit_root_tag(DW2_ParseCtx *ctx_out, DW2_Tag *tag, DW2_OffsetTableSet *offset_tables);
////////////////////////////////
//~ rjf: Tag Parsing
internal U64 dw2_read_tag(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out);
internal DW2_Attrib *dw2_attrib_from_kind(DW2_Tag *tag, DW_AttribKind kind);
internal U64 dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal *v);
////////////////////////////////
//~ rjf: Line Table Parsing
internal U64 dw2_read_line_table_header(Arena *arena, DW_Raw *raw, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out);
////////////////////////////////
//~ rjf: Offset Table Parsing (.debug_str_offsets, .debug_rnglists)
internal U64 dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out);
internal DW2_OffsetTableList dw2_offset_table_list_from_data(Arena *arena, String8 data);
internal B32 dw2_try_offset_from_table_idx(DW2_OffsetTable *tbl, U64 idx, U64 *out);
internal DW2_OffsetTableSet dw2_offset_table_set_from_raw(Arena *arena, DW_Raw *raw);
////////////////////////////////
//~ rjf: Range List Parsing (.debug_rnglists)
internal Rng1U64List dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val);
////////////////////////////////
//~ rjf: Location List Parsing (.debug_loclists)
internal DW2_LocList dw2_loclist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val);
////////////////////////////////
//~ rjf: Unwind Info Parsing (.debug_frame)
internal U64 dw2_read_cfi_header(String8 data, U64 off, DW_CFIHeader *cfi_header_out);
internal U64 dw2_read_cie(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie_out);
internal U64 dw2_read_fde(String8 data, U64 off, DW_Format fmt, Arch arch, DW_CIE *cie, DW_FDE *fde_out);
internal B32 dw2_try_cfi_from_data(String8 data, U64 off, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
#endif // DWARF_PARSE_2_H
-1
View File
@@ -8,4 +8,3 @@ internal B32 dw_is_dwarf_present_coff_section_table(String8 string_table, U64 se
internal DW_Raw dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
#endif // DWARF_PARSE_COFF_H
-371
View File
@@ -1,373 +1,2 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal DW_CFI_Row *
dw_make_cfi_row(Arena *arena, U64 reg_count)
{
DW_CFI_Row *row = push_array(arena, DW_CFI_Row, 1);
row->regs = push_array(arena, DW_CFI_Register, reg_count);
for EachIndex(reg_idx, reg_count) {
row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue;
}
return row;
}
internal void
dw_memcpy_cfi_row(DW_CFI_Row *dst, DW_CFI_Row *src, U64 reg_count)
{
dst->cfa = src->cfa;
MemoryCopyTyped(dst->regs, src->regs, reg_count);
}
internal DW_CFI_Row *
dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count)
{
DW_CFI_Row *new_row = dw_make_cfi_row(arena, reg_count);
dw_memcpy_cfi_row(new_row, row, reg_count);
return new_row;
}
internal DW_CFI_Unwind *
dw_cfi_unwind_init(Arena *arena,
Arch arch,
DW_CIE *cie,
DW_FDE *fde,
DW_DecodePtr *decode_ptr_func,
void *decode_ptr_ud)
{
Temp scratch = scratch_begin(&arena, 1);
DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1);
uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
uw->cie = cie;
uw->fde = fde;
uw->pc = fde->pc_range.min;
uw->arch = arch;
uw->reg_count = dw_reg_count_from_arch(arch);
// setup initial register rules
DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
uw->row = dw_make_cfi_row(arena, uw->reg_count);
uw->curr_inst = initial_insts.first;
if (!dw_cfi_next_row(arena, uw)) {
AssertAlways(0 && "unable to interpret initial row instructions");
}
// make first row from initial rules
uw->initial_row = uw->row;
uw->row = dw_copy_cfi_row(arena, uw->initial_row, uw->reg_count);
uw->curr_inst = uw->insts.first;
scratch_end(scratch);
return uw;
}
internal B32
dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw)
{
B32 is_row_valid = 0;
DW_CFA_InstNode *row_inst = uw->curr_inst;
// skip leading nops
while (uw->curr_inst) {
if (uw->curr_inst->v.opcode != DW_CFA_Nop) {
break;
}
uw->curr_inst = uw->curr_inst->next;
}
while (uw->curr_inst) {
DW_CFA_Inst *inst = &uw->curr_inst->v;
// validate register operands
DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode);
U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode);
for EachIndex(operand_idx, operand_count) {
if (operand_types[operand_idx] == DW_CFA_OperandType_Register) {
if (inst->operands[operand_idx].u64 >= uw->reg_count) {
goto exit;
}
}
}
switch (inst->opcode) {
// Row Creation Instructions
case DW_CFA_SetLoc: {
uw->pc = inst->operands[0].u64;
} break;
case DW_CFA_AdvanceLoc:
case DW_CFA_AdvanceLoc1:
case DW_CFA_AdvanceLoc2:
case DW_CFA_AdvanceLoc4: {
uw->pc += inst->operands[0].u64;
} break;
// CFA Definition Instructions
case DW_CFA_DefCfa:
case DW_CFA_DefCfaSf: {
U64 reg = inst->operands[0].u64;
S64 off = inst->operands[1].s64;
uw->row->cfa.rule = DW_CFA_Rule_RegOff;
uw->row->cfa.reg = reg;
uw->row->cfa.off = off;
} break;
case DW_CFA_DefCfaRegister: {
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
U64 reg = inst->operands[0].u64;
uw->row->cfa.reg = reg;
} break;
case DW_CFA_DefCfaOffset:
case DW_CFA_DefCfaOffsetSf: {
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
uw->row->cfa.off = inst->operands[0].s64;
} break;
case DW_CFA_DefCfaExpr: {
uw->row->cfa.rule = DW_CFA_Rule_Expression;
uw->row->cfa.expr = inst->operands[0].block;
} break;
// Register Rule Instructions
case DW_CFA_Undefined: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined;
} break;
case DW_CFA_SameValue: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue;
} break;
case DW_CFA_Offset:
case DW_CFA_OffsetExt:
case DW_CFA_OffsetExtSf: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_ValOffset:
case DW_CFA_ValOffsetSf: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_Register: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register;
uw->row->regs[reg].n = inst->operands[1].s64;
} break;
case DW_CFA_Expr: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression;
uw->row->regs[reg].expr = inst->operands[1].block;
} break;
case DW_CFA_ValExpr: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression;
uw->row->regs[reg].expr = inst->operands[1].block;
} break;
case DW_CFA_Restore:
case DW_CFA_RestoreExt: {
U64 reg = inst->operands[0].u64;
uw->row->regs[reg] = uw->initial_row->regs[reg];
} break;
// Row State Instructions
case DW_CFA_RememberState: {
DW_CFI_Row *new_row = dw_copy_cfi_row(arena, uw->row, uw->reg_count);
SLLStackPush(uw->row, new_row);
} break;
case DW_CFA_RestoreState: {
if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops
DW_CFI_Row *free_row = uw->row;
SLLStackPop(uw->row);
SLLStackPush(uw->free_rows, free_row);
} break;
case DW_CFA_Nop: {} break;
default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode
}
uw->curr_inst = uw->curr_inst->next;
if (uw->curr_inst) {
if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; }
}
}
is_row_valid = row_inst != 0;
exit:;
return is_row_valid;
}
internal DW_CFI_Row *
dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc)
{
Temp scratch = scratch_begin(&arena, 1);
B32 is_row_found = 0;
U64 reg_count = dw_reg_count_from_arch(arch);
DW_CFI_Unwind *uw = dw_cfi_unwind_init(scratch.arena, arch, cie, fde, decode_ptr_func, decode_ptr_ctx);
DW_CFI_Row *row = dw_copy_cfi_row(scratch.arena, uw->row, uw->reg_count);
U64 prev_pc = uw->pc;
while (dw_cfi_next_row(scratch.arena, uw)) {
if (prev_pc <= pc && pc < uw->pc) {
is_row_found = 1;
break;
}
dw_memcpy_cfi_row(row, uw->row, uw->reg_count);
prev_pc = uw->pc;
}
// handle last row
if (!is_row_found) {
if (contains_1u64(fde->pc_range, pc)) {
row = uw->row;
is_row_found = 1;
}
}
// copy out final row
DW_CFI_Row *result = 0;
if (is_row_found) {
result = dw_copy_cfi_row(arena, row, reg_count);
}
scratch_end(scratch);
return result;
}
internal MachineOpResult
dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out)
{
MachineOpResult unwind_status = MachineOpResult_Fail;
ARCH_Info *arch_info = arch_info_from_arch(arch);
switch(row->cfa.rule)
{
case DW_CFA_Rule_Null:{}break;
case DW_CFA_Rule_RegOff:
{
// TODO: report error (invalid register read)
U64 cfa_reg_value = 0;
U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg);
AssertAlways(reg_size <= sizeof(cfa_reg_value));
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, row->cfa.reg);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, &cfa_reg_value))
{
break;
}
*cfa_out = cfa_reg_value + row->cfa.off;
unwind_status = MachineOpResult_Ok;
}break;
case DW_CFA_Rule_Expression:
{
Temp scratch = scratch_begin(0,0);
DW_ExprValue value = {0};
DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_32Bit, byte_size_from_arch(arch), row->cfa.expr);
DW_ExprEvalResult eval_result = dw_eval_expr(scratch.arena, arch, DW_Format_32Bit, 0, 0, 0, 9999, expr, reg_block, mem_read_func, mem_read_ud, &value);
if (eval_result == DW_ExprEvalResult_Ok) {
if (DW_ExprValueType_IsInt(value.type)) {
*cfa_out = value.u64;
unwind_status = MachineOpResult_Ok;
}
} else if (eval_result == DW_ExprEvalResult_Maybe) {
unwind_status = MachineOpResult_Maybe;
}
scratch_end(scratch);
}break;
}
return unwind_status;
}
internal MachineOpResult
dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud)
{
Temp scratch = scratch_begin(0,0);
MachineOpResult unwind_status = MachineOpResult_Ok;
ARCH_Info *arch_info = arch_info_from_arch(arch);
U64 max_reg_size = dw_reg_max_size_from_arch(arch);
void *reg_buffer = push_array(scratch.arena, U8, max_reg_size);
U64 reg_count = dw_reg_count_from_arch(arch);
for EachIndex(reg_idx, reg_count)
{
DW_CFI_Register *reg = &row->regs[reg_idx];
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_idx);
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
switch(reg->rule)
{
default:{}break;
case DW_CFI_RegisterRule_Undefined: {} break;
case DW_CFI_RegisterRule_SameValue: {} break;
case DW_CFI_RegisterRule_Offset:
{
// read register value from memory
U64 addr = cfa + reg->n;
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
unwind_status = mem_read_func(addr, reg_buffer, reg_size, mem_read_ud);
if (unwind_status != MachineOpResult_Ok) { goto exit; }
// write register value to the thread context
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
}break;
case DW_CFI_RegisterRule_ValOffset:
{
// compute register value
U64 reg_value = cfa + reg->n;
// write register value to the thread context
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, &reg_value))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
}break;
case DW_CFI_RegisterRule_Register:
{
// read register value from another register
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
// write register value to the thread context
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
{
unwind_status = MachineOpResult_Fail;
goto exit;
}
if (unwind_status != MachineOpResult_Ok) { goto exit; }
}break;
case DW_CFI_RegisterRule_Expression:
{
// TODO: evaluate expression
NotImplemented;
}break;
case DW_CFI_RegisterRule_ValExpression:
{
// TODO: evaluate expression
NotImplemented;
}break;
case DW_CFI_RegisterRule_Architectural:
{
NotImplemented;
}break;
}
}
// update stack pointer
arch_reg_block_write_sp(arch_info, reg_block, cfa);
exit:;
scratch_end(scratch);
return unwind_status;
}
+29 -66
View File
@@ -4,78 +4,41 @@
#ifndef DWARF_UNWIND_H
#define DWARF_UNWIND_H
typedef enum DW_CFI_RegisterRule
typedef enum DW_UnwindRuleCode
{
DW_CFI_RegisterRule_Undefined,
DW_CFI_RegisterRule_SameValue,
DW_CFI_RegisterRule_Offset,
DW_CFI_RegisterRule_ValOffset,
DW_CFI_RegisterRule_Register,
DW_CFI_RegisterRule_Expression,
DW_CFI_RegisterRule_ValExpression,
DW_CFI_RegisterRule_Architectural
} DW_CFI_RegisterRule;
DW_UnwindRuleCode_SameVal,
DW_UnwindRuleCode_Undefined,
DW_UnwindRuleCode_Off,
DW_UnwindRuleCode_ValOff,
DW_UnwindRuleCode_Reg,
DW_UnwindRuleCode_Expr,
DW_UnwindRuleCode_ValExpr,
DW_UnwindRuleCode_Architectural,
}
DW_UnwindRuleCode;
typedef enum DW_CFA_Rule
typedef struct DW_UnwindRule DW_UnwindRule;
struct DW_UnwindRule
{
DW_CFA_Rule_Null,
DW_CFA_Rule_RegOff,
DW_CFA_Rule_Expression
} DW_CFA_Rule;
DW_UnwindRuleCode code;
DW_RegCode reg_code;
S64 s64;
String8 expr;
};
typedef struct DW_CFA
typedef struct DW_CFIRow DW_CFIRow;
struct DW_CFIRow
{
DW_CFA_Rule rule;
union {
struct {
DW_Reg reg;
S64 off;
};
String8 expr;
};
} DW_CFA;
U64 base_pc_off;
DW_UnwindRule cfa_rule;
DW_UnwindRule *reg_rules;
};
typedef struct DW_CFI_Register
typedef struct DW_CFIRowNode DW_CFIRowNode;
struct DW_CFIRowNode
{
DW_CFI_RegisterRule rule;
union {
S64 n;
String8 expr;
};
} DW_CFI_Register;
typedef struct DW_CFI_Row
{
DW_CFA cfa;
DW_CFI_Register *regs;
struct DW_CFI_Row *next;
} DW_CFI_Row;
typedef struct DW_CFI_Unwind
{
DW_CFA_InstList insts;
DW_CIE *cie;
DW_FDE *fde;
DW_CFI_Row *initial_row;
DW_CFI_Row *row;
DW_CFA_InstNode *curr_inst;
DW_CFI_Row *free_rows;
U64 pc;
Arch arch;
U64 reg_count;
} DW_CFI_Unwind;
////////////////////////////////
internal DW_CFI_Row * dw_make_cfi_row(Arena *arena, U64 reg_count);
internal DW_CFI_Row * dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count);
internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw);
internal DW_CFI_Row * dw_cfi_row_from_pc(Arena *arena, Arch arch, struct DW_CIE *cie, struct DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc);
internal MachineOpResult dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out);
internal MachineOpResult dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud);
DW_CFIRowNode *next;
DW_CFIRow v;
};
#endif // DWARF_UNWIND_H
-2
View File
@@ -1,2 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
-44
View File
@@ -1,44 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef DWARF_UNWIND_2_H
#define DWARF_UNWIND_2_H
typedef enum DW_UnwindRuleCode
{
DW_UnwindRuleCode_SameVal,
DW_UnwindRuleCode_Undefined,
DW_UnwindRuleCode_Off,
DW_UnwindRuleCode_ValOff,
DW_UnwindRuleCode_Reg,
DW_UnwindRuleCode_Expr,
DW_UnwindRuleCode_ValExpr,
DW_UnwindRuleCode_Architectural,
}
DW_UnwindRuleCode;
typedef struct DW_UnwindRule DW_UnwindRule;
struct DW_UnwindRule
{
DW_UnwindRuleCode code;
DW_RegCode reg_code;
S64 s64;
String8 expr;
};
typedef struct DW_CFIRow DW_CFIRow;
struct DW_CFIRow
{
U64 base_pc_off;
DW_UnwindRule cfa_rule;
DW_UnwindRule *reg_rules;
};
typedef struct DW_CFIRowNode DW_CFIRowNode;
struct DW_CFIRowNode
{
DW_CFIRowNode *next;
DW_CFIRow v;
};
#endif // DWARF_UNWIND_2_H