mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-10 15:58: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
|
||||
|
||||
+584
-2086
File diff suppressed because it is too large
Load Diff
+5
-61
@@ -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
|
||||
|
||||
@@ -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, ®_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, ®_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, ®_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, ®_idx);
|
||||
off += str8_deserial_read_sleb128(data, off, ®_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, ®_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;
|
||||
}
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+42
-209
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+369
-441
@@ -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
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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, ®_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
@@ -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
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user