mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 09:18:09 +00:00
dwarf parse/expr/unwind/dump 2 -> 1; move old stuff to obsolete
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
|
||||
@@ -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, ®_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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user