mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-11 08:08:08 +00:00
major clean-up pass over unwinding/module-info abstraction, + usage in the debug engine. simplified / cleaned up DWARF helpers for unwind info & expressions. decoupling unwinding / DWARF evaluation from memory read callbacks. light module info now prepared by demon layer - debug engine no longer duplicates per-backend parsing. unwind abstraction layer now does thin abstraction over unwinding backends, debug engine only calls abstraction. clean up demon to have fewer ad-hoc 'queries' on handles, and prefer sending info over debug events when possible / when it fits the usage pattern. move DWARF enum specifications to metacode, generate enums/xlists/tables/etc. decouple raddbg/radbin completely from old parsing helpers. replace portion of DWARF dumping; pull out some new parsing helpers from converter / dumper.
This commit is contained in:
+1
-1
@@ -49,7 +49,7 @@ commands =
|
|||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||||
.f1 = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.f1 = { .win = "build torture", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||||
|
|
||||||
//- rjf: [raddbg wsl]
|
//- rjf: [raddbg wsl]
|
||||||
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||||
|
|||||||
+12
-1
@@ -7,7 +7,6 @@ target:
|
|||||||
working_directory: build
|
working_directory: build
|
||||||
arguments: "--user:raddbg_test.user --project:raddbg_test.project"
|
arguments: "--user:raddbg_test.user --project:raddbg_test.project"
|
||||||
debug_subprocesses: 0
|
debug_subprocesses: 0
|
||||||
enabled: 1
|
|
||||||
}
|
}
|
||||||
target:
|
target:
|
||||||
{
|
{
|
||||||
@@ -19,6 +18,7 @@ target:
|
|||||||
{
|
{
|
||||||
executable: "build/mule_main.exe"
|
executable: "build/mule_main.exe"
|
||||||
working_directory: build
|
working_directory: build
|
||||||
|
enabled: 1
|
||||||
}
|
}
|
||||||
target:
|
target:
|
||||||
{
|
{
|
||||||
@@ -44,3 +44,14 @@ target:
|
|||||||
working_directory: build
|
working_directory: build
|
||||||
arguments: "rdi_from_pdb/* --gui"
|
arguments: "rdi_from_pdb/* --gui"
|
||||||
}
|
}
|
||||||
|
target:
|
||||||
|
{
|
||||||
|
executable: "build/metagen.exe"
|
||||||
|
working_directory: build
|
||||||
|
}
|
||||||
|
target:
|
||||||
|
{
|
||||||
|
executable: "build/radbin.exe"
|
||||||
|
working_directory: build
|
||||||
|
arguments: "--rdi raddbg"
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ arch_reg_code_from_rdi(Arch arch, RDI_RegCode code)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal ARCH_RegCode
|
internal ARCH_RegCode
|
||||||
arch_reg_code_from_dw(Arch arch, DW_Reg code)
|
arch_reg_code_from_dw(Arch arch, DW_RegCode code)
|
||||||
{
|
{
|
||||||
ARCH_RegCode result = 0;
|
ARCH_RegCode result = 0;
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, {0}, &arch_reg_code_rng_
|
|||||||
internal ARCH_Info *arch_info_from_arch(Arch arch);
|
internal ARCH_Info *arch_info_from_arch(Arch arch);
|
||||||
internal ARCH_RegCode arch_reg_code_from_name(ARCH_Info *arch_info, String8 name);
|
internal ARCH_RegCode arch_reg_code_from_name(ARCH_Info *arch_info, String8 name);
|
||||||
internal ARCH_RegCode arch_reg_code_from_rdi(Arch arch, RDI_RegCode code);
|
internal ARCH_RegCode arch_reg_code_from_rdi(Arch arch, RDI_RegCode code);
|
||||||
internal ARCH_RegCode arch_reg_code_from_dw(Arch arch, DW_Reg code);
|
internal ARCH_RegCode arch_reg_code_from_dw(Arch arch, DW_RegCode code);
|
||||||
internal B32 arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst);
|
internal B32 arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst);
|
||||||
internal B32 arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src);
|
internal B32 arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src);
|
||||||
internal U64 arch_ip_from_reg_block(ARCH_Info *arch_info, void *block);
|
internal U64 arch_ip_from_reg_block(ARCH_Info *arch_info, void *block);
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
|
|||||||
cache->slots_count = Max(256, params->slots_count);
|
cache->slots_count = Max(256, params->slots_count);
|
||||||
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
|
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
|
||||||
cache->stripes = stripe_array_alloc(cache_stripe->arena);
|
cache->stripes = stripe_array_alloc(cache_stripe->arena);
|
||||||
|
cache->stripe_free_node_ptrs = push_array(cache_stripe->arena, AC_NodePtr *, cache->stripes.count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cache != 0)
|
if(cache != 0)
|
||||||
@@ -73,6 +74,9 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
|
|||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
AC_Slot *slot = &cache->slots[slot_idx];
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||||
|
|
||||||
|
//- rjf: unpack thread context
|
||||||
|
B32 is_node_work_active = (ac_tctx != 0);
|
||||||
|
|
||||||
//- rjf: cache * key -> existing artifact
|
//- rjf: cache * key -> existing artifact
|
||||||
B32 artifact_is_stale = 1;
|
B32 artifact_is_stale = 1;
|
||||||
B32 got_artifact = 0;
|
B32 got_artifact = 0;
|
||||||
@@ -92,11 +96,16 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
|
|||||||
artifact_is_stale = is_stale;
|
artifact_is_stale = is_stale;
|
||||||
artifact = n->val;
|
artifact = n->val;
|
||||||
access_touch(access, &n->access_pt, stripe->cv);
|
access_touch(access, &n->access_pt, stripe->cv);
|
||||||
|
ins_atomic_u64_eval_assign(&n->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
|
||||||
}
|
}
|
||||||
if(is_stale)
|
if(is_stale)
|
||||||
{
|
{
|
||||||
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
|
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
|
||||||
need_request = got_task;
|
need_request = got_task;
|
||||||
|
if(is_node_work_active)
|
||||||
|
{
|
||||||
|
ins_atomic_u32_eval_assign(&n->other_nodes_depend_on_me, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -140,6 +149,10 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
|
|||||||
node->key = str8_copy(stripe->arena, key);
|
node->key = str8_copy(stripe->arena, key);
|
||||||
node->working_count = 1;
|
node->working_count = 1;
|
||||||
node->evict_threshold_us = params->evict_threshold_us;
|
node->evict_threshold_us = params->evict_threshold_us;
|
||||||
|
if(is_node_work_active)
|
||||||
|
{
|
||||||
|
node->other_nodes_depend_on_me = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
node->access_pt.last_time_touched_us = now_time_us();
|
node->access_pt.last_time_touched_us = now_time_us();
|
||||||
node->access_pt.last_update_idx_touched = update_tick_idx();
|
node->access_pt.last_update_idx_touched = update_tick_idx();
|
||||||
@@ -181,6 +194,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
|
|||||||
artifact_is_stale = (node->last_completed_gen == params->gen);
|
artifact_is_stale = (node->last_completed_gen == params->gen);
|
||||||
artifact = node->val;
|
artifact = node->val;
|
||||||
access_touch(access, &node->access_pt, stripe->cv);
|
access_touch(access, &node->access_pt, stripe->cv);
|
||||||
|
ins_atomic_u64_eval_assign(&node->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: abort if needed
|
// rjf: abort if needed
|
||||||
@@ -243,7 +257,9 @@ ac_async_tick(void)
|
|||||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
||||||
{
|
{
|
||||||
next = n->next;
|
next = n->next;
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) == 0)
|
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) &&
|
||||||
|
ins_atomic_u64_eval(&n->working_count) == 0 &&
|
||||||
|
(ins_atomic_u32_eval(&n->other_nodes_depend_on_me) == 0 || ac_shared->request_gen > n->last_touched_ac_request_gen))
|
||||||
{
|
{
|
||||||
slot_has_work = 1;
|
slot_has_work = 1;
|
||||||
if(!write_mode)
|
if(!write_mode)
|
||||||
@@ -327,6 +343,11 @@ ac_async_tick(void)
|
|||||||
lane_sync_u64(&tasks_count, 0);
|
lane_sync_u64(&tasks_count, 0);
|
||||||
lane_sync();
|
lane_sync();
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: set up artifact cache thread context
|
||||||
|
//
|
||||||
|
ac_tctx = push_array(scratch.arena, AC_TCTX, 1);
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- rjf: do all requests
|
//- rjf: do all requests
|
||||||
//
|
//
|
||||||
@@ -610,6 +631,30 @@ ac_async_tick(void)
|
|||||||
}
|
}
|
||||||
lane_sync();
|
lane_sync();
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: increment the request gen, only if all requests are empty
|
||||||
|
//
|
||||||
|
if(lane_idx() == 0)
|
||||||
|
{
|
||||||
|
B32 have_live_requests = 0;
|
||||||
|
for EachElement(idx, ac_shared->req_batches)
|
||||||
|
{
|
||||||
|
MutexScope(ac_shared->req_batches[idx].mutex)
|
||||||
|
{
|
||||||
|
have_live_requests = (ac_shared->req_batches[idx].wide_count != 0 || ac_shared->req_batches[idx].thin_count != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!have_live_requests)
|
||||||
|
{
|
||||||
|
ac_shared->request_gen += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: reset thread context
|
||||||
|
//
|
||||||
|
ac_tctx = 0;
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- rjf: disable cancellation scanning
|
//- rjf: disable cancellation scanning
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -59,6 +59,13 @@ struct AC_RequestNode
|
|||||||
AC_Request v;
|
AC_Request v;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct AC_NodePtr AC_NodePtr;
|
||||||
|
struct AC_NodePtr
|
||||||
|
{
|
||||||
|
AC_NodePtr *next;
|
||||||
|
struct AC_Node *node;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct AC_Node AC_Node;
|
typedef struct AC_Node AC_Node;
|
||||||
struct AC_Node
|
struct AC_Node
|
||||||
{
|
{
|
||||||
@@ -76,8 +83,9 @@ struct AC_Node
|
|||||||
U64 working_count;
|
U64 working_count;
|
||||||
U64 completion_count;
|
U64 completion_count;
|
||||||
U64 evict_threshold_us;
|
U64 evict_threshold_us;
|
||||||
|
U64 last_touched_ac_request_gen;
|
||||||
B32 cancelled;
|
B32 cancelled;
|
||||||
U64 _unused_;
|
B32 other_nodes_depend_on_me;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct AC_Slot AC_Slot;
|
typedef struct AC_Slot AC_Slot;
|
||||||
@@ -99,6 +107,7 @@ struct AC_Cache
|
|||||||
U64 slots_count;
|
U64 slots_count;
|
||||||
AC_Slot *slots;
|
AC_Slot *slots;
|
||||||
StripeArray stripes;
|
StripeArray stripes;
|
||||||
|
AC_NodePtr **stripe_free_node_ptrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct AC_RequestBatch AC_RequestBatch;
|
typedef struct AC_RequestBatch AC_RequestBatch;
|
||||||
@@ -114,10 +123,17 @@ struct AC_RequestBatch
|
|||||||
U64 thin_count;
|
U64 thin_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct AC_TCTX AC_TCTX;
|
||||||
|
struct AC_TCTX
|
||||||
|
{
|
||||||
|
U64 _unused_;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct AC_Shared AC_Shared;
|
typedef struct AC_Shared AC_Shared;
|
||||||
struct AC_Shared
|
struct AC_Shared
|
||||||
{
|
{
|
||||||
Arena *arena;
|
Arena *arena;
|
||||||
|
U64 request_gen;
|
||||||
|
|
||||||
// rjf: cache cache
|
// rjf: cache cache
|
||||||
U64 cache_slots_count;
|
U64 cache_slots_count;
|
||||||
@@ -136,6 +152,7 @@ struct AC_Shared
|
|||||||
//~ rjf: Globals
|
//~ rjf: Globals
|
||||||
|
|
||||||
global AC_Shared *ac_shared = 0;
|
global AC_Shared *ac_shared = 0;
|
||||||
|
thread_static AC_TCTX *ac_tctx = 0;
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Layer Initialization
|
//~ rjf: Layer Initialization
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "base_arena.c"
|
#include "base_arena.c"
|
||||||
#include "base_math.c"
|
#include "base_math.c"
|
||||||
#include "base_strings.c"
|
#include "base_strings.c"
|
||||||
|
#include "base_memory_map.c"
|
||||||
#include "base_hash.c"
|
#include "base_hash.c"
|
||||||
#include "base_system.c"
|
#include "base_system.c"
|
||||||
#include "base_threads.c"
|
#include "base_threads.c"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "base_arena.h"
|
#include "base_arena.h"
|
||||||
#include "base_math.h"
|
#include "base_math.h"
|
||||||
#include "base_strings.h"
|
#include "base_strings.h"
|
||||||
|
#include "base_memory_map.h"
|
||||||
#include "base_hash.h"
|
#include "base_hash.h"
|
||||||
#include "base_system.h"
|
#include "base_system.h"
|
||||||
#include "base_threads.h"
|
#include "base_threads.h"
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
#ifndef BASE_MEMORY_H
|
#ifndef BASE_MEMORY_H
|
||||||
#define BASE_MEMORY_H
|
#define BASE_MEMORY_H
|
||||||
|
|
||||||
typedef struct SharedMemory SharedMemory;
|
|
||||||
struct SharedMemory
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @per_os_impl Platform Memory Allocation
|
//~ rjf: @per_os_impl Platform Memory Allocation
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Memory Map Functions
|
||||||
|
|
||||||
|
internal void
|
||||||
|
memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data)
|
||||||
|
{
|
||||||
|
MemoryMapRangeNode *n = push_array(arena, MemoryMapRangeNode, 1);
|
||||||
|
n->v.vaddr_range = vaddr_range;
|
||||||
|
n->v.base = data;
|
||||||
|
SLLQueuePush(map->first_range, map->last_range, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
memory_map_read(MemoryMap *map, Rng1U64 range, void *dst)
|
||||||
|
{
|
||||||
|
U64 dst_vaddr = range.min;
|
||||||
|
{
|
||||||
|
for(MemoryMapRangeNode *n = map->first_range; n != 0; n = n->next)
|
||||||
|
{
|
||||||
|
if(contains_1u64(n->v.vaddr_range, dst_vaddr))
|
||||||
|
{
|
||||||
|
U64 src_off = dst_vaddr - n->v.vaddr_range.min;
|
||||||
|
U64 num_bytes_possible = n->v.vaddr_range.max - dst_vaddr;
|
||||||
|
U64 num_bytes_needed = range.max - dst_vaddr;
|
||||||
|
U64 num_bytes_to_read = Min(num_bytes_needed, num_bytes_possible);
|
||||||
|
MemoryCopy((U8 *)dst + (dst_vaddr - range.min), (U8 *)n->v.base + src_off, num_bytes_to_read);
|
||||||
|
dst_vaddr += num_bytes_to_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
U64 bytes_read = (dst_vaddr - range.min);
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_MEMORY_MAP_H
|
||||||
|
#define BASE_MEMORY_MAP_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Memory Map Types
|
||||||
|
|
||||||
|
typedef struct MemoryMapRange MemoryMapRange;
|
||||||
|
struct MemoryMapRange
|
||||||
|
{
|
||||||
|
Rng1U64 vaddr_range;
|
||||||
|
void *base;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct MemoryMapRangeNode MemoryMapRangeNode;
|
||||||
|
struct MemoryMapRangeNode
|
||||||
|
{
|
||||||
|
MemoryMapRangeNode *next;
|
||||||
|
MemoryMapRange v;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct MemoryMap MemoryMap;
|
||||||
|
struct MemoryMap
|
||||||
|
{
|
||||||
|
MemoryMapRangeNode *first_range;
|
||||||
|
MemoryMapRangeNode *last_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Memory Map Functions
|
||||||
|
|
||||||
|
internal void memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data);
|
||||||
|
internal U64 memory_map_read(MemoryMap *map, Rng1U64 range, void *dst);
|
||||||
|
#define memory_map_read_struct(map, vaddr, ptr) memory_map_read((map), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
|
||||||
|
|
||||||
|
#endif // BASE_MEMORY_MAP_H
|
||||||
@@ -4,8 +4,14 @@
|
|||||||
#ifndef BASE_SHARED_MEMORY_H
|
#ifndef BASE_SHARED_MEMORY_H
|
||||||
#define BASE_SHARED_MEMORY_H
|
#define BASE_SHARED_MEMORY_H
|
||||||
|
|
||||||
|
typedef struct SharedMemory SharedMemory;
|
||||||
|
struct SharedMemory
|
||||||
|
{
|
||||||
|
U64 u64[1];
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Shared Memory
|
//~ rjf: @per_os_impl Shared Memory
|
||||||
|
|
||||||
internal SharedMemory shared_memory_alloc(U64 size, String8 name);
|
internal SharedMemory shared_memory_alloc(U64 size, String8 name);
|
||||||
internal SharedMemory shared_memory_open(String8 name);
|
internal SharedMemory shared_memory_open(String8 name);
|
||||||
|
|||||||
+72
-27
@@ -1476,7 +1476,7 @@ str8_from_version(Arena *arena, U64 version)
|
|||||||
//~ rjf: String Path Helpers
|
//~ rjf: String Path Helpers
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
default_exe_name_suffix_from_os(OperatingSystem os)
|
program_ext_postfix_from_os(OperatingSystem os, B32 require_ext)
|
||||||
{
|
{
|
||||||
String8 result = {0};
|
String8 result = {0};
|
||||||
switch(os)
|
switch(os)
|
||||||
@@ -1486,36 +1486,15 @@ default_exe_name_suffix_from_os(OperatingSystem os)
|
|||||||
{
|
{
|
||||||
result = s(".exe");
|
result = s(".exe");
|
||||||
}break;
|
}break;
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
program_data_folder_prefix_from_os(OperatingSystem os)
|
|
||||||
{
|
|
||||||
String8 result = {0};
|
|
||||||
switch(os)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case OperatingSystem_Linux:
|
case OperatingSystem_Linux:
|
||||||
case OperatingSystem_Mac:
|
if(require_ext)
|
||||||
{
|
{
|
||||||
result = s(".");
|
result = s(".elf");
|
||||||
}break;
|
}break;
|
||||||
}
|
case OperatingSystem_Mac:
|
||||||
return result;
|
if(require_ext)
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
program_ext_postfix_from_os(OperatingSystem os)
|
|
||||||
{
|
|
||||||
String8 result = {0};
|
|
||||||
switch(os)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case OperatingSystem_Windows:
|
|
||||||
{
|
{
|
||||||
result = s(".exe");
|
result = s(".macho");
|
||||||
}break;
|
}break;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -3038,6 +3017,72 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out)
|
|||||||
return block_out->size;
|
return block_out->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out)
|
||||||
|
{
|
||||||
|
U64 value = 0;
|
||||||
|
U64 shift = 0;
|
||||||
|
U64 cursor = off;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
U8 byte = 0;
|
||||||
|
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
|
||||||
|
if(bytes_read != sizeof(byte))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
U8 val = byte & 0x7fu;
|
||||||
|
value |= ((U64)val) << shift;
|
||||||
|
cursor += bytes_read;
|
||||||
|
shift += 7u;
|
||||||
|
if((byte & 0x80u) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(value_out != 0)
|
||||||
|
{
|
||||||
|
*value_out = value;
|
||||||
|
}
|
||||||
|
U64 bytes_read = cursor - off;
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out)
|
||||||
|
{
|
||||||
|
U64 value = 0;
|
||||||
|
U64 shift = 0;
|
||||||
|
U64 cursor = off;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
U8 byte;
|
||||||
|
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
|
||||||
|
if(bytes_read != sizeof(byte))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
U8 val = byte & 0x7fu;
|
||||||
|
value |= ((U64)val) << shift;
|
||||||
|
cursor += bytes_read;
|
||||||
|
shift += 7u;
|
||||||
|
if((byte & 0x80u) == 0)
|
||||||
|
{
|
||||||
|
if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0)
|
||||||
|
{
|
||||||
|
value |= -(S64)(1ull << shift);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(value_out != 0)
|
||||||
|
{
|
||||||
|
*value_out = value;
|
||||||
|
}
|
||||||
|
U64 bytes_read = cursor - off;
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
internal int
|
internal int
|
||||||
|
|||||||
@@ -323,9 +323,7 @@ g_path_style_map[] =
|
|||||||
{ str8_lit_comp("system"), PathStyle_SystemAbsolute },
|
{ str8_lit_comp("system"), PathStyle_SystemAbsolute },
|
||||||
};
|
};
|
||||||
|
|
||||||
internal String8 default_exe_name_suffix_from_os(OperatingSystem os);
|
internal String8 program_ext_postfix_from_os(OperatingSystem os, B32 require_ext);
|
||||||
internal String8 program_data_folder_prefix_from_os(OperatingSystem os);
|
|
||||||
internal String8 program_ext_postfix_from_os(OperatingSystem os);
|
|
||||||
|
|
||||||
internal String8 str8_chop_last_slash(String8 string);
|
internal String8 str8_chop_last_slash(String8 string);
|
||||||
internal String8 str8_skip_last_slash(String8 string);
|
internal String8 str8_skip_last_slash(String8 string);
|
||||||
@@ -457,6 +455,8 @@ internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 of
|
|||||||
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
||||||
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
||||||
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
|
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
|
||||||
|
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
|
||||||
|
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ string buffer
|
//~ string buffer
|
||||||
|
|||||||
@@ -37,15 +37,9 @@ d_init(void)
|
|||||||
d_ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc();
|
d_ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc();
|
||||||
d_ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = rw_mutex_alloc();
|
d_ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = rw_mutex_alloc();
|
||||||
}
|
}
|
||||||
d_ctrl_state->module_image_info_cache.slots_count = 1024;
|
d_ctrl_state->module_info_cache.slots_count = 1024;
|
||||||
d_ctrl_state->module_image_info_cache.slots = push_array(arena, D_ModuleImageInfoCacheSlot, d_ctrl_state->module_image_info_cache.slots_count);
|
d_ctrl_state->module_info_cache.slots = push_array(arena, D_ModuleInfoCacheSlot, d_ctrl_state->module_info_cache.slots_count);
|
||||||
d_ctrl_state->module_image_info_cache.stripes_count = get_system_info()->logical_processor_count;
|
d_ctrl_state->module_info_cache.stripes = stripe_array_alloc(arena);
|
||||||
d_ctrl_state->module_image_info_cache.stripes = push_array(arena, D_ModuleImageInfoCacheStripe, d_ctrl_state->module_image_info_cache.stripes_count);
|
|
||||||
for(U64 idx = 0; idx < d_ctrl_state->module_image_info_cache.stripes_count; idx += 1)
|
|
||||||
{
|
|
||||||
d_ctrl_state->module_image_info_cache.stripes[idx].arena = arena_alloc();
|
|
||||||
d_ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = rw_mutex_alloc();
|
|
||||||
}
|
|
||||||
d_ctrl_state->u2c_ring_size = KB(64);
|
d_ctrl_state->u2c_ring_size = KB(64);
|
||||||
d_ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, d_ctrl_state->u2c_ring_size);
|
d_ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, d_ctrl_state->u2c_ring_size);
|
||||||
d_ctrl_state->u2c_ring_mutex = mutex_alloc();
|
d_ctrl_state->u2c_ring_mutex = mutex_alloc();
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ struct D_Entity
|
|||||||
D_TlsModel tls_model;
|
D_TlsModel tls_model;
|
||||||
U64 tls_index;
|
U64 tls_index;
|
||||||
U64 tls_offset;
|
U64 tls_offset;
|
||||||
|
U64 tls_root_vaddr;
|
||||||
OperatingSystem target_os;
|
OperatingSystem target_os;
|
||||||
D_MsgID src_msg_id;
|
D_MsgID src_msg_id;
|
||||||
};
|
};
|
||||||
|
|||||||
+325
-121
@@ -1358,6 +1358,7 @@ d_entity_store_apply_events(D_EntityCtxRWStore *store, D_EventList *list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
thread->stack_base = event->stack_base;
|
thread->stack_base = event->stack_base;
|
||||||
|
thread->tls_root_vaddr = event->tls_root;
|
||||||
}
|
}
|
||||||
//d_cached_ip_from_thread(&store->ctx, event->entity);
|
//d_cached_ip_from_thread(&store->ctx, event->entity);
|
||||||
}break;
|
}break;
|
||||||
@@ -1633,6 +1634,25 @@ d_sp_from_thread(D_Handle handle)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
d_thread_get_module_tls_vaddr(D_Handle thread, D_Handle module, U64 *vaddr_out)
|
||||||
|
{
|
||||||
|
B32 result = 0;
|
||||||
|
|
||||||
|
// rjf: resolve to demon
|
||||||
|
DMN_Handle thread_dmn = d_dmn_from_handle(thread);
|
||||||
|
DMN_Handle module_dmn = d_dmn_from_handle(module);
|
||||||
|
|
||||||
|
// rjf: compute vaddr
|
||||||
|
if(!dmn_handle_match(thread_dmn, dmn_handle_zero()) &&
|
||||||
|
!dmn_handle_match(module_dmn, dmn_handle_zero()))
|
||||||
|
{
|
||||||
|
result = dmn_thread_get_module_tls_vaddr(thread_dmn, module_dmn, vaddr_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: thread register cache reading
|
//- rjf: thread register cache reading
|
||||||
|
|
||||||
internal void *
|
internal void *
|
||||||
@@ -1695,14 +1715,6 @@ d_cached_reg_block_from_thread(Arena *arena, D_Handle handle)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
|
||||||
d_cached_tls_root_vaddr_from_thread(D_Handle handle)
|
|
||||||
{
|
|
||||||
DMN_Handle handle_dmn = d_dmn_from_handle(handle);
|
|
||||||
U64 result = dmn_tls_root_vaddr_from_thread(handle_dmn);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
d_cached_ip_from_thread(D_Handle handle)
|
d_cached_ip_from_thread(D_Handle handle)
|
||||||
{
|
{
|
||||||
@@ -1734,17 +1746,18 @@ d_cached_sp_from_thread(D_Handle handle)
|
|||||||
|
|
||||||
//- rjf: cache lookups
|
//- rjf: cache lookups
|
||||||
|
|
||||||
|
#if 0 // TODO(rjf): @unwind
|
||||||
internal PE_IntelPdata *
|
internal PE_IntelPdata *
|
||||||
d_intel_pdata_from_module_voff(Arena *arena, D_Handle module_handle, U64 voff)
|
d_intel_pdata_from_module_voff(Arena *arena, D_Handle module_handle, U64 voff)
|
||||||
{
|
{
|
||||||
PE_IntelPdata *first_pdata = 0;
|
PE_IntelPdata *first_pdata = 0;
|
||||||
{
|
{
|
||||||
U64 hash = d_hash_from_handle(module_handle);
|
U64 hash = d_hash_from_handle(module_handle);
|
||||||
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
|
U64 slot_idx = hash%d_ctrl_state->module_info_cache.slots_count;
|
||||||
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
|
U64 stripe_idx = slot_idx%d_ctrl_state->module_info_cache.stripes_count;
|
||||||
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
|
D_ModuleInfoCacheSlot *slot = &d_ctrl_state->module_info_cache.slots[slot_idx];
|
||||||
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
|
D_ModuleInfoCacheStripe *stripe = &d_ctrl_state->module_info_cache.stripes[stripe_idx];
|
||||||
MutexScopeR(stripe->rw_mutex) for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
|
MutexScopeR(stripe->rw_mutex) for(D_ModuleInfoCacheNode *n = slot->first; n != 0; n = n->next)
|
||||||
{
|
{
|
||||||
if(d_handle_match(n->module, module_handle))
|
if(d_handle_match(n->module, module_handle))
|
||||||
{
|
{
|
||||||
@@ -1800,70 +1813,54 @@ d_intel_pdata_from_module_voff(Arena *arena, D_Handle module_handle, U64 voff)
|
|||||||
}
|
}
|
||||||
return first_pdata;
|
return first_pdata;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal D_ModuleInfo *
|
||||||
|
d_info_from_module(Access *access, D_Handle module)
|
||||||
|
{
|
||||||
|
D_ModuleInfo *result = &d_module_info_nil;
|
||||||
|
{
|
||||||
|
D_ModuleInfoCache *cache = &d_ctrl_state->module_info_cache;
|
||||||
|
U64 hash = d_hash_from_handle(module);
|
||||||
|
U64 slot_idx = hash%cache->slots_count;
|
||||||
|
D_ModuleInfoCacheSlot *slot = &cache->slots[slot_idx];
|
||||||
|
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||||
|
MutexScopeR(stripe->rw_mutex) for(D_ModuleInfoCacheNode *n = slot->first; n != 0; n = n->next)
|
||||||
|
{
|
||||||
|
if(d_handle_match(n->module, module))
|
||||||
|
{
|
||||||
|
access_touch(access, &n->access_pt, stripe->cv);
|
||||||
|
result = &n->v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
d_entry_point_voff_from_module(D_Handle module_handle)
|
d_entry_point_voff_from_module(D_Handle module_handle)
|
||||||
{
|
{
|
||||||
U64 result = 0;
|
Access *access = access_open();
|
||||||
U64 hash = d_hash_from_handle(module_handle);
|
U64 result = d_info_from_module(access, module_handle)->entry_point_voff;
|
||||||
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
|
access_close(access);
|
||||||
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
|
|
||||||
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
|
|
||||||
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
|
|
||||||
MutexScopeR(stripe->rw_mutex) for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(d_handle_match(n->module, module_handle))
|
|
||||||
{
|
|
||||||
result = n->entry_point_voff;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
d_initial_debug_info_path_from_module(Arena *arena, D_Handle module_handle)
|
d_initial_debug_info_path_from_module(Arena *arena, D_Handle module_handle)
|
||||||
{
|
{
|
||||||
String8 result = {0};
|
Access *access = access_open();
|
||||||
U64 hash = d_hash_from_handle(module_handle);
|
String8 result = str8_copy(arena, d_info_from_module(access, module_handle)->local_debug_info_path);
|
||||||
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
|
access_close(access);
|
||||||
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
|
|
||||||
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
|
|
||||||
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
|
|
||||||
MutexScopeR(stripe->rw_mutex) for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(d_handle_match(n->module, module_handle))
|
|
||||||
{
|
|
||||||
result = str8_copy(arena, n->local_debug_info_path);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
d_raddbg_data_from_module(Arena *arena, D_Handle module_handle)
|
|
||||||
{
|
|
||||||
String8 result = {0};
|
|
||||||
U64 hash = d_hash_from_handle(module_handle);
|
|
||||||
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
|
|
||||||
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
|
|
||||||
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
|
|
||||||
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
|
|
||||||
MutexScopeR(stripe->rw_mutex) for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(d_handle_match(n->module, module_handle))
|
|
||||||
{
|
|
||||||
result = push_str8_copy(arena, n->raddbg_data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Unwinding Functions
|
//~ rjf: Unwinding Functions
|
||||||
|
|
||||||
|
#if 0 // TODO(rjf): @unwind
|
||||||
|
|
||||||
//- rjf: [dwarf]
|
//- rjf: [dwarf]
|
||||||
|
|
||||||
typedef struct D_MemoryReadContextDwarfX64 D_MemoryReadContextDwarfX64;
|
typedef struct D_MemoryReadContextDwarfX64 D_MemoryReadContextDwarfX64;
|
||||||
@@ -1930,11 +1927,11 @@ d_establish_frame_unwind_context__dwarf(Arena *arena, D_Handle process_handle, D
|
|||||||
EH_PtrCtx eh_ptr_ctx = {0};
|
EH_PtrCtx eh_ptr_ctx = {0};
|
||||||
{
|
{
|
||||||
U64 hash = d_hash_from_handle(module_handle);
|
U64 hash = d_hash_from_handle(module_handle);
|
||||||
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
|
U64 slot_idx = hash%d_ctrl_state->module_info_cache.slots_count;
|
||||||
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
|
U64 stripe_idx = slot_idx%d_ctrl_state->module_info_cache.stripes_count;
|
||||||
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
|
D_ModuleInfoCacheSlot *slot = &d_ctrl_state->module_info_cache.slots[slot_idx];
|
||||||
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
|
D_ModuleInfoCacheStripe *stripe = &d_ctrl_state->module_info_cache.stripes[stripe_idx];
|
||||||
MutexScopeR(stripe->rw_mutex) for EachNode(n, D_ModuleImageInfoCacheNode, slot->first)
|
MutexScopeR(stripe->rw_mutex) for EachNode(n, D_ModuleInfoCacheNode, slot->first)
|
||||||
{
|
{
|
||||||
if(d_handle_match(n->module, module_handle))
|
if(d_handle_match(n->module, module_handle))
|
||||||
{
|
{
|
||||||
@@ -2998,6 +2995,7 @@ d_unwind_step__pe_x64(D_Handle process_handle, D_Handle module_handle, U64 modul
|
|||||||
if(is_stale) {result.flags |= D_UnwindFlag_Stale;}
|
if(is_stale) {result.flags |= D_UnwindFlag_Stale;}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//- rjf: abstracted full unwind
|
//- rjf: abstracted full unwind
|
||||||
|
|
||||||
@@ -3008,35 +3006,149 @@ d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us)
|
|||||||
Temp scratch = scratch_begin(&arena, 1);
|
Temp scratch = scratch_begin(&arena, 1);
|
||||||
D_Unwind unwind = { .flags = D_UnwindFlag_Error };
|
D_Unwind unwind = { .flags = D_UnwindFlag_Error };
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: grab run state pre-unwind computing
|
||||||
|
//
|
||||||
|
U64 run_gen = d_run_gen();
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
//- rjf: unpack args
|
//- rjf: unpack args
|
||||||
|
//
|
||||||
D_Entity *thread_entity = d_entity_from_handle(thread);
|
D_Entity *thread_entity = d_entity_from_handle(thread);
|
||||||
D_Entity *process_entity = thread_entity->parent;
|
D_Entity *process_entity = thread_entity->parent;
|
||||||
Arch arch = thread_entity->arch;
|
Arch arch = thread_entity->arch;
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
||||||
U64 arch_reg_block_size = arch_info->reg_block_size;
|
U64 arch_reg_block_size = arch_info->reg_block_size;
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
//- rjf: grab initial register block
|
//- rjf: grab initial register block
|
||||||
|
//
|
||||||
void *regs_block = d_cached_reg_block_from_thread(scratch.arena, thread);
|
void *regs_block = d_cached_reg_block_from_thread(scratch.arena, thread);
|
||||||
B32 regs_block_good = (arch != Arch_Null && regs_block != 0);
|
B32 regs_block_good = (arch != Arch_Null && regs_block != 0);
|
||||||
|
|
||||||
//- rjf: loop & unwind
|
//////////////////////////////
|
||||||
|
//- rjf: grab initial memory
|
||||||
|
//
|
||||||
|
MemoryMap memory_map = {0};
|
||||||
|
{
|
||||||
|
// NOTE(rjf): we can pre-fill memory that we can expect to load here -
|
||||||
|
// otherwise we will lazily evaluate it via the unwinding backends below
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: push one frame for register block we already have
|
||||||
|
//
|
||||||
D_UnwindFrameNode *first_frame_node = 0;
|
D_UnwindFrameNode *first_frame_node = 0;
|
||||||
D_UnwindFrameNode *last_frame_node = 0;
|
D_UnwindFrameNode *last_frame_node = 0;
|
||||||
U64 frame_node_count = 0;
|
U64 frame_node_count = 0;
|
||||||
if(regs_block_good)
|
if(regs_block_good)
|
||||||
{
|
{
|
||||||
for(unwind.flags = 0;;)
|
D_UnwindFrameNode *frame_node = push_array(scratch.arena, D_UnwindFrameNode, 1);
|
||||||
|
D_UnwindFrame *f = &frame_node->v;
|
||||||
|
f->regs = push_array_no_zero(arena, U8, arch_reg_block_size);
|
||||||
|
MemoryCopy(f->regs, regs_block, arch_reg_block_size);
|
||||||
|
DLLPushBack(first_frame_node, last_frame_node, frame_node);
|
||||||
|
frame_node_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: loop & unwind
|
||||||
|
//
|
||||||
|
if(regs_block_good)
|
||||||
|
{
|
||||||
|
unwind.flags = 0;
|
||||||
|
for(;!unwind.flags;)
|
||||||
{
|
{
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
||||||
U64 rip = arch_ip_from_reg_block(arch_info, regs_block);
|
U64 start_ip = arch_ip_from_reg_block(arch_info, regs_block);
|
||||||
U64 rsp = arch_sp_from_reg_block(arch_info, regs_block);
|
U64 start_sp = arch_sp_from_reg_block(arch_info, regs_block);
|
||||||
|
|
||||||
// rjf: cancel on zero rip (except the top frame)
|
//- rjf: cancel on zero rip (except the top frame)
|
||||||
if(rip == 0 && frame_node_count > 0)
|
if(start_ip == 0 && frame_node_count > 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//- rjf: open access for this step
|
||||||
|
Access *access = access_open();
|
||||||
|
|
||||||
|
//- rjf: ip -> module / unpack
|
||||||
|
D_Entity *module_entity = d_module_from_process_vaddr(process_entity, start_ip);
|
||||||
|
D_ModuleInfo *module_info = d_info_from_module(access, module_entity->handle);
|
||||||
|
UWND_Unwinder unwinder = module_info->unwinder;
|
||||||
|
UWND_ModuleInfo unwinder_module_info = {module_entity->vaddr_range.min, module_info->unwind_info};
|
||||||
|
|
||||||
|
//- rjf: thread * module -> tls vaddr
|
||||||
|
U64 tls_vaddr = 0;
|
||||||
|
d_thread_get_module_tls_vaddr(thread_entity->handle, module_entity->handle, &tls_vaddr);
|
||||||
|
|
||||||
|
//- rjf: do one unwind step
|
||||||
|
B32 step_is_good = 0;
|
||||||
|
for(;!unwind.flags;)
|
||||||
|
{
|
||||||
|
// rjf: try step
|
||||||
|
U64 cfa = 0;
|
||||||
|
UWND_StepResult step = uwnd_step(unwinder, arch, &memory_map, &unwinder_module_info, tls_vaddr, regs_block, &cfa);
|
||||||
|
|
||||||
|
// rjf: if we failed to read memory, try to read that memory, equip to memory map.
|
||||||
|
// if it is stale and we run out of time, we will need to mark the whole unwind as
|
||||||
|
// stale. if it can't be read, the unwind fails.
|
||||||
|
if(step.status == UWND_StepStatus_FailedMemoryRead)
|
||||||
|
{
|
||||||
|
D_ProcessMemorySlice slice = d_process_memory_slice_from_vaddr_range(scratch.arena, process_entity->handle, step.missed_read_vaddr_range, 1, 0);
|
||||||
|
String8 data = slice.data;
|
||||||
|
if(slice.stale)
|
||||||
|
{
|
||||||
|
unwind.flags |= D_UnwindFlag_Stale;
|
||||||
|
}
|
||||||
|
else if(data.size < dim_1u64(step.missed_read_vaddr_range))
|
||||||
|
{
|
||||||
|
unwind.flags |= D_UnwindFlag_Error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memory_map_push(scratch.arena, &memory_map, step.missed_read_vaddr_range, data.str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: if the step itself failed, we just fail out.
|
||||||
|
else if(step.status == UWND_StepStatus_Error)
|
||||||
|
{
|
||||||
|
unwind.flags |= D_UnwindFlag_Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: if the step worked, we're good. equip this step's CFA to the previously added frame,
|
||||||
|
// then exit the step loop.
|
||||||
|
else if(step.status == UWND_StepStatus_Good)
|
||||||
|
{
|
||||||
|
last_frame_node->v.cfa = cfa;
|
||||||
|
step_is_good = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: push successful steps to frame list
|
||||||
|
if(step_is_good && arch_ip_from_reg_block(arch_info, regs_block) != 0 && arch_ip_from_reg_block(arch_info, regs_block) != start_ip)
|
||||||
|
{
|
||||||
|
D_UnwindFrameNode *frame_node = push_array(scratch.arena, D_UnwindFrameNode, 1);
|
||||||
|
D_UnwindFrame *f = &frame_node->v;
|
||||||
|
f->regs = push_array_no_zero(arena, U8, arch_reg_block_size);
|
||||||
|
MemoryCopy(f->regs, regs_block, arch_reg_block_size);
|
||||||
|
DLLPushBack(first_frame_node, last_frame_node, frame_node);
|
||||||
|
frame_node_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: close access
|
||||||
|
access_close(access);
|
||||||
|
|
||||||
|
//- rjf: exit if we made no progress on the unwind
|
||||||
|
if(arch_ip_from_reg_block(arch_info, regs_block) == start_ip ||
|
||||||
|
arch_sp_from_reg_block(arch_info, regs_block) == start_sp)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 // TODO(rjf): @unwind
|
||||||
// rip -> module
|
// rip -> module
|
||||||
D_Entity *module_entity = d_module_from_process_vaddr(process_entity, rip);
|
D_Entity *module_entity = d_module_from_process_vaddr(process_entity, rip);
|
||||||
|
|
||||||
@@ -3097,13 +3209,14 @@ d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us)
|
|||||||
}break;
|
}break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop unwinding on errors or stale data
|
// rjf: stop unwinding on errors or stale data
|
||||||
unwind.flags |= step_result.flags;
|
unwind.flags |= step_result.flags;
|
||||||
if(unwind.flags & (D_UnwindFlag_Stale|D_UnwindFlag_Error) ||
|
if(unwind.flags & (D_UnwindFlag_Stale|D_UnwindFlag_Error) ||
|
||||||
(arch_sp_from_reg_block(arch_info, regs_block) == rsp && arch_ip_from_reg_block(arch_info, regs_block) == rip))
|
(arch_sp_from_reg_block(arch_info, regs_block) == rsp && arch_ip_from_reg_block(arch_info, regs_block) == rip))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3758,23 +3871,47 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
|
|||||||
{
|
{
|
||||||
Temp scratch = scratch_begin(0,0);
|
Temp scratch = scratch_begin(0,0);
|
||||||
|
|
||||||
//- rjf: set up per-module info
|
//////////////////////////////
|
||||||
|
//- rjf: allocate / set up basic per-module info
|
||||||
|
//
|
||||||
Arena *arena = arena_alloc();
|
Arena *arena = arena_alloc();
|
||||||
String8 raddbg_data = d_data_from_process_vaddr_range(arena, process, shift_1u64(module_info->raddbg_info_voff_range, base_vaddr), 0);
|
String8 raddbg_data = d_data_from_process_vaddr_range(arena, process, shift_1u64(module_info->raddbg_info_voff_range, base_vaddr), 0);
|
||||||
U64 pdatas_count = dim_1u64(module_info->pe_intel_pdatas_vaddr_range) / sizeof(PE_IntelPdata);
|
|
||||||
String8 pdatas_data = d_data_from_process_vaddr_range(arena, process, module_info->pe_intel_pdatas_vaddr_range, 0);
|
//////////////////////////////
|
||||||
pdatas_count = Min(pdatas_count, pdatas_data.size / sizeof(PE_IntelPdata));
|
//- rjf: prepare unwind info
|
||||||
PE_IntelPdata *pdatas = (PE_IntelPdata *)pdatas_data.str;
|
//
|
||||||
EH_PtrCtx eh_ptr_ctx = {.pc_vaddr = max_U64, .text_vaddr = max_U64, .data_vaddr = max_U64, .func_vaddr = max_U64, .ptr_align = 0};
|
UWND_Unwinder unwinder = UWND_Unwinder_Null;
|
||||||
EH_FrameHdr eh_frame_hdr = {0};
|
void *unwind_info_opaque = 0;
|
||||||
B32 is_unwind_eh = 0;
|
|
||||||
if(module_info->eh_frame_header_vaddr_range.min != 0)
|
|
||||||
{
|
{
|
||||||
String8 eh_frame_hdr_data = d_data_from_process_vaddr_range(arena, process, module_info->eh_frame_header_vaddr_range, 0);
|
//- rjf: PE/x64 unwinder
|
||||||
eh_ptr_ctx.pc_vaddr = module_info->eh_frame_header_vaddr_range.min;
|
if(dim_1u64(module_info->pe_intel_pdatas_vaddr_range) != 0)
|
||||||
eh_ptr_ctx.data_vaddr = module_info->eh_frame_header_vaddr_range.min;
|
{
|
||||||
eh_frame_hdr = eh_parse_frame_hdr(eh_frame_hdr_data, byte_size_from_arch(module_info->arch), &eh_ptr_ctx);
|
unwinder = UWND_Unwinder_PEx64;
|
||||||
is_unwind_eh = 1;
|
PE_X64_UWND_ModuleUnwindInfo *unwind_info = push_array(arena, PE_X64_UWND_ModuleUnwindInfo, 1);
|
||||||
|
{
|
||||||
|
U64 pdatas_count = dim_1u64(module_info->pe_intel_pdatas_vaddr_range) / sizeof(PE_IntelPdata);
|
||||||
|
String8 pdatas_data = d_data_from_process_vaddr_range(arena, process, module_info->pe_intel_pdatas_vaddr_range, 0);
|
||||||
|
pdatas_count = Min(pdatas_count, pdatas_data.size / sizeof(PE_IntelPdata));
|
||||||
|
PE_IntelPdata *pdatas = (PE_IntelPdata *)pdatas_data.str;
|
||||||
|
unwind_info->pdatas = pdatas;
|
||||||
|
unwind_info->pdatas_count = pdatas_count;
|
||||||
|
}
|
||||||
|
unwind_info_opaque = unwind_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: .eh_frame unwinder
|
||||||
|
else if(dim_1u64(module_info->eh_frame_header_vaddr_range) != 0)
|
||||||
|
{
|
||||||
|
unwinder = UWND_Unwinder_EHFrame;
|
||||||
|
EH_UWND_ModuleUnwindInfo *unwind_info = push_array(arena, EH_UWND_ModuleUnwindInfo, 1);
|
||||||
|
{
|
||||||
|
String8 eh_frame_hdr_data = d_data_from_process_vaddr_range(arena, process, module_info->eh_frame_header_vaddr_range, 0);
|
||||||
|
unwind_info->ptr_ctx.pc_vaddr = module_info->eh_frame_header_vaddr_range.min;
|
||||||
|
unwind_info->ptr_ctx.data_vaddr = module_info->eh_frame_header_vaddr_range.min;
|
||||||
|
unwind_info->header = eh_parse_frame_hdr(eh_frame_hdr_data, byte_size_from_arch(module_info->arch), &unwind_info->ptr_ctx);
|
||||||
|
}
|
||||||
|
unwind_info_opaque = unwind_info;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
@@ -3853,19 +3990,33 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
|
|||||||
d_process_write_struct(process, base_vaddr + module_info->raddbg_is_attached_marker_voff, &new_value);
|
d_process_write_struct(process, base_vaddr + module_info->raddbg_is_attached_marker_voff, &new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: fill info
|
||||||
|
//
|
||||||
|
D_ModuleInfo info = {0};
|
||||||
|
{
|
||||||
|
info.entry_point_voff = module_info->entry_point_voff;
|
||||||
|
info.unwinder = unwinder;
|
||||||
|
info.unwind_info = unwind_info_opaque;
|
||||||
|
info.local_debug_info_path = initial_debug_info_path;
|
||||||
|
info.debug_info_unique_identifier = debug_info_unique_identifier;
|
||||||
|
info.raddbg_attached_marker_voff = module_info->raddbg_is_attached_marker_voff;
|
||||||
|
info.raddbg_data = raddbg_data;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- rjf: insert info into cache
|
//- rjf: insert info into cache
|
||||||
//
|
//
|
||||||
{
|
{
|
||||||
|
D_ModuleInfoCache *cache = &d_ctrl_state->module_info_cache;
|
||||||
U64 hash = d_hash_from_handle(module);
|
U64 hash = d_hash_from_handle(module);
|
||||||
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
|
U64 slot_idx = hash%cache->slots_count;
|
||||||
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
|
D_ModuleInfoCacheSlot *slot = &cache->slots[slot_idx];
|
||||||
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
|
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||||
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
|
|
||||||
MutexScopeW(stripe->rw_mutex)
|
MutexScopeW(stripe->rw_mutex)
|
||||||
{
|
{
|
||||||
D_ModuleImageInfoCacheNode *node = 0;
|
D_ModuleInfoCacheNode *node = 0;
|
||||||
for EachNode(n, D_ModuleImageInfoCacheNode, slot->first)
|
for EachNode(n, D_ModuleInfoCacheNode, slot->first)
|
||||||
{
|
{
|
||||||
if(d_handle_match(n->module, module))
|
if(d_handle_match(n->module, module))
|
||||||
{
|
{
|
||||||
@@ -3875,21 +4026,11 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DM
|
|||||||
}
|
}
|
||||||
if(!node)
|
if(!node)
|
||||||
{
|
{
|
||||||
node = push_array(arena, D_ModuleImageInfoCacheNode, 1);
|
node = push_array(arena, D_ModuleInfoCacheNode, 1);
|
||||||
DLLPushBack(slot->first, slot->last, node);
|
DLLPushBack(slot->first, slot->last, node);
|
||||||
node->module = module;
|
node->module = module;
|
||||||
node->arena = arena;
|
node->arena = arena;
|
||||||
node->pdatas = pdatas;
|
node->v = info;
|
||||||
node->pdatas_count = pdatas_count;
|
|
||||||
node->cfi_rebase = module_info->cfi_rebase;
|
|
||||||
node->is_unwind_eh = is_unwind_eh;
|
|
||||||
node->eh_frame_hdr = eh_frame_hdr;
|
|
||||||
node->eh_ptr_ctx = eh_ptr_ctx;
|
|
||||||
node->entry_point_voff = module_info->entry_point_voff;
|
|
||||||
node->local_debug_info_path = initial_debug_info_path;
|
|
||||||
node->debug_info_unique_identifier= debug_info_unique_identifier;
|
|
||||||
node->raddbg_attached_marker_voff = module_info->raddbg_is_attached_marker_voff;
|
|
||||||
node->raddbg_data = str8_copy(arena, raddbg_data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3903,19 +4044,19 @@ d_ctrl_thread__module_close(D_Handle process, D_Handle module, U64 base_vaddr)
|
|||||||
DMN_Handle process_dmn = d_dmn_from_handle(process);
|
DMN_Handle process_dmn = d_dmn_from_handle(process);
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- rjf: evict module image info from cache
|
//- rjf: evict module info from cache
|
||||||
//
|
//
|
||||||
U64 raddbg_attached_marker_voff = 0;
|
U64 raddbg_attached_marker_voff = 0;
|
||||||
{
|
{
|
||||||
|
D_ModuleInfoCache *cache = &d_ctrl_state->module_info_cache;
|
||||||
U64 hash = d_hash_from_handle(module);
|
U64 hash = d_hash_from_handle(module);
|
||||||
U64 slot_idx = hash%d_ctrl_state->module_image_info_cache.slots_count;
|
U64 slot_idx = hash%cache->slots_count;
|
||||||
U64 stripe_idx = slot_idx%d_ctrl_state->module_image_info_cache.stripes_count;
|
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||||
D_ModuleImageInfoCacheSlot *slot = &d_ctrl_state->module_image_info_cache.slots[slot_idx];
|
D_ModuleInfoCacheSlot *slot = &cache->slots[slot_idx];
|
||||||
D_ModuleImageInfoCacheStripe *stripe = &d_ctrl_state->module_image_info_cache.stripes[stripe_idx];
|
MutexScopeW(stripe->rw_mutex) for(;;)
|
||||||
MutexScopeW(stripe->rw_mutex)
|
|
||||||
{
|
{
|
||||||
D_ModuleImageInfoCacheNode *node = 0;
|
D_ModuleInfoCacheNode *node = 0;
|
||||||
for(D_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next)
|
for(D_ModuleInfoCacheNode *n = slot->first; n != 0; n = n->next)
|
||||||
{
|
{
|
||||||
if(d_handle_match(n->module, module))
|
if(d_handle_match(n->module, module))
|
||||||
{
|
{
|
||||||
@@ -3923,12 +4064,14 @@ d_ctrl_thread__module_close(D_Handle process, D_Handle module, U64 base_vaddr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(node)
|
if(node && access_pt_is_expired(&node->access_pt, .time = 0, .update_idxs = 0))
|
||||||
{
|
{
|
||||||
raddbg_attached_marker_voff = node->raddbg_attached_marker_voff;
|
raddbg_attached_marker_voff = node->v.raddbg_attached_marker_voff;
|
||||||
DLLRemove(slot->first, slot->last, node);
|
DLLRemove(slot->first, slot->last, node);
|
||||||
arena_release(node->arena);
|
arena_release(node->arena);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
cond_var_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4314,8 +4457,8 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D
|
|||||||
out_evt->parent = d_handle_from_dmn(D_MachineID_Local, event->process);
|
out_evt->parent = d_handle_from_dmn(D_MachineID_Local, event->process);
|
||||||
out_evt->arch = event->arch;
|
out_evt->arch = event->arch;
|
||||||
out_evt->entity_id = event->code;
|
out_evt->entity_id = event->code;
|
||||||
out_evt->stack_base = dmn_stack_base_vaddr_from_thread(event->thread);
|
out_evt->stack_base = event->stack_pointer;
|
||||||
out_evt->tls_root = dmn_tls_root_vaddr_from_thread(event->thread);
|
out_evt->tls_root = event->tls_root_vaddr;
|
||||||
out_evt->rip_vaddr = event->instruction_pointer;
|
out_evt->rip_vaddr = event->instruction_pointer;
|
||||||
out_evt->string = event->string;
|
out_evt->string = event->string;
|
||||||
}break;
|
}break;
|
||||||
@@ -5902,7 +6045,9 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg)
|
|||||||
//- rjf: add traps for module-baked entry points, if specified
|
//- rjf: add traps for module-baked entry points, if specified
|
||||||
if(!entries_found)
|
if(!entries_found)
|
||||||
{
|
{
|
||||||
String8 raddbg_data = d_raddbg_data_from_module(scratch.arena, module->handle);
|
Access *access = access_open();
|
||||||
|
D_ModuleInfo *module_info = d_info_from_module(access, module->handle);
|
||||||
|
String8 raddbg_data = module_info->raddbg_data;
|
||||||
U8 split_char = 0;
|
U8 split_char = 0;
|
||||||
String8List raddbg_data_text_parts = str8_split(scratch.arena, raddbg_data, &split_char, 1, 0);
|
String8List raddbg_data_text_parts = str8_split(scratch.arena, raddbg_data, &split_char, 1, 0);
|
||||||
for(String8Node *text_n = raddbg_data_text_parts.first; text_n != 0; text_n = text_n->next)
|
for(String8Node *text_n = raddbg_data_text_parts.first; text_n != 0; text_n = text_n->next)
|
||||||
@@ -5932,6 +6077,7 @@ d_ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
access_close(access);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: add traps for PID-correllated entry points
|
//- rjf: add traps for PID-correllated entry points
|
||||||
@@ -7091,6 +7237,64 @@ d_process_memory_read(D_Handle process, Rng1U64 range, B32 *is_stale_out, void *
|
|||||||
return good;
|
return good;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: TLS Address Artifact Cache Hooks / Lookups
|
||||||
|
|
||||||
|
internal AC_Artifact
|
||||||
|
d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out)
|
||||||
|
{
|
||||||
|
// rjf: unpack key
|
||||||
|
D_Handle thread = {0};
|
||||||
|
D_Handle module = {0};
|
||||||
|
{
|
||||||
|
U64 off = 0;
|
||||||
|
off += str8_deserial_read_struct(key, off, &thread);
|
||||||
|
off += str8_deserial_read_struct(key, off, &module);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: resolve to demon
|
||||||
|
DMN_Handle thread_dmn = d_dmn_from_handle(thread);
|
||||||
|
DMN_Handle module_dmn = d_dmn_from_handle(module);
|
||||||
|
|
||||||
|
// rjf: compute vaddr
|
||||||
|
U64 tls_vaddr = 0;
|
||||||
|
B32 success = 1;
|
||||||
|
if(!dmn_handle_match(thread_dmn, dmn_handle_zero()) &&
|
||||||
|
!dmn_handle_match(module_dmn, dmn_handle_zero()))
|
||||||
|
{
|
||||||
|
success = dmn_thread_get_module_tls_vaddr(thread_dmn, module_dmn, &tls_vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: if not successful -> retry
|
||||||
|
if(!success)
|
||||||
|
{
|
||||||
|
retry_out[0] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: package as artifact
|
||||||
|
AC_Artifact artifact = {0};
|
||||||
|
artifact.u64[0] = tls_vaddr;
|
||||||
|
return artifact;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void d_tls_vaddr_artifact_destroy(AC_Artifact artifact)
|
||||||
|
{
|
||||||
|
// NOTE(rjf): no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_handle, U64 endt_us, B32 *stale_out)
|
||||||
|
{
|
||||||
|
U64 result = 0;
|
||||||
|
Access *access = access_open();
|
||||||
|
D_Handle key_data[] = {thread_handle, module_handle};
|
||||||
|
String8 key = str8((U8 *)&key_data[0], sizeof(key_data));
|
||||||
|
AC_Artifact artifact = ac_artifact_from_key(access, key, d_tls_vaddr_artifact_create, d_tls_vaddr_artifact_destroy, endt_us, .stale_out = stale_out);
|
||||||
|
result = artifact.u64[0];
|
||||||
|
access_close(access);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Call Stack Artifact Cache Hooks / Lookups
|
//~ rjf: Call Stack Artifact Cache Hooks / Lookups
|
||||||
|
|
||||||
@@ -7226,7 +7430,7 @@ d_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U6
|
|||||||
{
|
{
|
||||||
pre_reg_gen = d_reg_gen();
|
pre_reg_gen = d_reg_gen();
|
||||||
pre_mem_gen = d_mem_gen();
|
pre_mem_gen = d_mem_gen();
|
||||||
unwind = d_unwind_from_thread(arena, thread_handle, now_time_us()+5000);
|
unwind = d_unwind_from_thread(arena, thread_handle, 0);
|
||||||
if(!(unwind.flags & D_UnwindFlag_Stale))
|
if(!(unwind.flags & D_UnwindFlag_Stale))
|
||||||
{
|
{
|
||||||
good = 1;
|
good = 1;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ struct D_Unwind
|
|||||||
D_UnwindFlags flags;
|
D_UnwindFlags flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0 // TODO(rjf): @unwind
|
||||||
typedef struct D_FrameUnwindContext D_FrameUnwindContext;
|
typedef struct D_FrameUnwindContext D_FrameUnwindContext;
|
||||||
struct D_FrameUnwindContext
|
struct D_FrameUnwindContext
|
||||||
{
|
{
|
||||||
@@ -57,6 +58,7 @@ struct D_FrameUnwindContext
|
|||||||
DW_CFI_Row *cfi_row;
|
DW_CFI_Row *cfi_row;
|
||||||
U64 ret_addr_reg;
|
U64 ret_addr_reg;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Call Stack Types
|
//~ rjf: Call Stack Types
|
||||||
@@ -171,21 +173,12 @@ struct D_ThreadRegCache
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Module Image Info Cache Types
|
//~ rjf: Module Image Info Cache Types
|
||||||
|
|
||||||
typedef struct D_ModuleImageInfoCacheNode D_ModuleImageInfoCacheNode;
|
typedef struct D_ModuleInfo D_ModuleInfo;
|
||||||
struct D_ModuleImageInfoCacheNode
|
struct D_ModuleInfo
|
||||||
{
|
{
|
||||||
D_ModuleImageInfoCacheNode *next;
|
|
||||||
D_ModuleImageInfoCacheNode *prev;
|
|
||||||
D_Handle module;
|
|
||||||
Arena *arena;
|
|
||||||
PE_IntelPdata *pdatas;
|
|
||||||
U64 pdatas_count;
|
|
||||||
U64 cfi_rebase;
|
|
||||||
String8 dwarf_unwind_data;
|
|
||||||
B32 is_unwind_eh;
|
|
||||||
EH_FrameHdr eh_frame_hdr;
|
|
||||||
EH_PtrCtx eh_ptr_ctx;
|
|
||||||
U64 entry_point_voff;
|
U64 entry_point_voff;
|
||||||
|
UWND_Unwinder unwinder;
|
||||||
|
void *unwind_info;
|
||||||
String8 local_debug_info_path;
|
String8 local_debug_info_path;
|
||||||
String8 local_server_cache_debug_info_path;
|
String8 local_server_cache_debug_info_path;
|
||||||
String8 debug_info_unique_identifier;
|
String8 debug_info_unique_identifier;
|
||||||
@@ -193,27 +186,30 @@ struct D_ModuleImageInfoCacheNode
|
|||||||
String8 raddbg_data;
|
String8 raddbg_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct D_ModuleImageInfoCacheSlot D_ModuleImageInfoCacheSlot;
|
typedef struct D_ModuleInfoCacheNode D_ModuleInfoCacheNode;
|
||||||
struct D_ModuleImageInfoCacheSlot
|
struct D_ModuleInfoCacheNode
|
||||||
{
|
|
||||||
D_ModuleImageInfoCacheNode *first;
|
|
||||||
D_ModuleImageInfoCacheNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D_ModuleImageInfoCacheStripe D_ModuleImageInfoCacheStripe;
|
|
||||||
struct D_ModuleImageInfoCacheStripe
|
|
||||||
{
|
{
|
||||||
|
D_ModuleInfoCacheNode *next;
|
||||||
|
D_ModuleInfoCacheNode *prev;
|
||||||
|
AccessPt access_pt;
|
||||||
|
D_Handle module;
|
||||||
Arena *arena;
|
Arena *arena;
|
||||||
RWMutex rw_mutex;
|
D_ModuleInfo v;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct D_ModuleImageInfoCache D_ModuleImageInfoCache;
|
typedef struct D_ModuleInfoCacheSlot D_ModuleInfoCacheSlot;
|
||||||
struct D_ModuleImageInfoCache
|
struct D_ModuleInfoCacheSlot
|
||||||
|
{
|
||||||
|
D_ModuleInfoCacheNode *first;
|
||||||
|
D_ModuleInfoCacheNode *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct D_ModuleInfoCache D_ModuleInfoCache;
|
||||||
|
struct D_ModuleInfoCache
|
||||||
{
|
{
|
||||||
U64 slots_count;
|
U64 slots_count;
|
||||||
D_ModuleImageInfoCacheSlot *slots;
|
D_ModuleInfoCacheSlot *slots;
|
||||||
U64 stripes_count;
|
StripeArray stripes;
|
||||||
D_ModuleImageInfoCacheStripe *stripes;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -340,7 +336,7 @@ struct D_CtrlState
|
|||||||
|
|
||||||
// rjf: caches
|
// rjf: caches
|
||||||
D_ThreadRegCache thread_reg_cache;
|
D_ThreadRegCache thread_reg_cache;
|
||||||
D_ModuleImageInfoCache module_image_info_cache;
|
D_ModuleInfoCache module_info_cache;
|
||||||
D_DumpCache dump_cache;
|
D_DumpCache dump_cache;
|
||||||
|
|
||||||
// rjf: generations
|
// rjf: generations
|
||||||
@@ -413,6 +409,7 @@ read_only global D_CallStackTreeNode d_call_stack_tree_node_nil =
|
|||||||
&d_call_stack_tree_node_nil,
|
&d_call_stack_tree_node_nil,
|
||||||
};
|
};
|
||||||
thread_static D_EntityCtxLookupAccel *d_entity_ctx_lookup_accel = 0;
|
thread_static D_EntityCtxLookupAccel *d_entity_ctx_lookup_accel = 0;
|
||||||
|
read_only global D_ModuleInfo d_module_info_nil = {0};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Basic Type Functions
|
//~ rjf: Basic Type Functions
|
||||||
@@ -550,10 +547,10 @@ internal B32 d_thread_read_reg_block(D_Handle handle, void *reg_block);
|
|||||||
internal B32 d_thread_write_reg_block(D_Handle thread, void *reg_block);
|
internal B32 d_thread_write_reg_block(D_Handle thread, void *reg_block);
|
||||||
internal U64 d_ip_from_thread(D_Handle handle);
|
internal U64 d_ip_from_thread(D_Handle handle);
|
||||||
internal U64 d_sp_from_thread(D_Handle handle);
|
internal U64 d_sp_from_thread(D_Handle handle);
|
||||||
|
internal B32 d_thread_get_module_tls_vaddr(D_Handle thread, D_Handle module, U64 *vaddr_out);
|
||||||
|
|
||||||
//- rjf: thread register cache reading
|
//- rjf: thread register cache reading
|
||||||
internal void *d_cached_reg_block_from_thread(Arena *arena, D_Handle handle);
|
internal void *d_cached_reg_block_from_thread(Arena *arena, D_Handle handle);
|
||||||
internal U64 d_cached_tls_root_vaddr_from_thread(D_Handle handle);
|
|
||||||
internal U64 d_cached_ip_from_thread(D_Handle handle);
|
internal U64 d_cached_ip_from_thread(D_Handle handle);
|
||||||
internal U64 d_cached_sp_from_thread(D_Handle handle);
|
internal U64 d_cached_sp_from_thread(D_Handle handle);
|
||||||
|
|
||||||
@@ -561,14 +558,17 @@ internal U64 d_cached_sp_from_thread(D_Handle handle);
|
|||||||
//~ rjf: Module Image Info Functions
|
//~ rjf: Module Image Info Functions
|
||||||
|
|
||||||
//- rjf: cache lookups
|
//- rjf: cache lookups
|
||||||
|
#if 0 // TODO(rjf): @unwind
|
||||||
internal PE_IntelPdata *d_intel_pdata_from_module_voff(Arena *arena, D_Handle module_handle, U64 voff);
|
internal PE_IntelPdata *d_intel_pdata_from_module_voff(Arena *arena, D_Handle module_handle, U64 voff);
|
||||||
|
#endif
|
||||||
|
internal D_ModuleInfo *d_info_from_module(Access *access, D_Handle module);
|
||||||
internal U64 d_entry_point_voff_from_module(D_Handle module_handle);
|
internal U64 d_entry_point_voff_from_module(D_Handle module_handle);
|
||||||
internal String8 d_initial_debug_info_path_from_module(Arena *arena, D_Handle module_handle);
|
internal String8 d_initial_debug_info_path_from_module(Arena *arena, D_Handle module_handle);
|
||||||
internal String8 d_raddbg_data_from_module(Arena *arena, D_Handle module_handle);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Unwinding Functions
|
//~ rjf: Unwinding Functions
|
||||||
|
|
||||||
|
#if 0 // TODO(rjf): @unwind
|
||||||
//- rjf: [dwarf]
|
//- rjf: [dwarf]
|
||||||
internal D_UnwindStepResult d_unwind_step_result_from_machine_op_result(MachineOpResult s);
|
internal D_UnwindStepResult d_unwind_step_result_from_machine_op_result(MachineOpResult s);
|
||||||
internal D_UnwindStepResult d_establish_frame_unwind_context__dwarf(Arena *arena, D_Handle process_handle, D_Handle module_handle, Arch arch, void *regs, U64 endt_us, D_FrameUnwindContext *ctx_out);
|
internal D_UnwindStepResult d_establish_frame_unwind_context__dwarf(Arena *arena, D_Handle process_handle, D_Handle module_handle, Arch arch, void *regs, U64 endt_us, D_FrameUnwindContext *ctx_out);
|
||||||
@@ -577,6 +577,7 @@ internal D_UnwindStepResult d_unwind_step__dwarf(D_Handle process_handle, Arch a
|
|||||||
//- rjf: [x64]
|
//- rjf: [x64]
|
||||||
internal U64 *d_unwind_reg_from_pe_gpr_reg__pe_x64(X64_RegBlock *regs, PE_UnwindGprRegX64 gpr_reg);
|
internal U64 *d_unwind_reg_from_pe_gpr_reg__pe_x64(X64_RegBlock *regs, PE_UnwindGprRegX64 gpr_reg);
|
||||||
internal D_UnwindStepResult d_unwind_step__pe_x64(D_Handle process_handle, D_Handle module_handle, U64 module_base_vaddr, X64_RegBlock *regs, U64 endt_us);
|
internal D_UnwindStepResult d_unwind_step__pe_x64(D_Handle process_handle, D_Handle module_handle, U64 module_base_vaddr, X64_RegBlock *regs, U64 endt_us);
|
||||||
|
#endif
|
||||||
|
|
||||||
//- rjf: abstracted full unwind
|
//- rjf: abstracted full unwind
|
||||||
internal D_Unwind d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us);
|
internal D_Unwind d_unwind_from_thread(Arena *arena, D_Handle thread, U64 endt_us);
|
||||||
@@ -673,6 +674,13 @@ internal D_ProcessMemorySlice d_process_memory_slice_from_vaddr_range(Arena *are
|
|||||||
internal B32 d_process_memory_read(D_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us);
|
internal B32 d_process_memory_read(D_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us);
|
||||||
#define d_process_memory_read_struct(process, vaddr, is_stale_out, ptr, endt_us) d_process_memory_read((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us))
|
#define d_process_memory_read_struct(process, vaddr, is_stale_out, ptr, endt_us) d_process_memory_read((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us))
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: TLS Address Artifact Cache Hooks / Lookups
|
||||||
|
|
||||||
|
internal AC_Artifact d_tls_vaddr_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||||
|
internal void d_tls_vaddr_artifact_destroy(AC_Artifact artifact);
|
||||||
|
internal U64 d_cached_tls_vaddr_from_thread_module(D_Handle thread_handle, D_Handle module_handle, U64 endt_us, B32 *stale_out);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Call Stack Artifact Cache Hooks / Lookups
|
//~ rjf: Call Stack Artifact Cache Hooks / Lookups
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ struct DMN_ModuleInfo
|
|||||||
// rjf: unwinding info
|
// rjf: unwinding info
|
||||||
Rng1U64 pe_intel_pdatas_vaddr_range;
|
Rng1U64 pe_intel_pdatas_vaddr_range;
|
||||||
Rng1U64 eh_frame_header_vaddr_range;
|
Rng1U64 eh_frame_header_vaddr_range;
|
||||||
U64 cfi_rebase;
|
|
||||||
|
|
||||||
// rjf: special raddbg data
|
// rjf: special raddbg data
|
||||||
Rng1U64 raddbg_info_voff_range;
|
Rng1U64 raddbg_info_voff_range;
|
||||||
@@ -135,6 +134,9 @@ struct DMN_Event
|
|||||||
|
|
||||||
// rjf: module info
|
// rjf: module info
|
||||||
DMN_ModuleInfo *module_info;
|
DMN_ModuleInfo *module_info;
|
||||||
|
|
||||||
|
// rjf: thread info
|
||||||
|
U64 tls_root_vaddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct DMN_EventNode DMN_EventNode;
|
typedef struct DMN_EventNode DMN_EventNode;
|
||||||
@@ -291,10 +293,9 @@ internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst);
|
|||||||
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
|
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
|
||||||
|
|
||||||
//- rjf: threads
|
//- rjf: threads
|
||||||
internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle);
|
|
||||||
internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle);
|
|
||||||
internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block);
|
internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block);
|
||||||
internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block);
|
internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block);
|
||||||
|
internal B32 dmn_thread_get_module_tls_vaddr(DMN_Handle thread, DMN_Handle module, U64 *vaddr_out);
|
||||||
|
|
||||||
//- rjf: system process listing
|
//- rjf: system process listing
|
||||||
internal void dmn_process_iter_begin(DMN_ProcessIter *iter);
|
internal void dmn_process_iter_begin(DMN_ProcessIter *iter);
|
||||||
|
|||||||
+448
-764
File diff suppressed because it is too large
Load Diff
+54
-1798
File diff suppressed because it is too large
Load Diff
+1338
-16
File diff suppressed because it is too large
Load Diff
@@ -1,62 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table)
|
|
||||||
{
|
|
||||||
B32 is_dwarf_present = 0;
|
|
||||||
for EachIndex(idx, section_count)
|
|
||||||
{
|
|
||||||
COFF_SectionHeader *header = §ion_table[idx];
|
|
||||||
String8 name = coff_name_from_section_header(string_table, header);
|
|
||||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
|
||||||
if(s == DW_Section_Null)
|
|
||||||
{
|
|
||||||
s = dw_section_dwo_kind_from_string(name);
|
|
||||||
}
|
|
||||||
is_dwarf_present = s != DW_Section_Null;
|
|
||||||
if(is_dwarf_present)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return is_dwarf_present;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DW_Raw
|
|
||||||
dw_input_from_coff_section_table(Arena *arena,
|
|
||||||
String8 raw_image,
|
|
||||||
String8 string_table,
|
|
||||||
U64 section_count,
|
|
||||||
COFF_SectionHeader *section_table)
|
|
||||||
{
|
|
||||||
DW_Raw input = {0};
|
|
||||||
B32 sect_status[ArrayCount(input.sec)] = {0};
|
|
||||||
|
|
||||||
for (U64 i = 0; i < section_count; ++i) {
|
|
||||||
COFF_SectionHeader *header = §ion_table[i];
|
|
||||||
Rng1U64 raw_data_range = rng_1u64(header->foff, header->vsize ? header->foff + header->vsize : header->foff + header->fsize);
|
|
||||||
String8 name = coff_name_from_section_header(string_table, header);
|
|
||||||
|
|
||||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
|
||||||
B32 is_dwo = 0;
|
|
||||||
if (s == DW_Section_Null) {
|
|
||||||
s = dw_section_dwo_kind_from_string(name);
|
|
||||||
is_dwo = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s != DW_Section_Null) {
|
|
||||||
if (sect_status[s]) {
|
|
||||||
Assert(!"too many debug sections with identical name, picking first");
|
|
||||||
} else {
|
|
||||||
sect_status[s] = 1;
|
|
||||||
DW_Section *d = &input.sec[s];
|
|
||||||
d->name = push_str8_copy(arena, name);
|
|
||||||
d->data = str8_substr(raw_image, raw_data_range);
|
|
||||||
d->is_dwo = is_dwo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
@@ -1185,7 +1185,7 @@ DW_PRINTER(dw_print_frame)
|
|||||||
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
||||||
DW_DescriptorEntry desc = {0};
|
DW_DescriptorEntry desc = {0};
|
||||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
||||||
if (desc.type == DW_DescriptorEntryType_CIE) {
|
if (desc.type == DW_DescriptorEntryKind_CIE) {
|
||||||
String8 raw_cie = str8_substr(debug_frame, desc.entry_range);
|
String8 raw_cie = str8_substr(debug_frame, desc.entry_range);
|
||||||
U64 restore_pos = arena_pos(scratch.arena);
|
U64 restore_pos = arena_pos(scratch.arena);
|
||||||
DW_CIE *cie = push_array(scratch.arena, DW_CIE, 1);
|
DW_CIE *cie = push_array(scratch.arena, DW_CIE, 1);
|
||||||
@@ -1202,8 +1202,8 @@ DW_PRINTER(dw_print_frame)
|
|||||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
||||||
String8 raw_desc = str8_substr(debug_frame, desc.entry_range);
|
String8 raw_desc = str8_substr(debug_frame, desc.entry_range);
|
||||||
switch (desc.type) {
|
switch (desc.type) {
|
||||||
case DW_DescriptorEntryType_Null: {} break;
|
case DW_DescriptorEntryKind_Null: {} break;
|
||||||
case DW_DescriptorEntryType_CIE: {
|
case DW_DescriptorEntryKind_CIE: {
|
||||||
DW_CIE cie = {0};
|
DW_CIE cie = {0};
|
||||||
if (dw_parse_cie(raw_desc, desc.format, arch, &cie)) {
|
if (dw_parse_cie(raw_desc, desc.format, arch, &cie)) {
|
||||||
String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, cie.format, 0, &cie, dw_decode_ptr_debug_frame, &cie, cie.insts);
|
String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, DW_Ext_All, cie.format, 0, &cie, dw_decode_ptr_debug_frame, &cie, cie.insts);
|
||||||
@@ -1229,7 +1229,7 @@ DW_PRINTER(dw_print_frame)
|
|||||||
dw_printf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min);
|
dw_printf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case DW_DescriptorEntryType_FDE: {
|
case DW_DescriptorEntryKind_FDE: {
|
||||||
DW_DescriptorEntry cie_desc = {0};
|
DW_DescriptorEntry cie_desc = {0};
|
||||||
U64 cie_desc_size = dw_parse_descriptor_entry_header(debug_frame, desc.cie_pointer, &cie_desc);
|
U64 cie_desc_size = dw_parse_descriptor_entry_header(debug_frame, desc.cie_pointer, &cie_desc);
|
||||||
String8 cie_data = str8_substr(debug_frame, cie_desc.entry_range);
|
String8 cie_data = str8_substr(debug_frame, cie_desc.entry_range);
|
||||||
|
|||||||
@@ -0,0 +1,718 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// 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
|
||||||
@@ -1578,111 +1578,3 @@ dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa,
|
|||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal String8
|
|
||||||
dw_encode_expr(Arena *arena, Arch arch, DW_Format format, DW_ExprEnc *encs, U64 encs_count)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
String8List *srl = push_array(scratch.arena, String8List, 1);
|
|
||||||
str8_serial_begin(scratch.arena, srl);
|
|
||||||
|
|
||||||
HashTable *label_map = hash_table_init(scratch.arena, 128);
|
|
||||||
|
|
||||||
struct Fixup { U64 offset; String8 label; struct Fixup *next; };
|
|
||||||
struct Fixup *first_fixup = 0, *last_fixup = 0;
|
|
||||||
|
|
||||||
for EachIndex(i, encs_count) {
|
|
||||||
DW_ExprEnc *e = &encs[i];
|
|
||||||
|
|
||||||
switch (e->type) {
|
|
||||||
case DW_ExprEncType_Null: {} break;
|
|
||||||
case DW_ExprEncType_Op: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->op);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_U8: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->u8);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_U16: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->u16);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_U32: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->u32);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_U64: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->u64);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_S8: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->s8);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_S16: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->s16);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_S32: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->s32);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_S64: {
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &e->s64);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_ULEB128: {
|
|
||||||
str8_serial_push_string(scratch.arena, srl, dw_write_uleb128(scratch.arena, e->u64));
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_SLEB128: {
|
|
||||||
str8_serial_push_string(scratch.arena, srl, dw_write_sleb128(scratch.arena, e->s64));
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_Addr: {
|
|
||||||
U64 addr_size = byte_size_from_arch(arch);
|
|
||||||
Assert(addr_size <= sizeof(e->addr));
|
|
||||||
str8_serial_push_string(scratch.arena, srl, str8((U8 *)&e->addr, addr_size));
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_Block: {
|
|
||||||
Assert(e->block.size <= max_U8);
|
|
||||||
str8_serial_push_u8(scratch.arena, srl, (U8)e->block.size);
|
|
||||||
str8_serial_push_string(scratch.arena, srl, e->block);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_DwarfUInt: {
|
|
||||||
switch (format) {
|
|
||||||
case DW_Format_Null: {} break;
|
|
||||||
case DW_Format_32Bit: { str8_serial_push_u32(scratch.arena, srl, e->u32); } break;
|
|
||||||
case DW_Format_64Bit: { str8_serial_push_u64(scratch.arena, srl, e->u64); } break;
|
|
||||||
default: { InvalidPath; } break;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_Label: {
|
|
||||||
struct Fixup *fixup = push_array(scratch.arena, struct Fixup, 1);
|
|
||||||
fixup->offset = srl->total_size;
|
|
||||||
fixup->label = e->label;
|
|
||||||
SLLQueuePush(first_fixup, last_fixup, fixup);
|
|
||||||
|
|
||||||
S16 delta_placeholder = 0;
|
|
||||||
str8_serial_push_struct(scratch.arena, srl, &delta_placeholder);
|
|
||||||
} break;
|
|
||||||
case DW_ExprEncType_DeclLabel: {
|
|
||||||
hash_table_push_string_u64(scratch.arena, label_map, e->label, srl->total_size);
|
|
||||||
} break;
|
|
||||||
default: { InvalidPath; } break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// finalize expression
|
|
||||||
String8 expr = str8_serial_end(arena, srl);
|
|
||||||
|
|
||||||
// apply fixups
|
|
||||||
for EachNode(fixup, struct Fixup, first_fixup) {
|
|
||||||
U64 label_offset;
|
|
||||||
if (!hash_table_search_string_u64(label_map, fixup->label, &label_offset)) {
|
|
||||||
Assert(0 && "undefined label");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
S64 delta = (S64)label_offset - (S64)fixup->offset;
|
|
||||||
AssertAlways(min_S16 <= delta && delta <= max_S16);
|
|
||||||
|
|
||||||
S16 *delta_ptr = (S16 *)(expr.str + fixup->offset);
|
|
||||||
*delta_ptr = delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -229,8 +229,5 @@ internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprV
|
|||||||
// evaluator
|
// 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);
|
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);
|
||||||
|
|
||||||
// encoder
|
|
||||||
internal String8 dw_encode_expr(Arena *arena, Arch arch, DW_Format format, DW_ExprEnc *encs, U64 encs_count);
|
|
||||||
|
|
||||||
#endif //DWARF_EXPR_H
|
#endif //DWARF_EXPR_H
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,393 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// 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
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal DW_CallFrameInfo
|
|
||||||
dw_call_frame_info_from_data(Arena *arena, Arch arch, U64 rebase, String8 debug_frame)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
// count CIE and FDE entries
|
|
||||||
U64 cie_count = 0, fde_count = 0;
|
|
||||||
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
|
||||||
DW_DescriptorEntry desc = {0};
|
|
||||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
|
||||||
if (desc_size == 0) { break; }
|
|
||||||
if (desc.type == DW_DescriptorEntryType_CIE) {
|
|
||||||
cie_count += 1;
|
|
||||||
} else if (desc.type == DW_DescriptorEntryType_FDE) {
|
|
||||||
fde_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse CIEs and build (offset -> CIE) hash table
|
|
||||||
HashTable *cie_ht = hash_table_init(scratch.arena, (U64)(cie_count * 1.3));
|
|
||||||
DW_CIE *cie = push_array(arena, DW_CIE, cie_count);
|
|
||||||
U64 parse_cie_count = 0;
|
|
||||||
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
|
||||||
DW_DescriptorEntry desc = {0};
|
|
||||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
|
||||||
if (desc_size == 0) { break; }
|
|
||||||
if (desc.type == DW_DescriptorEntryType_CIE) {
|
|
||||||
if (dw_parse_cie(str8_skip(debug_frame, cursor), desc.format, arch, &cie[parse_cie_count])) {
|
|
||||||
hash_table_push_u64_raw(scratch.arena, cie_ht, cursor, &cie[parse_cie_count]);
|
|
||||||
parse_cie_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse FDEs
|
|
||||||
DW_FDE *fde = push_array(arena, DW_FDE, fde_count);
|
|
||||||
U64 parse_fde_count = 0;
|
|
||||||
for (U64 cursor = 0, desc_size; cursor < debug_frame.size; cursor += desc_size) {
|
|
||||||
DW_DescriptorEntry desc = {0};
|
|
||||||
desc_size = dw_parse_descriptor_entry_header(debug_frame, cursor, &desc);
|
|
||||||
if (desc_size == 0) { break; }
|
|
||||||
if (desc.type == DW_DescriptorEntryType_FDE) {
|
|
||||||
DW_CIE *cie = hash_table_search_u64_raw(cie_ht, desc.cie_pointer);
|
|
||||||
if (dw_parse_fde(str8_skip(debug_frame, cursor), desc.format, cie, &fde[parse_fde_count])) {
|
|
||||||
fde[parse_fde_count].pc_range.min += rebase;
|
|
||||||
fde[parse_fde_count].pc_range.max += rebase;
|
|
||||||
parse_fde_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill out result
|
|
||||||
DW_CallFrameInfo cfi = {0};
|
|
||||||
cfi.cie_count = parse_cie_count;
|
|
||||||
cfi.fde_count = parse_fde_count;
|
|
||||||
cfi.cie = cie;
|
|
||||||
cfi.fde = fde;
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return cfi;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_HELP_H
|
|
||||||
#define DWARF_HELP_H
|
|
||||||
|
|
||||||
typedef struct DW_CallFrameInfo
|
|
||||||
{
|
|
||||||
U64 cie_count;
|
|
||||||
U64 fde_count;
|
|
||||||
DW_CIE *cie;
|
|
||||||
DW_FDE *fde;
|
|
||||||
} DW_CallFrameInfo;
|
|
||||||
|
|
||||||
internal DW_CallFrameInfo dw_call_frame_info_from_data(Arena *arena, Arch arch, U64 rebase, String8 debug_frame);
|
|
||||||
|
|
||||||
#endif // DWARF_HELP_H
|
|
||||||
|
|
||||||
+16
-12
@@ -2,17 +2,21 @@
|
|||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#include "dwarf/dwarf.c"
|
#include "dwarf/dwarf.c"
|
||||||
#include "dwarf/dwarf_parse.c"
|
// #include "dwarf/dwarf_parse.c"
|
||||||
#include "dwarf/dwarf_expr.c"
|
// #include "dwarf/dwarf_expr.c"
|
||||||
#include "dwarf/dwarf_coff.c"
|
#include "dwarf/dwarf_expr_2.c"
|
||||||
#include "dwarf/dwarf_elf.c"
|
// #include "dwarf/dwarf_unwind.c"
|
||||||
#include "dwarf/dwarf_unwind.c"
|
// #include "dwarf/dwarf_dump.c"
|
||||||
#include "dwarf/dwarf_dump.c"
|
|
||||||
#include "dwarf/dwarf_help.c"
|
|
||||||
#include "dwarf/dwarf_writer.c"
|
|
||||||
#include "dwarf/dwarf_parse_2.c"
|
#include "dwarf/dwarf_parse_2.c"
|
||||||
#include "dwarf/eh_frame.c"
|
#include "dwarf/dwarf_unwind_2.c"
|
||||||
#include "dwarf/eh_dump.c"
|
#include "dwarf/dwarf_dump_2.c"
|
||||||
#if defined(X64_H)
|
#if defined(COFF_H)
|
||||||
# include "dwarf/x64/dwarf_x64.c"
|
# include "dwarf/dwarf_parse_coff.c"
|
||||||
|
#endif
|
||||||
|
#if defined(ELF_H)
|
||||||
|
# include "dwarf/dwarf_parse_elf.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0 // TODO(rjf): this uses concepts from the old parser
|
||||||
|
# include "dwarf/dwarf_writer.c"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+16
-12
@@ -5,19 +5,23 @@
|
|||||||
#define DWARF_INC_H
|
#define DWARF_INC_H
|
||||||
|
|
||||||
#include "dwarf/dwarf.h"
|
#include "dwarf/dwarf.h"
|
||||||
#include "dwarf/dwarf_parse.h"
|
// #include "dwarf/dwarf_parse.h"
|
||||||
#include "dwarf/dwarf_expr.h"
|
// #include "dwarf/dwarf_expr.h"
|
||||||
#include "dwarf/dwarf_coff.h"
|
#include "dwarf/dwarf_expr_2.h"
|
||||||
#include "dwarf/dwarf_elf.h"
|
// #include "dwarf/dwarf_unwind.h"
|
||||||
#include "dwarf/dwarf_unwind.h"
|
// #include "dwarf/dwarf_dump.h"
|
||||||
#include "dwarf/dwarf_dump.h"
|
|
||||||
#include "dwarf/dwarf_help.h"
|
|
||||||
#include "dwarf/dwarf_writer.h"
|
|
||||||
#include "dwarf/dwarf_parse_2.h"
|
#include "dwarf/dwarf_parse_2.h"
|
||||||
#include "dwarf/eh_frame.h"
|
#include "dwarf/dwarf_unwind_2.h"
|
||||||
#include "dwarf/eh_dump.h"
|
#include "dwarf/dwarf_dump_2.h"
|
||||||
#if defined(X64_H)
|
#if defined(COFF_H)
|
||||||
# include "dwarf/x64/dwarf_x64.h"
|
# include "dwarf/dwarf_parse_coff.h"
|
||||||
|
#endif
|
||||||
|
#if defined(ELF_H)
|
||||||
|
# include "dwarf/dwarf_parse_elf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0 // TODO(rjf): this uses concepts from the old parser
|
||||||
|
# include "dwarf/dwarf_writer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // DWARF_INC_H
|
#endif // DWARF_INC_H
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
--- DWARF NOTES ---------------------------------------------------------------
|
|
||||||
|
|
||||||
DWARF V4 Spec: http://www.dwarfstd.org/doc/DWARF4.pdf
|
|
||||||
DWARF V5 Spec: http://www.dwarfstd.org/doc/DWARF5.pdf
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
$ (2021/04/30) On .debug_pubtypes, .debug_pubnames, and .debug_names:
|
|
||||||
|
|
||||||
.debug_pubtypes and .debug_pubnames are tables that map from a string (the name
|
|
||||||
of a type or function respectively) to an offset into .debug_info, which is the
|
|
||||||
offset of the Debug Information Entry (DIE, in DWARF terminology) of the info
|
|
||||||
associated with the string. THESE TWO SECTIONS ARE OPTIONAL. They don't show up
|
|
||||||
in every DWARF-holding file, and so they cannot be relied upon as acceleration
|
|
||||||
structures. But we're going to support parsing them, to make things a bit nicer
|
|
||||||
in cases where they are present. DWARF doesn't have much in the way of acceler-
|
|
||||||
ation structures built in, so our rationale is that we should take anything we
|
|
||||||
can get to make the format a bit more in some subset of the possible cases.
|
|
||||||
|
|
||||||
.debug_names is a DWARF V5 section that is intended to replace .debug_pubtypes
|
|
||||||
and .debug_pubnames. However, even in cases when DWARF V5 is produced at the
|
|
||||||
time of writing this, we have not found .debug_names sections being produced.
|
|
||||||
We did not exhaustively test all compilers and configurations, but it seems
|
|
||||||
that it is not well-supported at all by major compilers, and there's a very low
|
|
||||||
probability that a user will have that section, so our current thinking is
|
|
||||||
that there's no point in supporting it right now.
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
$ (2021/04/30) On producing DWARF V5 with Clang:
|
|
||||||
|
|
||||||
https://lists.llvm.org/pipermail/llvm-dev/2018-August/125068.html
|
|
||||||
|
|
||||||
By default it looks like (at the time of writing this) that Clang, by default,
|
|
||||||
will produce DWARF V4. To produce DWARF V5, however, you can use the -gdwarf-5
|
|
||||||
option. Even when that option is used, it seems that some features of V5 are
|
|
||||||
not used (for example, .debug_names).
|
|
||||||
|
|
||||||
The above link also says that this will produce .debug_names, but it doesn't as
|
|
||||||
of Clang 10.
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
+3
-11
@@ -53,18 +53,14 @@ str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out)
|
|||||||
{
|
{
|
||||||
U8 byte = 0;
|
U8 byte = 0;
|
||||||
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
|
U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte);
|
||||||
|
|
||||||
if(bytes_read != sizeof(byte))
|
if(bytes_read != sizeof(byte))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
U8 val = byte & 0x7fu;
|
U8 val = byte & 0x7fu;
|
||||||
value |= ((U64)val) << shift;
|
value |= ((U64)val) << shift;
|
||||||
|
|
||||||
cursor += bytes_read;
|
cursor += bytes_read;
|
||||||
shift += 7u;
|
shift += 7u;
|
||||||
|
|
||||||
if((byte & 0x80u) == 0)
|
if((byte & 0x80u) == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -92,13 +88,10 @@ str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out)
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
U8 val = byte & 0x7fu;
|
U8 val = byte & 0x7fu;
|
||||||
value |= ((U64)val) << shift;
|
value |= ((U64)val) << shift;
|
||||||
|
|
||||||
cursor += bytes_read;
|
cursor += bytes_read;
|
||||||
shift += 7u;
|
shift += 7u;
|
||||||
|
|
||||||
if((byte & 0x80u) == 0)
|
if((byte & 0x80u) == 0)
|
||||||
{
|
{
|
||||||
if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0)
|
if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0)
|
||||||
@@ -2912,7 +2905,7 @@ dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc
|
|||||||
|
|
||||||
U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64;
|
U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64;
|
||||||
desc_out->format = format;
|
desc_out->format = format;
|
||||||
desc_out->type = (id == id_type) ? DW_DescriptorEntryType_CIE : DW_DescriptorEntryType_FDE;
|
desc_out->type = (id == id_type) ? DW_DescriptorEntryKind_CIE : DW_DescriptorEntryKind_FDE;
|
||||||
desc_out->entry_range = entry_range;
|
desc_out->entry_range = entry_range;
|
||||||
desc_out->cie_pointer = id;
|
desc_out->cie_pointer = id;
|
||||||
desc_out->cie_pointer_off = length_size;
|
desc_out->cie_pointer_off = length_size;
|
||||||
@@ -2952,7 +2945,6 @@ dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out)
|
|||||||
TryRead(str8_deserial_read_sleb128(data, cursor, &data_align_factor), cursor, exit);
|
TryRead(str8_deserial_read_sleb128(data, cursor, &data_align_factor), cursor, exit);
|
||||||
|
|
||||||
U64 ret_addr_reg = 0;
|
U64 ret_addr_reg = 0;
|
||||||
U64 ret_addr_reg_size = 0;
|
|
||||||
if (version == DW_Version_1) { TryRead(str8_deserial_read(data, cursor, &ret_addr_reg, sizeof(U8), sizeof(U8)), cursor, exit); }
|
if (version == DW_Version_1) { TryRead(str8_deserial_read(data, cursor, &ret_addr_reg, sizeof(U8), sizeof(U8)), cursor, exit); }
|
||||||
else { TryRead(str8_deserial_read_uleb128(data, cursor, &ret_addr_reg), cursor, exit); }
|
else { TryRead(str8_deserial_read_uleb128(data, cursor, &ret_addr_reg), cursor, exit); }
|
||||||
|
|
||||||
@@ -3012,14 +3004,14 @@ dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *f
|
|||||||
B32 is_parsed = 0;
|
B32 is_parsed = 0;
|
||||||
DW_DescriptorEntry fde_desc = {0};
|
DW_DescriptorEntry fde_desc = {0};
|
||||||
dw_parse_descriptor_entry_header(data, fde_offset, &fde_desc);
|
dw_parse_descriptor_entry_header(data, fde_offset, &fde_desc);
|
||||||
if (fde_desc.type == DW_DescriptorEntryType_FDE) {
|
if (fde_desc.type == DW_DescriptorEntryKind_FDE) {
|
||||||
U64 cie_pointer_off = fde_desc.format == DW_Format_32Bit ? 4 : 12;
|
U64 cie_pointer_off = fde_desc.format == DW_Format_32Bit ? 4 : 12;
|
||||||
U64 cie_pointer = 0;
|
U64 cie_pointer = 0;
|
||||||
U64 cie_pointer_size = str8_deserial_read_dwarf_uint(data, fde_offset + cie_pointer_off, fde_desc.format, &cie_pointer);
|
U64 cie_pointer_size = str8_deserial_read_dwarf_uint(data, fde_offset + cie_pointer_off, fde_desc.format, &cie_pointer);
|
||||||
if (cie_pointer_size) {
|
if (cie_pointer_size) {
|
||||||
DW_DescriptorEntry cie_desc = {0};
|
DW_DescriptorEntry cie_desc = {0};
|
||||||
dw_parse_descriptor_entry_header(data, cie_pointer, &cie_desc);
|
dw_parse_descriptor_entry_header(data, cie_pointer, &cie_desc);
|
||||||
if (cie_desc.type == DW_DescriptorEntryType_CIE) {
|
if (cie_desc.type == DW_DescriptorEntryKind_CIE) {
|
||||||
if (dw_parse_cie(str8_substr(data, cie_desc.entry_range), cie_desc.format, arch, cie_out)) {
|
if (dw_parse_cie(str8_substr(data, cie_desc.entry_range), cie_desc.format, arch, cie_out)) {
|
||||||
if (dw_parse_fde(str8_substr(data, fde_desc.entry_range), fde_desc.format, cie_out, fde_out)) {
|
if (dw_parse_fde(str8_substr(data, fde_desc.entry_range), fde_desc.format, cie_out, fde_out)) {
|
||||||
is_parsed = 1;
|
is_parsed = 1;
|
||||||
|
|||||||
@@ -335,22 +335,6 @@ typedef struct DW_Expr
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// .debug_frame
|
// .debug_frame
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_DescriptorEntryType_Null,
|
|
||||||
DW_DescriptorEntryType_CIE,
|
|
||||||
DW_DescriptorEntryType_FDE
|
|
||||||
} DW_DescriptorEntryType;
|
|
||||||
|
|
||||||
typedef struct DW_DescriptorEntry
|
|
||||||
{
|
|
||||||
DW_DescriptorEntryType type;
|
|
||||||
DW_Format format;
|
|
||||||
Rng1U64 entry_range;
|
|
||||||
U64 cie_pointer_off;
|
|
||||||
U64 cie_pointer;
|
|
||||||
} DW_DescriptorEntry;
|
|
||||||
|
|
||||||
typedef struct DW_CIE
|
typedef struct DW_CIE
|
||||||
{
|
{
|
||||||
String8 insts;
|
String8 insts;
|
||||||
@@ -418,8 +402,6 @@ internal U64 dw_hash_from_string(String8 string);
|
|||||||
|
|
||||||
internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_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_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out);
|
||||||
internal U64 str8_deserial_read_uleb128 (String8 string, U64 off, U64 *value_out);
|
|
||||||
internal U64 str8_deserial_read_sleb128 (String8 string, U64 off, S64 *value_out);
|
|
||||||
internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_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 U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out);
|
||||||
|
|
||||||
|
|||||||
+611
-122
File diff suppressed because it is too large
Load Diff
+172
-7
@@ -4,6 +4,23 @@
|
|||||||
#ifndef DWARF_PARSE_2_H
|
#ifndef DWARF_PARSE_2_H
|
||||||
#define 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
|
//~ rjf: Unit Headers
|
||||||
|
|
||||||
@@ -21,6 +38,37 @@ struct DW2_UnitHeader
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Abbreviation Map (ID -> .debug_abbrev Offset)
|
//~ 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;
|
typedef struct DW2_AbbrevMapNode DW2_AbbrevMapNode;
|
||||||
struct DW2_AbbrevMapNode
|
struct DW2_AbbrevMapNode
|
||||||
{
|
{
|
||||||
@@ -36,6 +84,14 @@ struct DW2_AbbrevMap
|
|||||||
U64 slots_count;
|
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)
|
//~ rjf: Offset Tables (.debug_str_offsets, .debug_rnglists)
|
||||||
|
|
||||||
@@ -51,18 +107,55 @@ struct DW2_OffsetTable
|
|||||||
void *entries;
|
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
|
//~ rjf: Parsing Context Bundle
|
||||||
|
|
||||||
typedef struct DW2_ParseCtx DW2_ParseCtx;
|
typedef struct DW2_ParseCtx DW2_ParseCtx;
|
||||||
struct DW2_ParseCtx
|
struct DW2_ParseCtx
|
||||||
{
|
{
|
||||||
DW_Raw *raw;
|
|
||||||
// NOTE(rjf): all subsequent fields optional - top-level code fills out whatever
|
|
||||||
// it can from context.
|
|
||||||
DW_Version version;
|
DW_Version version;
|
||||||
DW_Format format;
|
DW_Format format;
|
||||||
DW_Ext ext;
|
DW_ExtFlags exts;
|
||||||
U64 addr_size;
|
U64 addr_size;
|
||||||
U64 unit_base_addr;
|
U64 unit_base_addr;
|
||||||
U64 unit_base_info_off;
|
U64 unit_base_info_off;
|
||||||
@@ -73,6 +166,7 @@ struct DW2_ParseCtx
|
|||||||
DW2_OffsetTable *loclists_table;
|
DW2_OffsetTable *loclists_table;
|
||||||
String8 unit_dir;
|
String8 unit_dir;
|
||||||
String8 unit_file;
|
String8 unit_file;
|
||||||
|
DW_Language language;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -229,6 +323,57 @@ struct DW2_LocList
|
|||||||
U64 count;
|
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
|
//~ rjf: Globals
|
||||||
|
|
||||||
@@ -239,6 +384,7 @@ global read_only DW2_Attrib dw2_attrib_nil = {0};
|
|||||||
|
|
||||||
internal U64 dw2_read_initial_length(String8 data, U64 off, U64 *out, DW_Format *fmt_out);
|
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 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)
|
//~ rjf: Unit Range Set Parsing (Top-Level .debug_info, .debug_aranges)
|
||||||
@@ -253,30 +399,41 @@ internal U64 dw2_read_unit_header(String8 data, U64 off, DW2_UnitHeader *out);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Abbreviation Map Parsing
|
//~ 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_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
|
//~ rjf: Form Value Parsing
|
||||||
|
|
||||||
internal U64 dw2_read_form_val(DW2_ParseCtx *ctx, String8 data, U64 off, DW_FormKind form_kind, U64 implicit_const, DW2_FormVal *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);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ 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
|
//~ rjf: Tag Parsing
|
||||||
|
|
||||||
internal U64 dw2_read_tag(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_Tag *tag_out);
|
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 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 U64 dw2_reference_info_off_from_form_val(DW2_ParseCtx *ctx, DW2_FormVal *v);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Line Table Parsing
|
//~ rjf: Line Table Parsing
|
||||||
|
|
||||||
internal U64 dw2_read_line_table_header(Arena *arena, DW2_ParseCtx *ctx, String8 data, U64 off, DW2_LineTableHeader *out);
|
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)
|
//~ rjf: Offset Table Parsing (.debug_str_offsets, .debug_rnglists)
|
||||||
|
|
||||||
internal U64 dw2_read_offset_table(String8 data, U64 off, DW2_OffsetTable *out);
|
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 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)
|
//~ rjf: Range List Parsing (.debug_rnglists)
|
||||||
@@ -288,4 +445,12 @@ internal Rng1U64List dw2_rnglist_from_form_val(Arena *arena, DW2_ParseCtx *ctx,
|
|||||||
|
|
||||||
internal DW2_LocList dw2_loclist_from_form_val(Arena *arena, DW2_ParseCtx *ctx, DW_Raw *raw, DW2_FormVal form_val);
|
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
|
#endif // DWARF_PARSE_2_H
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table)
|
||||||
|
{
|
||||||
|
B32 is_dwarf_present = 0;
|
||||||
|
for EachIndex(idx, section_count)
|
||||||
|
{
|
||||||
|
COFF_SectionHeader *header = §ion_table[idx];
|
||||||
|
String8 name = coff_name_from_section_header(string_table, header);
|
||||||
|
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||||
|
is_dwarf_present = s != DW_SectionKind_Null;
|
||||||
|
if(is_dwarf_present)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return is_dwarf_present;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DW_Raw
|
||||||
|
dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table)
|
||||||
|
{
|
||||||
|
DW_Raw input = {0};
|
||||||
|
B32 sect_status[ArrayCount(input.sec)] = {0};
|
||||||
|
for EachIndex(idx, section_count)
|
||||||
|
{
|
||||||
|
COFF_SectionHeader *header = §ion_table[idx];
|
||||||
|
Rng1U64 raw_data_range = rng_1u64(header->foff, header->vsize ? header->foff + header->vsize : header->foff + header->fsize);
|
||||||
|
String8 name = coff_name_from_section_header(string_table, header);
|
||||||
|
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||||
|
if(s != DW_SectionKind_Null)
|
||||||
|
{
|
||||||
|
if(!sect_status[s])
|
||||||
|
{
|
||||||
|
sect_status[s] = 1;
|
||||||
|
DW_Section *d = &input.sec[s];
|
||||||
|
d->name = push_str8_copy(arena, name);
|
||||||
|
d->data = str8_substr(raw_image, raw_data_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef DWARF_COFF_H
|
#ifndef DWARF_PARSE_COFF_H
|
||||||
#define DWARF_COFF_H
|
#define DWARF_PARSE_COFF_H
|
||||||
|
|
||||||
internal B32 dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
internal B32 dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
||||||
internal DW_Raw dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
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_COFF_H
|
#endif // DWARF_PARSE_COFF_H
|
||||||
|
|
||||||
@@ -11,11 +11,7 @@ dw_is_dwarf_present_from_elf_bin(String8 data, ELF_Bin *bin)
|
|||||||
if(shdr->sh_type != ELF_ShType_ProgBits) { continue; }
|
if(shdr->sh_type != ELF_ShType_ProgBits) { continue; }
|
||||||
String8 name = elf_name_from_shdr64(data, bin, shdr);
|
String8 name = elf_name_from_shdr64(data, bin, shdr);
|
||||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||||
if(s == DW_Section_Null)
|
is_dwarf_present = (s != DW_SectionKind_Null);
|
||||||
{
|
|
||||||
s = dw_section_dwo_kind_from_string(name);
|
|
||||||
}
|
|
||||||
is_dwarf_present = (s != DW_Section_Null);
|
|
||||||
if(is_dwarf_present)
|
if(is_dwarf_present)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -28,7 +24,7 @@ dw_is_dwarf_present_from_elf_bin(String8 data, ELF_Bin *bin)
|
|||||||
#include "third_party/sinfl/sinfl.h"
|
#include "third_party/sinfl/sinfl.h"
|
||||||
|
|
||||||
internal DW_Raw
|
internal DW_Raw
|
||||||
dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
dw_raw_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
||||||
{
|
{
|
||||||
DW_Raw result = {0};
|
DW_Raw result = {0};
|
||||||
B32 is_section_present[ArrayCount(result.sec)] = {0};
|
B32 is_section_present[ArrayCount(result.sec)] = {0};
|
||||||
@@ -41,14 +37,8 @@ dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
|||||||
String8 section_name = elf_name_from_shdr64(data, bin, shdr);
|
String8 section_name = elf_name_from_shdr64(data, bin, shdr);
|
||||||
DW_SectionKind section_kind = dw_section_kind_from_string(section_name);
|
DW_SectionKind section_kind = dw_section_kind_from_string(section_name);
|
||||||
String8 section_data__maybe_compressed = str8_substr(data, r1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size));
|
String8 section_data__maybe_compressed = str8_substr(data, r1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size));
|
||||||
B32 is_dwo = 0;
|
|
||||||
if(section_kind == DW_Section_Null)
|
|
||||||
{
|
|
||||||
section_kind = dw_section_dwo_kind_from_string(section_name);
|
|
||||||
is_dwo = (section_kind != DW_Section_Null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(section_kind == DW_Section_Null) { continue; } // skip unknown sections
|
if(section_kind == DW_SectionKind_Null) { continue; } // skip unknown sections
|
||||||
if(is_section_present[section_kind]) { continue; } // skip duplicate sections
|
if(is_section_present[section_kind]) { continue; } // skip duplicate sections
|
||||||
|
|
||||||
//- rjf: decompress section data if needed
|
//- rjf: decompress section data if needed
|
||||||
@@ -108,7 +98,6 @@ dw_input_from_elf_bin(Arena *arena, String8 data, ELF_Bin *bin)
|
|||||||
DW_Section *d = &result.sec[section_kind];
|
DW_Section *d = &result.sec[section_kind];
|
||||||
d->name = push_str8_copy(arena, section_name);
|
d->name = push_str8_copy(arena, section_name);
|
||||||
d->data = section_data__uncompressed;
|
d->data = section_data__uncompressed;
|
||||||
d->is_dwo = is_dwo;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef DWARF_ELF_H
|
#ifndef DWARF_PARSE_ELF_H
|
||||||
#define DWARF_ELF_H
|
#define DWARF_PARSE_ELF_H
|
||||||
|
|
||||||
internal B32 dw_is_dwarf_present_from_elf_bin(String8 raw_image, ELF_Bin *bin);
|
internal B32 dw_is_dwarf_present_from_elf_bin(String8 raw_image, ELF_Bin *bin);
|
||||||
internal DW_Raw dw_input_from_elf_bin(Arena *arena, String8 raw_image, ELF_Bin *bin);
|
internal DW_Raw dw_raw_from_elf_bin(Arena *arena, String8 raw_image, ELF_Bin *bin);
|
||||||
|
|
||||||
#endif // DWARF_ELF_H
|
#endif // DWARF_PARSE_ELF_H
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// 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
|
||||||
+231
-1
@@ -97,6 +97,119 @@ dw_writer_tag_chunk_list_push(Arena *arena, DW_WriterTagChunkList *list, U64 cap
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
dw_write_to_buffer_uleb128(U8 buffer[10], U64 v)
|
||||||
|
{
|
||||||
|
U64 buffer_size = 0;
|
||||||
|
U64 value = v;
|
||||||
|
do {
|
||||||
|
U8 byte = value & 0x7f;
|
||||||
|
value >>= 7;
|
||||||
|
if (value != 0) {
|
||||||
|
byte |= 0x80;
|
||||||
|
}
|
||||||
|
Assert(buffer_size < 10);
|
||||||
|
buffer[buffer_size++] = byte;
|
||||||
|
} while (value > 0);
|
||||||
|
return buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
dw_write_to_buffer_sleb128(U8 buffer[10], U64 v)
|
||||||
|
{
|
||||||
|
U64 buffer_size = 0;
|
||||||
|
for (S64 value = v, more = 1; more != 0; ) {
|
||||||
|
U8 byte = value & 0x7f;
|
||||||
|
value >>= 7;
|
||||||
|
U8 sign_bit = byte & 0x40;
|
||||||
|
if ((value == 0 && sign_bit == 0) || (value == -1 && sign_bit != 0)) {
|
||||||
|
more = 0;
|
||||||
|
} else {
|
||||||
|
byte |= 0x80;
|
||||||
|
}
|
||||||
|
Assert(buffer_size < 10);
|
||||||
|
buffer[buffer_size++] = byte;
|
||||||
|
}
|
||||||
|
return buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
dw_write_uleb128(Arena *arena, U64 v)
|
||||||
|
{
|
||||||
|
U8 buffer[10];
|
||||||
|
U64 buffer_size = dw_write_to_buffer_uleb128(buffer, v);
|
||||||
|
return str8_copy(arena, str8(buffer, buffer_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
dw_write_sleb128(Arena *arena, S64 v)
|
||||||
|
{
|
||||||
|
U8 buffer[10];
|
||||||
|
U64 buffer_size = dw_write_to_buffer_sleb128(buffer, v);
|
||||||
|
return str8_copy(arena, str8(buffer, buffer_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
dw_size_from_uleb128(U64 v)
|
||||||
|
{
|
||||||
|
U8 buffer[10];
|
||||||
|
return dw_write_to_buffer_uleb128(buffer, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
dw_size_from_sleb128(S64 v)
|
||||||
|
{
|
||||||
|
U8 buffer[10];
|
||||||
|
return dw_write_to_buffer_sleb128(buffer, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
dw_serial_push_length(Arena *arena, String8List *srl, DW_Format format, U64 length)
|
||||||
|
{
|
||||||
|
void *result;
|
||||||
|
if (format == DW_Format_64Bit) {
|
||||||
|
U8 buffer[sizeof(U32) + sizeof(U64)];
|
||||||
|
MemorySet(&buffer[0], 0xff, sizeof(U32));
|
||||||
|
MemoryCopy(buffer + sizeof(U32), &length, sizeof(length));
|
||||||
|
result = str8_serial_push_string(arena, srl, str8_array_fixed(buffer));
|
||||||
|
} else {
|
||||||
|
result = str8_serial_push_string(arena, srl, str8((U8 *)&length, sizeof(U32)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
dw_serial_push_uint(Arena *arena, String8List *srl, DW_Format format, U64 v)
|
||||||
|
{
|
||||||
|
String8 uint;
|
||||||
|
if (format == DW_Format_64Bit) {
|
||||||
|
U64 *ptr = push_array(arena, U64, 1);
|
||||||
|
*ptr = v;
|
||||||
|
uint = str8((U8 *)ptr, sizeof(*ptr));
|
||||||
|
} else {
|
||||||
|
U32 *ptr = push_array(arena, U32, 1);
|
||||||
|
*ptr = safe_cast_u32(v);
|
||||||
|
uint = str8((U8 *)ptr, sizeof(*ptr));
|
||||||
|
}
|
||||||
|
return str8_serial_push_string(arena, srl, uint);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
dw_serial_push_uleb128(Arena *arena, String8List *srl, U64 v)
|
||||||
|
{
|
||||||
|
U8 buffer[10];
|
||||||
|
U64 buffer_size = dw_write_to_buffer_uleb128(buffer, v);
|
||||||
|
return str8_serial_push_string(arena, srl, str8(buffer, buffer_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
dw_serial_push_sleb128(Arena *arena, String8List *srl, S64 v)
|
||||||
|
{
|
||||||
|
U8 buffer[10];
|
||||||
|
U64 buffer_size = dw_write_to_buffer_sleb128(buffer, v);
|
||||||
|
return str8_serial_push_string(arena, srl, str8(buffer, buffer_size));
|
||||||
|
}
|
||||||
|
|
||||||
internal DW_Writer *
|
internal DW_Writer *
|
||||||
dw_writer_begin(DW_Format format, DW_Version version, DW_CompUnitKind cu_kind, Arch arch)
|
dw_writer_begin(DW_Format format, DW_Version version, DW_CompUnitKind cu_kind, Arch arch)
|
||||||
{
|
{
|
||||||
@@ -1195,7 +1308,18 @@ dw_writer_emit(DW_Writer *writer)
|
|||||||
str8_serial_push_struct(writer->arena, srl, &writer->line.opcode_base);
|
str8_serial_push_struct(writer->arena, srl, &writer->line.opcode_base);
|
||||||
// (12) standard_opcode_lengths
|
// (12) standard_opcode_lengths
|
||||||
U8 *std_op_lens = push_array(writer->arena, U8, writer->line.opcode_base - 1);
|
U8 *std_op_lens = push_array(writer->arena, U8, writer->line.opcode_base - 1);
|
||||||
for (U64 i = 1; i < writer->line.opcode_base; i += 1) { std_op_lens[i-1] = dw_length_from_std_opcode(i); }
|
for (U64 i = 1; i < writer->line.opcode_base; i += 1)
|
||||||
|
{
|
||||||
|
U64 len = 0;
|
||||||
|
switch(i)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
#define X(name, code, len_) case DW_StdOpcode_##name:{len = (len_);}break;
|
||||||
|
DW_StdOpcode_XList
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
std_op_lens[i-1] = len;
|
||||||
|
}
|
||||||
str8_serial_push_string(writer->arena, srl, str8(std_op_lens, writer->line.opcode_base - 1));
|
str8_serial_push_string(writer->arena, srl, str8(std_op_lens, writer->line.opcode_base - 1));
|
||||||
// directory table
|
// directory table
|
||||||
str8_list_concat_in_place(srl, &dir_table_srl);
|
str8_list_concat_in_place(srl, &dir_table_srl);
|
||||||
@@ -1277,3 +1401,109 @@ dw_writer_emit_to_obj(DW_Writer *writer, OBJ *obj)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
dw_encode_expr(Arena *arena, Arch arch, DW_Format format, DW_ExprEnc *encs, U64 encs_count)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(&arena, 1);
|
||||||
|
|
||||||
|
String8List *srl = push_array(scratch.arena, String8List, 1);
|
||||||
|
str8_serial_begin(scratch.arena, srl);
|
||||||
|
|
||||||
|
HashTable *label_map = hash_table_init(scratch.arena, 128);
|
||||||
|
|
||||||
|
struct Fixup { U64 offset; String8 label; struct Fixup *next; };
|
||||||
|
struct Fixup *first_fixup = 0, *last_fixup = 0;
|
||||||
|
|
||||||
|
for EachIndex(i, encs_count) {
|
||||||
|
DW_ExprEnc *e = &encs[i];
|
||||||
|
|
||||||
|
switch (e->type) {
|
||||||
|
case DW_ExprEncType_Null: {} break;
|
||||||
|
case DW_ExprEncType_Op: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->op);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_U8: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->u8);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_U16: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->u16);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_U32: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->u32);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_U64: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->u64);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_S8: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->s8);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_S16: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->s16);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_S32: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->s32);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_S64: {
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &e->s64);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_ULEB128: {
|
||||||
|
str8_serial_push_string(scratch.arena, srl, dw_write_uleb128(scratch.arena, e->u64));
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_SLEB128: {
|
||||||
|
str8_serial_push_string(scratch.arena, srl, dw_write_sleb128(scratch.arena, e->s64));
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_Addr: {
|
||||||
|
U64 addr_size = byte_size_from_arch(arch);
|
||||||
|
Assert(addr_size <= sizeof(e->addr));
|
||||||
|
str8_serial_push_string(scratch.arena, srl, str8((U8 *)&e->addr, addr_size));
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_Block: {
|
||||||
|
Assert(e->block.size <= max_U8);
|
||||||
|
str8_serial_push_u8(scratch.arena, srl, (U8)e->block.size);
|
||||||
|
str8_serial_push_string(scratch.arena, srl, e->block);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_DwarfUInt: {
|
||||||
|
switch (format) {
|
||||||
|
case DW_Format_Null: {} break;
|
||||||
|
case DW_Format_32Bit: { str8_serial_push_u32(scratch.arena, srl, e->u32); } break;
|
||||||
|
case DW_Format_64Bit: { str8_serial_push_u64(scratch.arena, srl, e->u64); } break;
|
||||||
|
default: { InvalidPath; } break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_Label: {
|
||||||
|
struct Fixup *fixup = push_array(scratch.arena, struct Fixup, 1);
|
||||||
|
fixup->offset = srl->total_size;
|
||||||
|
fixup->label = e->label;
|
||||||
|
SLLQueuePush(first_fixup, last_fixup, fixup);
|
||||||
|
|
||||||
|
S16 delta_placeholder = 0;
|
||||||
|
str8_serial_push_struct(scratch.arena, srl, &delta_placeholder);
|
||||||
|
} break;
|
||||||
|
case DW_ExprEncType_DeclLabel: {
|
||||||
|
hash_table_push_string_u64(scratch.arena, label_map, e->label, srl->total_size);
|
||||||
|
} break;
|
||||||
|
default: { InvalidPath; } break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finalize expression
|
||||||
|
String8 expr = str8_serial_end(arena, srl);
|
||||||
|
|
||||||
|
// apply fixups
|
||||||
|
for EachNode(fixup, struct Fixup, first_fixup) {
|
||||||
|
U64 label_offset;
|
||||||
|
if (!hash_table_search_string_u64(label_map, fixup->label, &label_offset)) {
|
||||||
|
Assert(0 && "undefined label");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
S64 delta = (S64)label_offset - (S64)fixup->offset;
|
||||||
|
AssertAlways(min_S16 <= delta && delta <= max_S16);
|
||||||
|
|
||||||
|
S16 *delta_ptr = (S16 *)(expr.str + fixup->offset);
|
||||||
|
*delta_ptr = delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|||||||
@@ -245,6 +245,23 @@ typedef struct DW_Writer
|
|||||||
DW_WriterTagChunkList tag_chunk_list;
|
DW_WriterTagChunkList tag_chunk_list;
|
||||||
} DW_Writer;
|
} DW_Writer;
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Serializers
|
||||||
|
|
||||||
|
internal U64 dw_write_to_buffer_uleb128(U8 buffer[10], U64 v);
|
||||||
|
internal U64 dw_write_to_buffer_sleb128(U8 buffer[10], U64 v);
|
||||||
|
|
||||||
|
internal String8 dw_write_uleb128(Arena *arena, U64 v);
|
||||||
|
internal String8 dw_write_sleb128(Arena *arena, S64 v);
|
||||||
|
internal U64 dw_size_from_uleb128(U64 v);
|
||||||
|
internal U64 dw_size_from_sleb128(S64 v);
|
||||||
|
|
||||||
|
internal void * dw_serial_push_length(Arena *arena, String8List *srl, DW_Format format, U64 length);
|
||||||
|
internal void * dw_serial_push_uint(Arena *arena, String8List *srl, DW_Format format, U64 v);
|
||||||
|
internal void * dw_serial_push_uleb128(Arena *arena, String8List *srl, U64 v);
|
||||||
|
internal void * dw_serial_push_sleb128(Arena *arena, String8List *srl, S64 v);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Writer
|
// Writer
|
||||||
|
|
||||||
@@ -334,5 +351,8 @@ internal DW_IntEnc dw_int_enc_from_uint(U64 v);
|
|||||||
internal U64 dw_size_from_sint(S64 v);
|
internal U64 dw_size_from_sint(S64 v);
|
||||||
internal U64 dw_size_from_uint(U64 v);
|
internal U64 dw_size_from_uint(U64 v);
|
||||||
|
|
||||||
|
// encoder
|
||||||
|
internal String8 dw_encode_expr(Arena *arena, Arch arch, DW_Format format, DW_ExprEnc *encs, U64 encs_count);
|
||||||
|
|
||||||
#endif // DWARF_WRITER_H
|
#endif // DWARF_WRITER_H
|
||||||
|
|
||||||
|
|||||||
@@ -1,141 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal String8List
|
|
||||||
eh_dump_list_from_data(Arena *arena, Arch arch, U64 eh_frame_hdr_vaddr, U64 eh_frame_vaddr, String8 eh_frame_hdr, String8 eh_frame, EH_DumpSubsetFlags subset_flags)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List strings = {0};
|
|
||||||
#define dumpf(...) str8_list_pushf(arena, &strings, __VA_ARGS__)
|
|
||||||
|
|
||||||
EH_PtrCtx ptr_ctx = { .data_vaddr = eh_frame_hdr_vaddr };
|
|
||||||
EH_FrameHdr hdr = eh_parse_frame_hdr(eh_frame_hdr, byte_size_from_arch(arch), &ptr_ctx);
|
|
||||||
DW_Ext ext = DW_Ext_All;
|
|
||||||
|
|
||||||
if (subset_flags & EH_DumpSubsetFlag_EhFrameHdr) {
|
|
||||||
dumpf("eh_frame_hdr:\n");
|
|
||||||
dumpf("{\n");
|
|
||||||
dumpf(" version: %u\n", hdr.version);
|
|
||||||
dumpf(" eh_frame_ptr_enc: %S\n", eh_string_from_ptr_enc(scratch.arena, hdr.eh_frame_ptr_enc));
|
|
||||||
dumpf(" table_enc: %S\n", eh_string_from_ptr_enc(scratch.arena, hdr.table_enc));
|
|
||||||
dumpf(" fde_count: %llu\n", hdr.fde_count);
|
|
||||||
if (hdr.eh_frame_ptr_enc != EH_PtrEnc_Omit) {
|
|
||||||
dumpf(" eh_frame_ptr: 0x%I64x\n", hdr.eh_frame_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
dumpf(" Entries:\n");
|
|
||||||
dumpf(" {\n");
|
|
||||||
for (U64 cursor = 0; cursor < hdr.table.size; ) {
|
|
||||||
U64 entry_off = cursor;
|
|
||||||
|
|
||||||
U64 pc = 0;
|
|
||||||
U64 pc_size = eh_parse_ptr(hdr.table, cursor, cursor, &ptr_ctx, hdr.table_enc, &pc);
|
|
||||||
if (pc_size == 0) { break; }
|
|
||||||
cursor += pc_size;
|
|
||||||
|
|
||||||
U64 fde_addr = 0;
|
|
||||||
U64 fde_addr_size = eh_parse_ptr(hdr.table, cursor, cursor, &ptr_ctx, hdr.table_enc, &fde_addr);
|
|
||||||
if (fde_addr_size == 0) { break; }
|
|
||||||
cursor += fde_addr_size;
|
|
||||||
|
|
||||||
U64 fde_offset = fde_addr - eh_frame_vaddr;
|
|
||||||
dumpf(" { off=0x%04I64x, pc=0x%I64x, fde=0x%I64x }\n", entry_off, pc, fde_offset);
|
|
||||||
}
|
|
||||||
dumpf(" }\n");
|
|
||||||
|
|
||||||
dumpf("}\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subset_flags & EH_DumpSubsetFlag_EhFrame) {
|
|
||||||
dumpf(".eh_frame:\n");
|
|
||||||
dumpf("{\n");
|
|
||||||
for (U64 cursor = 0; cursor < eh_frame.size; ) {
|
|
||||||
DW_DescriptorEntry desc = {0};
|
|
||||||
U64 desc_size = eh_parse_descriptor_entry_header(eh_frame, cursor, &desc);
|
|
||||||
if (desc_size == 0) { break; }
|
|
||||||
|
|
||||||
switch (desc.type) {
|
|
||||||
case DW_DescriptorEntryType_Null: break;
|
|
||||||
case DW_DescriptorEntryType_CIE: {
|
|
||||||
String8 cie_data = str8_substr(eh_frame, desc.entry_range);
|
|
||||||
DW_CIE cie = {0};
|
|
||||||
if (eh_parse_cie(cie_data, desc.format, arch, eh_frame_vaddr + cursor, &ptr_ctx, &cie)) {
|
|
||||||
String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, ext, cie.format, 0, &cie, eh_decode_ptr, &ptr_ctx, cie.insts);
|
|
||||||
dumpf(" CIE: // entry range: %r\n", desc.entry_range);
|
|
||||||
dumpf(" {\n");
|
|
||||||
dumpf(" Format: %S\n", dw_string_from_format(desc.format));
|
|
||||||
dumpf(" Version: %u\n", cie.version);
|
|
||||||
dumpf(" Aug string: \"%S\"\n", cie.aug_string);
|
|
||||||
dumpf(" Code align: %I64u\n", cie.code_align_factor);
|
|
||||||
dumpf(" Data align: %I64d\n", cie.data_align_factor);
|
|
||||||
dumpf(" Return addr reg: %u\n", cie.ret_addr_reg);
|
|
||||||
if (cie.version > DW_Version_3) {
|
|
||||||
dumpf(" Address size: %u\n", cie.address_size);
|
|
||||||
dumpf(" Segment selector size: %u\n", cie.segment_selector_size);
|
|
||||||
}
|
|
||||||
dumpf(" Initial Insturction:\n");
|
|
||||||
dumpf(" {\n");
|
|
||||||
for EachNode(n, String8Node, init_insts_str_list.first) { dumpf(" %S\n", n->string); }
|
|
||||||
dumpf(" }\n");
|
|
||||||
dumpf(" }\n");
|
|
||||||
} else {
|
|
||||||
dumpf("ERROR: unable to parse CIE @ %I64x\n", desc.entry_range.min);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case DW_DescriptorEntryType_FDE: {
|
|
||||||
U64 cie_offset = desc.cie_pointer_off - desc.cie_pointer;
|
|
||||||
|
|
||||||
DW_CIE cie = {0};
|
|
||||||
{
|
|
||||||
DW_DescriptorEntry cie_desc = {0};
|
|
||||||
eh_parse_descriptor_entry_header(eh_frame, cie_offset, &cie_desc);
|
|
||||||
if (cie_desc.type == DW_DescriptorEntryType_CIE) {
|
|
||||||
String8 cie_data = str8_substr(eh_frame, cie_desc.entry_range);
|
|
||||||
eh_parse_cie(cie_data, cie_desc.format, arch, eh_frame_vaddr + cie_offset, &ptr_ctx, &cie);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String8 fde_raw = str8_substr(eh_frame, desc.entry_range);
|
|
||||||
DW_FDE fde = {0};
|
|
||||||
if (eh_parse_fde(fde_raw, desc.format, eh_frame_vaddr + cursor, &cie, &ptr_ctx, &fde)) {
|
|
||||||
String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, hdr.version, ext, fde.format, 0, &cie, eh_decode_ptr, &ptr_ctx, fde.insts);
|
|
||||||
|
|
||||||
dumpf(" FDE: // entry range: %r\n", desc.entry_range);
|
|
||||||
dumpf(" {\n");
|
|
||||||
{
|
|
||||||
dumpf(" Format: %S\n", dw_string_from_format(fde.format));
|
|
||||||
dumpf(" CIE: 0x%I64x\n", cie_offset);
|
|
||||||
dumpf(" PC range: %r\n", fde.pc_range);
|
|
||||||
dumpf(" Instructions:\n");
|
|
||||||
dumpf(" {\n");
|
|
||||||
for EachNode(n, String8Node, insts_str_list.first) { dumpf(" %S\n", n->string); }
|
|
||||||
dumpf(" }\n");
|
|
||||||
|
|
||||||
dumpf(" Unwind:\n");
|
|
||||||
dumpf(" {\n");
|
|
||||||
DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, &cie, &fde, eh_decode_ptr, &ptr_ctx);
|
|
||||||
do {
|
|
||||||
String8 cfa_str = dw_string_from_cfa(scratch.arena, arch, cie.address_size, hdr.version, ext, fde.format, cfi_unwind->row->cfa);
|
|
||||||
String8 cfi_row_str = dw_string_from_cfi_row(scratch.arena, arch, cie.address_size, hdr.version, ext, fde.format, cfi_unwind->row);
|
|
||||||
dumpf(" { PC: 0x%I64x, CFA: %-7S, Rules: { %S }\n", cfi_unwind->pc, cfa_str, cfi_row_str);
|
|
||||||
} while (dw_cfi_next_row(scratch.arena, cfi_unwind));
|
|
||||||
dumpf(" }\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dumpf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min);
|
|
||||||
}
|
|
||||||
dumpf(" }\n");
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor += desc_size;
|
|
||||||
}
|
|
||||||
dumpf("}\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef dumpf
|
|
||||||
scratch_end(scratch);
|
|
||||||
return strings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,470 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
eh_parse_ptr(String8 frame_base, U64 off, U64 pc, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out)
|
|
||||||
{
|
|
||||||
U64 ptr_off = off;
|
|
||||||
|
|
||||||
if (encoding == EH_PtrEnc_Omit) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// align read offset as needed
|
|
||||||
if (encoding == EH_PtrEnc_Aligned) {
|
|
||||||
ptr_off = AlignPow2(ptr_off, ptr_ctx->ptr_align);
|
|
||||||
encoding = EH_PtrEnc_Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode pointer value
|
|
||||||
U64 decode_size = 0;
|
|
||||||
U64 raw_ptr_size = 0;
|
|
||||||
U64 raw_ptr = 0;
|
|
||||||
switch (encoding & EH_PtrEnc_TypeMask) {
|
|
||||||
default: { InvalidPath; } break;
|
|
||||||
|
|
||||||
case EH_PtrEnc_Ptr : { raw_ptr_size = 8; } goto ufixed;
|
|
||||||
case EH_PtrEnc_UData2: { raw_ptr_size = 2; } goto ufixed;
|
|
||||||
case EH_PtrEnc_UData4: { raw_ptr_size = 4; } goto ufixed;
|
|
||||||
case EH_PtrEnc_UData8: { raw_ptr_size = 8; } goto ufixed;
|
|
||||||
ufixed: {
|
|
||||||
decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// TODO: Signed is actually just a flag that indicates this int is negavite.
|
|
||||||
// There shouldn't be a read for Signed.
|
|
||||||
// For instance, (EH_PtrEnc_UData2 | EH_PtrEnc_Signed) == EH_PtrEnc_SData etc.
|
|
||||||
case EH_PtrEnc_Signed: { raw_ptr_size = 8; } goto sfixed;
|
|
||||||
|
|
||||||
case EH_PtrEnc_SData2: { raw_ptr_size = 2; } goto sfixed;
|
|
||||||
case EH_PtrEnc_SData4: { raw_ptr_size = 4; } goto sfixed;
|
|
||||||
case EH_PtrEnc_SData8: { raw_ptr_size = 8; } goto sfixed;
|
|
||||||
sfixed: {
|
|
||||||
decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
|
||||||
raw_ptr = extend_sign64(raw_ptr, raw_ptr_size);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case EH_PtrEnc_ULEB128: { decode_size += str8_deserial_read_uleb128(frame_base, ptr_off, &raw_ptr); } break;
|
|
||||||
case EH_PtrEnc_SLEB128: { decode_size += str8_deserial_read_sleb128(frame_base, ptr_off, (S64*)&raw_ptr); } break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply relative bases
|
|
||||||
if (decode_size > 0) {
|
|
||||||
U64 ptr = raw_ptr;
|
|
||||||
switch (encoding & EH_PtrEnc_ModifierMask) {
|
|
||||||
case 0: break;
|
|
||||||
case EH_PtrEnc_PcRel: { ptr = pc + raw_ptr; } break;
|
|
||||||
case EH_PtrEnc_TextRel: { ptr = ptr_ctx->text_vaddr + raw_ptr; } break;
|
|
||||||
case EH_PtrEnc_DataRel: { ptr = ptr_ctx->data_vaddr + raw_ptr; } break;
|
|
||||||
case EH_PtrEnc_FuncRel: {
|
|
||||||
Assert(!"TODO: need a sample to verify implementation");
|
|
||||||
ptr = ptr_ctx->func_vaddr + raw_ptr;
|
|
||||||
} break;
|
|
||||||
default: { InvalidPath; } break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr_out) {
|
|
||||||
*ptr_out = ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return decode_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal EH_FrameHdr
|
|
||||||
eh_parse_frame_hdr(String8 data, U64 address_size, EH_PtrCtx *ptr_ctx)
|
|
||||||
{
|
|
||||||
EH_FrameHdr header = {0};
|
|
||||||
U64 cursor = 0;
|
|
||||||
|
|
||||||
U64 version_size = str8_deserial_read_struct(data, cursor, &header.version);
|
|
||||||
if (version_size == 0) { goto exit; }
|
|
||||||
cursor += version_size;
|
|
||||||
|
|
||||||
if (header.version == 1) {
|
|
||||||
U64 eh_frame_ptr_enc_size = str8_deserial_read_struct(data, cursor, &header.eh_frame_ptr_enc);
|
|
||||||
if (eh_frame_ptr_enc_size == 0) { goto exit; }
|
|
||||||
cursor += eh_frame_ptr_enc_size;
|
|
||||||
|
|
||||||
U64 fde_count_enc_size = str8_deserial_read_struct(data, cursor, &header.fde_count_enc);
|
|
||||||
if (fde_count_enc_size == 0) { goto exit; }
|
|
||||||
cursor += fde_count_enc_size;
|
|
||||||
|
|
||||||
U64 table_enc_size = str8_deserial_read_struct(data, cursor, &header.table_enc);
|
|
||||||
if (table_enc_size == 0) { goto exit; }
|
|
||||||
cursor += table_enc_size;
|
|
||||||
|
|
||||||
cursor += eh_parse_ptr(data, cursor, cursor, ptr_ctx, header.eh_frame_ptr_enc, &header.eh_frame_ptr);
|
|
||||||
cursor += eh_parse_ptr(data, cursor, cursor, ptr_ctx, header.fde_count_enc, &header.fde_count);
|
|
||||||
|
|
||||||
switch (header.table_enc & EH_PtrEnc_TypeMask) {
|
|
||||||
case EH_PtrEnc_Ptr: { header.field_byte_size = address_size; } break;
|
|
||||||
case EH_PtrEnc_ULEB128: { InvalidPath; } break; // TODO: when loading module convert these to UData8
|
|
||||||
case EH_PtrEnc_UData2: { header.field_byte_size = 2; } break;
|
|
||||||
case EH_PtrEnc_UData4: { header.field_byte_size = 4; } break;
|
|
||||||
case EH_PtrEnc_UData8: { header.field_byte_size = 8; } break;
|
|
||||||
case EH_PtrEnc_Signed: { header.field_byte_size = address_size; } break;
|
|
||||||
case EH_PtrEnc_SLEB128: { InvalidPath; } break; // TODO: when loading module convert these to UData8
|
|
||||||
case EH_PtrEnc_SData2: { header.field_byte_size = 2; } break;
|
|
||||||
case EH_PtrEnc_SData4: { header.field_byte_size = 4; } break;
|
|
||||||
case EH_PtrEnc_SData8: { header.field_byte_size = 8; } break;
|
|
||||||
default: { InvalidPath; } break;
|
|
||||||
}
|
|
||||||
header.entry_byte_size = header.field_byte_size * 2;
|
|
||||||
|
|
||||||
header.table = str8_skip(data, cursor);
|
|
||||||
AssertAlways(header.table.size == header.entry_byte_size * header.fde_count);
|
|
||||||
} else {
|
|
||||||
Assert(0 && "unknown version");
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
eh_parse_aug_data(String8 aug_string, String8 aug_data, U64 pc, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out)
|
|
||||||
{
|
|
||||||
// TODO:
|
|
||||||
// Handle "eh" param, it indicates presence of EH Data field.
|
|
||||||
// On 32bit arch it is a 4-byte and on 64-bit 8-byte value.
|
|
||||||
// Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
|
||||||
// Reference doc doesn't clarify structure for EH Data though
|
|
||||||
|
|
||||||
U64 cursor = 0;
|
|
||||||
|
|
||||||
U64 aug_data_size = 0;
|
|
||||||
EH_AugFlags aug_flags = 0;
|
|
||||||
EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit;
|
|
||||||
EH_PtrEnc addr_encoding = EH_PtrEnc_UData8;
|
|
||||||
EH_PtrEnc handler_encoding = EH_PtrEnc_Omit;
|
|
||||||
U64 handler_ip = 0;
|
|
||||||
if (str8_match(str8_prefix(aug_string, 1), str8_lit("z"), 0)) {
|
|
||||||
cursor = str8_deserial_read_uleb128(aug_data, cursor, &aug_data_size);
|
|
||||||
|
|
||||||
for (U8 *ptr = aug_string.str+1; ptr < (aug_string.str+aug_string.size); ptr += 1) {
|
|
||||||
switch (*ptr) {
|
|
||||||
case 'L': {
|
|
||||||
cursor += str8_deserial_read_struct(aug_data, cursor, &lsda_encoding);
|
|
||||||
aug_flags |= EH_AugFlag_HasLSDA;
|
|
||||||
} break;
|
|
||||||
case 'P': {
|
|
||||||
cursor += str8_deserial_read_struct(aug_data, cursor, &handler_encoding);
|
|
||||||
cursor += eh_parse_ptr(aug_data, cursor, pc + cursor, ptr_ctx, handler_encoding, &handler_ip);
|
|
||||||
aug_flags |= EH_AugFlag_HasHandler;
|
|
||||||
} break;
|
|
||||||
case 'R': {
|
|
||||||
cursor += str8_deserial_read_struct(aug_data, cursor, &addr_encoding);
|
|
||||||
aug_flags |= EH_AugFlag_HasAddrEnc;
|
|
||||||
} break;
|
|
||||||
case 'S': {
|
|
||||||
aug_flags |= EH_AugFlag_SignalFrame;
|
|
||||||
} break;
|
|
||||||
default: { Assert(!"failed to parse augmentation string"); goto exit; } break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aug_out) {
|
|
||||||
aug_out->handler_ip = handler_ip;
|
|
||||||
aug_out->handler_encoding = handler_encoding;
|
|
||||||
aug_out->lsda_encoding = handler_encoding;
|
|
||||||
aug_out->addr_encoding = addr_encoding;
|
|
||||||
aug_out->flags = aug_flags;
|
|
||||||
aug_out->size = aug_data_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
U64 parse_size = cursor;
|
|
||||||
return parse_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
eh_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out)
|
|
||||||
{
|
|
||||||
U32 first_four_bytes = 0;
|
|
||||||
str8_deserial_read_struct(data, off, &first_four_bytes);
|
|
||||||
DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit;
|
|
||||||
|
|
||||||
U64 length = 0;
|
|
||||||
U64 length_size = str8_deserial_read_dwarf_packed_size(data, off, &length);
|
|
||||||
if (length_size == 0) { goto exit; }
|
|
||||||
|
|
||||||
Rng1U64 entry_range = rng_1u64(off, off + length_size + length);
|
|
||||||
String8 entry_data = str8_substr(data, entry_range);
|
|
||||||
U64 id = 0;
|
|
||||||
U64 id_size = str8_deserial_read_dwarf_uint(entry_data, length_size, format, &id);
|
|
||||||
if (id_size == 0) { goto exit; }
|
|
||||||
|
|
||||||
desc_out->format = format;
|
|
||||||
desc_out->type = (id == 0) ? DW_DescriptorEntryType_CIE : DW_DescriptorEntryType_FDE;
|
|
||||||
desc_out->entry_range = entry_range;
|
|
||||||
desc_out->cie_pointer = id;
|
|
||||||
desc_out->cie_pointer_off = off + length_size;
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
return length + length_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
eh_parse_cie(String8 data, DW_Format format, Arch arch, U64 pc, EH_PtrCtx *ptr_ctx, DW_CIE *cie_out)
|
|
||||||
{
|
|
||||||
B32 is_parsed = 0;
|
|
||||||
U64 cursor = format == DW_Format_32Bit ? 4 : 12;
|
|
||||||
|
|
||||||
U64 cie_id = 0;
|
|
||||||
U64 cie_id_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id);
|
|
||||||
if (cie_id_size == 0) { goto exit; }
|
|
||||||
cursor += cie_id_size;
|
|
||||||
|
|
||||||
U8 version = 0;
|
|
||||||
U64 version_size = str8_deserial_read_struct(data, cursor, &version);
|
|
||||||
if (version_size == 0) { goto exit; }
|
|
||||||
cursor += version_size;
|
|
||||||
|
|
||||||
String8 aug_string = {0};
|
|
||||||
String8 aug_data = {0};
|
|
||||||
EH_Augmentation aug = {0};
|
|
||||||
U64 code_align_factor = 0;
|
|
||||||
S64 data_align_factor = 0;
|
|
||||||
U64 ret_addr_reg = max_U64;
|
|
||||||
if (version == 1) {
|
|
||||||
U64 aug_string_size = str8_deserial_read_cstr(data, cursor, &aug_string);
|
|
||||||
if (aug_string_size == 0) { goto exit; }
|
|
||||||
cursor += aug_string_size;
|
|
||||||
|
|
||||||
U64 eh_data = 0;
|
|
||||||
if (str8_match(aug_string, str8_lit("eh"), 0)) {
|
|
||||||
U64 arch_byte_size = byte_size_from_arch(arch);
|
|
||||||
cursor += str8_deserial_read(data, cursor, &eh_data, arch_byte_size, arch_byte_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 code_align_factor_size = str8_deserial_read_uleb128(data, cursor, &code_align_factor);
|
|
||||||
if (code_align_factor_size == 0) { goto exit; }
|
|
||||||
cursor += code_align_factor_size;
|
|
||||||
|
|
||||||
U64 data_align_factor_size = str8_deserial_read_sleb128(data, cursor, &data_align_factor);
|
|
||||||
if (data_align_factor_size == 0) { goto exit; }
|
|
||||||
cursor += data_align_factor_size;
|
|
||||||
|
|
||||||
ret_addr_reg = 0;
|
|
||||||
U64 ret_addr_reg_size = str8_deserial_read(data, cursor, &ret_addr_reg, sizeof(U8), sizeof(U8));
|
|
||||||
if (ret_addr_reg_size == 0) { goto exit; }
|
|
||||||
cursor += ret_addr_reg_size;
|
|
||||||
|
|
||||||
U64 aug_data_size = eh_parse_aug_data(aug_string, str8_skip(data, cursor), pc + cursor, ptr_ctx, &aug);
|
|
||||||
aug_data = str8_substr(data, r1u64(cursor, cursor + aug.size));
|
|
||||||
cursor += aug_data_size;
|
|
||||||
} else {
|
|
||||||
Assert(0 && "unexpected version");
|
|
||||||
}
|
|
||||||
|
|
||||||
cie_out->insts = str8_skip(data, cursor);
|
|
||||||
cie_out->aug_string = aug_string;
|
|
||||||
cie_out->aug_data = aug_data;
|
|
||||||
cie_out->code_align_factor = code_align_factor;
|
|
||||||
cie_out->data_align_factor = data_align_factor;
|
|
||||||
cie_out->ret_addr_reg = ret_addr_reg;
|
|
||||||
cie_out->format = format;
|
|
||||||
cie_out->version = version;
|
|
||||||
cie_out->address_size = byte_size_from_arch(arch);
|
|
||||||
cie_out->segment_selector_size = 0;
|
|
||||||
|
|
||||||
cie_out->ext[EH_CIE_Ext_LSDAEnc] = EH_PtrEnc_Omit;
|
|
||||||
cie_out->ext[EH_CIE_Ext_AddrEnc] = EH_PtrEnc_Omit;
|
|
||||||
cie_out->ext[EH_CIE_Ext_HandlerEnc] = EH_PtrEnc_Omit;
|
|
||||||
|
|
||||||
if (aug.flags & EH_AugFlag_HasLSDA) {
|
|
||||||
cie_out->ext[EH_CIE_Ext_LSDAEnc] = aug.lsda_encoding;
|
|
||||||
}
|
|
||||||
if (aug.flags & EH_AugFlag_HasAddrEnc) {
|
|
||||||
cie_out->ext[EH_CIE_Ext_AddrEnc] = aug.addr_encoding;
|
|
||||||
}
|
|
||||||
if (aug.flags & EH_AugFlag_HasHandler) {
|
|
||||||
cie_out->ext[EH_CIE_Ext_HandlerEnc] = aug.handler_encoding;
|
|
||||||
cie_out->ext[EH_CIE_Ext_HandlerIp ] = aug.handler_ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
is_parsed = 1;
|
|
||||||
exit:;
|
|
||||||
return is_parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
eh_parse_fde(String8 data, DW_Format format, U64 pc, DW_CIE *cie, EH_PtrCtx *ptr_ctx, DW_FDE *fde_out)
|
|
||||||
{
|
|
||||||
B32 is_parsed = 0;
|
|
||||||
U64 cursor = format == DW_Format_32Bit ? 8 : 20;
|
|
||||||
|
|
||||||
U64 pc_begin = 0;
|
|
||||||
U64 pc_delta = 0;
|
|
||||||
EH_PtrEnc addr_enc = cie->ext[EH_CIE_Ext_AddrEnc];
|
|
||||||
if (addr_enc != EH_PtrEnc_Omit) {
|
|
||||||
U64 pc_begin_size = eh_parse_ptr(data, cursor, pc + cursor, ptr_ctx, addr_enc, &pc_begin);
|
|
||||||
if (pc_begin_size == 0) { goto exit; }
|
|
||||||
cursor += pc_begin_size;
|
|
||||||
|
|
||||||
U64 pc_delta_size = eh_parse_ptr(data, cursor, pc + cursor, ptr_ctx, addr_enc & EH_PtrEnc_TypeMask, &pc_delta);
|
|
||||||
if (pc_delta_size == 0) { goto exit; }
|
|
||||||
cursor += pc_delta_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor + cie->aug_data.size > data.size) { goto exit; }
|
|
||||||
cursor += cie->aug_data.size;
|
|
||||||
|
|
||||||
fde_out->format = format;
|
|
||||||
fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_delta);
|
|
||||||
fde_out->insts = str8_skip(data, cursor);
|
|
||||||
|
|
||||||
is_parsed = 1;
|
|
||||||
exit:;
|
|
||||||
return is_parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
eh_find_nearest_fde(EH_FrameHdr header, EH_PtrCtx *ptr_ctx, U64 pc)
|
|
||||||
{
|
|
||||||
U64 fde_addr = max_U64;
|
|
||||||
U64 fde_idx = max_U64;
|
|
||||||
|
|
||||||
if (header.version == 1) {
|
|
||||||
if (header.fde_count > 0) {
|
|
||||||
U64 first = 0;
|
|
||||||
U64 first_size = eh_parse_ptr(header.table, 0, ptr_ctx->pc_vaddr, ptr_ctx, header.table_enc, &first);
|
|
||||||
AssertAlways(first_size);
|
|
||||||
if (first == pc) {
|
|
||||||
fde_idx = 0;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (first > pc) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 last_off = header.table.size - header.entry_byte_size;
|
|
||||||
U64 last = 0;
|
|
||||||
U64 last_size = eh_parse_ptr(header.table, last_off, ptr_ctx->pc_vaddr + last_off, ptr_ctx, header.table_enc, &last);
|
|
||||||
AssertAlways(last_size);
|
|
||||||
if (last <= pc) {
|
|
||||||
fde_idx = header.fde_count - 1;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
U64 l = 0;
|
|
||||||
U64 r = header.fde_count - 1;
|
|
||||||
while (l <= r) {
|
|
||||||
U64 m = l + (r - l) / 2;
|
|
||||||
U64 m_pc_off = m * header.entry_byte_size;
|
|
||||||
U64 m_pc = 0;
|
|
||||||
U64 m_pc_size = eh_parse_ptr(header.table, m_pc_off, ptr_ctx->pc_vaddr + m_pc_off, ptr_ctx, header.table_enc, &m_pc);
|
|
||||||
Assert(m_pc_size);
|
|
||||||
if (m_pc > pc) {
|
|
||||||
r = m - 1;
|
|
||||||
} else if (m_pc < pc) {
|
|
||||||
l = m + 1;
|
|
||||||
} else {
|
|
||||||
fde_idx = m;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fde_idx = l > 0 ? l-1 : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
if (fde_idx < header.fde_count) {
|
|
||||||
U64 fde_addr_off = (fde_idx * header.entry_byte_size) + header.field_byte_size;
|
|
||||||
U64 fde_addr_size = eh_parse_ptr(header.table, fde_addr_off, ptr_ctx->pc_vaddr + fde_addr_off, ptr_ctx, header.table_enc, &fde_addr);
|
|
||||||
Assert(fde_addr_size);
|
|
||||||
}
|
|
||||||
return fde_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal int
|
|
||||||
eh_frame_hdr_entry_sort(void *raw_a, void *raw_b)
|
|
||||||
{
|
|
||||||
return ((EH_FrameHdrEntry *)raw_a)->addr < ((EH_FrameHdrEntry *)raw_b)->addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
eh_frame_hdr_from_call_frame_info(Arena *arena, U64 fde_count, U64 *fde_offsets, DW_FDE *fde)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
// make .eh_frame_hdr
|
|
||||||
String8List srl = {0};
|
|
||||||
str8_serial_begin(scratch.arena, &srl);
|
|
||||||
str8_serial_push_u8(scratch.arena, &srl, 1); // version
|
|
||||||
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_Omit); // omit eh_frame_ptr field
|
|
||||||
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_UData8); // fde_count encoding
|
|
||||||
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_UData8); // table encoding
|
|
||||||
str8_serial_push_u64(scratch.arena, &srl, fde_count); // fde_count
|
|
||||||
String8 header = str8_serial_end(scratch.arena, &srl);
|
|
||||||
|
|
||||||
// alloc buffer for output
|
|
||||||
U64 buffer_size = header.size + sizeof(EH_FrameHdrEntry) * fde_count;
|
|
||||||
U8 *buffer = push_array(arena, U8, buffer_size);
|
|
||||||
|
|
||||||
// copy header
|
|
||||||
MemoryCopyStr8(buffer, header);
|
|
||||||
|
|
||||||
// write the table
|
|
||||||
EH_FrameHdrEntry *table = (EH_FrameHdrEntry *)(buffer + header.size);
|
|
||||||
for EachIndex(fde_idx, fde_count) {
|
|
||||||
table[fde_idx].addr = fde[fde_idx].pc_range.min;
|
|
||||||
table[fde_idx].fde_offset = fde_offsets[fde_idx];
|
|
||||||
}
|
|
||||||
radsort(table, fde_count, eh_frame_hdr_entry_sort);
|
|
||||||
|
|
||||||
String8 eh_frame_hdr = str8(buffer, buffer_size);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return eh_frame_hdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal
|
|
||||||
DW_DECODE_PTR(eh_decode_ptr)
|
|
||||||
{
|
|
||||||
EH_DecodePtrCtx *ctx = ud;
|
|
||||||
return eh_parse_ptr(data, 0, ctx->ptr_ctx->pc_vaddr, ctx->ptr_ctx, ctx->addr_enc, ptr_out);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
eh_string_from_ptr_enc_type(EH_PtrEnc type)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case EH_PtrEnc_Ptr: return str8_lit("Ptr");
|
|
||||||
case EH_PtrEnc_ULEB128: return str8_lit("ULEB128");
|
|
||||||
case EH_PtrEnc_UData2: return str8_lit("UData2");
|
|
||||||
case EH_PtrEnc_UData4: return str8_lit("UData4");
|
|
||||||
case EH_PtrEnc_UData8: return str8_lit("UData8");
|
|
||||||
case EH_PtrEnc_Signed: return str8_lit("Signed");
|
|
||||||
case EH_PtrEnc_SLEB128: return str8_lit("SLEB128");
|
|
||||||
case EH_PtrEnc_SData2: return str8_lit("SData2");
|
|
||||||
case EH_PtrEnc_SData4: return str8_lit("SData4");
|
|
||||||
case EH_PtrEnc_SData8: return str8_lit("SData8");
|
|
||||||
}
|
|
||||||
return str8_zero();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier)
|
|
||||||
{
|
|
||||||
switch (modifier) {
|
|
||||||
case EH_PtrEnc_PcRel: return str8_lit("PcRel");
|
|
||||||
case EH_PtrEnc_TextRel: return str8_lit("TextRel");
|
|
||||||
case EH_PtrEnc_DataRel: return str8_lit("DataRel");
|
|
||||||
case EH_PtrEnc_FuncRel: return str8_lit("FuncRel");
|
|
||||||
case EH_PtrEnc_Aligned: return str8_lit("Aligned");
|
|
||||||
}
|
|
||||||
return str8_zero();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc)
|
|
||||||
{
|
|
||||||
String8 type_str = eh_string_from_ptr_enc_type(enc & EH_PtrEnc_TypeMask);
|
|
||||||
String8 modifer_str = eh_string_from_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask);
|
|
||||||
String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero();
|
|
||||||
String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -3,3 +3,72 @@
|
|||||||
|
|
||||||
//- GENERATED CODE
|
//- GENERATED CODE
|
||||||
|
|
||||||
|
C_LINKAGE_BEGIN
|
||||||
|
String8 dw_regular_name_from_section_kind_table[18] =
|
||||||
|
{
|
||||||
|
str8_lit_comp(""),
|
||||||
|
str8_lit_comp(".debug_abbrev"),
|
||||||
|
str8_lit_comp(".debug_aranges"),
|
||||||
|
str8_lit_comp(".debug_frame"),
|
||||||
|
str8_lit_comp(".debug_info"),
|
||||||
|
str8_lit_comp(".debug_line"),
|
||||||
|
str8_lit_comp(".debug_loc"),
|
||||||
|
str8_lit_comp(".debug_macinfo"),
|
||||||
|
str8_lit_comp(".debug_pubnames"),
|
||||||
|
str8_lit_comp(".debug_pubtypes"),
|
||||||
|
str8_lit_comp(".debug_ranges"),
|
||||||
|
str8_lit_comp(".debug_str"),
|
||||||
|
str8_lit_comp(".debug_addr"),
|
||||||
|
str8_lit_comp(".debug_loclists"),
|
||||||
|
str8_lit_comp(".debug_rnglists"),
|
||||||
|
str8_lit_comp(".debug_str_offsets"),
|
||||||
|
str8_lit_comp(".debug_line_str"),
|
||||||
|
str8_lit_comp(".debug_names"),
|
||||||
|
};
|
||||||
|
|
||||||
|
String8 dw_macho_name_from_section_kind_table[18] =
|
||||||
|
{
|
||||||
|
str8_lit_comp(""),
|
||||||
|
str8_lit_comp("__debug_abbrev"),
|
||||||
|
str8_lit_comp("__debug_aranges"),
|
||||||
|
str8_lit_comp("__debug_frame"),
|
||||||
|
str8_lit_comp("__debug_info"),
|
||||||
|
str8_lit_comp("__debug_line"),
|
||||||
|
str8_lit_comp("__debug_loc"),
|
||||||
|
str8_lit_comp("__debug_macinfo"),
|
||||||
|
str8_lit_comp("__debug_pubnames"),
|
||||||
|
str8_lit_comp("__debug_pubtypes"),
|
||||||
|
str8_lit_comp("__debug_ranges"),
|
||||||
|
str8_lit_comp("__debug_str"),
|
||||||
|
str8_lit_comp("__debug_addr"),
|
||||||
|
str8_lit_comp("__debug_loclists"),
|
||||||
|
str8_lit_comp("__debug_rnglists"),
|
||||||
|
str8_lit_comp("__debug_str_offsets"),
|
||||||
|
str8_lit_comp("__debug_line_str"),
|
||||||
|
str8_lit_comp("__debug_names"),
|
||||||
|
};
|
||||||
|
|
||||||
|
String8 dw_dwo_name_from_section_kind_table[18] =
|
||||||
|
{
|
||||||
|
str8_lit_comp(""),
|
||||||
|
str8_lit_comp(".debug_abbrev.dwo"),
|
||||||
|
str8_lit_comp(".debug_aranges.dwo"),
|
||||||
|
str8_lit_comp(".debug_frame.dwo"),
|
||||||
|
str8_lit_comp(".debug_info.dwo"),
|
||||||
|
str8_lit_comp(".debug_line.dwo"),
|
||||||
|
str8_lit_comp(".debug_loc.dwo"),
|
||||||
|
str8_lit_comp(".debug_macinfo.dwo"),
|
||||||
|
str8_lit_comp(".debug_pubnames.dwo"),
|
||||||
|
str8_lit_comp(".debug_pubtypes.dwo"),
|
||||||
|
str8_lit_comp(".debug_ranges.dwo"),
|
||||||
|
str8_lit_comp(".debug_str.dwo"),
|
||||||
|
str8_lit_comp(".debug_addr.dwo"),
|
||||||
|
str8_lit_comp(".debug_loclists.dwo"),
|
||||||
|
str8_lit_comp(".debug_rnglists.dwo"),
|
||||||
|
str8_lit_comp(".debug_str_offsets.dwo"),
|
||||||
|
str8_lit_comp(".debug_line_str.dwo"),
|
||||||
|
str8_lit_comp(".debug_names.dwo"),
|
||||||
|
};
|
||||||
|
|
||||||
|
C_LINKAGE_END
|
||||||
|
|
||||||
|
|||||||
+1697
-16
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
t_dw_test_uleb128(U64 v, U64 expected_length)
|
t_dw_test_uleb128(U64 v, U64 expected_length)
|
||||||
{
|
{
|
||||||
@@ -63,6 +65,85 @@ Test(test_leb128)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
dw_test__form_match(DW_Form a, DW_Form b)
|
||||||
|
{
|
||||||
|
B32 is_match = 0;
|
||||||
|
|
||||||
|
if (a.kind == b.kind) {
|
||||||
|
switch (a.kind) {
|
||||||
|
case DW_Form_Null: {} break;
|
||||||
|
|
||||||
|
case DW_Form_Addr: { is_match = str8_match(a.addr, b.addr, 0); } break;
|
||||||
|
case DW_Form_String: { is_match = str8_match(a.string, b.string, 0); } break;
|
||||||
|
case DW_Form_ExprLoc: { is_match = str8_match(a.exprloc, b.exprloc, 0); } break;
|
||||||
|
|
||||||
|
case DW_Form_Block:
|
||||||
|
case DW_Form_Block1:
|
||||||
|
case DW_Form_Block2:
|
||||||
|
case DW_Form_Block4: {
|
||||||
|
is_match = str8_match(a.block, b.block, 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DW_Form_Data1:
|
||||||
|
case DW_Form_Data2:
|
||||||
|
case DW_Form_Data4:
|
||||||
|
case DW_Form_Data8:
|
||||||
|
case DW_Form_Data16: {
|
||||||
|
is_match = str8_match(a.data, b.data, 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DW_Form_Flag: { is_match = a.flag == b.flag; } break;
|
||||||
|
case DW_Form_SData: { is_match = a.sdata == b.sdata; } break;
|
||||||
|
case DW_Form_UData: { is_match = a.udata == b.udata; } break;
|
||||||
|
|
||||||
|
case DW_Form_RefAddr:
|
||||||
|
case DW_Form_Ref1:
|
||||||
|
case DW_Form_Ref2:
|
||||||
|
case DW_Form_Ref4:
|
||||||
|
case DW_Form_Ref8:
|
||||||
|
case DW_Form_RefUData:
|
||||||
|
case DW_Form_GNU_RefAlt: {
|
||||||
|
is_match = a.ref == b.ref;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DW_Form_Indirect: { NotImplemented; } break;
|
||||||
|
|
||||||
|
case DW_Form_SecOffset:
|
||||||
|
case DW_Form_LineStrp:
|
||||||
|
case DW_Form_GNU_StrpAlt: {
|
||||||
|
is_match = a.sec_offset == b.sec_offset;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DW_Form_ImplicitConst: { is_match = a.implicit_const, b.implicit_const; } break;
|
||||||
|
|
||||||
|
case DW_Form_Strx:
|
||||||
|
case DW_Form_Strx1:
|
||||||
|
case DW_Form_Strx2:
|
||||||
|
case DW_Form_Strx3:
|
||||||
|
case DW_Form_Strx4:
|
||||||
|
case DW_Form_Addrx:
|
||||||
|
case DW_Form_Addrx1:
|
||||||
|
case DW_Form_Addrx2:
|
||||||
|
case DW_Form_Addrx3:
|
||||||
|
case DW_Form_Addrx4:
|
||||||
|
case DW_Form_RngListx:
|
||||||
|
case DW_Form_LocListx: {
|
||||||
|
is_match = a.xval == b.xval;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case DW_Form_StrpSup: { is_match = a.strp_sup == b.strp_sup; } break;
|
||||||
|
|
||||||
|
case DW_Form_RefSup4: { NotImplemented; } break;
|
||||||
|
case DW_Form_RefSup8: { NotImplemented; } break;
|
||||||
|
|
||||||
|
default: { InvalidPath; } break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_match;
|
||||||
|
}
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
dwt_tags_must_match(DW_WriterTag *writer_tag, DW_TagNode *reader_tag)
|
dwt_tags_must_match(DW_WriterTag *writer_tag, DW_TagNode *reader_tag)
|
||||||
{
|
{
|
||||||
@@ -82,7 +163,7 @@ dwt_tags_must_match(DW_WriterTag *writer_tag, DW_TagNode *reader_tag)
|
|||||||
while (writer_attrib) {
|
while (writer_attrib) {
|
||||||
if (writer_attrib->kind != reader_attrib->v.attrib_kind) { goto exit; }
|
if (writer_attrib->kind != reader_attrib->v.attrib_kind) { goto exit; }
|
||||||
if (writer_attrib->form.reader.kind != reader_attrib->v.form.kind) { goto exit; }
|
if (writer_attrib->form.reader.kind != reader_attrib->v.form.kind) { goto exit; }
|
||||||
if ( ! dw_form_match(writer_attrib->form.reader, reader_attrib->v.form)) { goto exit; }
|
if ( ! dw_test__form_match(writer_attrib->form.reader, reader_attrib->v.form)) { goto exit; }
|
||||||
writer_attrib = writer_attrib->next;
|
writer_attrib = writer_attrib->next;
|
||||||
reader_attrib = reader_attrib->next;
|
reader_attrib = reader_attrib->next;
|
||||||
}
|
}
|
||||||
@@ -1011,7 +1092,6 @@ Test(plus_uconst)
|
|||||||
TestCheck(expr_value.addr == 0x123 + 4);
|
TestCheck(expr_value.addr == 0x123 + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
Test(reg_split_spill)
|
Test(reg_split_spill)
|
||||||
{
|
{
|
||||||
// setup register context
|
// setup register context
|
||||||
|
|||||||
@@ -0,0 +1,650 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
internal U64
|
||||||
|
eh_parse_ptr(String8 frame_base, U64 off, U64 pc, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out)
|
||||||
|
{
|
||||||
|
U64 ptr_off = off;
|
||||||
|
|
||||||
|
if (encoding == EH_PtrEnc_Omit) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// align read offset as needed
|
||||||
|
if (encoding == EH_PtrEnc_Aligned) {
|
||||||
|
ptr_off = AlignPow2(ptr_off, ptr_ctx->ptr_align);
|
||||||
|
encoding = EH_PtrEnc_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode pointer value
|
||||||
|
U64 decode_size = 0;
|
||||||
|
U64 raw_ptr_size = 0;
|
||||||
|
U64 raw_ptr = 0;
|
||||||
|
switch (encoding & EH_PtrEnc_TypeMask) {
|
||||||
|
default: { InvalidPath; } break;
|
||||||
|
|
||||||
|
case EH_PtrEnc_Ptr : { raw_ptr_size = 8; } goto ufixed;
|
||||||
|
case EH_PtrEnc_UData2: { raw_ptr_size = 2; } goto ufixed;
|
||||||
|
case EH_PtrEnc_UData4: { raw_ptr_size = 4; } goto ufixed;
|
||||||
|
case EH_PtrEnc_UData8: { raw_ptr_size = 8; } goto ufixed;
|
||||||
|
ufixed: {
|
||||||
|
decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// TODO: Signed is actually just a flag that indicates this int is negavite.
|
||||||
|
// There shouldn't be a read for Signed.
|
||||||
|
// For instance, (EH_PtrEnc_UData2 | EH_PtrEnc_Signed) == EH_PtrEnc_SData etc.
|
||||||
|
case EH_PtrEnc_Signed: { raw_ptr_size = 8; } goto sfixed;
|
||||||
|
|
||||||
|
case EH_PtrEnc_SData2: { raw_ptr_size = 2; } goto sfixed;
|
||||||
|
case EH_PtrEnc_SData4: { raw_ptr_size = 4; } goto sfixed;
|
||||||
|
case EH_PtrEnc_SData8: { raw_ptr_size = 8; } goto sfixed;
|
||||||
|
sfixed: {
|
||||||
|
decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
||||||
|
raw_ptr = extend_sign64(raw_ptr, raw_ptr_size);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case EH_PtrEnc_ULEB128: { decode_size += str8_deserial_read_uleb128(frame_base, ptr_off, &raw_ptr); } break;
|
||||||
|
case EH_PtrEnc_SLEB128: { decode_size += str8_deserial_read_sleb128(frame_base, ptr_off, (S64*)&raw_ptr); } break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply relative bases
|
||||||
|
if (decode_size > 0) {
|
||||||
|
U64 ptr = raw_ptr;
|
||||||
|
switch (encoding & EH_PtrEnc_ModifierMask) {
|
||||||
|
case 0: break;
|
||||||
|
case EH_PtrEnc_PcRel: { ptr = pc + raw_ptr; } break;
|
||||||
|
case EH_PtrEnc_TextRel: { ptr = ptr_ctx->text_vaddr + raw_ptr; } break;
|
||||||
|
case EH_PtrEnc_DataRel: { ptr = ptr_ctx->data_vaddr + raw_ptr; } break;
|
||||||
|
case EH_PtrEnc_FuncRel: {
|
||||||
|
Assert(!"TODO: need a sample to verify implementation");
|
||||||
|
ptr = ptr_ctx->func_vaddr + raw_ptr;
|
||||||
|
} break;
|
||||||
|
default: { InvalidPath; } break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptr_out) {
|
||||||
|
*ptr_out = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decode_size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal EH_FrameHdr
|
||||||
|
eh_parse_frame_hdr(String8 data, U64 address_size, EH_PtrCtx *ptr_ctx)
|
||||||
|
{
|
||||||
|
EH_FrameHdr header = {0};
|
||||||
|
U64 cursor = 0;
|
||||||
|
|
||||||
|
U64 version_size = str8_deserial_read_struct(data, cursor, &header.version);
|
||||||
|
if (version_size == 0) { goto exit; }
|
||||||
|
cursor += version_size;
|
||||||
|
|
||||||
|
if (header.version == 1) {
|
||||||
|
U64 eh_frame_ptr_enc_size = str8_deserial_read_struct(data, cursor, &header.eh_frame_ptr_enc);
|
||||||
|
if (eh_frame_ptr_enc_size == 0) { goto exit; }
|
||||||
|
cursor += eh_frame_ptr_enc_size;
|
||||||
|
|
||||||
|
U64 fde_count_enc_size = str8_deserial_read_struct(data, cursor, &header.fde_count_enc);
|
||||||
|
if (fde_count_enc_size == 0) { goto exit; }
|
||||||
|
cursor += fde_count_enc_size;
|
||||||
|
|
||||||
|
U64 table_enc_size = str8_deserial_read_struct(data, cursor, &header.table_enc);
|
||||||
|
if (table_enc_size == 0) { goto exit; }
|
||||||
|
cursor += table_enc_size;
|
||||||
|
|
||||||
|
cursor += eh_read_ptr(data, cursor, cursor, ptr_ctx, header.eh_frame_ptr_enc, &header.eh_frame_ptr);
|
||||||
|
cursor += eh_read_ptr(data, cursor, cursor, ptr_ctx, header.fde_count_enc, &header.fde_count);
|
||||||
|
|
||||||
|
switch (header.table_enc & EH_PtrEnc_TypeMask) {
|
||||||
|
case EH_PtrEnc_Ptr: { header.field_byte_size = address_size; } break;
|
||||||
|
case EH_PtrEnc_ULEB128: { InvalidPath; } break; // TODO: when loading module convert these to UData8
|
||||||
|
case EH_PtrEnc_UData2: { header.field_byte_size = 2; } break;
|
||||||
|
case EH_PtrEnc_UData4: { header.field_byte_size = 4; } break;
|
||||||
|
case EH_PtrEnc_UData8: { header.field_byte_size = 8; } break;
|
||||||
|
case EH_PtrEnc_Signed: { header.field_byte_size = address_size; } break;
|
||||||
|
case EH_PtrEnc_SLEB128: { InvalidPath; } break; // TODO: when loading module convert these to UData8
|
||||||
|
case EH_PtrEnc_SData2: { header.field_byte_size = 2; } break;
|
||||||
|
case EH_PtrEnc_SData4: { header.field_byte_size = 4; } break;
|
||||||
|
case EH_PtrEnc_SData8: { header.field_byte_size = 8; } break;
|
||||||
|
default: { InvalidPath; } break;
|
||||||
|
}
|
||||||
|
header.entry_byte_size = header.field_byte_size * 2;
|
||||||
|
|
||||||
|
header.table = str8_skip(data, cursor);
|
||||||
|
AssertAlways(header.table.size == header.entry_byte_size * header.fde_count);
|
||||||
|
} else {
|
||||||
|
Assert(0 && "unknown version");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:;
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
internal U64
|
||||||
|
eh_parse_aug_data(String8 aug_string, String8 aug_data, U64 pc, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
// Handle "eh" param, it indicates presence of EH Data field.
|
||||||
|
// On 32bit arch it is a 4-byte and on 64-bit 8-byte value.
|
||||||
|
// Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
||||||
|
// Reference doc doesn't clarify structure for EH Data though
|
||||||
|
|
||||||
|
U64 cursor = 0;
|
||||||
|
|
||||||
|
U64 aug_data_size = 0;
|
||||||
|
EH_AugFlags aug_flags = 0;
|
||||||
|
EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit;
|
||||||
|
EH_PtrEnc addr_encoding = EH_PtrEnc_UData8;
|
||||||
|
EH_PtrEnc handler_encoding = EH_PtrEnc_Omit;
|
||||||
|
U64 handler_ip = 0;
|
||||||
|
if (str8_match(str8_prefix(aug_string, 1), str8_lit("z"), 0)) {
|
||||||
|
cursor = str8_deserial_read_uleb128(aug_data, cursor, &aug_data_size);
|
||||||
|
|
||||||
|
for (U8 *ptr = aug_string.str+1; ptr < (aug_string.str+aug_string.size); ptr += 1) {
|
||||||
|
switch (*ptr) {
|
||||||
|
case 'L': {
|
||||||
|
cursor += str8_deserial_read_struct(aug_data, cursor, &lsda_encoding);
|
||||||
|
aug_flags |= EH_AugFlag_HasLSDA;
|
||||||
|
} break;
|
||||||
|
case 'P': {
|
||||||
|
cursor += str8_deserial_read_struct(aug_data, cursor, &handler_encoding);
|
||||||
|
cursor += eh_parse_ptr(aug_data, cursor, pc + cursor, ptr_ctx, handler_encoding, &handler_ip);
|
||||||
|
aug_flags |= EH_AugFlag_HasHandler;
|
||||||
|
} break;
|
||||||
|
case 'R': {
|
||||||
|
cursor += str8_deserial_read_struct(aug_data, cursor, &addr_encoding);
|
||||||
|
aug_flags |= EH_AugFlag_HasAddrEnc;
|
||||||
|
} break;
|
||||||
|
case 'S': {
|
||||||
|
aug_flags |= EH_AugFlag_SignalFrame;
|
||||||
|
} break;
|
||||||
|
default: { Assert(!"failed to parse augmentation string"); goto exit; } break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aug_out) {
|
||||||
|
aug_out->handler_ip = handler_ip;
|
||||||
|
aug_out->handler_encoding = handler_encoding;
|
||||||
|
aug_out->lsda_encoding = handler_encoding;
|
||||||
|
aug_out->addr_encoding = addr_encoding;
|
||||||
|
aug_out->flags = aug_flags;
|
||||||
|
aug_out->size = aug_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:;
|
||||||
|
U64 parse_size = cursor;
|
||||||
|
return parse_size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
eh_read_ptr(String8 data, U64 off, U64 pc, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out)
|
||||||
|
{
|
||||||
|
U64 start_off = off;
|
||||||
|
if(encoding != EH_PtrEnc_Omit)
|
||||||
|
{
|
||||||
|
// rjf: apply aligned encoding & align pointer offset
|
||||||
|
if(encoding == EH_PtrEnc_Aligned)
|
||||||
|
{
|
||||||
|
off = AlignPow2(off, ptr_ctx->ptr_align);
|
||||||
|
encoding = EH_PtrEnc_Ptr;
|
||||||
|
}
|
||||||
|
U64 start_ptr_read_off = off;
|
||||||
|
|
||||||
|
// rjf: decode pointer value
|
||||||
|
U64 raw_ptr_size = 0;
|
||||||
|
U64 raw_ptr = 0;
|
||||||
|
switch(encoding & EH_PtrEnc_TypeMask)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
|
||||||
|
// rjf: fixed-size pointer reads
|
||||||
|
case EH_PtrEnc_Ptr: {raw_ptr_size = 8;}goto ufixed;
|
||||||
|
case EH_PtrEnc_UData2:{raw_ptr_size = 2;}goto ufixed;
|
||||||
|
case EH_PtrEnc_UData4:{raw_ptr_size = 4;}goto ufixed;
|
||||||
|
case EH_PtrEnc_UData8:{raw_ptr_size = 8;}goto ufixed;
|
||||||
|
ufixed:
|
||||||
|
{
|
||||||
|
off += str8_deserial_read(data, off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// TODO: Signed is actually just a flag that indicates this int is negavite.
|
||||||
|
// There shouldn't be a read for Signed.
|
||||||
|
// For instance, (EH_PtrEnc_UData2 | EH_PtrEnc_Signed) == EH_PtrEnc_SData etc.
|
||||||
|
case EH_PtrEnc_Signed:{raw_ptr_size = 8;}goto sfixed;
|
||||||
|
|
||||||
|
// rjf: fixed-size pointer reads w/ sign extension
|
||||||
|
case EH_PtrEnc_SData2:{raw_ptr_size = 2;}goto sfixed;
|
||||||
|
case EH_PtrEnc_SData4:{raw_ptr_size = 4;}goto sfixed;
|
||||||
|
case EH_PtrEnc_SData8:{raw_ptr_size = 8;}goto sfixed;
|
||||||
|
sfixed:
|
||||||
|
{
|
||||||
|
off += str8_deserial_read(data, off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
||||||
|
raw_ptr = extend_sign64(raw_ptr, raw_ptr_size);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: uleb128/sleb128
|
||||||
|
case EH_PtrEnc_ULEB128:{off += str8_deserial_read_uleb128(data, off, &raw_ptr); }break;
|
||||||
|
case EH_PtrEnc_SLEB128:{off += str8_deserial_read_sleb128(data, off, (S64*)&raw_ptr);}break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: apply relative bases
|
||||||
|
U64 ptr = raw_ptr;
|
||||||
|
if(off != start_ptr_read_off)
|
||||||
|
{
|
||||||
|
switch(encoding & EH_PtrEnc_ModifierMask)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
case 0:{}break;
|
||||||
|
case EH_PtrEnc_PcRel: { ptr = pc + raw_ptr; } break;
|
||||||
|
case EH_PtrEnc_TextRel:{ ptr = ptr_ctx->text_vaddr + raw_ptr; } break;
|
||||||
|
case EH_PtrEnc_DataRel:{ ptr = ptr_ctx->data_vaddr + raw_ptr; } break;
|
||||||
|
case EH_PtrEnc_FuncRel:
|
||||||
|
{
|
||||||
|
Assert(!"TODO: need a sample to verify implementation");
|
||||||
|
ptr = ptr_ctx->func_vaddr + raw_ptr;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: fill output
|
||||||
|
if(ptr_out)
|
||||||
|
{
|
||||||
|
*ptr_out = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
U64 bytes_read = (off - start_off);
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
eh_read_aug_data(String8 data, U64 off, String8 string, U64 pc, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
// Handle "eh" param, it indicates presence of EH Data field.
|
||||||
|
// On 32bit arch it is a 4-byte and on 64-bit 8-byte value.
|
||||||
|
// Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
||||||
|
// Reference doc doesn't clarify structure for EH Data though
|
||||||
|
U64 start_off = off;
|
||||||
|
U64 aug_data_size = 0;
|
||||||
|
EH_AugFlags aug_flags = 0;
|
||||||
|
EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit;
|
||||||
|
EH_PtrEnc addr_encoding = EH_PtrEnc_UData8;
|
||||||
|
EH_PtrEnc handler_encoding = EH_PtrEnc_Omit;
|
||||||
|
U64 handler_ip = 0;
|
||||||
|
if(str8_match(str8_prefix(string, 1), str8_lit("z"), 0))
|
||||||
|
{
|
||||||
|
off += str8_deserial_read_uleb128(data, off, &aug_data_size);
|
||||||
|
for(U8 *ptr = string.str+1; ptr < (string.str+string.size); ptr += 1)
|
||||||
|
{
|
||||||
|
switch(*ptr)
|
||||||
|
{
|
||||||
|
default:{goto exit;}break;
|
||||||
|
case 'L':
|
||||||
|
{
|
||||||
|
off += str8_deserial_read_struct(data, off, &lsda_encoding);
|
||||||
|
aug_flags |= EH_AugFlag_HasLSDA;
|
||||||
|
}break;
|
||||||
|
case 'P':
|
||||||
|
{
|
||||||
|
off += str8_deserial_read_struct(data, off, &handler_encoding);
|
||||||
|
off += eh_read_ptr(data, off, pc + (off - start_off), ptr_ctx, handler_encoding, &handler_ip);
|
||||||
|
aug_flags |= EH_AugFlag_HasHandler;
|
||||||
|
}break;
|
||||||
|
case 'R':
|
||||||
|
{
|
||||||
|
off += str8_deserial_read_struct(data, off, &addr_encoding);
|
||||||
|
aug_flags |= EH_AugFlag_HasAddrEnc;
|
||||||
|
}break;
|
||||||
|
case 'S':
|
||||||
|
{
|
||||||
|
aug_flags |= EH_AugFlag_SignalFrame;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(aug_out != 0)
|
||||||
|
{
|
||||||
|
aug_out->handler_ip = handler_ip;
|
||||||
|
aug_out->handler_encoding = handler_encoding;
|
||||||
|
aug_out->lsda_encoding = handler_encoding;
|
||||||
|
aug_out->addr_encoding = addr_encoding;
|
||||||
|
aug_out->flags = aug_flags;
|
||||||
|
aug_out->size = aug_data_size;
|
||||||
|
}
|
||||||
|
exit:;
|
||||||
|
U64 bytes_read = (off - start_off);
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
eh_read_cfi_header(String8 data, U64 off, DW_CFIHeader *cfi_header_out)
|
||||||
|
{
|
||||||
|
U64 start_off = off;
|
||||||
|
|
||||||
|
// rjf: read length / format
|
||||||
|
U64 length = 0;
|
||||||
|
DW_Format fmt = DW_Format_Null;
|
||||||
|
U64 length_size = dw2_read_initial_length(data, off, &length, &fmt);
|
||||||
|
|
||||||
|
// rjf: find entry info, read ID
|
||||||
|
Rng1U64 entry_range = r1u64(off, off + length_size + length);
|
||||||
|
String8 entry_data = str8_substr(data, entry_range);
|
||||||
|
U64 id = 0;
|
||||||
|
U64 id_size = dw2_read_fmt_u64(entry_data, length_size, fmt, &id);
|
||||||
|
|
||||||
|
// rjf: fill
|
||||||
|
cfi_header_out->kind = (id == 0) ? DW_CFIKind_CIE : DW_CFIKind_FDE;
|
||||||
|
cfi_header_out->fmt = fmt;
|
||||||
|
cfi_header_out->entry_range = entry_range;
|
||||||
|
cfi_header_out->cie_pointer = id;
|
||||||
|
cfi_header_out->cie_pointer_off = off + length_size;
|
||||||
|
|
||||||
|
U64 bytes_read = (off - start_off);
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
eh_read_cie(String8 data, U64 off, DW_Format fmt, Arch arch, U64 pc, EH_PtrCtx *ptr_ctx, DW_CIE *cie_out)
|
||||||
|
{
|
||||||
|
U64 start_off = off;
|
||||||
|
|
||||||
|
// rjf: skip format-dependent prefix
|
||||||
|
off += (fmt == DW_Format_32Bit) ? 4 : 12;
|
||||||
|
|
||||||
|
// rjf: read id
|
||||||
|
U64 id = 0;
|
||||||
|
off += dw2_read_fmt_u64(data, off, fmt, &id);
|
||||||
|
|
||||||
|
// rjf: read version
|
||||||
|
U8 version = 0;
|
||||||
|
off += str8_deserial_read_struct(data, off, &version);
|
||||||
|
|
||||||
|
// rjf: read entry info
|
||||||
|
U64 aug_string_off_first = 0;
|
||||||
|
U64 aug_string_off_opl = 0;
|
||||||
|
U64 aug_data_off_first = 0;
|
||||||
|
U64 aug_data_off_opl = 0;
|
||||||
|
U64 code_align_factor = 0;
|
||||||
|
S64 data_align_factor = 0;
|
||||||
|
U64 ret_addr_reg = 0;
|
||||||
|
EH_Augmentation aug = {0};
|
||||||
|
if(version == 1)
|
||||||
|
{
|
||||||
|
// rjf: read aug string
|
||||||
|
aug_string_off_first = off;
|
||||||
|
String8 aug_string = {0};
|
||||||
|
off += str8_deserial_read_cstr(data, off, &aug_string);
|
||||||
|
aug_string_off_opl = off;
|
||||||
|
|
||||||
|
// rjf: read eh data
|
||||||
|
U64 eh_data = 0;
|
||||||
|
if(str8_match(aug_string, s("eh"), 0))
|
||||||
|
{
|
||||||
|
U64 arch_byte_size = byte_size_from_arch(arch);
|
||||||
|
off += str8_deserial_read(data, off, &eh_data, arch_byte_size, arch_byte_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: read align factors
|
||||||
|
off += str8_deserial_read_uleb128(data, off, &code_align_factor);
|
||||||
|
off += str8_deserial_read_sleb128(data, off, &data_align_factor);
|
||||||
|
|
||||||
|
// rjf: read return address register
|
||||||
|
off += str8_deserial_read(data, off, &ret_addr_reg, sizeof(U8), sizeof(U8));
|
||||||
|
|
||||||
|
// rjf: parse augmentation
|
||||||
|
aug_data_off_first = off;
|
||||||
|
U64 aug_data_size = eh_read_aug_data(data, off, aug_string, pc + (off - start_off), ptr_ctx, &aug);
|
||||||
|
aug_data_off_opl = off + aug.size;
|
||||||
|
off += aug_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: fill output
|
||||||
|
cie_out->aug_string_range = r1u64(aug_string_off_first, aug_string_off_opl);
|
||||||
|
cie_out->aug_data_range = r1u64(aug_data_off_first, aug_data_off_opl);
|
||||||
|
cie_out->code_align_factor = code_align_factor;
|
||||||
|
cie_out->data_align_factor = data_align_factor;
|
||||||
|
cie_out->ret_addr_reg = ret_addr_reg;
|
||||||
|
cie_out->format = fmt;
|
||||||
|
cie_out->version = version;
|
||||||
|
cie_out->address_size = byte_size_from_arch(arch);
|
||||||
|
cie_out->segment_selector_size = 0;
|
||||||
|
cie_out->ext[EH_CIE_Ext_LSDAEnc] = EH_PtrEnc_Omit;
|
||||||
|
cie_out->ext[EH_CIE_Ext_AddrEnc] = EH_PtrEnc_Omit;
|
||||||
|
cie_out->ext[EH_CIE_Ext_HandlerEnc] = EH_PtrEnc_Omit;
|
||||||
|
if(aug.flags & EH_AugFlag_HasLSDA)
|
||||||
|
{
|
||||||
|
cie_out->ext[EH_CIE_Ext_LSDAEnc] = aug.lsda_encoding;
|
||||||
|
}
|
||||||
|
if(aug.flags & EH_AugFlag_HasAddrEnc)
|
||||||
|
{
|
||||||
|
cie_out->ext[EH_CIE_Ext_AddrEnc] = aug.addr_encoding;
|
||||||
|
}
|
||||||
|
if(aug.flags & EH_AugFlag_HasHandler)
|
||||||
|
{
|
||||||
|
cie_out->ext[EH_CIE_Ext_HandlerEnc] = aug.handler_encoding;
|
||||||
|
cie_out->ext[EH_CIE_Ext_HandlerIp ] = aug.handler_ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 bytes_read = (off - start_off);
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
eh_read_fde(String8 data, U64 off, DW_Format fmt, Arch arch, U64 pc, EH_PtrCtx *ptr_ctx, DW_CIE *cie, DW_FDE *fde_out)
|
||||||
|
{
|
||||||
|
U64 start_off = off;
|
||||||
|
|
||||||
|
// rjf: skip format-dependent prefix
|
||||||
|
off += (fmt == DW_Format_32Bit) ? 8 : 20;
|
||||||
|
|
||||||
|
// rjf: read pc begin / delta
|
||||||
|
U64 pc_begin = 0;
|
||||||
|
U64 pc_delta = 0;
|
||||||
|
EH_PtrEnc addr_enc = cie->ext[EH_CIE_Ext_AddrEnc];
|
||||||
|
if(addr_enc != EH_PtrEnc_Omit)
|
||||||
|
{
|
||||||
|
off += eh_read_ptr(data, off, pc + (off - start_off), ptr_ctx, addr_enc, &pc_begin);
|
||||||
|
off += eh_read_ptr(data, off, pc + (off - start_off), ptr_ctx, addr_enc & EH_PtrEnc_TypeMask, &pc_delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: skip aug data
|
||||||
|
off += dim_1u64(cie->aug_data_range);
|
||||||
|
|
||||||
|
// rjf: fill output
|
||||||
|
fde_out->pc_range = r1u64(pc_begin, pc_begin + pc_delta);
|
||||||
|
|
||||||
|
U64 bytes_read = (off - start_off);
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
internal B32
|
||||||
|
eh_parse_fde(String8 data, DW_Format format, U64 pc, DW_CIE *cie, EH_PtrCtx *ptr_ctx, DW_FDE *fde_out)
|
||||||
|
{
|
||||||
|
B32 is_parsed = 0;
|
||||||
|
U64 cursor = format == DW_Format_32Bit ? 8 : 20;
|
||||||
|
|
||||||
|
U64 pc_begin = 0;
|
||||||
|
U64 pc_delta = 0;
|
||||||
|
EH_PtrEnc addr_enc = cie->ext[EH_CIE_Ext_AddrEnc];
|
||||||
|
if (addr_enc != EH_PtrEnc_Omit) {
|
||||||
|
U64 pc_begin_size = eh_parse_ptr(data, cursor, pc + cursor, ptr_ctx, addr_enc, &pc_begin);
|
||||||
|
if (pc_begin_size == 0) { goto exit; }
|
||||||
|
cursor += pc_begin_size;
|
||||||
|
|
||||||
|
U64 pc_delta_size = eh_parse_ptr(data, cursor, pc + cursor, ptr_ctx, addr_enc & EH_PtrEnc_TypeMask, &pc_delta);
|
||||||
|
if (pc_delta_size == 0) { goto exit; }
|
||||||
|
cursor += pc_delta_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor + cie->aug_data.size > data.size) { goto exit; }
|
||||||
|
cursor += cie->aug_data.size;
|
||||||
|
|
||||||
|
fde_out->format = format;
|
||||||
|
fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_delta);
|
||||||
|
fde_out->insts = str8_skip(data, cursor);
|
||||||
|
|
||||||
|
is_parsed = 1;
|
||||||
|
exit:;
|
||||||
|
return is_parsed;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
internal U64
|
||||||
|
eh_find_nearest_fde(EH_FrameHdr header, EH_PtrCtx *ptr_ctx, U64 pc)
|
||||||
|
{
|
||||||
|
U64 fde_addr = max_U64;
|
||||||
|
U64 fde_idx = max_U64;
|
||||||
|
|
||||||
|
if (header.version == 1) {
|
||||||
|
if (header.fde_count > 0) {
|
||||||
|
U64 first = 0;
|
||||||
|
U64 first_size = eh_parse_ptr(header.table, 0, ptr_ctx->pc_vaddr, ptr_ctx, header.table_enc, &first);
|
||||||
|
AssertAlways(first_size);
|
||||||
|
if (first == pc) {
|
||||||
|
fde_idx = 0;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (first > pc) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 last_off = header.table.size - header.entry_byte_size;
|
||||||
|
U64 last = 0;
|
||||||
|
U64 last_size = eh_parse_ptr(header.table, last_off, ptr_ctx->pc_vaddr + last_off, ptr_ctx, header.table_enc, &last);
|
||||||
|
AssertAlways(last_size);
|
||||||
|
if (last <= pc) {
|
||||||
|
fde_idx = header.fde_count - 1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 l = 0;
|
||||||
|
U64 r = header.fde_count - 1;
|
||||||
|
while (l <= r) {
|
||||||
|
U64 m = l + (r - l) / 2;
|
||||||
|
U64 m_pc_off = m * header.entry_byte_size;
|
||||||
|
U64 m_pc = 0;
|
||||||
|
U64 m_pc_size = eh_parse_ptr(header.table, m_pc_off, ptr_ctx->pc_vaddr + m_pc_off, ptr_ctx, header.table_enc, &m_pc);
|
||||||
|
Assert(m_pc_size);
|
||||||
|
if (m_pc > pc) {
|
||||||
|
r = m - 1;
|
||||||
|
} else if (m_pc < pc) {
|
||||||
|
l = m + 1;
|
||||||
|
} else {
|
||||||
|
fde_idx = m;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fde_idx = l > 0 ? l-1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:;
|
||||||
|
if (fde_idx < header.fde_count) {
|
||||||
|
U64 fde_addr_off = (fde_idx * header.entry_byte_size) + header.field_byte_size;
|
||||||
|
U64 fde_addr_size = eh_parse_ptr(header.table, fde_addr_off, ptr_ctx->pc_vaddr + fde_addr_off, ptr_ctx, header.table_enc, &fde_addr);
|
||||||
|
Assert(fde_addr_size);
|
||||||
|
}
|
||||||
|
return fde_addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal int
|
||||||
|
eh_frame_hdr_entry_sort(void *raw_a, void *raw_b)
|
||||||
|
{
|
||||||
|
return ((EH_FrameHdrEntry *)raw_a)->addr < ((EH_FrameHdrEntry *)raw_b)->addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
eh_frame_hdr_from_call_frame_info(Arena *arena, U64 fde_count, U64 *fde_offsets, DW_FDE *fde)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(&arena, 1);
|
||||||
|
|
||||||
|
// make .eh_frame_hdr
|
||||||
|
String8List srl = {0};
|
||||||
|
str8_serial_begin(scratch.arena, &srl);
|
||||||
|
str8_serial_push_u8(scratch.arena, &srl, 1); // version
|
||||||
|
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_Omit); // omit eh_frame_ptr field
|
||||||
|
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_UData8); // fde_count encoding
|
||||||
|
str8_serial_push_u8(scratch.arena, &srl, EH_PtrEnc_UData8); // table encoding
|
||||||
|
str8_serial_push_u64(scratch.arena, &srl, fde_count); // fde_count
|
||||||
|
String8 header = str8_serial_end(scratch.arena, &srl);
|
||||||
|
|
||||||
|
// alloc buffer for output
|
||||||
|
U64 buffer_size = header.size + sizeof(EH_FrameHdrEntry) * fde_count;
|
||||||
|
U8 *buffer = push_array(arena, U8, buffer_size);
|
||||||
|
|
||||||
|
// copy header
|
||||||
|
MemoryCopyStr8(buffer, header);
|
||||||
|
|
||||||
|
// write the table
|
||||||
|
EH_FrameHdrEntry *table = (EH_FrameHdrEntry *)(buffer + header.size);
|
||||||
|
for EachIndex(fde_idx, fde_count) {
|
||||||
|
table[fde_idx].addr = fde[fde_idx].pc_range.min;
|
||||||
|
table[fde_idx].fde_offset = fde_offsets[fde_idx];
|
||||||
|
}
|
||||||
|
radsort(table, fde_count, eh_frame_hdr_entry_sort);
|
||||||
|
|
||||||
|
String8 eh_frame_hdr = str8(buffer, buffer_size);
|
||||||
|
scratch_end(scratch);
|
||||||
|
return eh_frame_hdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
internal
|
||||||
|
DW_DECODE_PTR(eh_decode_ptr)
|
||||||
|
{
|
||||||
|
EH_DecodePtrCtx *ctx = ud;
|
||||||
|
return eh_parse_ptr(data, 0, ctx->ptr_ctx->pc_vaddr, ctx->ptr_ctx, ctx->addr_enc, ptr_out);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
eh_string_from_ptr_enc_type(EH_PtrEnc type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case EH_PtrEnc_Ptr: return str8_lit("Ptr");
|
||||||
|
case EH_PtrEnc_ULEB128: return str8_lit("ULEB128");
|
||||||
|
case EH_PtrEnc_UData2: return str8_lit("UData2");
|
||||||
|
case EH_PtrEnc_UData4: return str8_lit("UData4");
|
||||||
|
case EH_PtrEnc_UData8: return str8_lit("UData8");
|
||||||
|
case EH_PtrEnc_Signed: return str8_lit("Signed");
|
||||||
|
case EH_PtrEnc_SLEB128: return str8_lit("SLEB128");
|
||||||
|
case EH_PtrEnc_SData2: return str8_lit("SData2");
|
||||||
|
case EH_PtrEnc_SData4: return str8_lit("SData4");
|
||||||
|
case EH_PtrEnc_SData8: return str8_lit("SData8");
|
||||||
|
}
|
||||||
|
return str8_zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier)
|
||||||
|
{
|
||||||
|
switch (modifier) {
|
||||||
|
case EH_PtrEnc_PcRel: return str8_lit("PcRel");
|
||||||
|
case EH_PtrEnc_TextRel: return str8_lit("TextRel");
|
||||||
|
case EH_PtrEnc_DataRel: return str8_lit("DataRel");
|
||||||
|
case EH_PtrEnc_FuncRel: return str8_lit("FuncRel");
|
||||||
|
case EH_PtrEnc_Aligned: return str8_lit("Aligned");
|
||||||
|
}
|
||||||
|
return str8_zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal String8
|
||||||
|
eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc)
|
||||||
|
{
|
||||||
|
String8 type_str = eh_string_from_ptr_enc_type(enc & EH_PtrEnc_TypeMask);
|
||||||
|
String8 modifer_str = eh_string_from_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask);
|
||||||
|
String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero();
|
||||||
|
String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -107,10 +107,20 @@ typedef struct EH_DecodePtrCtx
|
|||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
|
#if 0
|
||||||
internal U64 eh_parse_ptr(String8 frame_base, U64 off, U64 pc, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out);
|
internal U64 eh_parse_ptr(String8 frame_base, U64 off, U64 pc, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out);
|
||||||
|
#endif
|
||||||
internal EH_FrameHdr eh_parse_frame_hdr(String8 data, U64 address_size, EH_PtrCtx *ptr_ctx);
|
internal EH_FrameHdr eh_parse_frame_hdr(String8 data, U64 address_size, EH_PtrCtx *ptr_ctx);
|
||||||
|
#if 0
|
||||||
internal U64 eh_parse_aug_data(String8 aug_string, String8 aug_data, U64 pc, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out);
|
internal U64 eh_parse_aug_data(String8 aug_string, String8 aug_data, U64 pc, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out);
|
||||||
internal B32 eh_parse_cie(String8 data, DW_Format format, Arch arch, U64 pc, EH_PtrCtx *ptr_ctx, DW_CIE *cie_out);
|
#endif
|
||||||
|
|
||||||
|
internal U64 eh_read_ptr(String8 data, U64 off, U64 pc, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out);
|
||||||
|
internal U64 eh_read_aug_data(String8 data, U64 off, String8 string, U64 pc, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out);
|
||||||
|
internal U64 eh_read_cfi_header(String8 data, U64 off, DW_CFIHeader *cfi_header_out);
|
||||||
|
internal U64 eh_read_cie(String8 data, U64 off, DW_Format fmt, Arch arch, U64 pc, EH_PtrCtx *ptr_ctx, DW_CIE *cie_out);
|
||||||
|
internal U64 eh_read_fde(String8 data, U64 off, DW_Format fmt, Arch arch, U64 pc, EH_PtrCtx *ptr_ctx, DW_CIE *cie, DW_FDE *fde_out);
|
||||||
|
|
||||||
internal B32 eh_parse_fde(String8 data, DW_Format format, U64 pc, DW_CIE *cie, EH_PtrCtx *ptr_ctx, DW_FDE *fde_out);
|
internal B32 eh_parse_fde(String8 data, DW_Format format, U64 pc, DW_CIE *cie, EH_PtrCtx *ptr_ctx, DW_FDE *fde_out);
|
||||||
internal U64 eh_find_nearest_fde(EH_FrameHdr header, EH_PtrCtx *ptr_ctx, U64 pc);
|
internal U64 eh_find_nearest_fde(EH_FrameHdr header, EH_PtrCtx *ptr_ctx, U64 pc);
|
||||||
internal String8 eh_frame_hdr_from_call_frame_info(Arena *arena, U64 fde_count, U64 *fde_offsets, struct DW_FDE *fde);
|
internal String8 eh_frame_hdr_from_call_frame_info(Arena *arena, U64 fde_count, U64 *fde_offsets, struct DW_FDE *fde);
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
internal String8List
|
||||||
|
eh_dump_list_from_data(Arena *arena, Arch arch, U64 eh_frame_hdr_vaddr, U64 eh_frame_vaddr, String8 eh_frame_hdr, String8 eh_frame, EH_DumpSubsetFlags subset_flags)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(&arena, 1);
|
||||||
|
String8List strings = {0};
|
||||||
|
#define dumpf(...) str8_list_pushf(arena, &strings, __VA_ARGS__)
|
||||||
|
|
||||||
|
EH_PtrCtx ptr_ctx = {.data_vaddr = eh_frame_hdr_vaddr};
|
||||||
|
EH_FrameHdr hdr = eh_parse_frame_hdr(eh_frame_hdr, byte_size_from_arch(arch), &ptr_ctx);
|
||||||
|
DW_ExtFlags exts = DW_ExtFlag_All;
|
||||||
|
|
||||||
|
//- rjf: eh frame header
|
||||||
|
if(subset_flags & EH_DumpSubsetFlag_EhFrameHdr)
|
||||||
|
{
|
||||||
|
dumpf(".eh_frame_hdr:\n");
|
||||||
|
dumpf("{\n");
|
||||||
|
dumpf(" version: %u\n", hdr.version);
|
||||||
|
dumpf(" eh_frame_ptr_enc: %S\n", eh_string_from_ptr_enc(scratch.arena, hdr.eh_frame_ptr_enc));
|
||||||
|
dumpf(" table_enc: %S\n", eh_string_from_ptr_enc(scratch.arena, hdr.table_enc));
|
||||||
|
dumpf(" fde_count: %llu\n", hdr.fde_count);
|
||||||
|
if(hdr.eh_frame_ptr_enc != EH_PtrEnc_Omit)
|
||||||
|
{
|
||||||
|
dumpf(" eh_frame_ptr: 0x%I64x\n", hdr.eh_frame_ptr);
|
||||||
|
}
|
||||||
|
dumpf(" Entries:\n");
|
||||||
|
dumpf(" {\n");
|
||||||
|
for(U64 cursor = 0; cursor < hdr.table.size; )
|
||||||
|
{
|
||||||
|
U64 entry_off = cursor;
|
||||||
|
U64 pc = 0;
|
||||||
|
U64 pc_size = eh_read_ptr(hdr.table, cursor, cursor, &ptr_ctx, hdr.table_enc, &pc);
|
||||||
|
if (pc_size == 0) { break; }
|
||||||
|
cursor += pc_size;
|
||||||
|
U64 fde_addr = 0;
|
||||||
|
U64 fde_addr_size = eh_read_ptr(hdr.table, cursor, cursor, &ptr_ctx, hdr.table_enc, &fde_addr);
|
||||||
|
if (fde_addr_size == 0) { break; }
|
||||||
|
cursor += fde_addr_size;
|
||||||
|
U64 fde_offset = fde_addr - eh_frame_vaddr;
|
||||||
|
dumpf(" { off=0x%04I64x, pc=0x%I64x, fde=0x%I64x }\n", entry_off, pc, fde_offset);
|
||||||
|
}
|
||||||
|
dumpf(" }\n");
|
||||||
|
dumpf("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: eh frame data
|
||||||
|
if(subset_flags & EH_DumpSubsetFlag_EhFrame)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
dumpf(".eh_frame:\n");
|
||||||
|
dumpf("{\n");
|
||||||
|
for(U64 cursor = 0; cursor < eh_frame.size;)
|
||||||
|
{
|
||||||
|
DW_CFIHeader header = {0};
|
||||||
|
U64 header_size = eh_read_cfi_header(eh_frame, cursor, &header);
|
||||||
|
switch(header.kind)
|
||||||
|
{
|
||||||
|
case DW_CFIKind_Null:{}break;
|
||||||
|
case DW_CFIKind_CIE:
|
||||||
|
{
|
||||||
|
DW_CIE cie = {0};
|
||||||
|
eh_read_cie(eh_frame, header.entry_range.min, header.fmt, arch, eh_frame_vaddr + cursor, &ptr_ctx, &cie);
|
||||||
|
if(cie.version != 0)
|
||||||
|
{
|
||||||
|
String8List init_insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, DW_Version_5, ext, cie.format, 0, &cie, eh_decode_ptr, &ptr_ctx, cie.insts);
|
||||||
|
String8 aug_string = str8_substr(eh_frame, cie.aug_string_range);
|
||||||
|
dumpf(" CIE: // entry range: [0x%I64x, 0x%I64x)\n", header.entry_range.min, header.entry_range.max);
|
||||||
|
dumpf(" {\n");
|
||||||
|
dumpf(" Format: %S\n", dw_string_from_format(desc.format));
|
||||||
|
dumpf(" Version: %u\n", cie.version);
|
||||||
|
dumpf(" Aug string: \"%S\"\n", aug_string);
|
||||||
|
dumpf(" Code align: %I64u\n", cie.code_align_factor);
|
||||||
|
dumpf(" Data align: %I64d\n", cie.data_align_factor);
|
||||||
|
dumpf(" Return addr reg: %u\n", cie.ret_addr_reg);
|
||||||
|
if(cie.version > DW_Version_3)
|
||||||
|
{
|
||||||
|
dumpf(" Address size: %u\n", cie.address_size);
|
||||||
|
dumpf(" Segment selector size: %u\n", cie.segment_selector_size);
|
||||||
|
}
|
||||||
|
dumpf(" Initial Insturction:\n");
|
||||||
|
dumpf(" {\n");
|
||||||
|
for EachNode(n, String8Node, init_insts_str_list.first)
|
||||||
|
{
|
||||||
|
dumpf(" %S\n", n->string);
|
||||||
|
}
|
||||||
|
dumpf(" }\n");
|
||||||
|
dumpf(" }\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dumpf("ERROR: unable to parse CIE @ %I64x\n", header.entry_range.min);
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFIKind_FDE:
|
||||||
|
{
|
||||||
|
U64 cie_offset = header.cie_pointer_off - header.cie_pointer;
|
||||||
|
|
||||||
|
DW_CIE cie = {0};
|
||||||
|
{
|
||||||
|
DW_DescriptorEntry cie_desc = {0};
|
||||||
|
eh_parse_descriptor_entry_header(eh_frame, cie_offset, &cie_desc);
|
||||||
|
if (cie_desc.type == DW_DescriptorEntryKind_CIE) {
|
||||||
|
String8 cie_data = str8_substr(eh_frame, cie_desc.entry_range);
|
||||||
|
eh_parse_cie(cie_data, cie_desc.format, arch, eh_frame_vaddr + cie_offset, &ptr_ctx, &cie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String8 fde_raw = str8_substr(eh_frame, desc.entry_range);
|
||||||
|
DW_FDE fde = {0};
|
||||||
|
if (eh_parse_fde(fde_raw, desc.format, eh_frame_vaddr + cursor, &cie, &ptr_ctx, &fde)) {
|
||||||
|
String8List insts_str_list = dw_string_list_from_cfi_program(scratch.arena, 0, arch, hdr.version, ext, fde.format, 0, &cie, eh_decode_ptr, &ptr_ctx, fde.insts);
|
||||||
|
|
||||||
|
dumpf(" FDE: // entry range: %r\n", desc.entry_range);
|
||||||
|
dumpf(" {\n");
|
||||||
|
{
|
||||||
|
dumpf(" Format: %S\n", dw_string_from_format(fde.format));
|
||||||
|
dumpf(" CIE: 0x%I64x\n", cie_offset);
|
||||||
|
dumpf(" PC range: %r\n", fde.pc_range);
|
||||||
|
dumpf(" Instructions:\n");
|
||||||
|
dumpf(" {\n");
|
||||||
|
for EachNode(n, String8Node, insts_str_list.first) { dumpf(" %S\n", n->string); }
|
||||||
|
dumpf(" }\n");
|
||||||
|
|
||||||
|
dumpf(" Unwind:\n");
|
||||||
|
dumpf(" {\n");
|
||||||
|
DW_CFI_Unwind *cfi_unwind = dw_cfi_unwind_init(scratch.arena, arch, &cie, &fde, eh_decode_ptr, &ptr_ctx);
|
||||||
|
do {
|
||||||
|
String8 cfa_str = dw_string_from_cfa(scratch.arena, arch, cie.address_size, hdr.version, ext, fde.format, cfi_unwind->row->cfa);
|
||||||
|
String8 cfi_row_str = dw_string_from_cfi_row(scratch.arena, arch, cie.address_size, hdr.version, ext, fde.format, cfi_unwind->row);
|
||||||
|
dumpf(" { PC: 0x%I64x, CFA: %-7S, Rules: { %S }\n", cfi_unwind->pc, cfa_str, cfi_row_str);
|
||||||
|
} while (dw_cfi_next_row(scratch.arena, cfi_unwind));
|
||||||
|
dumpf(" }\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dumpf("ERROR: unable to parse FDE @ %I64x\n", desc.entry_range.min);
|
||||||
|
}
|
||||||
|
dumpf(" }\n");
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor += desc_size;
|
||||||
|
}
|
||||||
|
dumpf("}\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef dumpf
|
||||||
|
scratch_end(scratch);
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
@@ -8,8 +8,8 @@
|
|||||||
//~ Dump Subset Types
|
//~ Dump Subset Types
|
||||||
|
|
||||||
#define EH_DumpSubset_XList \
|
#define EH_DumpSubset_XList \
|
||||||
X(EhFrameHdr, eh_frame_hdr, ".eh_frame_hdr") \
|
X(EhFrameHdr, eh_frame_hdr, ".eh_frame_hdr") \
|
||||||
X(EhFrame, eh_frame, ".eh_frame")
|
X(EhFrame, eh_frame, ".eh_frame")
|
||||||
|
|
||||||
typedef enum EH_DumpSubset {
|
typedef enum EH_DumpSubset {
|
||||||
#define X(name, name_lower, title) EH_DumpSubset_##name,
|
#define X(name, name_lower, title) EH_DumpSubset_##name,
|
||||||
@@ -0,0 +1,696 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
internal UWND_StepResult
|
||||||
|
eh_uwnd_step(Arch arch, MemoryMap *memory_map, UWND_ModuleInfo *module_info, U64 tls_vaddr, void *regs, U64 *cfa_out)
|
||||||
|
{
|
||||||
|
Temp scratch = scratch_begin(0, 0);
|
||||||
|
B32 done = 0;
|
||||||
|
UWND_StepResult result = {0};
|
||||||
|
EH_UWND_ModuleUnwindInfo *unwind_info = (EH_UWND_ModuleUnwindInfo *)module_info->unwind_info;
|
||||||
|
if(unwind_info != 0)
|
||||||
|
{
|
||||||
|
//- rjf: unpack context
|
||||||
|
EH_FrameHdr *header = &unwind_info->header;
|
||||||
|
EH_PtrCtx *ptr_ctx = &unwind_info->ptr_ctx;
|
||||||
|
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
||||||
|
U64 pc = arch_ip_from_reg_block(arch_info, regs);
|
||||||
|
|
||||||
|
//- rjf: set up new register values
|
||||||
|
void *new_regs = push_array(scratch.arena, U8, arch_info->reg_block_size);
|
||||||
|
MemoryCopy(new_regs, regs, arch_info->reg_block_size);
|
||||||
|
|
||||||
|
//- rjf: find nearest FDE entry to the IP
|
||||||
|
U64 fde_vaddr = 0;
|
||||||
|
if(header->version == 1 && header->fde_count != 0)
|
||||||
|
{
|
||||||
|
// rjf: binary search to find FDE number
|
||||||
|
U64 fde_num = 0;
|
||||||
|
{
|
||||||
|
U64 min_idx = 0;
|
||||||
|
U64 max_idx = header->fde_count-1;
|
||||||
|
for(;min_idx <= max_idx;)
|
||||||
|
{
|
||||||
|
U64 mid_idx = min_idx + (max_idx - min_idx) / 2;
|
||||||
|
U64 mid_pc_off = mid_idx*header->entry_byte_size;
|
||||||
|
U64 mid_pc = 0;
|
||||||
|
eh_read_ptr(header->table, mid_pc_off, ptr_ctx->pc_vaddr + mid_pc_off, ptr_ctx, header->table_enc, &mid_pc);
|
||||||
|
if(mid_pc > pc)
|
||||||
|
{
|
||||||
|
max_idx = mid_idx - 1;
|
||||||
|
}
|
||||||
|
else if(mid_pc < pc)
|
||||||
|
{
|
||||||
|
min_idx = mid_idx + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fde_num = mid_idx + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fde_num == 0)
|
||||||
|
{
|
||||||
|
fde_num = min_idx > 0 ? min_idx : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: FDE number -> FDE vaddr
|
||||||
|
if(0 < fde_num && fde_num <= header->fde_count)
|
||||||
|
{
|
||||||
|
U64 fde_vaddr_off = ((fde_num-1) * header->entry_byte_size) + header->field_byte_size;
|
||||||
|
eh_read_ptr(header->table, fde_vaddr_off, ptr_ctx->pc_vaddr + fde_vaddr_off, ptr_ctx, header->table_enc, &fde_vaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: parse info from FDE entry
|
||||||
|
DW_CIE cie = {0};
|
||||||
|
DW_FDE fde = {0};
|
||||||
|
U64 cie_inst_data_off = 0;
|
||||||
|
U64 fde_inst_data_off = 0;
|
||||||
|
String8 cie_inst_data = {0};
|
||||||
|
String8 fde_inst_data = {0};
|
||||||
|
if(fde_vaddr != 0)
|
||||||
|
{
|
||||||
|
// rjf: determine FDE's full address range
|
||||||
|
Rng1U64 fde_vaddr_range = {0};
|
||||||
|
DW_Format fde_fmt = DW_Format_Null;
|
||||||
|
{
|
||||||
|
// rjf: read initial length data
|
||||||
|
String8 initial_length_data = {0};
|
||||||
|
{
|
||||||
|
U8 *initial_length_data_buffer = push_array(scratch.arena, U8, 12);
|
||||||
|
Rng1U64 initial_length_vaddr_range = r1u64(fde_vaddr, fde_vaddr+12);
|
||||||
|
U64 initial_length_data_size = memory_map_read(memory_map, initial_length_vaddr_range, initial_length_data_buffer);
|
||||||
|
initial_length_data = str8(initial_length_data_buffer, initial_length_data_size);
|
||||||
|
if(initial_length_data_size < 4)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = initial_length_vaddr_range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: compute initial length
|
||||||
|
U64 length = 0;
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
dw2_read_initial_length(initial_length_data, 0, &length, &fde_fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: determine vaddr range of all FDE data
|
||||||
|
//
|
||||||
|
// TODO(rjf): are we sure this is supposed to *not* advance past the 8 byte length field
|
||||||
|
// when the initial 4 bytes are max_U32? this would mean that in 32-bit format, the length
|
||||||
|
// *does not* include the length encoding itself, but in 64-bit format, the length *does*
|
||||||
|
// include the length, but not the initial 4 bytes max_U32 marker. WTF?
|
||||||
|
//
|
||||||
|
fde_vaddr_range = r1u64(fde_vaddr, fde_vaddr + 4 + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: read FDE data
|
||||||
|
String8 fde_data = {0};
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
U64 fde_data_expected_size = dim_1u64(fde_vaddr_range);
|
||||||
|
U8 *fde_data_buffer = push_array(scratch.arena, U8, fde_data_expected_size);
|
||||||
|
U64 fde_data_size = memory_map_read(memory_map, fde_vaddr_range, fde_data_buffer);
|
||||||
|
if(fde_data_size != fde_data_expected_size)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = fde_vaddr_range;
|
||||||
|
}
|
||||||
|
fde_data = str8(fde_data_buffer, fde_data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: FDE data -> CIE address
|
||||||
|
U64 cie_vaddr = 0;
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
U64 cie_delta_off = (fde_fmt == DW_Format_32Bit ? 4 : 12);
|
||||||
|
U64 cie_delta = 0;
|
||||||
|
dw2_read_fmt_u64(fde_data, cie_delta_off, fde_fmt, &cie_delta);
|
||||||
|
cie_vaddr = (fde_vaddr + cie_delta_off) - cie_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: determine CIE's full address range
|
||||||
|
Rng1U64 cie_vaddr_range = {0};
|
||||||
|
DW_Format cie_fmt = DW_Format_Null;
|
||||||
|
{
|
||||||
|
// rjf: read initial length data
|
||||||
|
String8 initial_length_data = {0};
|
||||||
|
{
|
||||||
|
U8 *initial_length_data_buffer = push_array(scratch.arena, U8, 12);
|
||||||
|
Rng1U64 initial_length_vaddr_range = r1u64(cie_vaddr, cie_vaddr+12);
|
||||||
|
U64 initial_length_data_size = memory_map_read(memory_map, initial_length_vaddr_range, initial_length_data_buffer);
|
||||||
|
initial_length_data = str8(initial_length_data_buffer, initial_length_data_size);
|
||||||
|
if(initial_length_data_size < 4)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = initial_length_vaddr_range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: compute initial length
|
||||||
|
U64 length = 0;
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
dw2_read_initial_length(initial_length_data, 0, &length, &cie_fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: form full address range of CIE data
|
||||||
|
//
|
||||||
|
// TODO(rjf): is this busted? see above note in FDE parse
|
||||||
|
//
|
||||||
|
cie_vaddr_range = r1u64(cie_vaddr, cie_vaddr + 4 + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: read CIE data
|
||||||
|
String8 cie_data = {0};
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
U64 cie_data_expected_size = dim_1u64(cie_vaddr_range);
|
||||||
|
U8 *cie_data_buffer = push_array(scratch.arena, U8, cie_data_expected_size);
|
||||||
|
U64 cie_data_size = memory_map_read(memory_map, cie_vaddr_range, cie_data_buffer);
|
||||||
|
if(cie_data_size != cie_data_expected_size)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = cie_vaddr_range;
|
||||||
|
}
|
||||||
|
cie_data = str8(cie_data_buffer, cie_data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: parse CIE data, & FDE data
|
||||||
|
cie_inst_data_off = eh_read_cie(cie_data, 0, cie_fmt, arch, cie_vaddr_range.min, ptr_ctx, &cie);
|
||||||
|
fde_inst_data_off = eh_read_fde(fde_data, 0, fde_fmt, arch, fde_vaddr_range.min, ptr_ctx, &cie, &fde);
|
||||||
|
cie_inst_data = str8_skip(cie_data, cie_inst_data_off);
|
||||||
|
fde_inst_data = str8_skip(fde_data, fde_inst_data_off);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: parse CIE/FDE info, produce CFI row for this PC
|
||||||
|
U64 reg_count = dw_reg_count_from_arch(arch);
|
||||||
|
DW_CFIRow cfi_row = {0};
|
||||||
|
cfi_row.reg_rules = push_array(scratch.arena, DW_UnwindRule, reg_count);
|
||||||
|
if(!done && contains_1u64(fde.pc_range, pc))
|
||||||
|
{
|
||||||
|
U64 code_align_factor = cie.code_align_factor;
|
||||||
|
S64 data_align_factor = cie.data_align_factor;
|
||||||
|
DW_CFIRow initial_row = {0};
|
||||||
|
initial_row.reg_rules = push_array(scratch.arena, DW_UnwindRule, reg_count);
|
||||||
|
DW_CFIRowNode *top_row = 0;
|
||||||
|
DW_CFIRowNode *free_row = 0;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
String8 inst_data;
|
||||||
|
U64 inst_data_off;
|
||||||
|
}
|
||||||
|
program_tasks[] =
|
||||||
|
{
|
||||||
|
{cie_inst_data, cie_inst_data_off},
|
||||||
|
{fde_inst_data, fde_inst_data_off},
|
||||||
|
};
|
||||||
|
B32 computed_row = 0;
|
||||||
|
for EachElement(program_task_idx, program_tasks)
|
||||||
|
{
|
||||||
|
// rjf: exit if we computed the target row
|
||||||
|
if(computed_row)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: run unwind instruction program
|
||||||
|
String8 inst_data = program_tasks[program_task_idx].inst_data;
|
||||||
|
U64 inst_data_off = program_tasks[program_task_idx].inst_data_off;
|
||||||
|
for(U64 off = 0; off < inst_data.size;)
|
||||||
|
{
|
||||||
|
U64 start_off = off;
|
||||||
|
|
||||||
|
// rjf: read next opcode
|
||||||
|
DW_CFAOpCode raw_opcode = DW_CFAOpCode_Nop;
|
||||||
|
off += str8_deserial_read_struct(inst_data, off, &raw_opcode);
|
||||||
|
|
||||||
|
// rjf: unpack opcode (raw opcode can contain implicit operands)
|
||||||
|
DW_CFAOpCode opcode = raw_opcode & ~DW_CFAOpCodeMask_OpcodeHi;
|
||||||
|
U64 implicit_operand = 0;
|
||||||
|
if((raw_opcode & DW_CFAOpCodeMask_OpcodeHi) != 0)
|
||||||
|
{
|
||||||
|
opcode = (raw_opcode & DW_CFAOpCodeMask_OpcodeHi);
|
||||||
|
implicit_operand = raw_opcode & DW_CFAOpCodeMask_Operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: apply opcode
|
||||||
|
U64 new_base_pc_off = cfi_row.base_pc_off;
|
||||||
|
switch(opcode)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
case DW_CFAOpCode_Nop:{}break;
|
||||||
|
|
||||||
|
//- rjf: location adjustments
|
||||||
|
case DW_CFAOpCode_SetLoc:
|
||||||
|
{
|
||||||
|
off += eh_read_ptr(inst_data, off, ptr_ctx->pc_vaddr + inst_data_off + off, ptr_ctx, header->table_enc, &new_base_pc_off);
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_AdvanceLoc:
|
||||||
|
{
|
||||||
|
new_base_pc_off += implicit_operand * code_align_factor;
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_AdvanceLoc1:
|
||||||
|
{
|
||||||
|
U8 delta = 0;
|
||||||
|
off += str8_deserial_read_struct(inst_data, off, &delta);
|
||||||
|
new_base_pc_off += delta;
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_AdvanceLoc2:
|
||||||
|
{
|
||||||
|
U16 delta = 0;
|
||||||
|
off += str8_deserial_read_struct(inst_data, off, &delta);
|
||||||
|
new_base_pc_off += delta;
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_AdvanceLoc4:
|
||||||
|
{
|
||||||
|
U32 delta = 0;
|
||||||
|
off += str8_deserial_read_struct(inst_data, off, &delta);
|
||||||
|
new_base_pc_off += delta;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
//- rjf: row operations
|
||||||
|
case DW_CFAOpCode_RememberState:
|
||||||
|
{
|
||||||
|
// rjf: alloc row node
|
||||||
|
DW_CFIRowNode *n = free_row;
|
||||||
|
if(n != 0)
|
||||||
|
{
|
||||||
|
SLLStackPop(free_row);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n = push_array(scratch.arena, DW_CFIRowNode, 1);
|
||||||
|
n->v.reg_rules = push_array(scratch.arena, DW_UnwindRule, reg_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: copy current state
|
||||||
|
n->v.base_pc_off = cfi_row.base_pc_off;
|
||||||
|
n->v.cfa_rule = cfi_row.cfa_rule;
|
||||||
|
MemoryCopy(n->v.reg_rules, cfi_row.reg_rules, sizeof(cfi_row.reg_rules[0])*reg_count);
|
||||||
|
|
||||||
|
// rjf: push
|
||||||
|
SLLStackPush(top_row, n);
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_RestoreState:
|
||||||
|
if(top_row != 0)
|
||||||
|
{
|
||||||
|
// rjf: pop row
|
||||||
|
DW_CFIRowNode *n = top_row;
|
||||||
|
SLLStackPop(top_row);
|
||||||
|
|
||||||
|
// rjf: copy to current state
|
||||||
|
cfi_row.base_pc_off = n->v.base_pc_off;
|
||||||
|
cfi_row.cfa_rule = n->v.cfa_rule;
|
||||||
|
MemoryCopy(cfi_row.reg_rules, n->v.reg_rules, sizeof(cfi_row.reg_rules[0])*reg_count);
|
||||||
|
|
||||||
|
// rjf: free row
|
||||||
|
SLLStackPush(free_row, n);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
//- rjf: register rules
|
||||||
|
case DW_CFAOpCode_OffsetExt:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
U64 reg_off = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®_off);
|
||||||
|
reg_off *= data_align_factor;
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_Off;
|
||||||
|
cfi_row.reg_rules[reg].s64 = (S64)reg_off;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_OffsetExtSf:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
S64 reg_off = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
off += str8_deserial_read_sleb128(inst_data, off, ®_off);
|
||||||
|
reg_off *= data_align_factor;
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_Off;
|
||||||
|
cfi_row.reg_rules[reg].s64 = reg_off;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_Undefined:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_Undefined;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_SameValue:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_SameVal;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_Register:
|
||||||
|
{
|
||||||
|
U64 dst_reg = 0;
|
||||||
|
U64 src_reg = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, &dst_reg);
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, &src_reg);
|
||||||
|
if(dst_reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[dst_reg].code = DW_UnwindRuleCode_Reg;
|
||||||
|
cfi_row.reg_rules[dst_reg].reg_code = src_reg;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_Expr:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
U64 expr_size = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, &expr_size);
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_Expr;
|
||||||
|
cfi_row.reg_rules[reg].expr = str8_substr(inst_data, r1u64(off, off+expr_size));
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_ValOffset:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
U64 val_off = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, &val_off);
|
||||||
|
val_off *= data_align_factor;
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_ValOff;
|
||||||
|
cfi_row.reg_rules[reg].s64 = (S64)val_off;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_ValOffsetSf:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
S64 val_off = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
off += str8_deserial_read_sleb128(inst_data, off, &val_off);
|
||||||
|
val_off *= data_align_factor;
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_ValOff;
|
||||||
|
cfi_row.reg_rules[reg].s64 = val_off;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_ValExpr:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
U64 expr_size = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, &expr_size);
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_ValExpr;
|
||||||
|
cfi_row.reg_rules[reg].expr = str8_substr(inst_data, r1u64(off, off+expr_size));
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_Offset:
|
||||||
|
{
|
||||||
|
U64 offset = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, &offset);
|
||||||
|
offset *= data_align_factor;
|
||||||
|
U64 reg = implicit_operand;
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg].code = DW_UnwindRuleCode_Off;
|
||||||
|
cfi_row.reg_rules[reg].s64 = (S64)offset;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
//- rjf: CFA rules
|
||||||
|
case DW_CFAOpCode_DefCfa:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
U64 reg_off = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®_off);
|
||||||
|
cfi_row.cfa_rule.code = DW_UnwindRuleCode_Reg;
|
||||||
|
cfi_row.cfa_rule.reg_code = reg;
|
||||||
|
cfi_row.cfa_rule.s64 = (S64)reg_off;
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_DefCfaSf:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
S64 reg_off = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
off += str8_deserial_read_sleb128(inst_data, off, ®_off);
|
||||||
|
cfi_row.cfa_rule.code = DW_UnwindRuleCode_Reg;
|
||||||
|
cfi_row.cfa_rule.reg_code = reg;
|
||||||
|
cfi_row.cfa_rule.s64 = (S64)(reg_off * data_align_factor);
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_DefCfaRegister:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
cfi_row.cfa_rule.code = DW_UnwindRuleCode_Reg;
|
||||||
|
cfi_row.cfa_rule.reg_code = reg;
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_DefCfaOffset:
|
||||||
|
{
|
||||||
|
U64 reg_off = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®_off);
|
||||||
|
cfi_row.cfa_rule.s64 = (S64)reg_off;
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_DefCfaOffsetSf:
|
||||||
|
{
|
||||||
|
S64 reg_off = 0;
|
||||||
|
off += str8_deserial_read_sleb128(inst_data, off, ®_off);
|
||||||
|
cfi_row.cfa_rule.s64 = (S64)reg_off;
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_DefCfaExpr:
|
||||||
|
{
|
||||||
|
U64 expr_size = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, &expr_size);
|
||||||
|
cfi_row.cfa_rule.code = DW_UnwindRuleCode_Expr;
|
||||||
|
cfi_row.cfa_rule.expr = str8_substr(inst_data, r1u64(off, off+expr_size));
|
||||||
|
}break;
|
||||||
|
|
||||||
|
//- rjf: register state resets
|
||||||
|
case DW_CFAOpCode_Restore:
|
||||||
|
{
|
||||||
|
U64 reg = implicit_operand;
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg] = initial_row.reg_rules[reg];
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
case DW_CFAOpCode_RestoreExt:
|
||||||
|
{
|
||||||
|
U64 reg = 0;
|
||||||
|
off += str8_deserial_read_uleb128(inst_data, off, ®);
|
||||||
|
if(reg < reg_count)
|
||||||
|
{
|
||||||
|
cfi_row.reg_rules[reg] = initial_row.reg_rules[reg];
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: exit early if we found the CFI row for this pc
|
||||||
|
{
|
||||||
|
U64 pc_off = (pc - fde.pc_range.min);
|
||||||
|
if(cfi_row.base_pc_off <= pc_off && pc_off < new_base_pc_off)
|
||||||
|
{
|
||||||
|
computed_row = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: commit changes to CFI row base pc
|
||||||
|
cfi_row.base_pc_off = new_base_pc_off;
|
||||||
|
|
||||||
|
// rjf: abort if we made no parsing progress
|
||||||
|
if(off == start_off)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: on cie program -> save current state as 'initial state', to be
|
||||||
|
// potentially restored by fde
|
||||||
|
{
|
||||||
|
initial_row.base_pc_off = cfi_row.base_pc_off;
|
||||||
|
initial_row.cfa_rule = cfi_row.cfa_rule;
|
||||||
|
MemoryCopy(initial_row.reg_rules, cfi_row.reg_rules, sizeof(initial_row.reg_rules[0])*reg_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: evaluate frame base vaddr (CFA) via CFI row rule
|
||||||
|
U64 cfa = 0;
|
||||||
|
if(!done) switch(cfi_row.cfa_rule.code)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
case DW_UnwindRuleCode_Reg:
|
||||||
|
{
|
||||||
|
U64 cfa_reg_val = 0;
|
||||||
|
DW_RegCode dw_reg_code = cfi_row.cfa_rule.reg_code;
|
||||||
|
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, dw_reg_code);
|
||||||
|
arch_reg_block_read_range(arch_info, regs, arch_info->reg_code_rng_table[reg_code], &cfa_reg_val);
|
||||||
|
cfa = cfa_reg_val + cfi_row.cfa_rule.s64;
|
||||||
|
}break;
|
||||||
|
case DW_UnwindRuleCode_Expr:
|
||||||
|
{
|
||||||
|
String8 expr = cfi_row.cfa_rule.expr;
|
||||||
|
DW_EvalState eval_state = {0};
|
||||||
|
DW_Eval eval = dw_eval(scratch.arena, cie.format, arch, memory_map, regs, 0, 0, tls_vaddr, &eval_state, expr, 1000);
|
||||||
|
if(eval.status == DW_EvalStatus_FailedMemoryRead)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = eval.missed_read_vaddr_range;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cfa = eval.val.u512.u64[0];
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: apply CFI row rules to registers
|
||||||
|
if(!done) for EachIndex(reg_idx, reg_count)
|
||||||
|
{
|
||||||
|
DW_UnwindRule *rule = &cfi_row.reg_rules[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];
|
||||||
|
U64 reg_size = dim_1u16(reg_rng);
|
||||||
|
switch(rule->code)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case DW_UnwindRuleCode_Undefined:
|
||||||
|
case DW_UnwindRuleCode_SameVal:{}break;
|
||||||
|
case DW_UnwindRuleCode_Off:
|
||||||
|
{
|
||||||
|
Temp temp = temp_begin(scratch.arena);
|
||||||
|
U64 addr = cfa + rule->s64;
|
||||||
|
Rng1U64 reg_value_vaddr_range = r1u64(addr, addr+reg_size);
|
||||||
|
U8 *reg_value_buffer = push_array(temp.arena, U8, reg_size);
|
||||||
|
if(memory_map_read(memory_map, reg_value_vaddr_range, reg_value_buffer) != reg_size)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = reg_value_vaddr_range;
|
||||||
|
}
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
arch_reg_block_write_range(arch_info, new_regs, reg_rng, reg_value_buffer);
|
||||||
|
}
|
||||||
|
temp_end(temp);
|
||||||
|
}break;
|
||||||
|
case DW_UnwindRuleCode_ValOff:
|
||||||
|
{
|
||||||
|
U64 reg_value = cfa + rule->s64;
|
||||||
|
Rng1U16 write_range = r1u16(reg_rng.min, Min(reg_rng.max, reg_rng.min + sizeof(reg_value)));
|
||||||
|
arch_reg_block_write_range(arch_info, new_regs, write_range, ®_value);
|
||||||
|
}break;
|
||||||
|
case DW_UnwindRuleCode_Reg:
|
||||||
|
{
|
||||||
|
Temp temp = temp_begin(scratch.arena);
|
||||||
|
DW_RegCode src_reg_code_dw = rule->reg_code;
|
||||||
|
ARCH_RegCode src_reg_code = arch_reg_code_from_dw(arch, src_reg_code_dw);
|
||||||
|
Rng1U16 src_reg_rng = arch_info->reg_code_rng_table[src_reg_code];
|
||||||
|
U64 src_reg_size = dim_1u16(src_reg_rng);
|
||||||
|
U64 read_size = Min(src_reg_size, reg_size);
|
||||||
|
U8 *src_reg_val_buffer = push_array(temp.arena, U8, read_size);
|
||||||
|
arch_reg_block_read_range(arch_info, regs, src_reg_rng, src_reg_val_buffer);
|
||||||
|
arch_reg_block_write_range(arch_info, new_regs, reg_rng, src_reg_val_buffer);
|
||||||
|
temp_end(temp);
|
||||||
|
}break;
|
||||||
|
case DW_UnwindRuleCode_Expr:
|
||||||
|
{
|
||||||
|
Temp temp = temp_begin(scratch.arena);
|
||||||
|
String8 expr = rule->expr;
|
||||||
|
DW_EvalState eval_state = {0};
|
||||||
|
DW_Eval eval = dw_eval(scratch.arena, cie.format, arch, memory_map, regs, 0, cfa, tls_vaddr, &eval_state, expr, 1000);
|
||||||
|
if(eval.status == DW_EvalStatus_FailedMemoryRead)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = eval.missed_read_vaddr_range;
|
||||||
|
}
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
U64 reg_val_vaddr = eval.val.u512.u64[0];
|
||||||
|
Rng1U64 reg_value_vaddr_range = r1u64(reg_val_vaddr, reg_val_vaddr+reg_size);
|
||||||
|
U8 *reg_value_buffer = push_array(temp.arena, U8, reg_size);
|
||||||
|
if(memory_map_read(memory_map, reg_value_vaddr_range, reg_value_buffer) != reg_size)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = reg_value_vaddr_range;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arch_reg_block_write_range(arch_info, new_regs, reg_rng, reg_value_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp_end(scratch);
|
||||||
|
}break;
|
||||||
|
case DW_UnwindRuleCode_ValExpr:
|
||||||
|
{
|
||||||
|
Temp temp = temp_begin(scratch.arena);
|
||||||
|
String8 expr = rule->expr;
|
||||||
|
DW_EvalState eval_state = {0};
|
||||||
|
DW_Eval eval = dw_eval(scratch.arena, cie.format, arch, memory_map, regs, 0, cfa, tls_vaddr, &eval_state, expr, 1000);
|
||||||
|
if(eval.status == DW_EvalStatus_FailedMemoryRead)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = eval.missed_read_vaddr_range;
|
||||||
|
}
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
U512 reg_val = eval.val.u512;
|
||||||
|
arch_reg_block_write_range(arch_info, new_regs, reg_rng, ®_val);
|
||||||
|
}
|
||||||
|
temp_end(scratch);
|
||||||
|
}break;
|
||||||
|
case DW_UnwindRuleCode_Architectural:
|
||||||
|
{
|
||||||
|
// NOTE(rjf): the DWARF spec says that this code implies:
|
||||||
|
//
|
||||||
|
// "The rule is defined externally to this specification by the augmenter"
|
||||||
|
//
|
||||||
|
// so leaving this blank until we know exactly what that means.
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- TODO(rjf): old code was replacing the stack pointer with the CFA.
|
||||||
|
// this is surely incorrect, no? isn't the entire point of the CFA
|
||||||
|
// to be *not* necessarily the stack pointer? and wouldn't the stack
|
||||||
|
// pointer be modified via the above rules? so what are we doing
|
||||||
|
// here?
|
||||||
|
//
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
arch_reg_block_write_sp(arch_info, new_regs, cfa);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: commit new register values, if we succeeded
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
result.status = UWND_StepStatus_Good;
|
||||||
|
MemoryCopy(regs, new_regs, arch_info->reg_block_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scratch_end(scratch);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef EH_FRAME_UNWIND_H
|
||||||
|
#define EH_FRAME_UNWIND_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Module Unwind Info Type
|
||||||
|
|
||||||
|
typedef struct EH_UWND_ModuleUnwindInfo EH_UWND_ModuleUnwindInfo;
|
||||||
|
struct EH_UWND_ModuleUnwindInfo
|
||||||
|
{
|
||||||
|
EH_FrameHdr header;
|
||||||
|
EH_PtrCtx ptr_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Unwinding Abstraction Implementation
|
||||||
|
|
||||||
|
internal UWND_StepResult eh_uwnd_step(Arch arch, MemoryMap *memory_map, UWND_ModuleInfo *module_info, U64 tls_vaddr, void *regs, U64 *cfa_out);
|
||||||
|
|
||||||
|
#endif // EH_FRAME_UNWIND_H
|
||||||
@@ -276,7 +276,7 @@ commit_memory_large(void *ptr, U64 size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Shared Memory
|
//~ rjf: @per_os_impl Shared Memory
|
||||||
|
|
||||||
internal SharedMemory
|
internal SharedMemory
|
||||||
shared_memory_alloc(U64 size, String8 name)
|
shared_memory_alloc(U64 size, String8 name)
|
||||||
|
|||||||
@@ -515,7 +515,6 @@ lnx_dmn_module_info_from_process_module(Arena *arena, pid_t pid, int memory_fd,
|
|||||||
info->tls_index = tls_index;
|
info->tls_index = tls_index;
|
||||||
info->tls_offset = tls_offset;
|
info->tls_offset = tls_offset;
|
||||||
info->eh_frame_header_vaddr_range = eh_frame_header_vaddr_range;
|
info->eh_frame_header_vaddr_range = eh_frame_header_vaddr_range;
|
||||||
info->cfi_rebase = module_rebase;
|
|
||||||
info->raddbg_info_voff_range = raddbg_info_voff_range;
|
info->raddbg_info_voff_range = raddbg_info_voff_range;
|
||||||
info->raddbg_is_attached_marker_voff = raddbg_is_attached_marker_voff;
|
info->raddbg_is_attached_marker_voff = raddbg_is_attached_marker_voff;
|
||||||
}
|
}
|
||||||
@@ -1016,6 +1015,7 @@ lnx_dmn_thread_alloc(LNX_DMN_Process *process, LNX_DMN_ThreadState thread_state,
|
|||||||
thread->state = thread_state;
|
thread->state = thread_state;
|
||||||
thread->process = process;
|
thread->process = process;
|
||||||
thread->reg_block = reg_block;
|
thread->reg_block = reg_block;
|
||||||
|
thread->dtv_base_vaddr = lnx_dmn_tls_root_vaddr_from_reg_block(process->fd, process->ctx->arch, reg_block);
|
||||||
if(thread_state == LNX_DMN_ThreadState_Stopped)
|
if(thread_state == LNX_DMN_ThreadState_Stopped)
|
||||||
{
|
{
|
||||||
thread->is_reg_block_dirty = !lnx_dmn_thread_read_reg_block(thread);
|
thread->is_reg_block_dirty = !lnx_dmn_thread_read_reg_block(thread);
|
||||||
@@ -1823,6 +1823,30 @@ lnx_dmn_set_single_step_flag(LNX_DMN_Thread *thread, B32 is_on)
|
|||||||
return is_flag_set;
|
return is_flag_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
lnx_dmn_tls_root_vaddr_from_reg_block(int fd, Arch arch, void *reg_block)
|
||||||
|
{
|
||||||
|
U64 result = 0;
|
||||||
|
switch(arch)
|
||||||
|
{
|
||||||
|
case Arch_x86:
|
||||||
|
case Arch_arm32:
|
||||||
|
case Arch_arm64:
|
||||||
|
case Arch_Null:
|
||||||
|
case Arch_COUNT:{}break;
|
||||||
|
case Arch_x64:
|
||||||
|
{
|
||||||
|
X64_RegBlock *reg_block_x64 = (X64_RegBlock *)reg_block;
|
||||||
|
U64 dtv_pointer = 0;
|
||||||
|
if(lnx_dmn_read_struct(fd, reg_block_x64->fsbase + 8, &dtv_pointer))
|
||||||
|
{
|
||||||
|
result = dtv_pointer;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
lnx_dmn_thread_ptr_list_push_node(LNX_DMN_ThreadPtrList *list, LNX_DMN_ThreadPtrNode *n)
|
lnx_dmn_thread_ptr_list_push_node(LNX_DMN_ThreadPtrList *list, LNX_DMN_ThreadPtrNode *n)
|
||||||
{
|
{
|
||||||
@@ -1896,6 +1920,8 @@ lnx_dmn_push_event_create_thread(Arena *arena, DMN_EventList *events, LNX_DMN_Th
|
|||||||
e->thread = lnx_dmn_handle_from_thread(thread);
|
e->thread = lnx_dmn_handle_from_thread(thread);
|
||||||
e->arch = thread->process->ctx->arch;
|
e->arch = thread->process->ctx->arch;
|
||||||
e->code = thread->tid;
|
e->code = thread->tid;
|
||||||
|
// TODO(rjf): e->stack_pointer = ???;
|
||||||
|
e->tls_root_vaddr = thread->dtv_base_vaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
@@ -3239,46 +3265,6 @@ dmn_process_write(DMN_Handle process_handle, Rng1U64 range, void *src)
|
|||||||
|
|
||||||
//- rjf: threads
|
//- rjf: threads
|
||||||
|
|
||||||
internal U64
|
|
||||||
dmn_stack_base_vaddr_from_thread(DMN_Handle thread_handle)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
dmn_tls_root_vaddr_from_thread(DMN_Handle thread_handle)
|
|
||||||
{
|
|
||||||
U64 tls_root_vaddr = max_U64;
|
|
||||||
DMN_AccessScope
|
|
||||||
{
|
|
||||||
LNX_DMN_Thread *thread = lnx_dmn_thread_from_handle(thread_handle);
|
|
||||||
if(thread)
|
|
||||||
{
|
|
||||||
switch(thread->process->ctx->arch)
|
|
||||||
{
|
|
||||||
case Arch_Null: {} break;
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
X64_RegBlock *reg_block = thread->reg_block;
|
|
||||||
U64 dtv_pointer = 0;
|
|
||||||
if(lnx_dmn_read_struct(thread->process->fd, reg_block->fsbase + 8, &dtv_pointer))
|
|
||||||
{
|
|
||||||
tls_root_vaddr = dtv_pointer;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case Arch_x86:
|
|
||||||
case Arch_arm32:
|
|
||||||
case Arch_arm64:
|
|
||||||
{
|
|
||||||
NotImplemented;
|
|
||||||
} break;
|
|
||||||
default: { InvalidPath; } break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tls_root_vaddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
dmn_thread_read_reg_block(DMN_Handle thread_handle, void *reg_block)
|
dmn_thread_read_reg_block(DMN_Handle thread_handle, void *reg_block)
|
||||||
{
|
{
|
||||||
@@ -3316,6 +3302,40 @@ dmn_thread_write_reg_block(DMN_Handle thread_handle, void *reg_block)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
dmn_thread_get_module_tls_vaddr(DMN_Handle thread_handle, DMN_Handle module_handle, U64 *vaddr_out)
|
||||||
|
{
|
||||||
|
B32 result = 0;
|
||||||
|
DMN_AccessScope
|
||||||
|
{
|
||||||
|
LNX_DMN_Thread *thread = lnx_dmn_thread_from_handle(thread_handle);
|
||||||
|
if(thread != 0)
|
||||||
|
{
|
||||||
|
LNX_DMN_Process *process = thread->process;
|
||||||
|
LNX_DMN_Module *module = lnx_dmn_module_from_handle(module_handle);
|
||||||
|
if(process != 0 && module != 0)
|
||||||
|
{
|
||||||
|
Arch arch = thread->process->ctx->arch;
|
||||||
|
U64 addr_size = byte_size_from_arch(arch);
|
||||||
|
U64 dtv_base_vaddr = thread->dtv_base_vaddr;
|
||||||
|
U64 dtv_entry_size = 2 * addr_size;
|
||||||
|
U64 module_dtv_ptr_vaddr = dtv_base_vaddr + module->tls_index * dtv_entry_size;
|
||||||
|
U64 module_dtv_vaddr = 0;
|
||||||
|
if(lnx_dmn_read(process->fd, r1u64(module_dtv_ptr_vaddr, module_dtv_ptr_vaddr+addr_size), &module_dtv_vaddr) == addr_size)
|
||||||
|
{
|
||||||
|
U64 unallocated_dtv_vaddr_marker = (addr_size == 4 ? max_U32 : max_U64);
|
||||||
|
if(module_dtv_vaddr != unallocated_dtv_vaddr_marker)
|
||||||
|
{
|
||||||
|
vaddr_out[0] = module_dtv_vaddr + module->tls_offset;
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: system process listing
|
//- rjf: system process listing
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ typedef struct LNX_DMN_Thread
|
|||||||
B32 pass_through_signal;
|
B32 pass_through_signal;
|
||||||
U64 pass_through_signo;
|
U64 pass_through_signo;
|
||||||
U64 orig_rax;
|
U64 orig_rax;
|
||||||
|
U64 dtv_base_vaddr;
|
||||||
|
|
||||||
struct LNX_DMN_Thread *next;
|
struct LNX_DMN_Thread *next;
|
||||||
struct LNX_DMN_Thread *prev;
|
struct LNX_DMN_Thread *prev;
|
||||||
@@ -476,6 +477,7 @@ internal void lnx_dmn_thread_write_sp(LNX_DMN_Thread *thread, U64 sp);
|
|||||||
internal B32 lnx_dmn_thread_read_reg_block(LNX_DMN_Thread *thread);
|
internal B32 lnx_dmn_thread_read_reg_block(LNX_DMN_Thread *thread);
|
||||||
internal B32 lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread);
|
internal B32 lnx_dmn_thread_write_reg_block(LNX_DMN_Thread *thread);
|
||||||
internal B32 lnx_dmn_set_single_step_flag(LNX_DMN_Thread *thread, B32 is_on);
|
internal B32 lnx_dmn_set_single_step_flag(LNX_DMN_Thread *thread, B32 is_on);
|
||||||
|
internal U64 lnx_dmn_tls_root_vaddr_from_reg_block(int fd, Arch arch, void *reg_block);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ List Helpers
|
//~ List Helpers
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ lnx_window_from_x11window(Window window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
|
//~ rjf: @per_os_impl Main Initialization API (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_init(void)
|
wm_init(void)
|
||||||
@@ -75,7 +75,7 @@ wm_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Graphics System Info (Implemented Per-OS)
|
//~ rjf: @per_os_impl Graphics System Info (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_SystemInfo *
|
internal WM_SystemInfo *
|
||||||
wm_get_system_info(void)
|
wm_get_system_info(void)
|
||||||
@@ -84,7 +84,7 @@ wm_get_system_info(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Clipboards (Implemented Per-OS)
|
//~ rjf: @per_os_impl Clipboards (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_set_clipboard_text(String8 string)
|
wm_set_clipboard_text(String8 string)
|
||||||
@@ -100,7 +100,7 @@ wm_get_clipboard_text(Arena *arena)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Windows (Implemented Per-OS)
|
//~ rjf: @per_os_impl Windows (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_Window
|
internal WM_Window
|
||||||
wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title)
|
wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title)
|
||||||
@@ -342,7 +342,7 @@ wm_dpi_from_window(WM_Window handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks External Windows (Implemented Per-OS)
|
//~ rjf: @per_os_impl External Windows (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_ExtWindow
|
internal WM_ExtWindow
|
||||||
wm_focused_external_window(void)
|
wm_focused_external_window(void)
|
||||||
@@ -359,7 +359,7 @@ wm_focus_external_window(WM_ExtWindow handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Monitors (Implemented Per-OS)
|
//~ rjf: @per_os_impl Monitors (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_MonitorArray
|
internal WM_MonitorArray
|
||||||
wm_push_monitors_array(Arena *arena)
|
wm_push_monitors_array(Arena *arena)
|
||||||
@@ -407,7 +407,7 @@ wm_dpi_from_monitor(WM_Monitor monitor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Events (Implemented Per-OS)
|
//~ rjf: @per_os_impl Events (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_send_wakeup_event(void)
|
wm_send_wakeup_event(void)
|
||||||
@@ -449,209 +449,209 @@ wm_get_events(Arena *arena, B32 wait)
|
|||||||
{
|
{
|
||||||
default:{}break;
|
default:{}break;
|
||||||
|
|
||||||
//- rjf: key presses/releases
|
//- rjf: key presses/releases
|
||||||
case KeyPress:
|
case KeyPress:
|
||||||
case KeyRelease:
|
case KeyRelease:
|
||||||
{
|
|
||||||
// rjf: determine flags
|
|
||||||
WM_Modifiers modifiers = 0;
|
|
||||||
if(evt.xkey.state & ShiftMask) { modifiers |= WM_Modifier_Shift; }
|
|
||||||
if(evt.xkey.state & ControlMask) { modifiers |= WM_Modifier_Ctrl; }
|
|
||||||
if(evt.xkey.state & Mod1Mask) { modifiers |= WM_Modifier_Alt; }
|
|
||||||
|
|
||||||
// rjf: map keycode -> keysym & codepoint
|
|
||||||
LNX_WM_Window *window = lnx_window_from_x11window(evt.xkey.window);
|
|
||||||
KeySym keysym = 0;
|
|
||||||
U8 text[256] = {0};
|
|
||||||
U64 text_size = Xutf8LookupString(window->xic, &evt.xkey, (char *)text, sizeof(text), &keysym, 0);
|
|
||||||
|
|
||||||
// rjf: map keysym -> WM_Key
|
|
||||||
B32 is_right_sided = 0;
|
|
||||||
WM_Key key = WM_Key_Null;
|
|
||||||
switch(keysym)
|
|
||||||
{
|
{
|
||||||
default:
|
// rjf: determine flags
|
||||||
{
|
WM_Modifiers modifiers = 0;
|
||||||
if(0){}
|
if(evt.xkey.state & ShiftMask) { modifiers |= WM_Modifier_Shift; }
|
||||||
else if(XK_F1 <= keysym && keysym <= XK_F24) { key = (WM_Key)(WM_Key_F1 + (keysym - XK_F1)); }
|
if(evt.xkey.state & ControlMask) { modifiers |= WM_Modifier_Ctrl; }
|
||||||
else if('0' <= keysym && keysym <= '9') { key = WM_Key_0 + (keysym-'0'); }
|
if(evt.xkey.state & Mod1Mask) { modifiers |= WM_Modifier_Alt; }
|
||||||
}break;
|
|
||||||
case XK_Escape:{key = WM_Key_Esc;};break;
|
|
||||||
case XK_BackSpace:{key = WM_Key_Backspace;}break;
|
|
||||||
case XK_Delete:{key = WM_Key_Delete;}break;
|
|
||||||
case XK_Return:{key = WM_Key_Return;}break;
|
|
||||||
case XK_Pause:{key = WM_Key_Pause;}break;
|
|
||||||
case XK_Tab:{key = WM_Key_Tab;}break;
|
|
||||||
case XK_Left:{key = WM_Key_Left;}break;
|
|
||||||
case XK_Right:{key = WM_Key_Right;}break;
|
|
||||||
case XK_Up:{key = WM_Key_Up;}break;
|
|
||||||
case XK_Down:{key = WM_Key_Down;}break;
|
|
||||||
case XK_Home:{key = WM_Key_Home;}break;
|
|
||||||
case XK_End:{key = WM_Key_End;}break;
|
|
||||||
case XK_Page_Up:{key = WM_Key_PageUp;}break;
|
|
||||||
case XK_Page_Down:{key = WM_Key_PageDown;}break;
|
|
||||||
case XK_Alt_L:{ key = WM_Key_Alt; }break;
|
|
||||||
case XK_Alt_R:{ key = WM_Key_Alt; is_right_sided = 1;}break;
|
|
||||||
case XK_Shift_L:{ key = WM_Key_Shift; }break;
|
|
||||||
case XK_Shift_R:{ key = WM_Key_Shift; is_right_sided = 1;}break;
|
|
||||||
case XK_Control_L:{ key = WM_Key_Ctrl; }break;
|
|
||||||
case XK_Control_R:{ key = WM_Key_Ctrl; is_right_sided = 1;}break;
|
|
||||||
case '-':{key = WM_Key_Minus;}break;
|
|
||||||
case '=':{key = WM_Key_Equal;}break;
|
|
||||||
case '[':{key = WM_Key_LeftBracket;}break;
|
|
||||||
case ']':{key = WM_Key_RightBracket;}break;
|
|
||||||
case ';':{key = WM_Key_Semicolon;}break;
|
|
||||||
case '\'':{key = WM_Key_Quote;}break;
|
|
||||||
case '.':{key = WM_Key_Period;}break;
|
|
||||||
case ',':{key = WM_Key_Comma;}break;
|
|
||||||
case '/':{key = WM_Key_Slash;}break;
|
|
||||||
case '\\':{key = WM_Key_BackSlash;}break;
|
|
||||||
case '\t':{key = WM_Key_Tab;}break;
|
|
||||||
case 'a':case 'A':{key = WM_Key_A;}break;
|
|
||||||
case 'b':case 'B':{key = WM_Key_B;}break;
|
|
||||||
case 'c':case 'C':{key = WM_Key_C;}break;
|
|
||||||
case 'd':case 'D':{key = WM_Key_D;}break;
|
|
||||||
case 'e':case 'E':{key = WM_Key_E;}break;
|
|
||||||
case 'f':case 'F':{key = WM_Key_F;}break;
|
|
||||||
case 'g':case 'G':{key = WM_Key_G;}break;
|
|
||||||
case 'h':case 'H':{key = WM_Key_H;}break;
|
|
||||||
case 'i':case 'I':{key = WM_Key_I;}break;
|
|
||||||
case 'j':case 'J':{key = WM_Key_J;}break;
|
|
||||||
case 'k':case 'K':{key = WM_Key_K;}break;
|
|
||||||
case 'l':case 'L':{key = WM_Key_L;}break;
|
|
||||||
case 'm':case 'M':{key = WM_Key_M;}break;
|
|
||||||
case 'n':case 'N':{key = WM_Key_N;}break;
|
|
||||||
case 'o':case 'O':{key = WM_Key_O;}break;
|
|
||||||
case 'p':case 'P':{key = WM_Key_P;}break;
|
|
||||||
case 'q':case 'Q':{key = WM_Key_Q;}break;
|
|
||||||
case 'r':case 'R':{key = WM_Key_R;}break;
|
|
||||||
case 's':case 'S':{key = WM_Key_S;}break;
|
|
||||||
case 't':case 'T':{key = WM_Key_T;}break;
|
|
||||||
case 'u':case 'U':{key = WM_Key_U;}break;
|
|
||||||
case 'v':case 'V':{key = WM_Key_V;}break;
|
|
||||||
case 'w':case 'W':{key = WM_Key_W;}break;
|
|
||||||
case 'x':case 'X':{key = WM_Key_X;}break;
|
|
||||||
case 'y':case 'Y':{key = WM_Key_Y;}break;
|
|
||||||
case 'z':case 'Z':{key = WM_Key_Z;}break;
|
|
||||||
case ' ':{key = WM_Key_Space;}break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push text event
|
// rjf: map keycode -> keysym & codepoint
|
||||||
if(evt.type == KeyPress && text_size != 0)
|
LNX_WM_Window *window = lnx_window_from_x11window(evt.xkey.window);
|
||||||
{
|
KeySym keysym = 0;
|
||||||
for(U64 off = 0; off < text_size;)
|
U8 text[256] = {0};
|
||||||
|
U64 text_size = Xutf8LookupString(window->xic, &evt.xkey, (char *)text, sizeof(text), &keysym, 0);
|
||||||
|
|
||||||
|
// rjf: map keysym -> WM_Key
|
||||||
|
B32 is_right_sided = 0;
|
||||||
|
WM_Key key = WM_Key_Null;
|
||||||
|
switch(keysym)
|
||||||
{
|
{
|
||||||
UnicodeDecode decode = utf8_decode(text+off, text_size-off);
|
default:
|
||||||
if(decode.codepoint != 0 && (decode.codepoint >= 32 || decode.codepoint == '\t'))
|
|
||||||
{
|
{
|
||||||
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_Text);
|
if(0){}
|
||||||
e->window.u64[0] = (U64)window;
|
else if(XK_F1 <= keysym && keysym <= XK_F24) { key = (WM_Key)(WM_Key_F1 + (keysym - XK_F1)); }
|
||||||
e->character = decode.codepoint;
|
else if('0' <= keysym && keysym <= '9') { key = WM_Key_0 + (keysym-'0'); }
|
||||||
}
|
}break;
|
||||||
if(decode.inc == 0)
|
case XK_Escape:{key = WM_Key_Esc;};break;
|
||||||
{
|
case XK_BackSpace:{key = WM_Key_Backspace;}break;
|
||||||
break;
|
case XK_Delete:{key = WM_Key_Delete;}break;
|
||||||
}
|
case XK_Return:{key = WM_Key_Return;}break;
|
||||||
off += decode.inc;
|
case XK_Pause:{key = WM_Key_Pause;}break;
|
||||||
|
case XK_Tab:{key = WM_Key_Tab;}break;
|
||||||
|
case XK_Left:{key = WM_Key_Left;}break;
|
||||||
|
case XK_Right:{key = WM_Key_Right;}break;
|
||||||
|
case XK_Up:{key = WM_Key_Up;}break;
|
||||||
|
case XK_Down:{key = WM_Key_Down;}break;
|
||||||
|
case XK_Home:{key = WM_Key_Home;}break;
|
||||||
|
case XK_End:{key = WM_Key_End;}break;
|
||||||
|
case XK_Page_Up:{key = WM_Key_PageUp;}break;
|
||||||
|
case XK_Page_Down:{key = WM_Key_PageDown;}break;
|
||||||
|
case XK_Alt_L:{ key = WM_Key_Alt; }break;
|
||||||
|
case XK_Alt_R:{ key = WM_Key_Alt; is_right_sided = 1;}break;
|
||||||
|
case XK_Shift_L:{ key = WM_Key_Shift; }break;
|
||||||
|
case XK_Shift_R:{ key = WM_Key_Shift; is_right_sided = 1;}break;
|
||||||
|
case XK_Control_L:{ key = WM_Key_Ctrl; }break;
|
||||||
|
case XK_Control_R:{ key = WM_Key_Ctrl; is_right_sided = 1;}break;
|
||||||
|
case '-':{key = WM_Key_Minus;}break;
|
||||||
|
case '=':{key = WM_Key_Equal;}break;
|
||||||
|
case '[':{key = WM_Key_LeftBracket;}break;
|
||||||
|
case ']':{key = WM_Key_RightBracket;}break;
|
||||||
|
case ';':{key = WM_Key_Semicolon;}break;
|
||||||
|
case '\'':{key = WM_Key_Quote;}break;
|
||||||
|
case '.':{key = WM_Key_Period;}break;
|
||||||
|
case ',':{key = WM_Key_Comma;}break;
|
||||||
|
case '/':{key = WM_Key_Slash;}break;
|
||||||
|
case '\\':{key = WM_Key_BackSlash;}break;
|
||||||
|
case '\t':{key = WM_Key_Tab;}break;
|
||||||
|
case 'a':case 'A':{key = WM_Key_A;}break;
|
||||||
|
case 'b':case 'B':{key = WM_Key_B;}break;
|
||||||
|
case 'c':case 'C':{key = WM_Key_C;}break;
|
||||||
|
case 'd':case 'D':{key = WM_Key_D;}break;
|
||||||
|
case 'e':case 'E':{key = WM_Key_E;}break;
|
||||||
|
case 'f':case 'F':{key = WM_Key_F;}break;
|
||||||
|
case 'g':case 'G':{key = WM_Key_G;}break;
|
||||||
|
case 'h':case 'H':{key = WM_Key_H;}break;
|
||||||
|
case 'i':case 'I':{key = WM_Key_I;}break;
|
||||||
|
case 'j':case 'J':{key = WM_Key_J;}break;
|
||||||
|
case 'k':case 'K':{key = WM_Key_K;}break;
|
||||||
|
case 'l':case 'L':{key = WM_Key_L;}break;
|
||||||
|
case 'm':case 'M':{key = WM_Key_M;}break;
|
||||||
|
case 'n':case 'N':{key = WM_Key_N;}break;
|
||||||
|
case 'o':case 'O':{key = WM_Key_O;}break;
|
||||||
|
case 'p':case 'P':{key = WM_Key_P;}break;
|
||||||
|
case 'q':case 'Q':{key = WM_Key_Q;}break;
|
||||||
|
case 'r':case 'R':{key = WM_Key_R;}break;
|
||||||
|
case 's':case 'S':{key = WM_Key_S;}break;
|
||||||
|
case 't':case 'T':{key = WM_Key_T;}break;
|
||||||
|
case 'u':case 'U':{key = WM_Key_U;}break;
|
||||||
|
case 'v':case 'V':{key = WM_Key_V;}break;
|
||||||
|
case 'w':case 'W':{key = WM_Key_W;}break;
|
||||||
|
case 'x':case 'X':{key = WM_Key_X;}break;
|
||||||
|
case 'y':case 'Y':{key = WM_Key_Y;}break;
|
||||||
|
case 'z':case 'Z':{key = WM_Key_Z;}break;
|
||||||
|
case ' ':{key = WM_Key_Space;}break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push key event
|
// rjf: push text event
|
||||||
|
if(evt.type == KeyPress && text_size != 0)
|
||||||
|
{
|
||||||
|
for(U64 off = 0; off < text_size;)
|
||||||
|
{
|
||||||
|
UnicodeDecode decode = utf8_decode(text+off, text_size-off);
|
||||||
|
if(decode.codepoint != 0 && (decode.codepoint >= 32 || decode.codepoint == '\t'))
|
||||||
|
{
|
||||||
|
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_Text);
|
||||||
|
e->window.u64[0] = (U64)window;
|
||||||
|
e->character = decode.codepoint;
|
||||||
|
}
|
||||||
|
if(decode.inc == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
off += decode.inc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: push key event
|
||||||
|
{
|
||||||
|
WM_Event *e = wm_event_list_push_new(arena, &evts, evt.type == KeyPress ? WM_EventKind_Press : WM_EventKind_Release);
|
||||||
|
e->window.u64[0] = (U64)window;
|
||||||
|
e->modifiers = modifiers;
|
||||||
|
e->key = key;
|
||||||
|
e->right_sided = is_right_sided;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
//- rjf: mouse button presses/releases
|
||||||
|
case ButtonPress:
|
||||||
|
case ButtonRelease:
|
||||||
{
|
{
|
||||||
WM_Event *e = wm_event_list_push_new(arena, &evts, evt.type == KeyPress ? WM_EventKind_Press : WM_EventKind_Release);
|
// rjf: determine flags
|
||||||
e->window.u64[0] = (U64)window;
|
WM_Modifiers modifiers = 0;
|
||||||
e->modifiers = modifiers;
|
if(evt.xbutton.state & ShiftMask) { modifiers |= WM_Modifier_Shift; }
|
||||||
e->key = key;
|
if(evt.xbutton.state & ControlMask) { modifiers |= WM_Modifier_Ctrl; }
|
||||||
e->right_sided = is_right_sided;
|
if(evt.xbutton.state & Mod1Mask) { modifiers |= WM_Modifier_Alt; }
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: mouse button presses/releases
|
// rjf: map button -> WM_Key
|
||||||
case ButtonPress:
|
WM_Key key = WM_Key_Null;
|
||||||
case ButtonRelease:
|
switch(evt.xbutton.button)
|
||||||
{
|
{
|
||||||
// rjf: determine flags
|
default:{}break;
|
||||||
WM_Modifiers modifiers = 0;
|
case Button1:{key = WM_Key_LeftMouseButton;}break;
|
||||||
if(evt.xbutton.state & ShiftMask) { modifiers |= WM_Modifier_Shift; }
|
case Button2:{key = WM_Key_MiddleMouseButton;}break;
|
||||||
if(evt.xbutton.state & ControlMask) { modifiers |= WM_Modifier_Ctrl; }
|
case Button3:{key = WM_Key_RightMouseButton;}break;
|
||||||
if(evt.xbutton.state & Mod1Mask) { modifiers |= WM_Modifier_Alt; }
|
}
|
||||||
|
|
||||||
// rjf: map button -> WM_Key
|
// rjf: push event
|
||||||
WM_Key key = WM_Key_Null;
|
LNX_WM_Window *window = lnx_window_from_x11window(evt.xbutton.window);
|
||||||
switch(evt.xbutton.button)
|
if(key != WM_Key_Null)
|
||||||
{
|
{
|
||||||
default:{}break;
|
WM_Event *e = wm_event_list_push_new(arena, &evts, evt.type == ButtonPress ? WM_EventKind_Press : WM_EventKind_Release);
|
||||||
case Button1:{key = WM_Key_LeftMouseButton;}break;
|
e->window.u64[0] = (U64)window;
|
||||||
case Button2:{key = WM_Key_MiddleMouseButton;}break;
|
e->modifiers = modifiers;
|
||||||
case Button3:{key = WM_Key_RightMouseButton;}break;
|
e->key = key;
|
||||||
}
|
e->pos = v2f32((F32)evt.xbutton.x, (F32)evt.xbutton.y);
|
||||||
|
}
|
||||||
|
else if(evt.xbutton.button == Button4 ||
|
||||||
|
evt.xbutton.button == Button5)
|
||||||
|
{
|
||||||
|
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_Scroll);
|
||||||
|
e->window.u64[0] = (U64)window;
|
||||||
|
e->modifiers = modifiers;
|
||||||
|
e->delta = v2f32(0, evt.xbutton.button == Button4 ? -1.f : +1.f);
|
||||||
|
e->pos = v2f32((F32)evt.xbutton.x, (F32)evt.xbutton.y);
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
// rjf: push event
|
//- rjf: mouse motion
|
||||||
LNX_WM_Window *window = lnx_window_from_x11window(evt.xbutton.window);
|
case MotionNotify:
|
||||||
if(key != WM_Key_Null)
|
|
||||||
{
|
|
||||||
WM_Event *e = wm_event_list_push_new(arena, &evts, evt.type == ButtonPress ? WM_EventKind_Press : WM_EventKind_Release);
|
|
||||||
e->window.u64[0] = (U64)window;
|
|
||||||
e->modifiers = modifiers;
|
|
||||||
e->key = key;
|
|
||||||
e->pos = v2f32((F32)evt.xbutton.x, (F32)evt.xbutton.y);
|
|
||||||
}
|
|
||||||
else if(evt.xbutton.button == Button4 ||
|
|
||||||
evt.xbutton.button == Button5)
|
|
||||||
{
|
|
||||||
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_Scroll);
|
|
||||||
e->window.u64[0] = (U64)window;
|
|
||||||
e->modifiers = modifiers;
|
|
||||||
e->delta = v2f32(0, evt.xbutton.button == Button4 ? -1.f : +1.f);
|
|
||||||
e->pos = v2f32((F32)evt.xbutton.x, (F32)evt.xbutton.y);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: mouse motion
|
|
||||||
case MotionNotify:
|
|
||||||
{
|
|
||||||
LNX_WM_Window *window = lnx_window_from_x11window(evt.xclient.window);
|
|
||||||
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_MouseMove);
|
|
||||||
e->window.u64[0] = (U64)window;
|
|
||||||
e->pos.x = (F32)evt.xmotion.x;
|
|
||||||
e->pos.y = (F32)evt.xmotion.y;
|
|
||||||
set_mouse_cursor = 1;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: window focus/unfocus
|
|
||||||
case FocusIn:
|
|
||||||
{
|
|
||||||
}break;
|
|
||||||
case FocusOut:
|
|
||||||
{
|
|
||||||
LNX_WM_Window *window = lnx_window_from_x11window(evt.xfocus.window);
|
|
||||||
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_WindowLoseFocus);
|
|
||||||
e->window.u64[0] = (U64)window;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: client messages
|
|
||||||
case ClientMessage:
|
|
||||||
{
|
|
||||||
if((Atom)evt.xclient.data.l[0] == lnx_wm_state->wm_delete_window_atom)
|
|
||||||
{
|
{
|
||||||
LNX_WM_Window *window = lnx_window_from_x11window(evt.xclient.window);
|
LNX_WM_Window *window = lnx_window_from_x11window(evt.xclient.window);
|
||||||
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_WindowClose);
|
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_MouseMove);
|
||||||
e->window.u64[0] = (U64)window;
|
e->window.u64[0] = (U64)window;
|
||||||
}
|
e->pos.x = (F32)evt.xmotion.x;
|
||||||
else if((Atom)evt.xclient.data.l[0] == lnx_wm_state->wm_sync_request_atom)
|
e->pos.y = (F32)evt.xmotion.y;
|
||||||
|
set_mouse_cursor = 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
//- rjf: window focus/unfocus
|
||||||
|
case FocusIn:
|
||||||
{
|
{
|
||||||
LNX_WM_Window *window = lnx_window_from_x11window(evt.xclient.window);
|
}break;
|
||||||
if(window != 0)
|
case FocusOut:
|
||||||
|
{
|
||||||
|
LNX_WM_Window *window = lnx_window_from_x11window(evt.xfocus.window);
|
||||||
|
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_WindowLoseFocus);
|
||||||
|
e->window.u64[0] = (U64)window;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
//- rjf: client messages
|
||||||
|
case ClientMessage:
|
||||||
|
{
|
||||||
|
if((Atom)evt.xclient.data.l[0] == lnx_wm_state->wm_delete_window_atom)
|
||||||
{
|
{
|
||||||
window->counter_value = 0;
|
LNX_WM_Window *window = lnx_window_from_x11window(evt.xclient.window);
|
||||||
window->counter_value |= evt.xclient.data.l[2];
|
WM_Event *e = wm_event_list_push_new(arena, &evts, WM_EventKind_WindowClose);
|
||||||
window->counter_value |= (evt.xclient.data.l[3] << 32);
|
e->window.u64[0] = (U64)window;
|
||||||
XSyncValue value;
|
|
||||||
XSyncIntToValue(&value, window->counter_value);
|
|
||||||
XSyncSetCounter(lnx_wm_state->display, window->counter_xid, value);
|
|
||||||
}
|
}
|
||||||
}
|
else if((Atom)evt.xclient.data.l[0] == lnx_wm_state->wm_sync_request_atom)
|
||||||
}break;
|
{
|
||||||
|
LNX_WM_Window *window = lnx_window_from_x11window(evt.xclient.window);
|
||||||
|
if(window != 0)
|
||||||
|
{
|
||||||
|
window->counter_value = 0;
|
||||||
|
window->counter_value |= evt.xclient.data.l[2];
|
||||||
|
window->counter_value |= (evt.xclient.data.l[3] << 32);
|
||||||
|
XSyncValue value;
|
||||||
|
XSyncIntToValue(&value, window->counter_value);
|
||||||
|
XSyncSetCounter(lnx_wm_state->display, window->counter_xid, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(set_mouse_cursor)
|
if(set_mouse_cursor)
|
||||||
@@ -716,7 +716,7 @@ wm_mouse_from_window(WM_Window handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Cursors (Implemented Per-OS)
|
//~ rjf: @per_os_impl Cursors (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_set_cursor(WM_Cursor cursor)
|
wm_set_cursor(WM_Cursor cursor)
|
||||||
@@ -725,7 +725,7 @@ wm_set_cursor(WM_Cursor cursor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS)
|
//~ rjf: @per_os_impl Native User-Facing Graphical Messages (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_graphical_message(B32 error, String8 title, String8 message)
|
wm_graphical_message(B32 error, String8 title, String8 message)
|
||||||
@@ -745,7 +745,7 @@ wm_graphical_pick_file(Arena *arena, String8 initial_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Shell Operations
|
//~ rjf: @per_os_impl Shell Operations
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_show_in_filesystem_ui(String8 path)
|
wm_show_in_filesystem_ui(String8 path)
|
||||||
|
|||||||
@@ -220,7 +220,24 @@ entry_point(CmdLine *cmdline)
|
|||||||
MD_Node *file = n->v.root;
|
MD_Node *file = n->v.root;
|
||||||
for MD_EachNode(node, file->first)
|
for MD_EachNode(node, file->first)
|
||||||
{
|
{
|
||||||
|
// rjf: @enum tags -> generate strings from table generators
|
||||||
MD_Node *tag = md_tag_from_string(node, str8_lit("enum"), 0);
|
MD_Node *tag = md_tag_from_string(node, str8_lit("enum"), 0);
|
||||||
|
String8List gen_strings = {0};
|
||||||
|
if(!md_node_is_nil(tag))
|
||||||
|
{
|
||||||
|
gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: @table_enum tags -> generate strings from 'name' column from table
|
||||||
|
if(md_node_is_nil(tag))
|
||||||
|
{
|
||||||
|
tag = md_tag_from_string(node, str8_lit("table_enum"), 0);
|
||||||
|
String8 gen_string = str8f(mg_arena, "{ expand(%S a) `$(a.name) = $(a.code)` }", node->string);
|
||||||
|
MD_Node *gen_node = md_tree_from_string(mg_arena, gen_string);
|
||||||
|
gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: generate
|
||||||
if(!md_node_is_nil(tag))
|
if(!md_node_is_nil(tag))
|
||||||
{
|
{
|
||||||
String8 enum_name = node->string;
|
String8 enum_name = node->string;
|
||||||
@@ -232,7 +249,6 @@ entry_point(CmdLine *cmdline)
|
|||||||
String8 enum_base_type_name = tag->first->string;
|
String8 enum_base_type_name = tag->first->string;
|
||||||
String8 layer_key = mg_layer_key_from_path(file->string);
|
String8 layer_key = mg_layer_key_from_path(file->string);
|
||||||
MG_Layer *layer = mg_layer_from_key(layer_key);
|
MG_Layer *layer = mg_layer_from_key(layer_key);
|
||||||
String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node);
|
|
||||||
if(enum_base_type_name.size == 0)
|
if(enum_base_type_name.size == 0)
|
||||||
{
|
{
|
||||||
str8_list_pushf(mg_arena, &layer->enums, "typedef enum %S\n{\n", enum_name);
|
str8_list_pushf(mg_arena, &layer->enums, "typedef enum %S\n{\n", enum_name);
|
||||||
|
|||||||
@@ -0,0 +1,936 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Helpers
|
||||||
|
|
||||||
|
internal PE_IntelPdata *
|
||||||
|
pe_x64_uwnd_intel_pdata_from_voff(PE_X64_UWND_ModuleUnwindInfo *unwind_info, U64 voff)
|
||||||
|
{
|
||||||
|
PE_IntelPdata *first_pdata = 0;
|
||||||
|
{
|
||||||
|
PE_IntelPdata *pdatas = unwind_info->pdatas;
|
||||||
|
U64 pdatas_count = unwind_info->pdatas_count;
|
||||||
|
if(pdatas_count != 0 && voff >= pdatas[0].voff_first)
|
||||||
|
{
|
||||||
|
// NOTE(rjf):
|
||||||
|
//
|
||||||
|
// binary search:
|
||||||
|
// find max index s.t. pdata_array[index].voff_first <= voff
|
||||||
|
// we assume (i < j) -> (pdata_array[i].voff_first < pdata_array[j].voff_first)
|
||||||
|
//
|
||||||
|
U64 index = pdatas_count;
|
||||||
|
U64 min = 0;
|
||||||
|
U64 opl = pdatas_count;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
U64 mid = (min + opl)/2;
|
||||||
|
PE_IntelPdata *pdata = pdatas + mid;
|
||||||
|
if(voff < pdata->voff_first)
|
||||||
|
{
|
||||||
|
opl = mid;
|
||||||
|
}
|
||||||
|
else if(pdata->voff_first < voff)
|
||||||
|
{
|
||||||
|
min = mid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = mid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(min + 1 >= opl)
|
||||||
|
{
|
||||||
|
index = min;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: if we are in range fill result
|
||||||
|
{
|
||||||
|
PE_IntelPdata *pdata = pdatas + index;
|
||||||
|
if(pdata->voff_first <= voff && voff < pdata->voff_one_past_last)
|
||||||
|
{
|
||||||
|
first_pdata = pdata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first_pdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal X64_RegCode
|
||||||
|
pe_x64_uwnd_reg_code_from_pe_gpr_reg(PE_UnwindGprRegX64 gpr_reg)
|
||||||
|
{
|
||||||
|
X64_RegCode result = X64_RegCode_nil;
|
||||||
|
switch(gpr_reg)
|
||||||
|
{
|
||||||
|
case PE_UnwindGprRegX64_RAX:{result = X64_RegCode_rax;}break;
|
||||||
|
case PE_UnwindGprRegX64_RCX:{result = X64_RegCode_rcx;}break;
|
||||||
|
case PE_UnwindGprRegX64_RDX:{result = X64_RegCode_rdx;}break;
|
||||||
|
case PE_UnwindGprRegX64_RBX:{result = X64_RegCode_rbx;}break;
|
||||||
|
case PE_UnwindGprRegX64_RSP:{result = X64_RegCode_rsp;}break;
|
||||||
|
case PE_UnwindGprRegX64_RBP:{result = X64_RegCode_rbp;}break;
|
||||||
|
case PE_UnwindGprRegX64_RSI:{result = X64_RegCode_rsi;}break;
|
||||||
|
case PE_UnwindGprRegX64_RDI:{result = X64_RegCode_rdi;}break;
|
||||||
|
case PE_UnwindGprRegX64_R8 :{result = X64_RegCode_r8;}break;
|
||||||
|
case PE_UnwindGprRegX64_R9 :{result = X64_RegCode_r9;}break;
|
||||||
|
case PE_UnwindGprRegX64_R10:{result = X64_RegCode_r10;}break;
|
||||||
|
case PE_UnwindGprRegX64_R11:{result = X64_RegCode_r11;}break;
|
||||||
|
case PE_UnwindGprRegX64_R12:{result = X64_RegCode_r12;}break;
|
||||||
|
case PE_UnwindGprRegX64_R13:{result = X64_RegCode_r13;}break;
|
||||||
|
case PE_UnwindGprRegX64_R14:{result = X64_RegCode_r14;}break;
|
||||||
|
case PE_UnwindGprRegX64_R15:{result = X64_RegCode_r15;}break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Unwinding Abstraction Implementation
|
||||||
|
|
||||||
|
internal UWND_StepResult
|
||||||
|
pe_x64_uwnd_step(Arch arch, MemoryMap *memory_map, UWND_ModuleInfo *module_info, U64 tls_vaddr, void *regs_opaque, U64 *cfa_out)
|
||||||
|
{
|
||||||
|
UWND_StepResult result = {UWND_StepStatus_Error};
|
||||||
|
PE_X64_UWND_ModuleUnwindInfo *unwind_info = (PE_X64_UWND_ModuleUnwindInfo *)module_info->unwind_info;
|
||||||
|
X64_RegBlock *regs = (X64_RegBlock *)regs_opaque;
|
||||||
|
if(unwind_info != 0)
|
||||||
|
{
|
||||||
|
B32 done = 0;
|
||||||
|
Temp scratch = scratch_begin(0, 0);
|
||||||
|
X64_RegBlock *new_regs = push_array(scratch.arena, X64_RegBlock, 1);
|
||||||
|
MemoryCopyStruct(new_regs, regs);
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
//- rjf: on PE/x64, the frame base address is always RSP
|
||||||
|
//
|
||||||
|
cfa_out[0] = new_regs->rsp;
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
//- rjf: unpack context from rip
|
||||||
|
//
|
||||||
|
U64 rip_voff = new_regs->rip - module_info->base_vaddr;
|
||||||
|
PE_IntelPdata *first_pdata = pe_x64_uwnd_intel_pdata_from_voff(unwind_info, rip_voff);
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
//- rjf: pdata -> detect if in epilog
|
||||||
|
//
|
||||||
|
B32 has_pdata_and_in_epilog = 0;
|
||||||
|
U64 instruction_data_size_cap = 256;
|
||||||
|
Rng1U64 instruction_data_vaddr_range = r1u64(new_regs->rip, new_regs->rip+instruction_data_size_cap);
|
||||||
|
String8 instruction_data = {0};
|
||||||
|
if(!done && first_pdata)
|
||||||
|
{
|
||||||
|
// NOTE(allen): There are restrictions placed on how an epilog is allowed
|
||||||
|
// to be formed (https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160)
|
||||||
|
// Here we interpret machine code directly according to the rules
|
||||||
|
// given there to determine if the code we're looking at looks like an epilog.
|
||||||
|
|
||||||
|
//- rjf: read instruction memory
|
||||||
|
U8 *instruction_data_buffer = push_array(scratch.arena, U8, instruction_data_size_cap);
|
||||||
|
U64 instruction_data_size = memory_map_read(memory_map, instruction_data_vaddr_range, instruction_data_buffer);
|
||||||
|
instruction_data = str8(instruction_data_buffer, instruction_data_size);
|
||||||
|
if(instruction_data.size == 0)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = instruction_data_vaddr_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: set up parsing state
|
||||||
|
B32 is_epilog = 0;
|
||||||
|
|
||||||
|
//- rjf: check first instruction, determine if we should keep parsing & from where
|
||||||
|
U64 read_off = 0;
|
||||||
|
B32 keep_parsing = 0;
|
||||||
|
if(!done && instruction_data.size >= 4)
|
||||||
|
{
|
||||||
|
U8 inst[4] = {0};
|
||||||
|
str8_deserial_read(instruction_data, read_off, &inst[0], sizeof(inst), sizeof(inst));
|
||||||
|
keep_parsing = 1;
|
||||||
|
if((inst[0] & 0xF8) == 0x48)
|
||||||
|
{
|
||||||
|
switch(inst[1])
|
||||||
|
{
|
||||||
|
// rjf: add $nnnn,%rsp
|
||||||
|
case 0x81:
|
||||||
|
{
|
||||||
|
if(inst[0] == 0x48 && inst[2] == 0xC4)
|
||||||
|
{
|
||||||
|
read_off += 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keep_parsing = 0;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: add $n,%rsp
|
||||||
|
case 0x83:
|
||||||
|
{
|
||||||
|
if(inst[0] == 0x48 && inst[2] == 0xC4)
|
||||||
|
{
|
||||||
|
read_off += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keep_parsing = 0;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: lea n(reg),%rsp
|
||||||
|
case 0x8D:
|
||||||
|
{
|
||||||
|
if((inst[0] & 0x06) == 0 &&
|
||||||
|
((inst[2] >> 3) & 0x07) == 0x04 &&
|
||||||
|
(inst[2] & 0x07) != 0x04)
|
||||||
|
{
|
||||||
|
U8 imm_size = (inst[2] >> 6);
|
||||||
|
|
||||||
|
// rjf: 1-byte immediate
|
||||||
|
if(imm_size == 1)
|
||||||
|
{
|
||||||
|
read_off += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: 4-byte immediate
|
||||||
|
else if(imm_size == 2)
|
||||||
|
{
|
||||||
|
read_off += 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: other case
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keep_parsing = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keep_parsing = 0;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: continue parsing instructions
|
||||||
|
for(;!done && keep_parsing;)
|
||||||
|
{
|
||||||
|
// rjf: read next instruction byte
|
||||||
|
B32 inst_byte_good = 1;
|
||||||
|
U8 inst_byte = 0;
|
||||||
|
if(str8_deserial_read_struct(instruction_data, read_off, &inst_byte) == 0)
|
||||||
|
{
|
||||||
|
inst_byte_good = 0;
|
||||||
|
keep_parsing = 0;
|
||||||
|
}
|
||||||
|
read_off += 1;
|
||||||
|
|
||||||
|
// rjf: when (... I don't know ...) rely on the next byte
|
||||||
|
B32 check_inst_byte_good = inst_byte_good;
|
||||||
|
U8 check_inst_byte = inst_byte;
|
||||||
|
if(inst_byte_good && (inst_byte & 0xF0) == 0x40)
|
||||||
|
{
|
||||||
|
if(str8_deserial_read_struct(instruction_data, read_off, &check_inst_byte) == 0)
|
||||||
|
{
|
||||||
|
check_inst_byte_good = 0;
|
||||||
|
keep_parsing = 0;
|
||||||
|
}
|
||||||
|
read_off += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: check instruction byte
|
||||||
|
if(check_inst_byte_good)
|
||||||
|
{
|
||||||
|
switch(check_inst_byte)
|
||||||
|
{
|
||||||
|
default:{keep_parsing = 0;}break;
|
||||||
|
|
||||||
|
// rjf: pop
|
||||||
|
case 0x58:case 0x59:case 0x5A:case 0x5B:
|
||||||
|
case 0x5C:case 0x5D:case 0x5E:case 0x5F:
|
||||||
|
{
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: ret
|
||||||
|
case 0xC2:
|
||||||
|
case 0xC3:
|
||||||
|
{
|
||||||
|
is_epilog = 1;
|
||||||
|
keep_parsing = 0;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: jmp nnnn
|
||||||
|
case 0xE9:
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// TODO(rjf): old code here was reading the jump's immediate value, applying the delta,
|
||||||
|
// and continued parsing if the jump destination address fell within the same pdata.
|
||||||
|
// but from what I can tell, the only legal usage of a jump within an epilog is to end
|
||||||
|
// the epilog, and jump to another function; if the jump stays in the function, it is
|
||||||
|
// an illegal epilog sequence. so, I've instead just changed this to treat any jmps
|
||||||
|
// which escape the pdata, and also end the pdata, as marking the epilog.
|
||||||
|
//
|
||||||
|
// I am not sure if this is correct w.r.t. chained pdatas, however, since presumably
|
||||||
|
// a jump could also land elsewhere in the same function - we may need to also look for
|
||||||
|
// stack pointer modifications etc. - those together with a jump in this context may
|
||||||
|
// let us tell the difference.
|
||||||
|
//
|
||||||
|
S32 imm = 0;
|
||||||
|
B32 imm_good = (str8_deserial_read_struct(instruction_data, read_off, &imm) == sizeof(imm));
|
||||||
|
U64 next_vaddr = (instruction_data_vaddr_range.min + read_off + sizeof(imm) + imm);
|
||||||
|
U64 next_voff = (next_vaddr - module_info->base_vaddr);
|
||||||
|
if((next_voff < first_pdata->voff_first || first_pdata->voff_one_past_last <= next_voff) &&
|
||||||
|
read_off + sizeof(imm) == first_pdata->voff_one_past_last)
|
||||||
|
{
|
||||||
|
is_epilog = 1;
|
||||||
|
}
|
||||||
|
keep_parsing = 0;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: rep; ret (for amd64 prediction bug)
|
||||||
|
case 0xF3:
|
||||||
|
{
|
||||||
|
U8 next_inst_byte = 0;
|
||||||
|
B32 next_inst_byte_good = (str8_deserial_read_struct(instruction_data, read_off, &next_inst_byte) == sizeof(next_inst_byte));
|
||||||
|
read_off += 1;
|
||||||
|
keep_parsing = 0;
|
||||||
|
if(next_inst_byte_good)
|
||||||
|
{
|
||||||
|
is_epilog = (next_inst_byte == 0xC3);
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
has_pdata_and_in_epilog = is_epilog;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
//- rjf: pdata & in epilog -> epilog unwind
|
||||||
|
//
|
||||||
|
if(!done && first_pdata && has_pdata_and_in_epilog)
|
||||||
|
{
|
||||||
|
U64 read_off = 0;
|
||||||
|
for(B32 keep_parsing = 1; !done && keep_parsing;)
|
||||||
|
{
|
||||||
|
//- rjf: assume no more parsing after this instruction
|
||||||
|
keep_parsing = 0;
|
||||||
|
|
||||||
|
//- rjf: read next instruction byte
|
||||||
|
U8 inst_byte = 0;
|
||||||
|
if(str8_deserial_read_struct(instruction_data, read_off, &inst_byte) == 0)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
read_off += 1;
|
||||||
|
|
||||||
|
//- rjf: extract rex from instruction byte
|
||||||
|
U8 rex = 0;
|
||||||
|
if((inst_byte & 0xF0) == 0x40)
|
||||||
|
{
|
||||||
|
rex = inst_byte & 0xF; // rex prefix
|
||||||
|
if(str8_deserial_read_struct(instruction_data, read_off, &inst_byte) == 0)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
read_off += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: parse remainder of instruction
|
||||||
|
switch(inst_byte)
|
||||||
|
{
|
||||||
|
// rjf: pop
|
||||||
|
case 0x58:case 0x59:case 0x5A:case 0x5B:
|
||||||
|
case 0x5C:case 0x5D:case 0x5E:case 0x5F:
|
||||||
|
{
|
||||||
|
// rjf: read value at rsp
|
||||||
|
U64 sp = new_regs->rsp;
|
||||||
|
U64 value = 0;
|
||||||
|
if(memory_map_read_struct(memory_map, sp, &value) != sizeof(value))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(sp, sp+sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: modify registers
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
PE_UnwindGprRegX64 gpr_reg = (inst_byte - 0x58) + (rex & 1)*8;
|
||||||
|
X64_RegCode reg_code = pe_x64_uwnd_reg_code_from_pe_gpr_reg(gpr_reg);
|
||||||
|
Rng1U16 reg_rng = x64_reg_code_rng_table[reg_code];
|
||||||
|
U64 *reg_ptr = (U64 *)((U8 *)®s + reg_rng.min);
|
||||||
|
reg_ptr[0] = value;
|
||||||
|
new_regs->rsp = sp + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: not a final instruction, so keep parsing
|
||||||
|
keep_parsing = 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: add $nnnn,%rsp
|
||||||
|
case 0x81:
|
||||||
|
{
|
||||||
|
// rjf: skip one byte (we already know what it is in this scenario)
|
||||||
|
read_off += 1;
|
||||||
|
|
||||||
|
// rjf: read the 4-byte immediate
|
||||||
|
S32 imm = 0;
|
||||||
|
B32 imm_is_good = (str8_deserial_read_struct(instruction_data, read_off, &imm) == sizeof(imm));
|
||||||
|
if(!imm_is_good)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
read_off += sizeof(imm);
|
||||||
|
|
||||||
|
// rjf: update stack pointer
|
||||||
|
new_regs->rsp = (U64)(new_regs->rsp + imm);
|
||||||
|
|
||||||
|
// rjf: not a final instruction; keep parsing
|
||||||
|
keep_parsing = 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: add $n,%rsp
|
||||||
|
case 0x83:
|
||||||
|
{
|
||||||
|
// rjf: skip one byte (we already know what it is in this scenario)
|
||||||
|
read_off += 1;
|
||||||
|
|
||||||
|
// rjf: read the 1-byte immediate
|
||||||
|
S8 imm = 0;
|
||||||
|
B32 imm_is_good = (str8_deserial_read_struct(instruction_data, read_off, &imm) == sizeof(imm));
|
||||||
|
if(!imm_is_good)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
read_off += sizeof(imm);
|
||||||
|
|
||||||
|
// rjf: update stack pointer
|
||||||
|
new_regs->rsp = (U64)(new_regs->rsp + imm);
|
||||||
|
|
||||||
|
// rjf: not a final instruction; keep parsing
|
||||||
|
keep_parsing = 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: lea imm8/imm32,$rsp
|
||||||
|
case 0x8D:
|
||||||
|
{
|
||||||
|
// rjf: read source register
|
||||||
|
U8 modrm = 0;
|
||||||
|
B32 modrm_is_good = (str8_deserial_read_struct(instruction_data, read_off, &modrm) == sizeof(modrm));
|
||||||
|
if(!modrm_is_good)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
read_off += 1;
|
||||||
|
|
||||||
|
// rjf: unpack register value
|
||||||
|
PE_UnwindGprRegX64 gpr_reg = (modrm & 7) + (rex & 1)*8;
|
||||||
|
X64_RegCode reg_code = pe_x64_uwnd_reg_code_from_pe_gpr_reg(gpr_reg);
|
||||||
|
Rng1U16 reg_rng = x64_reg_code_rng_table[reg_code];
|
||||||
|
U64 *reg_ptr = (U64 *)((U8 *)®s + reg_rng.min);
|
||||||
|
U64 reg_value = reg_ptr[0];
|
||||||
|
|
||||||
|
// rjf: read immediate
|
||||||
|
S32 imm = 0;
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
// rjf: read 1-byte immediate
|
||||||
|
if((modrm >> 6) == 1)
|
||||||
|
{
|
||||||
|
S8 imm8 = 0;
|
||||||
|
B32 imm8_is_good = (str8_deserial_read_struct(instruction_data, read_off, &imm8) == sizeof(imm8));
|
||||||
|
if(!imm8_is_good)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
read_off += 1;
|
||||||
|
imm = (S32)imm8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: read 4-byte immediate
|
||||||
|
else
|
||||||
|
{
|
||||||
|
B32 imm32_is_good = (str8_deserial_read_struct(instruction_data, read_off, &imm) == sizeof(imm));
|
||||||
|
done = !imm32_is_good;
|
||||||
|
read_off += sizeof(imm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: update stack pointer
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
new_regs->rsp = (U64)(reg_value + imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: not a final instruction; keep parsing
|
||||||
|
keep_parsing = 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: ret $nn
|
||||||
|
case 0xC2:
|
||||||
|
{
|
||||||
|
// rjf: read new ip
|
||||||
|
U64 sp = new_regs->rsp;
|
||||||
|
U64 new_ip = 0;
|
||||||
|
if(memory_map_read_struct(memory_map, sp, &new_ip) != sizeof(new_ip))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(sp, sp+sizeof(new_ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: read 2-byte immediate & advance stack pointer
|
||||||
|
U16 imm = 0;
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
done = (str8_deserial_read_struct(instruction_data, read_off, &imm) < sizeof(imm));
|
||||||
|
}
|
||||||
|
U64 new_sp = sp + 8 + imm;
|
||||||
|
|
||||||
|
// rjf: commit registers
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
new_regs->rip = new_ip;
|
||||||
|
new_regs->rsp = new_sp;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: ret / rep; ret
|
||||||
|
case 0xF3:
|
||||||
|
{
|
||||||
|
// Assert(!"Hit me!");
|
||||||
|
}break;
|
||||||
|
case 0xC3:
|
||||||
|
{
|
||||||
|
// rjf: read new ip
|
||||||
|
U64 sp = new_regs->rsp;
|
||||||
|
U64 new_ip = 0;
|
||||||
|
if(memory_map_read_struct(memory_map, sp, &new_ip) != sizeof(new_ip))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(sp, sp+sizeof(new_ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: advance stack pointer
|
||||||
|
U64 new_sp = sp + 8;
|
||||||
|
|
||||||
|
// rjf: commit registers
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
new_regs->rip = new_ip;
|
||||||
|
new_regs->rsp = new_sp;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: jmp nnnn
|
||||||
|
case 0xE9:
|
||||||
|
{
|
||||||
|
// Assert(!"Hit Me");
|
||||||
|
// TODO(allen): general idea: read the immediate, move the ip, leave the sp, done
|
||||||
|
// we don't have any cases to exercise this right now. no guess implementation!
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// rjf: Sjmp n
|
||||||
|
case 0xEB:
|
||||||
|
{
|
||||||
|
// Assert(!"Hit Me");
|
||||||
|
// TODO(allen): general idea: read the immediate, move the ip, leave the sp, done
|
||||||
|
// we don't have any cases to exercise this right now. no guess implementation!
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: pdata & not in epilog -> xdata unwind
|
||||||
|
//
|
||||||
|
B32 xdata_unwind_did_machframe = 0;
|
||||||
|
if(!done && first_pdata && !has_pdata_and_in_epilog)
|
||||||
|
{
|
||||||
|
//- rjf: get frame reg
|
||||||
|
B32 bad_frame_reg_info = 0;
|
||||||
|
X64_RegCode frame_reg_code = X64_RegCode_rsp;
|
||||||
|
U64 frame_off = 0;
|
||||||
|
{
|
||||||
|
// rjf: read unwind info header
|
||||||
|
U64 unwind_info_off = first_pdata->voff_unwind_info;
|
||||||
|
PE_UnwindInfo unwind_info = {0};
|
||||||
|
if(memory_map_read_struct(memory_map, module_info->base_vaddr+unwind_info_off, &unwind_info) != sizeof(unwind_info))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(module_info->base_vaddr+unwind_info_off, module_info->base_vaddr+unwind_info_off+sizeof(unwind_info));;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: unpack header
|
||||||
|
U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info.frame);
|
||||||
|
U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info.frame);
|
||||||
|
if(frame_reg_id != 0)
|
||||||
|
{
|
||||||
|
frame_reg_code = pe_x64_uwnd_reg_code_from_pe_gpr_reg(frame_reg_id);
|
||||||
|
bad_frame_reg_info = (frame_reg_code == X64_RegCode_nil); // NOTE(rjf): frame_reg should never be 0 at this point, in valid exe
|
||||||
|
}
|
||||||
|
frame_off = frame_off_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: iterate pdatas, apply opcodes
|
||||||
|
PE_IntelPdata *last_pdata = 0;
|
||||||
|
PE_IntelPdata *pdata = first_pdata;
|
||||||
|
if(!done && !bad_frame_reg_info) for(B32 keep_parsing = 1; !done && keep_parsing && pdata != last_pdata;)
|
||||||
|
{
|
||||||
|
//- rjf: read unwind info
|
||||||
|
U64 unwind_info_off = pdata->voff_unwind_info;
|
||||||
|
PE_UnwindInfo unwind_info = {0};
|
||||||
|
if(memory_map_read_struct(memory_map, module_info->base_vaddr+unwind_info_off, &unwind_info) != sizeof(unwind_info))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(module_info->base_vaddr+unwind_info_off, module_info->base_vaddr+unwind_info_off+sizeof(unwind_info));;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: read unwind codes
|
||||||
|
PE_UnwindCode *unwind_codes = push_array(scratch.arena, PE_UnwindCode, unwind_info.codes_num);
|
||||||
|
Rng1U64 unwind_codes_vaddr_range = r1u64(module_info->base_vaddr+unwind_info_off+sizeof(unwind_info),
|
||||||
|
module_info->base_vaddr+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCode)*unwind_info.codes_num);
|
||||||
|
if(memory_map_read(memory_map, unwind_codes_vaddr_range, unwind_codes) != dim_1u64(unwind_codes_vaddr_range))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = unwind_codes_vaddr_range;;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: unpack frame base
|
||||||
|
U64 frame_base = new_regs->rsp;
|
||||||
|
if(frame_reg_code != X64_RegCode_nil)
|
||||||
|
{
|
||||||
|
Rng1U16 frame_reg_rng = x64_reg_code_rng_table[frame_reg_code];
|
||||||
|
U64 raw_frame_base = *(U64 *)((U8 *)regs + frame_reg_rng.min);
|
||||||
|
U64 adjusted_frame_base = raw_frame_base - frame_off*16;
|
||||||
|
frame_base = adjusted_frame_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: apply opcodes
|
||||||
|
PE_UnwindCode *code_ptr = unwind_codes;
|
||||||
|
PE_UnwindCode *code_opl = unwind_codes + unwind_info.codes_num;
|
||||||
|
for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr)
|
||||||
|
{
|
||||||
|
// rjf: unpack opcode info
|
||||||
|
U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags);
|
||||||
|
U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags);
|
||||||
|
U32 slot_count = pe_slot_count_from_unwind_op_code(op_code);
|
||||||
|
if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1)
|
||||||
|
{
|
||||||
|
slot_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: detect bad slot counts
|
||||||
|
if(slot_count == 0 || code_ptr+slot_count > code_opl)
|
||||||
|
{
|
||||||
|
keep_parsing = 0;
|
||||||
|
done = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: set next op code pointer
|
||||||
|
next_code_ptr = code_ptr + slot_count;
|
||||||
|
|
||||||
|
// rjf: interpret this op code
|
||||||
|
U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog;
|
||||||
|
if(code_voff <= rip_voff)
|
||||||
|
{
|
||||||
|
switch(op_code)
|
||||||
|
{
|
||||||
|
case PE_UnwindOpCode_PUSH_NONVOL:
|
||||||
|
{
|
||||||
|
// rjf: read value from stack pointer
|
||||||
|
U64 rsp = new_regs->rsp;
|
||||||
|
U64 value = 0;
|
||||||
|
if(memory_map_read_struct(memory_map, rsp, &value) != sizeof(value))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(rsp, rsp+sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: commit registers
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
X64_RegCode reg_code = pe_x64_uwnd_reg_code_from_pe_gpr_reg(op_info);
|
||||||
|
Rng1U16 reg_rng = x64_reg_code_rng_table[reg_code];
|
||||||
|
*(U64 *)((U8 *)regs + reg_rng.min) = value;
|
||||||
|
new_regs->rsp = rsp + 8;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_ALLOC_LARGE:
|
||||||
|
{
|
||||||
|
// rjf: read alloc size
|
||||||
|
U64 size = 0;
|
||||||
|
if(op_info == 0)
|
||||||
|
{
|
||||||
|
size = code_ptr[1].u16*8;
|
||||||
|
}
|
||||||
|
else if(op_info == 1)
|
||||||
|
{
|
||||||
|
size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: advance stack pointer
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
new_regs->rsp += size;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_ALLOC_SMALL:
|
||||||
|
{
|
||||||
|
// rjf: advance stack pointer
|
||||||
|
new_regs->rsp += op_info*8 + 8;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_SET_FPREG:
|
||||||
|
{
|
||||||
|
// rjf: put stack pointer back to the frame base
|
||||||
|
new_regs->rsp = frame_base;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_SAVE_NONVOL:
|
||||||
|
{
|
||||||
|
// rjf: read value from frame base
|
||||||
|
U64 off = code_ptr[1].u16*8;
|
||||||
|
U64 addr = frame_base + off;
|
||||||
|
U64 value = 0;
|
||||||
|
if(memory_map_read_struct(memory_map, addr, &value) != sizeof(value))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(addr, addr+sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: commit to register
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
X64_RegCode reg_code = pe_x64_uwnd_reg_code_from_pe_gpr_reg(op_info);
|
||||||
|
Rng1U16 reg_rng = x64_reg_code_rng_table[reg_code];
|
||||||
|
*(U64 *)((U8 *)regs + reg_rng.min) = value;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_SAVE_NONVOL_FAR:
|
||||||
|
{
|
||||||
|
// rjf: read value from frame base
|
||||||
|
U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16);
|
||||||
|
U64 addr = frame_base + off;
|
||||||
|
U64 value = 0;
|
||||||
|
if(memory_map_read_struct(memory_map, addr, &value) != sizeof(value))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(addr, addr+sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: commit to register
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
X64_RegCode reg_code = pe_x64_uwnd_reg_code_from_pe_gpr_reg(op_info);
|
||||||
|
Rng1U16 reg_rng = x64_reg_code_rng_table[reg_code];
|
||||||
|
*(U64 *)((U8 *)regs + reg_rng.min) = value;
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_EPILOG:
|
||||||
|
{
|
||||||
|
keep_parsing = 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_SPARE_CODE:
|
||||||
|
{
|
||||||
|
// TODO(rjf): ???
|
||||||
|
keep_parsing = 0;
|
||||||
|
done = 1;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_SAVE_XMM128:
|
||||||
|
{
|
||||||
|
// rjf: read new register values
|
||||||
|
U8 buf[16];
|
||||||
|
U64 off = code_ptr[1].u16*16;
|
||||||
|
U64 addr = frame_base + off;
|
||||||
|
Rng1U64 read_vaddr_range = r1u64(addr, addr+sizeof(buf));
|
||||||
|
if(memory_map_read(memory_map, read_vaddr_range, buf) != sizeof(buf))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = read_vaddr_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: commit to register
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
void *xmm_reg = (&new_regs->zmm0) + op_info;
|
||||||
|
MemoryCopy(xmm_reg, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_SAVE_XMM128_FAR:
|
||||||
|
{
|
||||||
|
// rjf: read new register values
|
||||||
|
U8 buf[16];
|
||||||
|
U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16);
|
||||||
|
U64 addr = frame_base + off;
|
||||||
|
Rng1U64 read_vaddr_range = r1u64(addr, addr+sizeof(buf));
|
||||||
|
if(memory_map_read(memory_map, read_vaddr_range, buf) != sizeof(buf))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = read_vaddr_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: commit to register
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
void *xmm_reg = (&new_regs->zmm0) + op_info;
|
||||||
|
MemoryCopy(xmm_reg, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case PE_UnwindOpCode_PUSH_MACHFRAME:
|
||||||
|
{
|
||||||
|
// NOTE(rjf): this was found by stepping through kernel code after an exception was
|
||||||
|
// thrown, encountered in the exception_stepping_tests (after the throw) in mule_main
|
||||||
|
if(op_info > 1)
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: unpack stack pointer
|
||||||
|
U64 sp_og = new_regs->rsp;
|
||||||
|
U64 sp_adj = sp_og;
|
||||||
|
if(op_info == 1)
|
||||||
|
{
|
||||||
|
sp_adj += 8;
|
||||||
|
}
|
||||||
|
U64 sp_after_ip = sp_adj + 8;
|
||||||
|
U64 sp_after_ss = sp_after_ip + 8;
|
||||||
|
U64 sp_after_rflags = sp_after_ss + 8;
|
||||||
|
|
||||||
|
// rjf: read new ip value
|
||||||
|
U64 ip_value = 0;
|
||||||
|
if(!done && memory_map_read_struct(memory_map, sp_adj, &ip_value) != sizeof(ip_value))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(sp_adj, sp_adj + sizeof(ip_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: read new ss value
|
||||||
|
U16 ss_value = 0;
|
||||||
|
if(!done && memory_map_read_struct(memory_map, sp_after_ip, &ss_value) != sizeof(ss_value))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(sp_after_ip, sp_after_ip + sizeof(ss_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: read new rflags value
|
||||||
|
U64 rflags_value = 0;
|
||||||
|
if(!done && memory_map_read_struct(memory_map, sp_after_ss, &rflags_value) != sizeof(rflags_value))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(sp_after_ss, sp_after_ss + sizeof(rflags_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: read new sp value
|
||||||
|
U64 sp_value = 0;
|
||||||
|
if(!done && memory_map_read_struct(memory_map, sp_after_rflags, &sp_value) != sizeof(sp_value))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(sp_after_rflags, sp_after_rflags + sizeof(sp_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: commit registers
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
new_regs->rip = ip_value;
|
||||||
|
new_regs->ss = ss_value;
|
||||||
|
new_regs->rflags = rflags_value;
|
||||||
|
new_regs->rsp = sp_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: mark machine frame
|
||||||
|
xdata_unwind_did_machframe = !done;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- rjf: iterate to next pdata
|
||||||
|
if(keep_parsing)
|
||||||
|
{
|
||||||
|
U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info.header);
|
||||||
|
if(!(flags & PE_UnwindInfoFlag_CHAINED))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
U64 code_count_rounded = AlignPow2(unwind_info.codes_num, sizeof(PE_UnwindCode));
|
||||||
|
U64 code_size = code_count_rounded*sizeof(PE_UnwindCode);
|
||||||
|
U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size;
|
||||||
|
last_pdata = pdata;
|
||||||
|
pdata = push_array(scratch.arena, PE_IntelPdata, 1);
|
||||||
|
if(memory_map_read_struct(memory_map, module_info->base_vaddr+chained_pdata_off, pdata) != sizeof(*pdata))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(module_info->base_vaddr+chained_pdata_off, module_info->base_vaddr+chained_pdata_off+sizeof(*pdata));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer
|
||||||
|
//
|
||||||
|
if(!done && (!first_pdata || (!has_pdata_and_in_epilog && !xdata_unwind_did_machframe)))
|
||||||
|
{
|
||||||
|
// rjf: read new ip
|
||||||
|
U64 sp = new_regs->rsp;
|
||||||
|
U64 new_ip = 0;
|
||||||
|
if(memory_map_read_struct(memory_map, sp, &new_ip) != sizeof(new_ip))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
result.status = UWND_StepStatus_FailedMemoryRead;
|
||||||
|
result.missed_read_vaddr_range = r1u64(sp, sp+sizeof(new_ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
// rjf: commit
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
U64 new_sp = sp+8;
|
||||||
|
new_regs->rip = new_ip;
|
||||||
|
new_regs->rsp = new_sp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- rjf: if not done -> successful step
|
||||||
|
//
|
||||||
|
if(!done)
|
||||||
|
{
|
||||||
|
result.status = UWND_StepStatus_Good;
|
||||||
|
MemoryCopyStruct(regs, new_regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef PE_X64_UNWIND_H
|
||||||
|
#define PE_X64_UNWIND_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Module Unwind Info Type
|
||||||
|
|
||||||
|
typedef struct PE_X64_UWND_ModuleUnwindInfo PE_X64_UWND_ModuleUnwindInfo;
|
||||||
|
struct PE_X64_UWND_ModuleUnwindInfo
|
||||||
|
{
|
||||||
|
PE_IntelPdata *pdatas;
|
||||||
|
U64 pdatas_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Helpers
|
||||||
|
|
||||||
|
internal PE_IntelPdata *pe_x64_uwnd_intel_pdata_from_voff(PE_X64_UWND_ModuleUnwindInfo *unwind_info, U64 voff);
|
||||||
|
internal X64_RegCode pe_x64_uwnd_reg_code_from_pe_gpr_reg(PE_UnwindGprRegX64 gpr_reg);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Unwinding Abstraction Implementation
|
||||||
|
|
||||||
|
internal UWND_StepResult pe_x64_uwnd_step(Arch arch, MemoryMap *memory_map, UWND_ModuleInfo *module_info, U64 tls_vaddr, void *regs_opaque, U64 *cfa_out);
|
||||||
|
|
||||||
|
#endif // PE_X64_UNWIND_H
|
||||||
+7
-4
@@ -824,7 +824,7 @@ rb_thread_entry_point(void *p)
|
|||||||
ELF_Bin bin = elf_bin_from_data(scratch.arena, dbg_data);
|
ELF_Bin bin = elf_bin_from_data(scratch.arena, dbg_data);
|
||||||
convert_params.arch = arch_from_elf_machine(bin.hdr.e_machine);
|
convert_params.arch = arch_from_elf_machine(bin.hdr.e_machine);
|
||||||
convert_params.base_vaddr = elf_base_addr_from_bin(&bin);
|
convert_params.base_vaddr = elf_base_addr_from_bin(&bin);
|
||||||
convert_params.raw = dw_input_from_elf_bin(scratch.arena, dbg_data, &bin);
|
convert_params.raw = dw_raw_from_elf_bin(scratch.arena, dbg_data, &bin);
|
||||||
convert_params.path_style = PathStyle_UnixAbsolute;
|
convert_params.path_style = PathStyle_UnixAbsolute;
|
||||||
convert_params.binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, dbg_data, &bin, &bin.shdrs);
|
convert_params.binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, dbg_data, &bin, &bin.shdrs);
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
@@ -1442,7 +1442,7 @@ rb_thread_entry_point(void *p)
|
|||||||
else if(f->format == RB_FileFormat_ELF32 ||
|
else if(f->format == RB_FileFormat_ELF32 ||
|
||||||
f->format == RB_FileFormat_ELF64)
|
f->format == RB_FileFormat_ELF64)
|
||||||
{
|
{
|
||||||
dw = dw_input_from_elf_bin(arena, f->data, &elf);
|
dw = dw_raw_from_elf_bin(arena, f->data, &elf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1526,8 +1526,11 @@ rb_thread_entry_point(void *p)
|
|||||||
{
|
{
|
||||||
if(lane_idx() == 0)
|
if(lane_idx() == 0)
|
||||||
{
|
{
|
||||||
str8_list_pushf(arena, &output_blobs, "// %S (%S) (DWARF)\n\n", deterministic ? str8_skip_last_slash(f->path) : f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format"));
|
str8_list_pushf(arena, &output_blobs, "\n// %S (%S) (DWARF)\n\n", deterministic ? str8_skip_last_slash(f->path) : f->path, f->format ? rb_file_format_display_name_table[f->format] : str8_lit("Unsupported format"));
|
||||||
String8List dump = dw_dump_list_from_sections(arena, &dw, arch, dw_dump_subset_flags, verbose);
|
}
|
||||||
|
String8List dump = dw_dump_list_from_raw(arena, &dw, arch, dw_dump_subset_flags);
|
||||||
|
if(lane_idx() == 0)
|
||||||
|
{
|
||||||
str8_list_concat_in_place(&output_blobs, &dump);
|
str8_list_concat_in_place(&output_blobs, &dump);
|
||||||
}
|
}
|
||||||
lane_sync();
|
lane_sync();
|
||||||
|
|||||||
@@ -25,7 +25,13 @@
|
|||||||
#include "elf/elf_dump.h"
|
#include "elf/elf_dump.h"
|
||||||
#include "codeview/codeview.h"
|
#include "codeview/codeview.h"
|
||||||
#include "codeview/codeview_parse.h"
|
#include "codeview/codeview_parse.h"
|
||||||
#include "dwarf/dwarf_inc.h"
|
#include "dwarf/dwarf.h"
|
||||||
|
#include "dwarf/dwarf_parse_2.h"
|
||||||
|
#include "dwarf/dwarf_parse_coff.h"
|
||||||
|
#include "dwarf/dwarf_parse_elf.h"
|
||||||
|
#include "dwarf/dwarf_dump_2.h"
|
||||||
|
#include "eh_frame/eh_frame.h"
|
||||||
|
#include "eh_frame/eh_frame_dump.h"
|
||||||
#include "msf/msf.h"
|
#include "msf/msf.h"
|
||||||
#include "msf/msf_parse.h"
|
#include "msf/msf_parse.h"
|
||||||
#include "pdb/pdb.h"
|
#include "pdb/pdb.h"
|
||||||
@@ -53,7 +59,13 @@
|
|||||||
#include "elf/elf_dump.c"
|
#include "elf/elf_dump.c"
|
||||||
#include "codeview/codeview.c"
|
#include "codeview/codeview.c"
|
||||||
#include "codeview/codeview_parse.c"
|
#include "codeview/codeview_parse.c"
|
||||||
#include "dwarf/dwarf_inc.c"
|
#include "dwarf/dwarf.c"
|
||||||
|
#include "dwarf/dwarf_parse_2.c"
|
||||||
|
#include "dwarf/dwarf_parse_coff.c"
|
||||||
|
#include "dwarf/dwarf_parse_elf.c"
|
||||||
|
#include "dwarf/dwarf_dump_2.c"
|
||||||
|
#include "eh_frame/eh_frame.c"
|
||||||
|
#include "eh_frame/eh_frame_dump.c"
|
||||||
#include "msf/msf.c"
|
#include "msf/msf.c"
|
||||||
#include "msf/msf_parse.c"
|
#include "msf/msf_parse.c"
|
||||||
#include "pdb/pdb.c"
|
#include "pdb/pdb.c"
|
||||||
|
|||||||
@@ -11380,7 +11380,7 @@ rd_frame(void)
|
|||||||
U64 rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count);
|
U64 rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count);
|
||||||
D_Entity *module = d_module_from_process_vaddr(process, rip_vaddr);
|
D_Entity *module = d_module_from_process_vaddr(process, rip_vaddr);
|
||||||
U64 rip_voff = d_voff_from_vaddr(module, rip_vaddr);
|
U64 rip_voff = d_voff_from_vaddr(module, rip_vaddr);
|
||||||
U64 tls_root_vaddr = d_cached_tls_root_vaddr_from_thread(thread->handle);
|
U64 tls_root_vaddr = thread->tls_root_vaddr;
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
@@ -12212,8 +12212,10 @@ rd_frame(void)
|
|||||||
{
|
{
|
||||||
for EachIndex(idx, modules.count)
|
for EachIndex(idx, modules.count)
|
||||||
{
|
{
|
||||||
|
Access *access = access_open();
|
||||||
D_Entity *module = modules.v[idx];
|
D_Entity *module = modules.v[idx];
|
||||||
String8 raddbg_data = d_raddbg_data_from_module(scratch.arena, module->handle);
|
D_ModuleInfo *module_info = d_info_from_module(access, module->handle);
|
||||||
|
String8 raddbg_data = module_info->raddbg_data;
|
||||||
U8 split_char = 0;
|
U8 split_char = 0;
|
||||||
String8List raddbg_data_text_parts = str8_split(scratch.arena, raddbg_data, &split_char, 1, 0);
|
String8List raddbg_data_text_parts = str8_split(scratch.arena, raddbg_data, &split_char, 1, 0);
|
||||||
U64 cfg_idx = 0;
|
U64 cfg_idx = 0;
|
||||||
@@ -12230,6 +12232,7 @@ rd_frame(void)
|
|||||||
cfg_node_ptr_list_push(scratch.arena, &immediate_type_views, n->v);
|
cfg_node_ptr_list_push(scratch.arena, &immediate_type_views, n->v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
access_close(access);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12333,7 +12336,7 @@ rd_frame(void)
|
|||||||
ctx->module_base[0] = module->vaddr_range.min;
|
ctx->module_base[0] = module->vaddr_range.min;
|
||||||
ctx->frame_base = push_array(scratch.arena, U64, 1);
|
ctx->frame_base = push_array(scratch.arena, U64, 1);
|
||||||
ctx->tls_base = push_array(scratch.arena, U64, 1);
|
ctx->tls_base = push_array(scratch.arena, U64, 1);
|
||||||
ctx->tls_base[0] = d_query_cached_tls_base_vaddr_from_process_root_rip(process, tls_root_vaddr, rip_vaddr);
|
ctx->tls_base[0] = d_cached_tls_vaddr_from_thread_module(thread->handle, module->handle, rd_state->frame_eval_memread_endt_us, 0);
|
||||||
ctx->cfa = d_query_cached_cfa_from_thread_unwind(thread, unwind_count);
|
ctx->cfa = d_query_cached_cfa_from_thread_unwind(thread, unwind_count);
|
||||||
}
|
}
|
||||||
e_select_interpret_ctx(interpret_ctx, eval_dbg_infos_primary->rdi, rip_voff);
|
e_select_interpret_ctx(interpret_ctx, eval_dbg_infos_primary->rdi, rip_voff);
|
||||||
@@ -16810,7 +16813,7 @@ rd_frame(void)
|
|||||||
D_EntityArray all_processes = d_entity_array_from_kind(D_EntityKind_Process);
|
D_EntityArray all_processes = d_entity_array_from_kind(D_EntityKind_Process);
|
||||||
|
|
||||||
// rjf: no processes before this one -> new session
|
// rjf: no processes before this one -> new session
|
||||||
if(process_count_pre_tick == 0)
|
if(process_count_pre_tick == 0 && all_processes.count != 0)
|
||||||
{
|
{
|
||||||
D_Entity *process = all_processes.v[0];
|
D_Entity *process = all_processes.v[0];
|
||||||
CFG_Node *target = cfg_node_from_id(process->src_msg_id);
|
CFG_Node *target = cfg_node_from_id(process->src_msg_id);
|
||||||
|
|||||||
@@ -330,6 +330,9 @@
|
|||||||
#include "pdb/pdb_parse.h"
|
#include "pdb/pdb_parse.h"
|
||||||
#include "pdb/pdb_stringize.h"
|
#include "pdb/pdb_stringize.h"
|
||||||
#include "dwarf/dwarf_inc.h"
|
#include "dwarf/dwarf_inc.h"
|
||||||
|
#include "eh_frame/eh_frame.h"
|
||||||
|
#include "eh_frame/eh_frame_dump.h"
|
||||||
|
#include "unwind/unwind_inc.h"
|
||||||
#include "rdi_from_coff/rdi_from_coff.h"
|
#include "rdi_from_coff/rdi_from_coff.h"
|
||||||
#include "rdi_from_elf/rdi_from_elf.h"
|
#include "rdi_from_elf/rdi_from_elf.h"
|
||||||
#include "rdi_from_pdb/rdi_from_pdb.h"
|
#include "rdi_from_pdb/rdi_from_pdb.h"
|
||||||
@@ -384,6 +387,9 @@
|
|||||||
#include "pdb/pdb_parse.c"
|
#include "pdb/pdb_parse.c"
|
||||||
#include "pdb/pdb_stringize.c"
|
#include "pdb/pdb_stringize.c"
|
||||||
#include "dwarf/dwarf_inc.c"
|
#include "dwarf/dwarf_inc.c"
|
||||||
|
#include "eh_frame/eh_frame.c"
|
||||||
|
#include "eh_frame/eh_frame_dump.c"
|
||||||
|
#include "unwind/unwind_inc.c"
|
||||||
#include "rdi_from_coff/rdi_from_coff.c"
|
#include "rdi_from_coff/rdi_from_coff.c"
|
||||||
#include "rdi_from_elf/rdi_from_elf.c"
|
#include "rdi_from_elf/rdi_from_elf.c"
|
||||||
#include "rdi_from_pdb/rdi_from_pdb.c"
|
#include "rdi_from_pdb/rdi_from_pdb.c"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
internal String8
|
internal String8
|
||||||
rd_test__test_binary_path(Arena *arena, TestCtx *ctx, String8 name)
|
rd_test__test_binary_path(Arena *arena, TestCtx *ctx, String8 name)
|
||||||
{
|
{
|
||||||
String8 path = str8f(arena, "%S/%S/%S%S", ctx->input_data_path, name, name, program_ext_postfix_from_os(OperatingSystem_CURRENT));
|
String8 path = str8f(arena, "%S/%S/%S%S", ctx->input_data_path, name, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 1));
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ internal String8
|
|||||||
rd_test__raddbg_path(Arena *arena, CmdLine *cmdline)
|
rd_test__raddbg_path(Arena *arena, CmdLine *cmdline)
|
||||||
{
|
{
|
||||||
String8 raddbg_exe_name = cmd_line_has_flag(cmdline, s("gui")) ? s("raddbg") : s("raddbg_non_graphical");
|
String8 raddbg_exe_name = cmd_line_has_flag(cmdline, s("gui")) ? s("raddbg") : s("raddbg_non_graphical");
|
||||||
String8 raddbg_exe_filename = str8f(arena, "%S/%S%S", get_process_info()->binary_path, raddbg_exe_name, program_ext_postfix_from_os(OperatingSystem_CURRENT));
|
String8 raddbg_exe_filename = str8f(arena, "%S/%S%S", get_process_info()->binary_path, raddbg_exe_name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 0));
|
||||||
return raddbg_exe_filename;
|
return raddbg_exe_filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1401,6 +1401,7 @@ lane_sync(); if(flags & (1ull<<(kind))) ProfScope((char *)rdi_name_title_from_du
|
|||||||
}
|
}
|
||||||
lane_sync();
|
lane_sync();
|
||||||
|
|
||||||
|
#undef DumpSubsetKind
|
||||||
#undef DumpSubset
|
#undef DumpSubset
|
||||||
#undef dumpf
|
#undef dumpf
|
||||||
#undef dump
|
#undef dump
|
||||||
|
|||||||
@@ -2752,7 +2752,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
|
|||||||
|
|
||||||
arch = arch_from_elf_machine(bin.hdr.e_machine);
|
arch = arch_from_elf_machine(bin.hdr.e_machine);
|
||||||
image_base = elf_base_addr_from_bin(&bin);
|
image_base = elf_base_addr_from_bin(&bin);
|
||||||
input = dw_input_from_elf_bin(scratch.arena, params->dbg_data, &bin);
|
input = dw_raw_from_elf_bin(scratch.arena, params->dbg_data, &bin);
|
||||||
path_style = PathStyle_UnixAbsolute;
|
path_style = PathStyle_UnixAbsolute;
|
||||||
|
|
||||||
g_d2r_shared.binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, params->dbg_data, &bin, &bin.shdrs);
|
g_d2r_shared.binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, params->dbg_data, &bin, &bin.shdrs);
|
||||||
|
|||||||
@@ -82,9 +82,9 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
ProfScope("gather unit ranges from .debug_info, .debug_aranges") if(lane_idx() == 0)
|
ProfScope("gather unit ranges from .debug_info, .debug_aranges") if(lane_idx() == 0)
|
||||||
{
|
{
|
||||||
unit_info_ranges = push_array(scratch.arena, Rng1U64Array, 1);
|
unit_info_ranges = push_array(scratch.arena, Rng1U64Array, 1);
|
||||||
*unit_info_ranges = dw2_unit_ranges_from_data(scratch.arena, raw->sec[DW_Section_Info].data);
|
*unit_info_ranges = dw2_unit_ranges_from_data(scratch.arena, raw->sec[DW_SectionKind_Info].data);
|
||||||
unit_arange_ranges = push_array(scratch.arena, Rng1U64Array, 1);
|
unit_arange_ranges = push_array(scratch.arena, Rng1U64Array, 1);
|
||||||
*unit_arange_ranges = dw2_unit_ranges_from_data(scratch.arena, raw->sec[DW_Section_ARanges].data);
|
*unit_arange_ranges = dw2_unit_ranges_from_data(scratch.arena, raw->sec[DW_SectionKind_ARanges].data);
|
||||||
}
|
}
|
||||||
lane_sync_u64(&unit_info_ranges, 0);
|
lane_sync_u64(&unit_info_ranges, 0);
|
||||||
lane_sync_u64(&unit_arange_ranges, 0);
|
lane_sync_u64(&unit_arange_ranges, 0);
|
||||||
@@ -107,7 +107,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
lane_sync_u64(&unit_info_tag_ranges, 0);
|
lane_sync_u64(&unit_info_tag_ranges, 0);
|
||||||
|
|
||||||
// rjf: parse all unit headers
|
// rjf: parse all unit headers
|
||||||
String8 data = raw->sec[DW_Section_Info].data;
|
String8 data = raw->sec[DW_SectionKind_Info].data;
|
||||||
Rng1U64 range = lane_range(unit_count);
|
Rng1U64 range = lane_range(unit_count);
|
||||||
for EachInRange(idx, range)
|
for EachInRange(idx, range)
|
||||||
{
|
{
|
||||||
@@ -135,7 +135,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
U64 unit_take_idx_ = 0;
|
U64 unit_take_idx_ = 0;
|
||||||
U64 *unit_take_idx_ptr = &unit_take_idx_;
|
U64 *unit_take_idx_ptr = &unit_take_idx_;
|
||||||
lane_sync_u64(&unit_take_idx_ptr, 0);
|
lane_sync_u64(&unit_take_idx_ptr, 0);
|
||||||
String8 data = raw->sec[DW_Section_ARanges].data;
|
String8 data = raw->sec[DW_SectionKind_ARanges].data;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
// rjf: take unit
|
// rjf: take unit
|
||||||
@@ -264,115 +264,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
////////////////////////////
|
////////////////////////////
|
||||||
//- rjf: build all abbreviation maps, build (unit -> abbrev map)
|
//- rjf: build all abbreviation maps, build (unit -> abbrev map)
|
||||||
//
|
//
|
||||||
U64 abbrev_map_count = 0;
|
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);
|
||||||
U64 *abbrev_map_off_from_idx_table = 0;
|
|
||||||
DW2_AbbrevMap *abbrev_map_from_idx_table = 0;
|
|
||||||
DW2_AbbrevMap **abbrev_map_from_unit_idx_table = 0;
|
|
||||||
ProfScope("build all abbreviation maps, build (unit -> abbrev map)")
|
|
||||||
{
|
|
||||||
//- rjf: gather deduplicated .debug_abbrev offsets, representing beginnings
|
|
||||||
// of abbreviation tables. we want to do this because many units may refer
|
|
||||||
// to the same abbreviation table.
|
|
||||||
//
|
|
||||||
typedef struct AbbrevOffNode AbbrevOffNode;
|
|
||||||
struct AbbrevOffNode
|
|
||||||
{
|
|
||||||
AbbrevOffNode *order_next;
|
|
||||||
AbbrevOffNode *hash_next;
|
|
||||||
U64 off;
|
|
||||||
U64 idx;
|
|
||||||
};
|
|
||||||
U64 abbrev_off_slots_count = unit_count;
|
|
||||||
AbbrevOffNode **abbrev_off_slots = 0;
|
|
||||||
ProfScope("gather deduplicated .debug_abbrev offsets") if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
AbbrevOffNode *abbrev_off_first = 0;
|
|
||||||
AbbrevOffNode *abbrev_off_last = 0;
|
|
||||||
abbrev_off_slots = push_array(scratch.arena, AbbrevOffNode *, abbrev_off_slots_count);
|
|
||||||
for EachIndex(unit_idx, unit_count)
|
|
||||||
{
|
|
||||||
U64 abbrev_off = unit_headers[unit_idx].abbrev_off;
|
|
||||||
U64 hash = u64_hash_from_str8(str8_struct(&abbrev_off));
|
|
||||||
U64 slot_idx = hash%abbrev_off_slots_count;
|
|
||||||
AbbrevOffNode *node = 0;
|
|
||||||
for(AbbrevOffNode *n = abbrev_off_slots[slot_idx]; n != 0; n = n->hash_next)
|
|
||||||
{
|
|
||||||
if(n->off == abbrev_off)
|
|
||||||
{
|
|
||||||
node = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(node == 0)
|
|
||||||
{
|
|
||||||
node = push_array(scratch.arena, AbbrevOffNode, 1);
|
|
||||||
SLLStackPush_N(abbrev_off_slots[slot_idx], node, hash_next);
|
|
||||||
SLLQueuePush_N(abbrev_off_first, abbrev_off_last, node, order_next);
|
|
||||||
node->off = abbrev_off;
|
|
||||||
node->idx = abbrev_map_count;
|
|
||||||
abbrev_map_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
abbrev_map_off_from_idx_table = push_array(scratch.arena, U64, abbrev_map_count);
|
|
||||||
abbrev_map_from_idx_table = push_array(scratch.arena, DW2_AbbrevMap, abbrev_map_count);
|
|
||||||
abbrev_map_from_unit_idx_table = push_array(scratch.arena, DW2_AbbrevMap *, unit_count);
|
|
||||||
{
|
|
||||||
U64 abbrev_map_idx = 0;
|
|
||||||
for(AbbrevOffNode *n = abbrev_off_first; n != 0; n = n->order_next)
|
|
||||||
{
|
|
||||||
abbrev_map_off_from_idx_table[abbrev_map_idx] = n->off;
|
|
||||||
abbrev_map_idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync_u64(&abbrev_off_slots, 0);
|
|
||||||
lane_sync_u64(&abbrev_map_count, 0);
|
|
||||||
lane_sync_u64(&abbrev_map_off_from_idx_table, 0);
|
|
||||||
lane_sync_u64(&abbrev_map_from_idx_table, 0);
|
|
||||||
lane_sync_u64(&abbrev_map_from_unit_idx_table, 0);
|
|
||||||
|
|
||||||
//- rjf: build all unique abbreviation maps
|
|
||||||
ProfScope("build all unique abbreviation maps")
|
|
||||||
{
|
|
||||||
String8 abbrev_data = raw->sec[DW_Section_Abbrev].data;
|
|
||||||
U64 abbrev_map_take_idx = 0;
|
|
||||||
U64 *abbrev_map_take_idx_ptr = &abbrev_map_take_idx;
|
|
||||||
lane_sync_u64(&abbrev_map_take_idx_ptr, 0);
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
U64 abbrev_map_idx = ins_atomic_u64_inc_eval(abbrev_map_take_idx_ptr) - 1;
|
|
||||||
if(abbrev_map_idx >= abbrev_map_count)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
abbrev_map_from_idx_table[abbrev_map_idx] = dw2_abbrev_map_from_data(scratch.arena, abbrev_data, abbrev_map_off_from_idx_table[abbrev_map_idx]);
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: build unit -> abbrev map table
|
|
||||||
ProfScope("build unit -> abbrev map table")
|
|
||||||
{
|
|
||||||
Rng1U64 range = lane_range(unit_count);
|
|
||||||
for EachInRange(unit_idx, range)
|
|
||||||
{
|
|
||||||
U64 abbrev_off = unit_headers[unit_idx].abbrev_off;
|
|
||||||
U64 hash = u64_hash_from_str8(str8_struct(&abbrev_off));
|
|
||||||
U64 slot_idx = hash%abbrev_off_slots_count;
|
|
||||||
U64 abbrev_map_idx = 0;
|
|
||||||
for(AbbrevOffNode *n = abbrev_off_slots[slot_idx]; n != 0; n = n->hash_next)
|
|
||||||
{
|
|
||||||
if(n->off == abbrev_off)
|
|
||||||
{
|
|
||||||
abbrev_map_idx = n->idx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
abbrev_map_from_unit_idx_table[unit_idx] = &abbrev_map_from_idx_table[abbrev_map_idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
//- rjf: parse all unit offsets tables
|
//- rjf: parse all unit offsets tables
|
||||||
@@ -399,249 +291,62 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
//
|
//
|
||||||
// thank you, again, DWARF.
|
// thank you, again, DWARF.
|
||||||
//
|
//
|
||||||
U64 str_offsets_tables_count = 0;
|
DW2_OffsetTableSet *offset_tables = 0;
|
||||||
DW2_OffsetTable *str_offsets_tables = 0;
|
|
||||||
Rng1U64 *str_offsets_tables_ranges = 0;
|
|
||||||
U64 rnglists_tables_count = 0;
|
|
||||||
DW2_OffsetTable *rnglists_tables = 0;
|
|
||||||
Rng1U64 *rnglists_tables_ranges = 0;
|
|
||||||
U64 addr_tables_count = 0;
|
|
||||||
DW2_OffsetTable *addr_tables = 0;
|
|
||||||
Rng1U64 *addr_tables_ranges = 0;
|
|
||||||
U64 loclists_tables_count = 0;
|
|
||||||
DW2_OffsetTable *loclists_tables = 0;
|
|
||||||
Rng1U64 *loclists_tables_ranges = 0;
|
|
||||||
ProfScope("parse all offset tables (.debug_rnglists, .debug_str_offsets, .debug_addr, .debug_loclists)") if(lane_idx() == 0)
|
ProfScope("parse all offset tables (.debug_rnglists, .debug_str_offsets, .debug_addr, .debug_loclists)") if(lane_idx() == 0)
|
||||||
{
|
{
|
||||||
struct
|
offset_tables = push_array(scratch.arena, DW2_OffsetTableSet, 1);
|
||||||
{
|
offset_tables[0] = dw2_offset_table_set_from_raw(scratch.arena, raw);
|
||||||
String8 data;
|
|
||||||
U64 *tables_count_out;
|
|
||||||
DW2_OffsetTable **tables_out;
|
|
||||||
Rng1U64 **tables_ranges_out;
|
|
||||||
}
|
|
||||||
tasks[] =
|
|
||||||
{
|
|
||||||
{raw->sec[DW_Section_StrOffsets].data, &str_offsets_tables_count, &str_offsets_tables, &str_offsets_tables_ranges},
|
|
||||||
{raw->sec[DW_Section_RngLists].data, &rnglists_tables_count, &rnglists_tables, &rnglists_tables_ranges},
|
|
||||||
{raw->sec[DW_Section_Addr].data, &addr_tables_count, &addr_tables, &addr_tables_ranges},
|
|
||||||
{raw->sec[DW_Section_LocLists].data, &loclists_tables_count, &loclists_tables, &loclists_tables_ranges},
|
|
||||||
};
|
|
||||||
for EachElement(task_idx, tasks)
|
|
||||||
{
|
|
||||||
Temp scratch2 = scratch_begin(&scratch.arena, 1);
|
|
||||||
String8 data = tasks[task_idx].data;
|
|
||||||
|
|
||||||
//- rjf: gather all tables (loose)
|
|
||||||
typedef struct TableNode TableNode;
|
|
||||||
struct TableNode
|
|
||||||
{
|
|
||||||
TableNode *next;
|
|
||||||
DW2_OffsetTable v;
|
|
||||||
Rng1U64 range;
|
|
||||||
};
|
|
||||||
TableNode *first_table = 0;
|
|
||||||
TableNode *last_table = 0;
|
|
||||||
U64 table_count = 0;
|
|
||||||
for(U64 off = 0; off < data.size;)
|
|
||||||
{
|
|
||||||
U64 start_off = off;
|
|
||||||
DW2_OffsetTable table = {0};
|
|
||||||
off += dw2_read_offset_table(data, off, &table);
|
|
||||||
if(table.entries != 0)
|
|
||||||
{
|
|
||||||
TableNode *n = push_array(scratch2.arena, TableNode, 1);
|
|
||||||
SLLQueuePush(first_table, last_table, n);
|
|
||||||
n->v = table;
|
|
||||||
n->range = r1u64(start_off, off);
|
|
||||||
table_count += 1;
|
|
||||||
}
|
|
||||||
if(off == start_off)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: tighten
|
|
||||||
tasks[task_idx].tables_count_out[0] = table_count;
|
|
||||||
tasks[task_idx].tables_out[0] = push_array(scratch.arena, DW2_OffsetTable, table_count);
|
|
||||||
tasks[task_idx].tables_ranges_out[0] = push_array(scratch.arena, Rng1U64, table_count);
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for EachNode(n, TableNode, first_table)
|
|
||||||
{
|
|
||||||
tasks[task_idx].tables_out[0][idx] = n->v;
|
|
||||||
tasks[task_idx].tables_ranges_out[0][idx] = n->range;
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lane_sync_u64(&str_offsets_tables_count, 0);
|
lane_sync_u64(&offset_tables, 0);
|
||||||
lane_sync_u64(&str_offsets_tables, 0);
|
|
||||||
lane_sync_u64(&str_offsets_tables_ranges, 0);
|
|
||||||
lane_sync_u64(&rnglists_tables_count, 0);
|
|
||||||
lane_sync_u64(&rnglists_tables, 0);
|
|
||||||
lane_sync_u64(&rnglists_tables_ranges, 0);
|
|
||||||
lane_sync_u64(&addr_tables_count, 0);
|
|
||||||
lane_sync_u64(&addr_tables, 0);
|
|
||||||
lane_sync_u64(&addr_tables_ranges, 0);
|
|
||||||
lane_sync_u64(&loclists_tables_count, 0);
|
|
||||||
lane_sync_u64(&loclists_tables, 0);
|
|
||||||
lane_sync_u64(&loclists_tables_ranges, 0);
|
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
//- rjf: build per-unit parsing contexts
|
//- rjf: build per-unit parsing contexts, parse compilation unit tags
|
||||||
//
|
//
|
||||||
DW2_ParseCtx *unit_parse_ctxs = 0;
|
DW2_ParseCtx *unit_parse_ctxs = 0;
|
||||||
|
DW2_Tag *unit_root_tags = 0;
|
||||||
{
|
{
|
||||||
if(lane_idx() == 0)
|
if(lane_idx() == 0)
|
||||||
{
|
{
|
||||||
unit_parse_ctxs = push_array(scratch.arena, DW2_ParseCtx, unit_count);
|
unit_parse_ctxs = push_array(scratch.arena, DW2_ParseCtx, unit_count);
|
||||||
|
unit_root_tags = push_array(scratch.arena, DW2_Tag, unit_count);
|
||||||
}
|
}
|
||||||
lane_sync_u64(&unit_parse_ctxs, 0);
|
lane_sync_u64(&unit_parse_ctxs, 0);
|
||||||
|
lane_sync_u64(&unit_root_tags, 0);
|
||||||
Rng1U64 range = lane_range(unit_count);
|
Rng1U64 range = lane_range(unit_count);
|
||||||
for EachInRange(unit_idx, range)
|
for EachInRange(unit_idx, range)
|
||||||
{
|
{
|
||||||
DW2_UnitHeader *hdr = &unit_headers[unit_idx];
|
DW2_UnitHeader *hdr = &unit_headers[unit_idx];
|
||||||
DW2_ParseCtx *ctx = &unit_parse_ctxs[unit_idx];
|
DW2_ParseCtx *ctx = &unit_parse_ctxs[unit_idx];
|
||||||
ctx->raw = raw;
|
|
||||||
ctx->version = hdr->version;
|
|
||||||
ctx->format = hdr->format;
|
|
||||||
ctx->addr_size = hdr->addr_size;
|
|
||||||
ctx->unit_base_info_off = unit_info_ranges->v[unit_idx].min;
|
|
||||||
ctx->abbrev_map = abbrev_map_from_unit_idx_table[unit_idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
////////////////////////////
|
// rjf: equip initial info - just enough to do a bootstrapping parse of the root tag
|
||||||
//- rjf: do initial parse of each unit's root-level tag
|
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);
|
||||||
// an incredible NOTE: this is actually not sufficient. because this tag parse
|
|
||||||
// is what informs us which .debug_str_offsets table each unit should be associated
|
|
||||||
// with (via the StrOffsetsBase attribute), we actually don't have the right string
|
|
||||||
// offset table *before* we parse this, which means we can't resolve some of the
|
|
||||||
// string attribute values.
|
|
||||||
//
|
|
||||||
// so, in another incredible twist of fate, we actually must do this *twice*. first,
|
|
||||||
// to find *just the StrOffsetsBase*, and then, to actually fully resolve everything.
|
|
||||||
//
|
|
||||||
// (all of the above is also true for RngListsBase)
|
|
||||||
//
|
|
||||||
DW2_Tag *unit_root_tags__pre_offset_tables = 0;
|
|
||||||
{
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
unit_root_tags__pre_offset_tables = push_array(scratch.arena, DW2_Tag, unit_count);
|
|
||||||
}
|
|
||||||
lane_sync_u64(&unit_root_tags__pre_offset_tables, 0);
|
|
||||||
Rng1U64 range = lane_range(unit_count);
|
|
||||||
for EachInRange(unit_idx, range)
|
|
||||||
{
|
|
||||||
dw2_read_tag(scratch.arena, &unit_parse_ctxs[unit_idx], raw->sec[DW_Section_Info].data, unit_info_tag_ranges[unit_idx].min, &unit_root_tags__pre_offset_tables[unit_idx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
////////////////////////////
|
// rjf: do bootstrapping parse
|
||||||
//- rjf: look up base addresses for each unit - equip to per-unit parsing contexts
|
//
|
||||||
//
|
// an incredible NOTE: the above context info is actually not sufficient for general
|
||||||
{
|
// parsing, because this "bootstrapping" tag parse is what informs us which
|
||||||
Rng1U64 range = lane_range(unit_count);
|
// .debug_str_offsets table each unit should be associated with (via the
|
||||||
for EachInRange(unit_idx, range)
|
// StrOffsetsBase attribute), we actually don't have the right string offset table
|
||||||
{
|
// *before* we parse this, which means we can't resolve some of the string attribute
|
||||||
DW2_Tag *unit_root_tag = &unit_root_tags__pre_offset_tables[unit_idx];
|
// values.
|
||||||
DW2_Attrib *low_pc_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_LowPc);
|
//
|
||||||
U64 low_pc = low_pc_attrib->val.addr;
|
// so, in another incredible twist of fate, we actually must do this *twice*. first,
|
||||||
unit_parse_ctxs[unit_idx].unit_base_addr = low_pc;
|
// to find *just the StrOffsetsBase*, and then, to actually fully resolve everything.
|
||||||
}
|
//
|
||||||
}
|
// (all of the above is also true for RngListsBase)
|
||||||
lane_sync();
|
//
|
||||||
|
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
|
||||||
//- rjf: look up offset tables for each unit (.debug_str_offsets, .debug_rnglists, etc.);
|
dw2_parse_ctx_equip_unit_root_tag(ctx, &root_tag_bootstrap, offset_tables);
|
||||||
// equip to per-unit parsing contexts
|
|
||||||
//
|
|
||||||
{
|
|
||||||
Rng1U64Array rnglists_tables_ranges_array = {rnglists_tables_ranges, rnglists_tables_count};
|
|
||||||
Rng1U64Array str_offsets_tables_ranges_array = {str_offsets_tables_ranges, str_offsets_tables_count};
|
|
||||||
Rng1U64Array addr_tables_ranges_array = {addr_tables_ranges, addr_tables_count};
|
|
||||||
Rng1U64Array loclist_tables_ranges_array = {loclists_tables_ranges, loclists_tables_count};
|
|
||||||
Rng1U64 range = lane_range(unit_count);
|
|
||||||
for EachInRange(unit_idx, range)
|
|
||||||
{
|
|
||||||
DW2_Tag *unit_root_tag = &unit_root_tags__pre_offset_tables[unit_idx];
|
|
||||||
|
|
||||||
// rjf: find rnglists table
|
// rjf: do non-bootstrapping parse
|
||||||
{
|
dw2_read_tag(scratch.arena, raw, ctx, raw->sec[DW_SectionKind_Info].data, unit_info_tag_ranges[unit_idx].min, &unit_root_tags[unit_idx]);
|
||||||
DW2_Attrib *rnglists_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_RngListsBase);
|
|
||||||
U64 rnglists_base_off = rnglists_base_off_attrib->val.u128.u64[0];
|
|
||||||
U64 rnglists_table_num = rng1u64_array_num_from_value__binary_search(&rnglists_tables_ranges_array, rnglists_base_off);
|
|
||||||
if(0 < rnglists_table_num && rnglists_table_num <= rnglists_tables_ranges_array.count)
|
|
||||||
{
|
|
||||||
DW2_OffsetTable *table = &rnglists_tables[rnglists_table_num-1];
|
|
||||||
unit_parse_ctxs[unit_idx].rnglists_table = table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: find str offsets table
|
// rjf: equip info extracted from non-bootstrapping parse
|
||||||
{
|
dw2_parse_ctx_equip_unit_root_tag(ctx, &unit_root_tags[unit_idx], offset_tables);
|
||||||
DW2_Attrib *str_offsets_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_StrOffsetsBase);
|
|
||||||
U64 str_offsets_base_off = str_offsets_base_off_attrib->val.u128.u64[0];
|
|
||||||
U64 str_offsets_table_num = rng1u64_array_num_from_value__binary_search(&str_offsets_tables_ranges_array, str_offsets_base_off);
|
|
||||||
if(0 < str_offsets_table_num && str_offsets_table_num <= str_offsets_tables_ranges_array.count)
|
|
||||||
{
|
|
||||||
DW2_OffsetTable *table = &str_offsets_tables[str_offsets_table_num-1];
|
|
||||||
unit_parse_ctxs[unit_idx].str_offsets_table = table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: find addr table
|
|
||||||
{
|
|
||||||
DW2_Attrib *addr_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_AddrBase);
|
|
||||||
U64 addr_base_off = addr_base_off_attrib->val.u128.u64[0];
|
|
||||||
U64 addr_table_num = rng1u64_array_num_from_value__binary_search(&addr_tables_ranges_array, addr_base_off);
|
|
||||||
if(0 < addr_table_num && addr_table_num <= addr_tables_ranges_array.count)
|
|
||||||
{
|
|
||||||
DW2_OffsetTable *table = &addr_tables[addr_table_num-1];
|
|
||||||
unit_parse_ctxs[unit_idx].addr_table = table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: find addr table
|
|
||||||
{
|
|
||||||
DW2_Attrib *loclist_base_off_attrib = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_LocListsBase);
|
|
||||||
U64 loclist_base_off = loclist_base_off_attrib->val.u128.u64[0];
|
|
||||||
U64 loclist_table_num = rng1u64_array_num_from_value__binary_search(&loclist_tables_ranges_array, loclist_base_off);
|
|
||||||
if(0 < loclist_table_num && loclist_table_num <= loclist_tables_ranges_array.count)
|
|
||||||
{
|
|
||||||
DW2_OffsetTable *table = &loclists_tables[loclist_table_num-1];
|
|
||||||
unit_parse_ctxs[unit_idx].loclists_table = table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
////////////////////////////
|
|
||||||
//- rjf: do parse of each unit's root tag AFTER finding the right .debug_str_offsets table
|
|
||||||
//
|
|
||||||
// (excellent work everyone - thank you for reminding me why RDI is necessary)
|
|
||||||
//
|
|
||||||
DW2_Tag *unit_root_tags = 0;
|
|
||||||
{
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
unit_root_tags = push_array(scratch.arena, DW2_Tag, unit_count);
|
|
||||||
}
|
|
||||||
lane_sync_u64(&unit_root_tags, 0);
|
|
||||||
Rng1U64 range = lane_range(unit_count);
|
|
||||||
for EachInRange(unit_idx, range)
|
|
||||||
{
|
|
||||||
dw2_read_tag(scratch.arena, &unit_parse_ctxs[unit_idx], raw->sec[DW_Section_Info].data, unit_info_tag_ranges[unit_idx].min, &unit_root_tags[unit_idx]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lane_sync();
|
lane_sync();
|
||||||
@@ -671,8 +376,8 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
DW2_Tag *unit_root_tag = &unit_root_tags[unit_idx];
|
DW2_Tag *unit_root_tag = &unit_root_tags[unit_idx];
|
||||||
DW2_Attrib *stmt_list = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_StmtList);
|
DW2_Attrib *stmt_list = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_StmtList);
|
||||||
U64 line_info_off = stmt_list->val.u128.u64[0];
|
U64 line_info_off = stmt_list->val.u128.u64[0];
|
||||||
String8 line_info_data = raw->sec[DW_Section_Line].data;
|
String8 line_info_data = raw->sec[DW_SectionKind_Line].data;
|
||||||
dw2_read_line_table_header(scratch.arena, ctx, line_info_data, line_info_off, &unit_line_table_headers[unit_idx]);
|
dw2_read_line_table_header(scratch.arena, raw, ctx, line_info_data, line_info_off, &unit_line_table_headers[unit_idx]);
|
||||||
}
|
}
|
||||||
lane_sync();
|
lane_sync();
|
||||||
}
|
}
|
||||||
@@ -825,7 +530,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
DW2_Tag *unit_root_tag = &unit_root_tags[unit_idx];
|
DW2_Tag *unit_root_tag = &unit_root_tags[unit_idx];
|
||||||
DW2_Attrib *stmt_list = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_StmtList);
|
DW2_Attrib *stmt_list = dw2_attrib_from_kind(unit_root_tag, DW_AttribKind_StmtList);
|
||||||
U64 line_info_off = stmt_list->val.u128.u64[0];
|
U64 line_info_off = stmt_list->val.u128.u64[0];
|
||||||
String8 all_line_info_data = raw->sec[DW_Section_Line].data;
|
String8 all_line_info_data = raw->sec[DW_SectionKind_Line].data;
|
||||||
String8 unit_line_table_data = str8_substr(all_line_info_data, r1u64(line_table_header->line_program_off, line_info_off + line_table_header->total_unit_data_size));
|
String8 unit_line_table_data = str8_substr(all_line_info_data, r1u64(line_table_header->line_program_off, line_info_off + line_table_header->total_unit_data_size));
|
||||||
|
|
||||||
//- rjf: build unit's line table
|
//- rjf: build unit's line table
|
||||||
@@ -1295,7 +1000,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
//- rjf: reading the next tag
|
//- rjf: reading the next tag
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
off += dw2_read_tag(scratch3.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &tag);
|
off += dw2_read_tag(scratch3.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
|
||||||
|
|
||||||
//- rjf: do tree navigations
|
//- rjf: do tree navigations
|
||||||
if(tag.has_children)
|
if(tag.has_children)
|
||||||
@@ -1508,7 +1213,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
// rjf: read tag
|
// rjf: read tag
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
off += dw2_read_tag(tag_scratch.arena, origin_unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &tag);
|
off += dw2_read_tag(tag_scratch.arena, raw, origin_unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
|
||||||
|
|
||||||
// rjf: is this one of the tags we'd like to dedup? -> gather
|
// rjf: is this one of the tags we'd like to dedup? -> gather
|
||||||
if(tag.kind == DW_TagKind_ArrayType ||
|
if(tag.kind == DW_TagKind_ArrayType ||
|
||||||
@@ -1667,7 +1372,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
// rjf: read tag
|
// rjf: read tag
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
t_off += dw2_read_tag(tag_scratch.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, t_off, &tag);
|
t_off += dw2_read_tag(tag_scratch.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, t_off, &tag);
|
||||||
|
|
||||||
// rjf: determine if tag should be skipped from hashing
|
// rjf: determine if tag should be skipped from hashing
|
||||||
B32 should_skip_tag = (tag.kind == DW_TagKind_LexicalBlock ||
|
B32 should_skip_tag = (tag.kind == DW_TagKind_LexicalBlock ||
|
||||||
@@ -1691,14 +1396,14 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
for(DW2_AttribNode *n = tag.attribs.first; n != 0; n = n->next)
|
for(DW2_AttribNode *n = tag.attribs.first; n != 0; n = n->next)
|
||||||
{
|
{
|
||||||
// rjf: non-reference? -> combine attribute value info
|
// rjf: non-reference? -> combine attribute value info
|
||||||
if(n->v.val.kind != DW_Form_RefAddr &&
|
if(n->v.val.kind != DW_FormKind_RefAddr &&
|
||||||
n->v.val.kind != DW_Form_Ref1 &&
|
n->v.val.kind != DW_FormKind_Ref1 &&
|
||||||
n->v.val.kind != DW_Form_Ref2 &&
|
n->v.val.kind != DW_FormKind_Ref2 &&
|
||||||
n->v.val.kind != DW_Form_Ref4 &&
|
n->v.val.kind != DW_FormKind_Ref4 &&
|
||||||
n->v.val.kind != DW_Form_Ref8 &&
|
n->v.val.kind != DW_FormKind_Ref8 &&
|
||||||
n->v.val.kind != DW_Form_RefUData &&
|
n->v.val.kind != DW_FormKind_RefUData &&
|
||||||
n->v.val.kind != DW_Form_RefSup4 &&
|
n->v.val.kind != DW_FormKind_RefSup4 &&
|
||||||
n->v.val.kind != DW_Form_RefSig8 &&
|
n->v.val.kind != DW_FormKind_RefSig8 &&
|
||||||
((tag.kind != DW_TagKind_SubProgram &&
|
((tag.kind != DW_TagKind_SubProgram &&
|
||||||
tag.kind != DW_TagKind_FormalParameter) ||
|
tag.kind != DW_TagKind_FormalParameter) ||
|
||||||
(n->v.attrib_kind != DW_AttribKind_Name &&
|
(n->v.attrib_kind != DW_AttribKind_Name &&
|
||||||
@@ -2090,7 +1795,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
// rjf: parse this type's tag
|
// rjf: parse this type's tag
|
||||||
U64 read_off = info_off;
|
U64 read_off = info_off;
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
read_off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, read_off, &tag);
|
read_off += dw2_read_tag(scratch2.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, read_off, &tag);
|
||||||
|
|
||||||
// rjf: find direct types from this type tag
|
// rjf: find direct types from this type tag
|
||||||
typedef struct DirectTypeNode DirectTypeNode;
|
typedef struct DirectTypeNode DirectTypeNode;
|
||||||
@@ -2146,7 +1851,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
// rjf: read child tag
|
// rjf: read child tag
|
||||||
DW2_Tag child_tag = {0};
|
DW2_Tag child_tag = {0};
|
||||||
read_off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, read_off, &child_tag);
|
read_off += dw2_read_tag(scratch2.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, read_off, &child_tag);
|
||||||
|
|
||||||
// rjf: formal parameters -> gather direct types
|
// rjf: formal parameters -> gather direct types
|
||||||
if(depth == 1 && child_tag.kind == DW_TagKind_FormalParameter)
|
if(depth == 1 && child_tag.kind == DW_TagKind_FormalParameter)
|
||||||
@@ -2315,7 +2020,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
// rjf: parse root-level tag
|
// rjf: parse root-level tag
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
U64 tag_info_size = dw2_read_tag(temp.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, info_off, &tag);
|
U64 tag_info_size = dw2_read_tag(temp.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, info_off, &tag);
|
||||||
|
|
||||||
// rjf: extract common attributes
|
// rjf: extract common attributes
|
||||||
DW2_Attrib *name_attrib = &dw2_attrib_nil;
|
DW2_Attrib *name_attrib = &dw2_attrib_nil;
|
||||||
@@ -2453,7 +2158,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
// rjf: read child tag
|
// rjf: read child tag
|
||||||
DW2_Tag child_tag = {0};
|
DW2_Tag child_tag = {0};
|
||||||
off += dw2_read_tag(scratch3.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &child_tag);
|
off += dw2_read_tag(scratch3.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &child_tag);
|
||||||
|
|
||||||
// rjf: gather parameters
|
// rjf: gather parameters
|
||||||
if(depth == 1 && child_tag.kind == DW_TagKind_FormalParameter)
|
if(depth == 1 && child_tag.kind == DW_TagKind_FormalParameter)
|
||||||
@@ -2654,7 +2359,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
{
|
{
|
||||||
U64 start_off = off;
|
U64 start_off = off;
|
||||||
DW2_Tag child_tag = {0};
|
DW2_Tag child_tag = {0};
|
||||||
off += dw2_read_tag(temp.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &child_tag);
|
off += dw2_read_tag(temp.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &child_tag);
|
||||||
if(child_tag.kind == DW_TagKind_SubrangeType)
|
if(child_tag.kind == DW_TagKind_SubrangeType)
|
||||||
{
|
{
|
||||||
// rjf: extract bounds attribs
|
// rjf: extract bounds attribs
|
||||||
@@ -2681,8 +2386,9 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
// rjf: resolve lower bound
|
// rjf: resolve lower bound
|
||||||
U64 lower_bound = 0;
|
U64 lower_bound = 0;
|
||||||
|
if(lower_bound_attrib != &dw2_attrib_nil)
|
||||||
{
|
{
|
||||||
if(dw_is_form_kind_ref(unit_parse_ctx->version, unit_parse_ctx->ext, lower_bound_attrib->val.kind))
|
if(dw_attrib_class_from_form_kind(unit_parse_ctx->version, unit_parse_ctx->exts, lower_bound_attrib->val.kind) & DW_AttribClass_Reference)
|
||||||
{
|
{
|
||||||
log_infof("[.debug_info@0x%I64x] Array type lower bound is a variable; this is not currently supported.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] Array type lower bound is a variable; this is not currently supported.\n", start_off);
|
||||||
}
|
}
|
||||||
@@ -2691,6 +2397,13 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
lower_bound = lower_bound_attrib->val.u128.u64[0];
|
lower_bound = lower_bound_attrib->val.u128.u64[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else switch(unit_parse_ctx->language)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
#define X(name, code, default_array_lower_bound) case DW_Language_##name:{lower_bound = (default_array_lower_bound);}break;
|
||||||
|
DW_Language_XList
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
// rjf: resolve upper bound
|
// rjf: resolve upper bound
|
||||||
U64 upper_bound = 0;
|
U64 upper_bound = 0;
|
||||||
@@ -2701,7 +2414,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
}
|
}
|
||||||
else if(upper_bound_attrib != &dw2_attrib_nil)
|
else if(upper_bound_attrib != &dw2_attrib_nil)
|
||||||
{
|
{
|
||||||
if(dw_is_form_kind_ref(unit_parse_ctx->version, unit_parse_ctx->ext, upper_bound_attrib->val.kind))
|
if(dw_attrib_class_from_form_kind(unit_parse_ctx->version, unit_parse_ctx->exts, upper_bound_attrib->val.kind) & DW_AttribClass_Reference)
|
||||||
{
|
{
|
||||||
log_infof("[.debug_info@0x%I64x] Array type upper bound is a variable; this is not currently supported.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] Array type upper bound is a variable; this is not currently supported.\n", start_off);
|
||||||
}
|
}
|
||||||
@@ -2833,7 +2546,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
// rjf: read namespace tag
|
// rjf: read namespace tag
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, info_off, &tag);
|
dw2_read_tag(scratch2.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, info_off, &tag);
|
||||||
DW2_Attrib *name_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Name);
|
DW2_Attrib *name_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Name);
|
||||||
String8 name = name_attrib->val.string;
|
String8 name = name_attrib->val.string;
|
||||||
|
|
||||||
@@ -2917,7 +2630,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
// rjf: parse tag
|
// rjf: parse tag
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
U64 tag_parse_off = off;
|
U64 tag_parse_off = off;
|
||||||
off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &tag);
|
off += dw2_read_tag(scratch2.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
|
||||||
|
|
||||||
// rjf: unpack tag attributes
|
// rjf: unpack tag attributes
|
||||||
DW2_Attrib *name_attrib = &dw2_attrib_nil;
|
DW2_Attrib *name_attrib = &dw2_attrib_nil;
|
||||||
@@ -3183,7 +2896,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
{
|
{
|
||||||
U64 voff_base = lopc_attrib->val.addr - base_vaddr;
|
U64 voff_base = lopc_attrib->val.addr - base_vaddr;
|
||||||
U64 voff_opl = 0;
|
U64 voff_opl = 0;
|
||||||
if(dw_attrib_class_from_form_kind(unit_parse_ctx->version, hipc_attrib->val.kind) & (1<<DW_AttribClass_Address))
|
if(dw_attrib_class_from_form_kind(unit_parse_ctx->version, unit_parse_ctx->exts, hipc_attrib->val.kind) & (1<<DW_AttribClass_Address))
|
||||||
{
|
{
|
||||||
voff_opl = voff_base + hipc_attrib->val.u128.u64[0];
|
voff_opl = voff_base + hipc_attrib->val.u128.u64[0];
|
||||||
}
|
}
|
||||||
@@ -3298,7 +3011,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
//- rjf: parse tag
|
//- rjf: parse tag
|
||||||
//
|
//
|
||||||
DW2_Tag tag = {0};
|
DW2_Tag tag = {0};
|
||||||
off += dw2_read_tag(scratch2.arena, unit_parse_ctx, raw->sec[DW_Section_Info].data, off, &tag);
|
off += dw2_read_tag(scratch2.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
|
||||||
|
|
||||||
////////////////////////
|
////////////////////////
|
||||||
//- rjf: gather attributes from tag
|
//- rjf: gather attributes from tag
|
||||||
@@ -3365,7 +3078,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
{
|
{
|
||||||
U64 voff_base = lopc_attrib->val.addr - base_vaddr;
|
U64 voff_base = lopc_attrib->val.addr - base_vaddr;
|
||||||
U64 voff_opl = 0;
|
U64 voff_opl = 0;
|
||||||
if(dw_attrib_class_from_form_kind(unit_parse_ctx->version, hipc_attrib->val.kind) & (1<<DW_AttribClass_Address))
|
if(dw_attrib_class_from_form_kind(unit_parse_ctx->version, unit_parse_ctx->exts, hipc_attrib->val.kind) & (1<<DW_AttribClass_Address))
|
||||||
{
|
{
|
||||||
voff_opl = voff_base + hipc_attrib->val.u128.u64[0];
|
voff_opl = voff_base + hipc_attrib->val.u128.u64[0];
|
||||||
}
|
}
|
||||||
@@ -3467,19 +3180,19 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
switch(attrib->val.kind)
|
switch(attrib->val.kind)
|
||||||
{
|
{
|
||||||
default:{}break;
|
default:{}break;
|
||||||
case DW_Form_ExprLoc:
|
case DW_FormKind_ExprLoc:
|
||||||
{
|
{
|
||||||
U64 expr_info_off = attrib->val.u128.u64[0];
|
U64 expr_info_off = attrib->val.u128.u64[0];
|
||||||
U64 expr_info_size = attrib->val.u128.u64[1];
|
U64 expr_info_size = attrib->val.u128.u64[1];
|
||||||
String8 expr = str8_substr(raw->sec[DW_Section_Info].data, r1u64(expr_info_off, expr_info_off+expr_info_size));
|
String8 expr = str8_substr(raw->sec[DW_SectionKind_Info].data, r1u64(expr_info_off, expr_info_off+expr_info_size));
|
||||||
DW2_LocNode *n = push_array(scratch2.arena, DW2_LocNode, 1);
|
DW2_LocNode *n = push_array(scratch2.arena, DW2_LocNode, 1);
|
||||||
n->v.expr = expr;
|
n->v.expr = expr;
|
||||||
n->v.range = r1u64(0, max_U64);
|
n->v.range = r1u64(0, max_U64);
|
||||||
SLLQueuePush(locs.first, locs.last, n);
|
SLLQueuePush(locs.first, locs.last, n);
|
||||||
locs.count += 1;
|
locs.count += 1;
|
||||||
}break;
|
}break;
|
||||||
case DW_Form_LocListx: // NOTE(rjf): dwarf5+, loclistx -> location list offset table
|
case DW_FormKind_LocListx: // NOTE(rjf): dwarf5+, loclistx -> location list offset table
|
||||||
case DW_Form_SecOffset: // NOTE(rjf): pre-dwarf5, location section offset -> a location list
|
case DW_FormKind_SecOffset: // NOTE(rjf): pre-dwarf5, location section offset -> a location list
|
||||||
{
|
{
|
||||||
locs = dw2_loclist_from_form_val(scratch2.arena, unit_parse_ctx, raw, attrib->val);
|
locs = dw2_loclist_from_form_val(scratch2.arena, unit_parse_ctx, raw, attrib->val);
|
||||||
}break;
|
}break;
|
||||||
@@ -3550,31 +3263,36 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
DW_ExprOp opcode = 0;
|
DW_ExprOp opcode = 0;
|
||||||
expr_off += str8_deserial_read_struct(expr, expr_off, &opcode);
|
expr_off += str8_deserial_read_struct(expr, expr_off, &opcode);
|
||||||
|
|
||||||
|
//- rjf: unpack opcode
|
||||||
|
DW_ExprOpInfo *opcode_info = dw_info_from_expr_op(unit_parse_ctx->version, unit_parse_ctx->exts, opcode);
|
||||||
|
U64 operands_count = opcode_info->operand_count;
|
||||||
|
DW_ExprOperandKind operands_kinds[2] = {opcode_info->operand_kinds[0], opcode_info->operand_kinds[1]};
|
||||||
|
U64 push_count = opcode_info->push_count;
|
||||||
|
U64 pop_count = opcode_info->pop_count;
|
||||||
|
|
||||||
//- rjf: read op operands
|
//- rjf: read op operands
|
||||||
U64 operands_count = dw_operand_count_from_expr_op(opcode);
|
|
||||||
DW_ExprOperandType *operands_types = dw_operand_types_from_expr_opcode(opcode);
|
|
||||||
U64 operand_u64s[2] = {0};
|
U64 operand_u64s[2] = {0};
|
||||||
S64 operand_s64s[2] = {0};
|
S64 operand_s64s[2] = {0};
|
||||||
String8 operand_str8s[2] = {0};
|
String8 operand_str8s[2] = {0};
|
||||||
for EachIndex(operand_idx, operands_count)
|
for EachIndex(operand_idx, operands_count)
|
||||||
{
|
{
|
||||||
switch(operands_types[operand_idx])
|
switch(operands_kinds[operand_idx])
|
||||||
{
|
{
|
||||||
case DW_ExprOperandType_Null:
|
case DW_ExprOperandKind_Null:
|
||||||
default:{}break;
|
default:{}break;
|
||||||
case DW_ExprOperandType_U8: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], 1, 1);}break;
|
case DW_ExprOperandKind_U8: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], 1, 1);}break;
|
||||||
case DW_ExprOperandType_U16: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], 2, 2);}break;
|
case DW_ExprOperandKind_U16: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], 2, 2);}break;
|
||||||
case DW_ExprOperandType_U32: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], 4, 4);}break;
|
case DW_ExprOperandKind_U32: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], 4, 4);}break;
|
||||||
case DW_ExprOperandType_U64: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], 8, 8);}break;
|
case DW_ExprOperandKind_U64: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], 8, 8);}break;
|
||||||
case DW_ExprOperandType_S8: {expr_off += str8_deserial_read(expr, expr_off, &operand_s64s[operand_idx], 1, 1);}break;
|
case DW_ExprOperandKind_S8: {expr_off += str8_deserial_read(expr, expr_off, &operand_s64s[operand_idx], 1, 1);}break;
|
||||||
case DW_ExprOperandType_S16: {expr_off += str8_deserial_read(expr, expr_off, &operand_s64s[operand_idx], 2, 2);}break;
|
case DW_ExprOperandKind_S16: {expr_off += str8_deserial_read(expr, expr_off, &operand_s64s[operand_idx], 2, 2);}break;
|
||||||
case DW_ExprOperandType_S32: {expr_off += str8_deserial_read(expr, expr_off, &operand_s64s[operand_idx], 4, 4);}break;
|
case DW_ExprOperandKind_S32: {expr_off += str8_deserial_read(expr, expr_off, &operand_s64s[operand_idx], 4, 4);}break;
|
||||||
case DW_ExprOperandType_S64: {expr_off += str8_deserial_read(expr, expr_off, &operand_s64s[operand_idx], 8, 8);}break;
|
case DW_ExprOperandKind_S64: {expr_off += str8_deserial_read(expr, expr_off, &operand_s64s[operand_idx], 8, 8);}break;
|
||||||
case DW_ExprOperandType_ULEB128: {expr_off += str8_deserial_read_uleb128(expr, expr_off, &operand_u64s[operand_idx]);} break;
|
case DW_ExprOperandKind_ULEB128: {expr_off += str8_deserial_read_uleb128(expr, expr_off, &operand_u64s[operand_idx]);} break;
|
||||||
case DW_ExprOperandType_SLEB128: {expr_off += str8_deserial_read_sleb128(expr, expr_off, &operand_s64s[operand_idx]);} break;
|
case DW_ExprOperandKind_SLEB128: {expr_off += str8_deserial_read_sleb128(expr, expr_off, &operand_s64s[operand_idx]);} break;
|
||||||
case DW_ExprOperandType_Addr: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], unit_parse_ctx->addr_size, unit_parse_ctx->addr_size);}break;
|
case DW_ExprOperandKind_Addr: {expr_off += str8_deserial_read(expr, expr_off, &operand_u64s[operand_idx], unit_parse_ctx->addr_size, unit_parse_ctx->addr_size);}break;
|
||||||
case DW_ExprOperandType_DwarfUInt: {expr_off += dw2_read_fmt_u64(expr, expr_off, unit_parse_ctx->format, &operand_u64s[operand_idx]);}break;
|
case DW_ExprOperandKind_DwarfUInt: {expr_off += dw2_read_fmt_u64(expr, expr_off, unit_parse_ctx->format, &operand_u64s[operand_idx]);}break;
|
||||||
case DW_ExprOperandType_Block:
|
case DW_ExprOperandKind_Block:
|
||||||
{
|
{
|
||||||
U8 block_size = 0;
|
U8 block_size = 0;
|
||||||
expr_off += str8_deserial_read_struct(expr, expr_off, &block_size);
|
expr_off += str8_deserial_read_struct(expr, expr_off, &block_size);
|
||||||
@@ -3587,7 +3305,6 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
//- rjf: pop stack values
|
//- rjf: pop stack values
|
||||||
D2R2_ExprVal popped_vals[2] = {0};
|
D2R2_ExprVal popped_vals[2] = {0};
|
||||||
{
|
{
|
||||||
U64 pop_count = dw_pop_count_from_expr_op(opcode);
|
|
||||||
pop_count = Min(pop_count, ArrayCount(popped_vals));
|
pop_count = Min(pop_count, ArrayCount(popped_vals));
|
||||||
for EachIndex(pop_idx, pop_count)
|
for EachIndex(pop_idx, pop_count)
|
||||||
{
|
{
|
||||||
@@ -3905,7 +3622,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
//- rjf: TLS offsets
|
//- rjf: TLS offsets
|
||||||
case DW_ExprOp_FormTlsAddress:
|
case DW_ExprOp_FormTlsAddress:
|
||||||
case DW_ExprOp_GNU_PushTlsAddress:
|
case DW_GNU_ExprOp_PushTlsAddress:
|
||||||
{
|
{
|
||||||
rdim_bytecode_push_op(arena, &dst_bytecode, RDI_EvalOp_TLSOff, 0);
|
rdim_bytecode_push_op(arena, &dst_bytecode, RDI_EvalOp_TLSOff, 0);
|
||||||
rdim_bytecode_push_op(arena, &dst_bytecode, RDI_EvalOp_Add, RDI_EvalTypeGroup_U);
|
rdim_bytecode_push_op(arena, &dst_bytecode, RDI_EvalOp_Add, RDI_EvalTypeGroup_U);
|
||||||
@@ -3916,7 +3633,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
//- rjf: call site value
|
//- rjf: call site value
|
||||||
case DW_ExprOp_EntryValue:
|
case DW_ExprOp_EntryValue:
|
||||||
case DW_ExprOp_GNU_EntryValue:
|
case DW_GNU_ExprOp_EntryValue:
|
||||||
{
|
{
|
||||||
// TODO(rjf): expr op entry value ops
|
// TODO(rjf): expr op entry value ops
|
||||||
}break;
|
}break;
|
||||||
@@ -3975,24 +3692,24 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
log_infof("[.debug_info@0x%I64x] DWARF expression call operation encountered. This is not supported for location info.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] DWARF expression call operation encountered. This is not supported for location info.\n", start_off);
|
||||||
}break;
|
}break;
|
||||||
case DW_ExprOp_ImplicitPointer:
|
case DW_ExprOp_ImplicitPointer:
|
||||||
case DW_ExprOp_GNU_ImplicitPointer:
|
case DW_GNU_ExprOp_ImplicitPointer:
|
||||||
{
|
{
|
||||||
dst_bytecode_is_good = 0;
|
dst_bytecode_is_good = 0;
|
||||||
log_infof("[.debug_info@0x%I64x] DWARF expression implicit pointer operation encountered. This is not supported for location info.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] DWARF expression implicit pointer operation encountered. This is not supported for location info.\n", start_off);
|
||||||
}break;
|
}break;
|
||||||
case DW_ExprOp_GNU_ParameterRef:
|
case DW_GNU_ExprOp_ParameterRef:
|
||||||
{
|
{
|
||||||
dst_bytecode_is_good = 0;
|
dst_bytecode_is_good = 0;
|
||||||
log_infof("[.debug_info@0x%I64x] DWARF expression GNU_ParameterRef operation encountered. This is not supported for location info.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] DWARF expression GNU_ParameterRef operation encountered. This is not supported for location info.\n", start_off);
|
||||||
}break;
|
}break;
|
||||||
case DW_ExprOp_DerefType:
|
case DW_ExprOp_DerefType:
|
||||||
case DW_ExprOp_GNU_DerefType:
|
case DW_GNU_ExprOp_DerefType:
|
||||||
{
|
{
|
||||||
dst_bytecode_is_good = 0;
|
dst_bytecode_is_good = 0;
|
||||||
log_infof("[.debug_info@0x%I64x] DWARF expression DerefType operation encountered. This is not supported for location info.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] DWARF expression DerefType operation encountered. This is not supported for location info.\n", start_off);
|
||||||
}break;
|
}break;
|
||||||
case DW_ExprOp_ConstType:
|
case DW_ExprOp_ConstType:
|
||||||
case DW_ExprOp_GNU_ConstType:
|
case DW_GNU_ExprOp_ConstType:
|
||||||
{
|
{
|
||||||
dst_bytecode_is_good = 0;
|
dst_bytecode_is_good = 0;
|
||||||
log_infof("[.debug_info@0x%I64x] DWARF expression ConstType operation encountered. This is not supported for location info.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] DWARF expression ConstType operation encountered. This is not supported for location info.\n", start_off);
|
||||||
@@ -4012,7 +3729,7 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
dst_bytecode_is_good = 0;
|
dst_bytecode_is_good = 0;
|
||||||
log_infof("[.debug_info@0x%I64x] DWARF expression Rot (rotate) operation encountered. This is not supported for location info.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] DWARF expression Rot (rotate) operation encountered. This is not supported for location info.\n", start_off);
|
||||||
}break;
|
}break;
|
||||||
case DW_ExprOp_GNU_UnInit:
|
case DW_GNU_ExprOp_UnInit:
|
||||||
{
|
{
|
||||||
dst_bytecode_is_good = 0;
|
dst_bytecode_is_good = 0;
|
||||||
log_infof("[.debug_info@0x%I64x] DWARF expression GNU_UnInit operation encountered. This is not supported for location info.\n", start_off);
|
log_infof("[.debug_info@0x%I64x] DWARF expression GNU_UnInit operation encountered. This is not supported for location info.\n", start_off);
|
||||||
@@ -4022,7 +3739,6 @@ d2r2_convert(Arena *arena, D2R2_ConvertParams *params)
|
|||||||
|
|
||||||
//- rjf: push values to stack
|
//- rjf: push values to stack
|
||||||
{
|
{
|
||||||
U64 push_count = dw_push_count_from_expr_op(opcode);
|
|
||||||
push_count = Min(push_count, ArrayCount(push_vals));
|
push_count = Min(push_count, ArrayCount(push_vals));
|
||||||
for EachIndex(push_idx, push_count)
|
for EachIndex(push_idx, push_count)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
//
|
//
|
||||||
// [ ] d2r_types alias size and byte size on __float80 typedef mismatch
|
// [ ] d2r_types alias size and byte size on __float80 typedef mismatch
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
internal RDI_Parsed *
|
internal RDI_Parsed *
|
||||||
d2r_rdi_from_dwarf_writer(Arena *arena, DW_Writer *writer)
|
d2r_rdi_from_dwarf_writer(Arena *arena, DW_Writer *writer)
|
||||||
{
|
{
|
||||||
@@ -156,19 +158,19 @@ dw_writer_tag_end(writer); \
|
|||||||
|
|
||||||
#define TestBuiltinType(n, bs, r) \
|
#define TestBuiltinType(n, bs, r) \
|
||||||
do { \
|
do { \
|
||||||
RDI_TypeNode *alias = d2rt_type_from_name(rdi, &types_map, n); \
|
RDI_TypeNode *alias = d2rt_type_from_name(rdi, &types_map, n); \
|
||||||
T_Ok(alias); \
|
T_Ok(alias); \
|
||||||
T_Ok(alias->kind == RDI_TypeKind_Alias); \
|
T_Ok(alias->kind == RDI_TypeKind_Alias); \
|
||||||
T_Ok(alias->flags == 0); \
|
T_Ok(alias->flags == 0); \
|
||||||
T_Ok(alias->byte_size == bs); \
|
T_Ok(alias->byte_size == bs); \
|
||||||
RDI_TypeNode *type = rdi_element_from_name_idx(rdi, TypeNodes, alias->user_defined.direct_type_idx); \
|
RDI_TypeNode *type = rdi_element_from_name_idx(rdi, TypeNodes, alias->user_defined.direct_type_idx); \
|
||||||
T_Ok(type); \
|
T_Ok(type); \
|
||||||
T_Ok(type->kind == RDI_TypeKind_##r); \
|
T_Ok(type->kind == RDI_TypeKind_##r); \
|
||||||
T_Ok(type->flags == 0); \
|
T_Ok(type->flags == 0); \
|
||||||
T_Ok(type->byte_size == alias->byte_size); \
|
T_Ok(type->byte_size == alias->byte_size); \
|
||||||
U64 expected_name_size = 0; \
|
U64 expected_name_size = 0; \
|
||||||
U8 *expected_name = rdi_string_from_type_kind(RDI_TypeKind_##r, &expected_name_size); \
|
U8 *expected_name = rdi_string_from_type_kind(RDI_TypeKind_##r, &expected_name_size); \
|
||||||
T_Ok(str8_match(str8_from_rdi_string_idx(rdi, type->built_in.name_string_idx), str8(expected_name, expected_name_size), 0)); \
|
T_Ok(str8_match(str8_from_rdi_string_idx(rdi, type->built_in.name_string_idx), str8(expected_name, expected_name_size), 0)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
TestBuiltinType("char", 1, Char8);
|
TestBuiltinType("char", 1, Char8);
|
||||||
TestBuiltinType("char8_t", 1, UChar8);
|
TestBuiltinType("char8_t", 1, UChar8);
|
||||||
@@ -290,11 +292,11 @@ SKIP(d2r_line_table)
|
|||||||
|
|
||||||
if ( ! t_match_linef(&g_output, "%S:%llu", test_table[i].file->path, test_table[i].ln)) {
|
if ( ! t_match_linef(&g_output, "%S:%llu", test_table[i].file->path, test_table[i].ln)) {
|
||||||
t_errorf("ERROR: conversion produced unexpected output for \"radbin %S\"\n" \
|
t_errorf("ERROR: conversion produced unexpected output for \"radbin %S\"\n" \
|
||||||
" Expected: %S:%llu\n" \
|
" Expected: %S:%llu\n" \
|
||||||
" Got: %S\n",
|
" Got: %S\n",
|
||||||
cmdl,
|
cmdl,
|
||||||
test_table[i].file->path, (unsigned long long)test_table[i].ln,
|
test_table[i].file->path, (unsigned long long)test_table[i].ln,
|
||||||
g_output);
|
g_output);
|
||||||
|
|
||||||
if (g_verbose) {
|
if (g_verbose) {
|
||||||
t_invoke_radbin("-dump -only:line_tables a.rdi");
|
t_invoke_radbin("-dump -only:line_tables a.rdi");
|
||||||
@@ -594,4 +596,4 @@ TEST(d2r_general)
|
|||||||
|
|
||||||
dw_writer_end(&writer);
|
dw_writer_end(&writer);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -58,11 +58,13 @@
|
|||||||
#include "pdb/pdb_parse.h"
|
#include "pdb/pdb_parse.h"
|
||||||
#include "pdb/pdb_stringize.h"
|
#include "pdb/pdb_stringize.h"
|
||||||
#include "dwarf/dwarf_inc.h"
|
#include "dwarf/dwarf_inc.h"
|
||||||
|
#include "eh_frame/eh_frame.h"
|
||||||
|
#include "eh_frame/eh_frame_dump.h"
|
||||||
|
#include "unwind/unwind_inc.h"
|
||||||
#include "llvm/llvm.h"
|
#include "llvm/llvm.h"
|
||||||
#include "rdi_from_coff/rdi_from_coff.h"
|
#include "rdi_from_coff/rdi_from_coff.h"
|
||||||
#include "rdi_from_elf/rdi_from_elf.h"
|
#include "rdi_from_elf/rdi_from_elf.h"
|
||||||
#include "rdi_from_pdb/rdi_from_pdb.h"
|
#include "rdi_from_pdb/rdi_from_pdb.h"
|
||||||
#include "rdi_from_dwarf/rdi_from_dwarf.h"
|
|
||||||
#include "rdi_from_dwarf/rdi_from_dwarf_2.h"
|
#include "rdi_from_dwarf/rdi_from_dwarf_2.h"
|
||||||
#include "obj/obj.h"
|
#include "obj/obj.h"
|
||||||
#include "radbin/radbin.h"
|
#include "radbin/radbin.h"
|
||||||
@@ -133,11 +135,13 @@
|
|||||||
#include "pdb/pdb_parse.c"
|
#include "pdb/pdb_parse.c"
|
||||||
#include "pdb/pdb_stringize.c"
|
#include "pdb/pdb_stringize.c"
|
||||||
#include "dwarf/dwarf_inc.c"
|
#include "dwarf/dwarf_inc.c"
|
||||||
|
#include "eh_frame/eh_frame.c"
|
||||||
|
#include "eh_frame/eh_frame_dump.c"
|
||||||
|
#include "unwind/unwind_inc.c"
|
||||||
#include "llvm/llvm.c"
|
#include "llvm/llvm.c"
|
||||||
#include "rdi_from_coff/rdi_from_coff.c"
|
#include "rdi_from_coff/rdi_from_coff.c"
|
||||||
#include "rdi_from_elf/rdi_from_elf.c"
|
#include "rdi_from_elf/rdi_from_elf.c"
|
||||||
#include "rdi_from_pdb/rdi_from_pdb.c"
|
#include "rdi_from_pdb/rdi_from_pdb.c"
|
||||||
#include "rdi_from_dwarf/rdi_from_dwarf.c"
|
|
||||||
#include "rdi_from_dwarf/rdi_from_dwarf_2.c"
|
#include "rdi_from_dwarf/rdi_from_dwarf_2.c"
|
||||||
#include "obj/obj.c"
|
#include "obj/obj.c"
|
||||||
#include "radbin/radbin.c"
|
#include "radbin/radbin.c"
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
//- GENERATED CODE
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
//- GENERATED CODE
|
||||||
|
|
||||||
|
#ifndef UNWIND_META_H
|
||||||
|
#define UNWIND_META_H
|
||||||
|
|
||||||
|
typedef enum UWND_Unwinder
|
||||||
|
{
|
||||||
|
UWND_Unwinder_Null,
|
||||||
|
UWND_Unwinder_PEx64,
|
||||||
|
UWND_Unwinder_EHFrame,
|
||||||
|
UWND_Unwinder_COUNT,
|
||||||
|
} UWND_Unwinder;
|
||||||
|
|
||||||
|
#define UWND_Unwinder_XList \
|
||||||
|
X(PEx64, pe_x64)\
|
||||||
|
X(EHFrame, eh)\
|
||||||
|
|
||||||
|
#endif // UNWIND_META_H
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Generated Code
|
||||||
|
|
||||||
|
#include "unwind/generated/unwind.meta.c"
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Abstracted Unwind Step Functions
|
||||||
|
|
||||||
|
internal UWND_StepResult
|
||||||
|
uwnd_step(UWND_Unwinder unwinder, Arch arch, MemoryMap *memory_map, UWND_ModuleInfo *module_info, U64 tls_vaddr, void *regs, U64 *cfa_out)
|
||||||
|
{
|
||||||
|
UWND_StepResult result = {UWND_StepStatus_Error};
|
||||||
|
switch(unwinder)
|
||||||
|
{
|
||||||
|
default:{}break;
|
||||||
|
#define X(name, namespace_lower) case UWND_Unwinder_##name:{result = namespace_lower##_uwnd_step(arch, memory_map, module_info, tls_vaddr, regs, cfa_out);}break;
|
||||||
|
UWND_Unwinder_XList
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef UNWIND_H
|
||||||
|
#define UNWIND_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Generated Code
|
||||||
|
|
||||||
|
#include "unwind/generated/unwind.meta.h"
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Unwind Artifact Types
|
||||||
|
|
||||||
|
typedef enum UWND_StepStatus
|
||||||
|
{
|
||||||
|
UWND_StepStatus_Error,
|
||||||
|
UWND_StepStatus_FailedMemoryRead,
|
||||||
|
UWND_StepStatus_Good,
|
||||||
|
}
|
||||||
|
UWND_StepStatus;
|
||||||
|
|
||||||
|
typedef struct UWND_StepResult UWND_StepResult;
|
||||||
|
struct UWND_StepResult
|
||||||
|
{
|
||||||
|
UWND_StepStatus status;
|
||||||
|
Rng1U64 missed_read_vaddr_range;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Module Info
|
||||||
|
|
||||||
|
typedef struct UWND_ModuleInfo UWND_ModuleInfo;
|
||||||
|
struct UWND_ModuleInfo
|
||||||
|
{
|
||||||
|
U64 base_vaddr;
|
||||||
|
void *unwind_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Abstracted Unwind Step Functions
|
||||||
|
|
||||||
|
internal UWND_StepResult uwnd_step(UWND_Unwinder unwinder, Arch arch, MemoryMap *memory_map, UWND_ModuleInfo *module_info, U64 tls_vaddr, void *regs, U64 *cfa_out);
|
||||||
|
|
||||||
|
#endif // UNWIND_H
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
@table(name namespace_lower)
|
||||||
|
UWND_UnwinderTable:
|
||||||
|
{
|
||||||
|
{PEx64 pe_x64 }
|
||||||
|
{EHFrame eh }
|
||||||
|
}
|
||||||
|
|
||||||
|
@enum UWND_Unwinder:
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
@expand(UWND_UnwinderTable a) `$(a.name)`,
|
||||||
|
COUNT
|
||||||
|
}
|
||||||
|
|
||||||
|
@xlist UWND_Unwinder_XList:
|
||||||
|
{
|
||||||
|
@expand(UWND_UnwinderTable a) `$(a.name), $(a.namespace_lower)`
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#include "unwind.c"
|
||||||
|
#if defined(PE_H) && defined(X64_H)
|
||||||
|
# include "pe/x64/unwind/pe_x64_unwind.c"
|
||||||
|
#endif
|
||||||
|
#if defined(EH_FRAME_H)
|
||||||
|
# include "eh_frame/unwind/eh_frame_unwind.c"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef UNWIND_INC_H
|
||||||
|
#define UNWIND_INC_H
|
||||||
|
|
||||||
|
#include "unwind.h"
|
||||||
|
#if defined(PE_H) && defined(X64_H)
|
||||||
|
# include "pe/x64/unwind/pe_x64_unwind.h"
|
||||||
|
#endif
|
||||||
|
#if defined(EH_FRAME_H)
|
||||||
|
# include "eh_frame/unwind/eh_frame_unwind.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // UNWIND_INC_H
|
||||||
@@ -316,7 +316,7 @@ commit_memory_large(void *ptr, U64 size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Shared Memory
|
//~ rjf: @per_os_impl Shared Memory
|
||||||
|
|
||||||
internal SharedMemory
|
internal SharedMemory
|
||||||
shared_memory_alloc(U64 size, String8 name)
|
shared_memory_alloc(U64 size, String8 name)
|
||||||
@@ -476,7 +476,7 @@ thread_detach(Thread thread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Safe Calls
|
//~ rjf: @per_os_impl Safe Calls
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr)
|
safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr)
|
||||||
|
|||||||
@@ -1217,6 +1217,50 @@ w32_dmn_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
w32_dmn_thread_stack_base_vaddr_from_tlb_vaddr(HANDLE process, Arch arch, U64 tlb_vaddr)
|
||||||
|
{
|
||||||
|
U64 stack_base_vaddr = 0;
|
||||||
|
{
|
||||||
|
switch(arch)
|
||||||
|
{
|
||||||
|
case Arch_Null:
|
||||||
|
case Arch_COUNT:
|
||||||
|
case Arch_arm64:
|
||||||
|
case Arch_arm32:
|
||||||
|
case Arch_x86:
|
||||||
|
{}break;
|
||||||
|
case Arch_x64:
|
||||||
|
{
|
||||||
|
U64 stack_base_vaddr = tlb_vaddr + 0x8;
|
||||||
|
w32_dmn_process_read(process, r1u64(stack_base_vaddr, stack_base_vaddr+8), &stack_base_vaddr);
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stack_base_vaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
w32_dmn_thread_tls_root_vaddr_from_tlb_vaddr(Arch arch, U64 tlb_vaddr)
|
||||||
|
{
|
||||||
|
U64 result = 0;
|
||||||
|
switch(arch)
|
||||||
|
{
|
||||||
|
case Arch_Null:
|
||||||
|
case Arch_COUNT:
|
||||||
|
{}break;
|
||||||
|
case Arch_arm64:
|
||||||
|
case Arch_arm32:
|
||||||
|
case Arch_x86:
|
||||||
|
{}break;
|
||||||
|
case Arch_x64:
|
||||||
|
{
|
||||||
|
result = tlb_vaddr + 88;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: remote thread injection
|
//- rjf: remote thread injection
|
||||||
|
|
||||||
internal DWORD
|
internal DWORD
|
||||||
@@ -2066,6 +2110,10 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
|||||||
thread->thread.thread_local_base = tls_base;
|
thread->thread.thread_local_base = tls_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rjf: unpack thread addresses
|
||||||
|
U64 stack_base_vaddr = w32_dmn_thread_stack_base_vaddr_from_tlb_vaddr(process_handle, module_info->arch, tls_base);
|
||||||
|
U64 tls_root_vaddr = w32_dmn_thread_tls_root_vaddr_from_tlb_vaddr(module_info->arch, tls_base);
|
||||||
|
|
||||||
// rjf: put thread into suspended state, so it matches expected initial state
|
// rjf: put thread into suspended state, so it matches expected initial state
|
||||||
SuspendThread(thread_handle);
|
SuspendThread(thread_handle);
|
||||||
|
|
||||||
@@ -2096,11 +2144,13 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
|||||||
// rjf: create thread
|
// rjf: create thread
|
||||||
{
|
{
|
||||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||||
e->kind = DMN_EventKind_CreateThread;
|
e->kind = DMN_EventKind_CreateThread;
|
||||||
e->process = w32_dmn_handle_from_entity(process);
|
e->process = w32_dmn_handle_from_entity(process);
|
||||||
e->thread = w32_dmn_handle_from_entity(thread);
|
e->thread = w32_dmn_handle_from_entity(thread);
|
||||||
e->arch = module_info->arch;
|
e->arch = module_info->arch;
|
||||||
e->code = evt.dwThreadId;
|
e->code = evt.dwThreadId;
|
||||||
|
e->stack_pointer = stack_base_vaddr;
|
||||||
|
e->tls_root_vaddr= tls_root_vaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: load module
|
// rjf: load module
|
||||||
@@ -2192,6 +2242,10 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
|||||||
DWORD sus_result = SuspendThread(thread->handle);
|
DWORD sus_result = SuspendThread(thread->handle);
|
||||||
(void)sus_result;
|
(void)sus_result;
|
||||||
|
|
||||||
|
// rjf: unpack thread addresses
|
||||||
|
U64 stack_base_vaddr = w32_dmn_thread_stack_base_vaddr_from_tlb_vaddr(process->handle, thread->arch, (U64)evt.u.CreateThread.lpThreadLocalBase);
|
||||||
|
U64 tls_root_vaddr = w32_dmn_thread_tls_root_vaddr_from_tlb_vaddr(thread->arch, (U64)evt.u.CreateThread.lpThreadLocalBase);
|
||||||
|
|
||||||
// rjf: unpack thread name
|
// rjf: unpack thread name
|
||||||
String8 thread_name = {0};
|
String8 thread_name = {0};
|
||||||
if(w32_dmn_GetThreadDescription != 0)
|
if(w32_dmn_GetThreadDescription != 0)
|
||||||
@@ -2213,11 +2267,13 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
|||||||
{
|
{
|
||||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||||
e->kind = DMN_EventKind_CreateThread;
|
e->kind = DMN_EventKind_CreateThread;
|
||||||
e->process = w32_dmn_handle_from_entity(process);
|
e->process = w32_dmn_handle_from_entity(process);
|
||||||
e->thread = w32_dmn_handle_from_entity(thread);
|
e->thread = w32_dmn_handle_from_entity(thread);
|
||||||
e->arch = thread->arch;
|
e->arch = thread->arch;
|
||||||
e->code = evt.dwThreadId;
|
e->code = evt.dwThreadId;
|
||||||
e->string = thread_name;
|
e->string = thread_name;
|
||||||
|
e->stack_pointer = stack_base_vaddr;
|
||||||
|
e->tls_root_vaddr = tls_root_vaddr;
|
||||||
}
|
}
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
@@ -3207,78 +3263,6 @@ dmn_process_write(DMN_Handle process, Rng1U64 range, void *src)
|
|||||||
|
|
||||||
//- rjf: threads
|
//- rjf: threads
|
||||||
|
|
||||||
internal Arch
|
|
||||||
dmn_arch_from_thread(DMN_Handle handle)
|
|
||||||
{
|
|
||||||
Arch arch = Arch_Null;
|
|
||||||
DMN_AccessScope
|
|
||||||
{
|
|
||||||
W32_DMN_Entity *entity = w32_dmn_entity_from_handle(handle);
|
|
||||||
arch = entity->arch;
|
|
||||||
}
|
|
||||||
return arch;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
dmn_stack_base_vaddr_from_thread(DMN_Handle handle)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
DMN_AccessScope
|
|
||||||
{
|
|
||||||
W32_DMN_Entity *thread = w32_dmn_entity_from_handle(handle);
|
|
||||||
if(thread->kind == W32_DMN_EntityKind_Thread)
|
|
||||||
{
|
|
||||||
W32_DMN_Entity *process = thread->parent;
|
|
||||||
U64 tlb = thread->thread.thread_local_base;
|
|
||||||
switch(thread->arch)
|
|
||||||
{
|
|
||||||
case Arch_Null:
|
|
||||||
case Arch_COUNT:
|
|
||||||
{}break;
|
|
||||||
case Arch_arm64:
|
|
||||||
case Arch_arm32:
|
|
||||||
case Arch_x86:
|
|
||||||
{NotImplemented;}break;
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
U64 stack_base_addr = tlb + 0x8;
|
|
||||||
w32_dmn_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+8), &result);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
dmn_tls_root_vaddr_from_thread(DMN_Handle handle)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
DMN_AccessScope
|
|
||||||
{
|
|
||||||
W32_DMN_Entity *entity = w32_dmn_entity_from_handle(handle);
|
|
||||||
if(entity->kind == W32_DMN_EntityKind_Thread)
|
|
||||||
{
|
|
||||||
result = entity->thread.thread_local_base;
|
|
||||||
switch(entity->arch)
|
|
||||||
{
|
|
||||||
case Arch_Null:
|
|
||||||
case Arch_COUNT:
|
|
||||||
{}break;
|
|
||||||
case Arch_arm64:
|
|
||||||
case Arch_arm32:
|
|
||||||
case Arch_x86:
|
|
||||||
{NotImplemented;}break;
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
result += 88;
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block)
|
dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block)
|
||||||
{
|
{
|
||||||
@@ -3303,6 +3287,31 @@ dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
dmn_thread_get_module_tls_vaddr(DMN_Handle thread_handle, DMN_Handle module_handle, U64 *vaddr_out)
|
||||||
|
{
|
||||||
|
B32 result = 0;
|
||||||
|
DMN_AccessScope
|
||||||
|
{
|
||||||
|
W32_DMN_Entity *thread = w32_dmn_entity_from_handle(thread_handle);
|
||||||
|
W32_DMN_Entity *process = thread->parent;
|
||||||
|
W32_DMN_Entity *module = w32_dmn_entity_from_handle(module_handle);
|
||||||
|
Arch arch = thread->arch;
|
||||||
|
U64 addr_size = byte_size_from_arch(arch);
|
||||||
|
U64 tls_vaddr = w32_dmn_thread_tls_root_vaddr_from_tlb_vaddr(arch, thread->thread.thread_local_base);
|
||||||
|
U64 tls_addr_array_vaddr = 0;
|
||||||
|
if(w32_dmn_process_read_struct(process->handle, tls_vaddr, &tls_addr_array_vaddr) == addr_size)
|
||||||
|
{
|
||||||
|
U64 tls_ptr_vaddr = tls_addr_array_vaddr + module->module.tls_index*addr_size;
|
||||||
|
if(w32_dmn_process_read_struct(process->handle, tls_ptr_vaddr, vaddr_out) == addr_size)
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: system process listing
|
//- rjf: system process listing
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ struct W32_DMN_Entity
|
|||||||
{
|
{
|
||||||
Rng1U64 vaddr_range;
|
Rng1U64 vaddr_range;
|
||||||
U64 address_of_name_pointer;
|
U64 address_of_name_pointer;
|
||||||
|
U64 tls_index;
|
||||||
B32 is_main;
|
B32 is_main;
|
||||||
B32 name_is_unicode;
|
B32 name_is_unicode;
|
||||||
}
|
}
|
||||||
@@ -349,6 +350,8 @@ internal DMN_ModuleInfo *w32_dmn_module_info_from_process_module(Arena *arena, H
|
|||||||
//- rjf: threads
|
//- rjf: threads
|
||||||
internal B32 w32_dmn_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block);
|
internal B32 w32_dmn_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block);
|
||||||
internal B32 w32_dmn_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block);
|
internal B32 w32_dmn_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block);
|
||||||
|
internal U64 w32_dmn_thread_stack_base_vaddr_from_tlb_vaddr(HANDLE process, Arch arch, U64 tlb_vaddr);
|
||||||
|
internal U64 w32_dmn_thread_tls_root_vaddr_from_tlb_vaddr(Arch arch, U64 tlb_vaddr);
|
||||||
|
|
||||||
//- rjf: remote thread injection
|
//- rjf: remote thread injection
|
||||||
internal DWORD w32_dmn_inject_thread(HANDLE process, U64 start_address);
|
internal DWORD w32_dmn_inject_thread(HANDLE process, U64 start_address);
|
||||||
|
|||||||
@@ -815,7 +815,7 @@ w32_wm_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM b
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
|
//~ rjf: @per_os_impl Main Initialization API (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_init(void)
|
wm_init(void)
|
||||||
@@ -995,7 +995,7 @@ wm_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Graphics System Info (Implemented Per-OS)
|
//~ rjf: @per_os_impl Graphics System Info (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_SystemInfo *
|
internal WM_SystemInfo *
|
||||||
wm_get_system_info(void)
|
wm_get_system_info(void)
|
||||||
@@ -1004,7 +1004,7 @@ wm_get_system_info(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Clipboards (Implemented Per-OS)
|
//~ rjf: @per_os_impl Clipboards (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_set_clipboard_text(String8 string)
|
wm_set_clipboard_text(String8 string)
|
||||||
@@ -1053,7 +1053,7 @@ wm_get_clipboard_text(Arena *arena)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Windows (Implemented Per-OS)
|
//~ rjf: @per_os_impl Windows (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_Window
|
internal WM_Window
|
||||||
wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title)
|
wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title)
|
||||||
@@ -1385,7 +1385,7 @@ wm_dpi_from_window(WM_Window handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks External Windows (Implemented Per-OS)
|
//~ rjf: @per_os_impl External Windows (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_ExtWindow
|
internal WM_ExtWindow
|
||||||
wm_focused_external_window(void)
|
wm_focused_external_window(void)
|
||||||
@@ -1407,7 +1407,7 @@ wm_focus_external_window(WM_ExtWindow handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Monitors (Implemented Per-OS)
|
//~ rjf: @per_os_impl Monitors (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_MonitorArray
|
internal WM_MonitorArray
|
||||||
wm_push_monitors_array(Arena *arena)
|
wm_push_monitors_array(Arena *arena)
|
||||||
@@ -1494,7 +1494,7 @@ wm_dpi_from_monitor(WM_Monitor monitor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Events (Implemented Per-OS)
|
//~ rjf: @per_os_impl Events (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_send_wakeup_event(void)
|
wm_send_wakeup_event(void)
|
||||||
@@ -1573,7 +1573,7 @@ wm_mouse_from_window(WM_Window handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Cursors (Implemented Per-OS)
|
//~ rjf: @per_os_impl Cursors (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_set_cursor(WM_Cursor cursor)
|
wm_set_cursor(WM_Cursor cursor)
|
||||||
@@ -1615,7 +1615,7 @@ hcursor = curs; }break;
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS)
|
//~ rjf: @per_os_impl Native User-Facing Graphical Messages (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_graphical_message(B32 error, String8 title, String8 message)
|
wm_graphical_message(B32 error, String8 title, String8 message)
|
||||||
@@ -1651,7 +1651,7 @@ wm_graphical_pick_file(Arena *arena, String8 initial_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Shell Operations
|
//~ rjf: @per_os_impl Shell Operations
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_show_in_filesystem_ui(String8 path)
|
wm_show_in_filesystem_ui(String8 path)
|
||||||
|
|||||||
@@ -161,23 +161,23 @@ internal void wm_event_list_concat_in_place(WM_EventList *dst, WM_EventList *to_
|
|||||||
internal WM_Event *wm_event_list_push_new(Arena *arena, WM_EventList *evts, WM_EventKind kind);
|
internal WM_Event *wm_event_list_push_new(Arena *arena, WM_EventList *evts, WM_EventKind kind);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
|
//~ rjf: @per_os_impl Main Initialization API (Implemented Per-OS)
|
||||||
|
|
||||||
internal void wm_init(void);
|
internal void wm_init(void);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Graphics System Info (Implemented Per-OS)
|
//~ rjf: @per_os_impl Graphics System Info (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_SystemInfo *wm_get_system_info(void);
|
internal WM_SystemInfo *wm_get_system_info(void);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Clipboards (Implemented Per-OS)
|
//~ rjf: @per_os_impl Clipboards (Implemented Per-OS)
|
||||||
|
|
||||||
internal void wm_set_clipboard_text(String8 string);
|
internal void wm_set_clipboard_text(String8 string);
|
||||||
internal String8 wm_get_clipboard_text(Arena *arena);
|
internal String8 wm_get_clipboard_text(Arena *arena);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Windows (Implemented Per-OS)
|
//~ rjf: @per_os_impl Windows (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_Window wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title);
|
internal WM_Window wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title);
|
||||||
internal void wm_window_close(WM_Window window);
|
internal void wm_window_close(WM_Window window);
|
||||||
@@ -202,13 +202,13 @@ internal Rng2F32 wm_client_rect_from_window(WM_Window window);
|
|||||||
internal F32 wm_dpi_from_window(WM_Window window);
|
internal F32 wm_dpi_from_window(WM_Window window);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks External Windows (Implemented Per-OS)
|
//~ rjf: @per_os_impl External Windows (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_ExtWindow wm_focused_external_window(void);
|
internal WM_ExtWindow wm_focused_external_window(void);
|
||||||
internal void wm_focus_external_window(WM_ExtWindow ext_window);
|
internal void wm_focus_external_window(WM_ExtWindow ext_window);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Monitors (Implemented Per-OS)
|
//~ rjf: @per_os_impl Monitors (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_MonitorArray wm_push_monitors_array(Arena *arena);
|
internal WM_MonitorArray wm_push_monitors_array(Arena *arena);
|
||||||
internal WM_Monitor wm_primary_monitor(void);
|
internal WM_Monitor wm_primary_monitor(void);
|
||||||
@@ -218,7 +218,7 @@ internal Vec2F32 wm_dim_from_monitor(WM_Monitor monitor);
|
|||||||
internal F32 wm_dpi_from_monitor(WM_Monitor monitor);
|
internal F32 wm_dpi_from_monitor(WM_Monitor monitor);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Events (Implemented Per-OS)
|
//~ rjf: @per_os_impl Events (Implemented Per-OS)
|
||||||
|
|
||||||
internal void wm_send_wakeup_event(void);
|
internal void wm_send_wakeup_event(void);
|
||||||
internal WM_EventList wm_get_events(Arena *arena, B32 wait);
|
internal WM_EventList wm_get_events(Arena *arena, B32 wait);
|
||||||
@@ -227,18 +227,18 @@ internal B32 wm_key_is_down(WM_Key key);
|
|||||||
internal Vec2F32 wm_mouse_from_window(WM_Window window);
|
internal Vec2F32 wm_mouse_from_window(WM_Window window);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Cursors (Implemented Per-OS)
|
//~ rjf: @per_os_impl Cursors (Implemented Per-OS)
|
||||||
|
|
||||||
internal void wm_set_cursor(WM_Cursor cursor);
|
internal void wm_set_cursor(WM_Cursor cursor);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS)
|
//~ rjf: @per_os_impl Native User-Facing Graphical Messages (Implemented Per-OS)
|
||||||
|
|
||||||
internal void wm_graphical_message(B32 error, String8 title, String8 message);
|
internal void wm_graphical_message(B32 error, String8 title, String8 message);
|
||||||
internal String8 wm_graphical_pick_file(Arena *arena, String8 initial_path);
|
internal String8 wm_graphical_pick_file(Arena *arena, String8 initial_path);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Shell Operations
|
//~ rjf: @per_os_impl Shell Operations
|
||||||
|
|
||||||
internal void wm_show_in_filesystem_ui(String8 path);
|
internal void wm_show_in_filesystem_ui(String8 path);
|
||||||
internal void wm_open_in_browser(String8 url);
|
internal void wm_open_in_browser(String8 url);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Main Initialization API (Implemented Per-OS)
|
//~ rjf: @per_os_impl Main Initialization API (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_init(void)
|
wm_init(void)
|
||||||
@@ -7,7 +7,7 @@ wm_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Graphics System Info (Implemented Per-OS)
|
//~ rjf: @per_os_impl Graphics System Info (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_SystemInfo *
|
internal WM_SystemInfo *
|
||||||
wm_get_system_info(void)
|
wm_get_system_info(void)
|
||||||
@@ -18,7 +18,7 @@ wm_get_system_info(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Clipboards (Implemented Per-OS)
|
//~ rjf: @per_os_impl Clipboards (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_set_clipboard_text(String8 string)
|
wm_set_clipboard_text(String8 string)
|
||||||
@@ -32,7 +32,7 @@ wm_get_clipboard_text(Arena *arena)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Windows (Implemented Per-OS)
|
//~ rjf: @per_os_impl Windows (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_Window
|
internal WM_Window
|
||||||
wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title)
|
wm_window_open(Rng2F32 rect, WM_WindowFlags flags, String8 title)
|
||||||
@@ -151,7 +151,7 @@ wm_dpi_from_window(WM_Window window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks External Windows (Implemented Per-OS)
|
//~ rjf: @per_os_impl External Windows (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_ExtWindow
|
internal WM_ExtWindow
|
||||||
wm_focused_external_window(void)
|
wm_focused_external_window(void)
|
||||||
@@ -166,7 +166,7 @@ wm_focus_external_window(WM_ExtWindow handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Monitors (Implemented Per-OS)
|
//~ rjf: @per_os_impl Monitors (Implemented Per-OS)
|
||||||
|
|
||||||
internal WM_MonitorArray
|
internal WM_MonitorArray
|
||||||
wm_push_monitors_array(Arena *arena)
|
wm_push_monitors_array(Arena *arena)
|
||||||
@@ -209,7 +209,7 @@ wm_dpi_from_monitor(WM_Monitor monitor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Events (Implemented Per-OS)
|
//~ rjf: @per_os_impl Events (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_send_wakeup_event(void)
|
wm_send_wakeup_event(void)
|
||||||
@@ -243,7 +243,7 @@ wm_mouse_from_window(WM_Window window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Cursors (Implemented Per-OS)
|
//~ rjf: @per_os_impl Cursors (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_set_cursor(WM_Cursor cursor)
|
wm_set_cursor(WM_Cursor cursor)
|
||||||
@@ -251,7 +251,7 @@ wm_set_cursor(WM_Cursor cursor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS)
|
//~ rjf: @per_os_impl Native User-Facing Graphical Messages (Implemented Per-OS)
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_graphical_message(B32 error, String8 title, String8 message)
|
wm_graphical_message(B32 error, String8 title, String8 message)
|
||||||
@@ -265,7 +265,7 @@ wm_graphical_pick_file(Arena *arena, String8 initial_path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: @os_hooks Shell Operations
|
//~ rjf: @per_os_impl Shell Operations
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
wm_show_in_filesystem_ui(String8 path)
|
wm_show_in_filesystem_ui(String8 path)
|
||||||
|
|||||||
Reference in New Issue
Block a user