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