mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-13 07:32:23 -07:00
WIP parser for MSVC C++ exceptions unwind info
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U64
|
||||
mscrt_parse_func_info(Arena *arena,
|
||||
String8 raw_data,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *sections,
|
||||
U64 off,
|
||||
MSCRT_FuncInfo *func_info)
|
||||
{
|
||||
U64 cursor = off;
|
||||
|
||||
U32 handler_data_voff = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &handler_data_voff);
|
||||
|
||||
// TODO: what is this? padding?
|
||||
U32 unknown = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &unknown);
|
||||
|
||||
// read function info
|
||||
U64 handler_data_foff = coff_foff_from_voff(sections, section_count, handler_data_voff);
|
||||
|
||||
MSCRT_FuncInfo32 func_info32 = {0};
|
||||
str8_deserial_read_struct(raw_data, handler_data_foff, &func_info32);
|
||||
|
||||
// unwind map
|
||||
MSCRT_UnwindMap32 *unwind_map = push_array(arena, MSCRT_UnwindMap32, func_info32.max_state);
|
||||
U64 unwind_map_foff = coff_foff_from_voff(sections, section_count, func_info32.unwind_map_voff);
|
||||
cursor += str8_deserial_read_array(raw_data, unwind_map_foff, &unwind_map[0], func_info32.max_state);
|
||||
|
||||
// read ip states
|
||||
MSCRT_IPState32 *ip_map = push_array(arena, MSCRT_IPState32, func_info32.ip_map_count);
|
||||
U64 ip_map_foff = coff_foff_from_voff(sections, section_count, func_info32.ip_map_voff);
|
||||
str8_deserial_read_array(raw_data, ip_map_foff, &ip_map[0], func_info32.ip_map_count);
|
||||
|
||||
// read try map
|
||||
MSCRT_TryMapBlock *try_block_map = push_array(arena, MSCRT_TryMapBlock, func_info32.try_block_map_count);
|
||||
U64 try_map_foff = coff_foff_from_voff(sections, section_count, func_info32.try_block_map_voff);
|
||||
for (U32 imap = 0; imap < func_info32.try_block_map_count; ++imap) {
|
||||
MSCRT_TryMapBlock32 map32 = {0};
|
||||
str8_deserial_read_struct(raw_data, try_map_foff + imap*sizeof(map32), &map32);
|
||||
|
||||
// convert try map to in-memory version
|
||||
MSCRT_TryMapBlock *map = &try_block_map[imap];
|
||||
map->try_low = map32.try_low;
|
||||
map->try_high = map32.try_high;
|
||||
map->catch_high = map32.catch_high;
|
||||
map->catch_handlers_count = map32.catch_handlers_count;
|
||||
map->catch_handlers = push_array(arena, MSCRT_EhHandlerType32, map32.catch_handlers_count);
|
||||
|
||||
// read handlers
|
||||
U64 catch_handlers_foff = coff_foff_from_voff(sections, section_count, map32.catch_handlers_voff);
|
||||
str8_deserial_read_array(raw_data, catch_handlers_foff, &map->catch_handlers[0], map->catch_handlers_count);
|
||||
}
|
||||
|
||||
// read exception spec list
|
||||
MSCRT_ExceptionSpecTypeList es_type_list = {0};
|
||||
if (func_info32.es_type_list_voff) {
|
||||
MSCRT_ExceptionSpecTypeList32 es_list32 = {0};
|
||||
U64 es_list_foff = coff_foff_from_voff(sections, section_count, func_info32.es_type_list_voff);
|
||||
str8_deserial_read_struct(raw_data, es_list_foff, &es_list32);
|
||||
|
||||
es_type_list.count = es_list32.count;
|
||||
es_type_list.handlers = push_array(arena, MSCRT_EhHandlerType32, es_list32.count);
|
||||
|
||||
U64 handlers_foff = coff_foff_from_voff(sections, section_count, es_list32.handlers_voff);
|
||||
str8_deserial_read_array(raw_data, handlers_foff, &es_type_list.handlers[0], es_type_list.count);
|
||||
}
|
||||
|
||||
// pack result
|
||||
func_info->magic = func_info32.magic;
|
||||
func_info->max_state = func_info32.max_state;
|
||||
func_info->unwind_map = unwind_map;
|
||||
func_info->try_block_map_count = func_info32.try_block_map_count;
|
||||
func_info->try_block_map = try_block_map;
|
||||
func_info->ip_map_count = func_info32.ip_map_count;
|
||||
func_info->ip_map = ip_map;
|
||||
func_info->frame_offset_unwind_helper = func_info32.frame_offset_unwind_helper;
|
||||
func_info->es_type_list = es_type_list;
|
||||
func_info->eh_flags = func_info32.eh_flags;
|
||||
|
||||
U64 parse_size = (cursor - off);
|
||||
return parse_size;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64
|
||||
mscrt_parse_handler_type_v4(String8 raw_data, U64 offset, U64 func_voff, MSCRT_EhHandlerTypeV4 *handler)
|
||||
{
|
||||
U64 cursor = offset;
|
||||
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->flags);
|
||||
if (handler->flags & MSCRT_EhHandlerV4Flag_Adjectives) {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->adjectives);
|
||||
}
|
||||
if (handler->flags & MSCRT_EhHandlerV4Flag_DispType) {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->type_voff);
|
||||
}
|
||||
if (handler->flags & MSCRT_EhHandlerV4Flag_DispCatchObj) {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->catch_obj_voff);
|
||||
}
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &handler->catch_code_voff);
|
||||
|
||||
U32 cont_type = (handler->flags & MSCRT_EhHandlerV4Flag_ContVOffMask) >> MSCRT_EhHandlerV4Flag_ContVOffShift;
|
||||
if (handler->flags & MSCRT_EhHandlerV4Flag_ContIsVOff) {
|
||||
switch (cont_type) {
|
||||
case MSCRT_ContV4Type_NoMetadata: break;
|
||||
case MSCRT_ContV4Type_OneFuncRelAddr: {
|
||||
S32 v = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &v);
|
||||
handler->catch_funclet_cont_addr[0] = (U64)v;
|
||||
handler->catch_funclet_cont_addr_count = 1;
|
||||
} break;
|
||||
case MSCRT_ContV4Type_TwoFuncRelAddr: {
|
||||
S32 v1 = 0, v2 = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &v1);
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &v2);
|
||||
handler->catch_funclet_cont_addr[0] = (U64)v1;
|
||||
handler->catch_funclet_cont_addr[1] = (U64)v2;
|
||||
handler->catch_funclet_cont_addr_count = 2;
|
||||
} break;
|
||||
}
|
||||
} else {
|
||||
switch (cont_type) {
|
||||
case MSCRT_ContV4Type_NoMetadata: {
|
||||
} break;
|
||||
case MSCRT_ContV4Type_OneFuncRelAddr: {
|
||||
U32 v = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &v);
|
||||
handler->catch_funclet_cont_addr[0] = func_voff + (U64)v;
|
||||
handler->catch_funclet_cont_addr_count = 1;
|
||||
} break;
|
||||
case MSCRT_ContV4Type_TwoFuncRelAddr: {
|
||||
U32 v1 = 0, v2 = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &v1);
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &v2);
|
||||
handler->catch_funclet_cont_addr[0] = func_voff + (U64)v1;
|
||||
handler->catch_funclet_cont_addr[1] = func_voff + (U64)v2;
|
||||
handler->catch_funclet_cont_addr_count = 2;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
U64 read_size = cursor - offset;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
mscrt_parse_handler_type_v4_array(Arena *arena,
|
||||
String8 raw_data,
|
||||
U64 offset,
|
||||
U64 func_voff,
|
||||
MSCRT_EhHandlerTypeV4Array *array_out)
|
||||
{
|
||||
U64 cursor = offset;
|
||||
U32 count = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &count);
|
||||
|
||||
MSCRT_EhHandlerTypeV4 *handlers = 0;
|
||||
if (count) {
|
||||
handlers = push_array(arena, MSCRT_EhHandlerTypeV4, count);
|
||||
for (U32 i = 0; i < count; ++i) {
|
||||
cursor += mscrt_parse_handler_type_v4(raw_data, cursor, func_voff, &handlers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
array_out->count = count;
|
||||
array_out->v = handlers;
|
||||
|
||||
U64 read_size = cursor - offset;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
mscrt_parse_unwind_v4_entry(String8 raw_data, U64 offset, MSCRT_UnwindEntryV4 *entry_out)
|
||||
{
|
||||
U64 cursor = offset;
|
||||
|
||||
U32 type_and_next_off = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &type_and_next_off);
|
||||
|
||||
entry_out->type = type_and_next_off & 0x3;
|
||||
entry_out->next_off = type_and_next_off >> 2;
|
||||
|
||||
switch (entry_out->type) {
|
||||
case MSCRT_UnwindMapV4Type_DtorWithObj:
|
||||
case MSCRT_UnwindMapV4Type_DtorWithPtrToObj: {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->action);
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->object);
|
||||
} break;
|
||||
case MSCRT_UnwindMapV4Type_VOFF: {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &entry_out->action);
|
||||
} break;
|
||||
case MSCRT_UnwindMapV4Type_NoUW: {
|
||||
// no action and/or object is associated with this type
|
||||
} break;
|
||||
default: {
|
||||
Assert(!"unknown unwind entry type");
|
||||
} break;
|
||||
}
|
||||
|
||||
U64 read_size = cursor - offset;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
mscrt_parse_unwind_map_v4(Arena *arena, String8 raw_data, U64 off, MSCRT_UnwindMapV4 *map_out)
|
||||
{
|
||||
U64 cursor = off;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &map_out->count);
|
||||
map_out->v = push_array(arena, MSCRT_UnwindEntryV4, map_out->count);
|
||||
for (U32 i = 0; i < map_out->count; ++i) {
|
||||
cursor += mscrt_parse_unwind_v4_entry(raw_data, cursor, &map_out->v[i]);
|
||||
}
|
||||
U64 read_size = cursor - off;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
mscrt_parse_try_block_map_array_v4(Arena *arena,
|
||||
String8 raw_data,
|
||||
U64 off,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *sections,
|
||||
U64 func_voff,
|
||||
MSCRT_TryBlockMapV4Array *map_out)
|
||||
{
|
||||
U64 cursor = off;
|
||||
|
||||
U32 try_block_map_count = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &try_block_map_count);
|
||||
|
||||
MSCRT_TryBlockMapV4 *try_block_map = push_array(arena, MSCRT_TryBlockMapV4, try_block_map_count);
|
||||
for (U32 itry = 0; itry < try_block_map_count; ++itry) {
|
||||
MSCRT_TryBlockMapV4 *try_block = &try_block_map[itry];
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->try_low);
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->try_high);
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &try_block->catch_high);
|
||||
|
||||
S32 handler_array_voff = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &handler_array_voff);
|
||||
|
||||
U64 handler_array_foff = coff_foff_from_voff(sections, section_count, (U32)handler_array_voff);
|
||||
mscrt_parse_handler_type_v4_array(arena, raw_data, handler_array_foff, func_voff, &try_block->handlers);
|
||||
}
|
||||
|
||||
map_out->count = try_block_map_count;
|
||||
map_out->v = try_block_map;
|
||||
|
||||
U64 read_size = cursor - off;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
mscrt_parse_ip2state_map_v4(Arena *arena,
|
||||
String8 raw_data,
|
||||
U64 off,
|
||||
U64 func_voff,
|
||||
MSCRT_IP2State32V4 *ip2state_map_out)
|
||||
{
|
||||
U64 cursor = off;
|
||||
|
||||
U32 count = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &count);
|
||||
|
||||
U32 *voffs = push_array(arena, U32, count);
|
||||
S32 *states = push_array(arena, S32, count);
|
||||
|
||||
U32 prev_voff = func_voff;
|
||||
for (U32 i = 0; i < count; ++i) {
|
||||
// virtual offsets are encoded as deltas
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &voffs[i]);
|
||||
voffs[i] += prev_voff;
|
||||
prev_voff = voffs[i];
|
||||
|
||||
// states are encoded with +1 to avoid encoding negative integers
|
||||
U32 encoded_state = 0;
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &encoded_state);
|
||||
states[i] = (S32)encoded_state - 1;
|
||||
}
|
||||
|
||||
ip2state_map_out->count = count;
|
||||
ip2state_map_out->voffs = voffs;
|
||||
ip2state_map_out->states = states;
|
||||
|
||||
U64 read_size = cursor - off;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
mscrt_parse_func_info_v4(Arena *arena,
|
||||
String8 raw_data,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *sections,
|
||||
U64 off,
|
||||
U64 func_voff,
|
||||
MSCRT_ParsedFuncInfoV4 *func_info_out)
|
||||
{
|
||||
U64 cursor = off;
|
||||
|
||||
MSCRT_FuncInfo32V4 func_info = {0};
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.header);
|
||||
if (func_info.header & MSCRT_FuncInfoV4Flag_IsBBT) {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.bbt_flags);
|
||||
}
|
||||
if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.unwind_map_voff);
|
||||
}
|
||||
if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.try_block_map_voff);
|
||||
}
|
||||
if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) {
|
||||
// TODO: separted IP state map
|
||||
NotImplemented;
|
||||
} else {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.ip_to_state_map_voff);
|
||||
}
|
||||
if (func_info.header & MSCRT_FuncInfoV4Flag_IsCatch) {
|
||||
cursor += str8_deserial_read_struct(raw_data, cursor, &func_info.wrt_frame_establisher_voff);
|
||||
}
|
||||
|
||||
MSCRT_UnwindMapV4 unwind_map = {0};
|
||||
if (func_info.header & MSCRT_FuncInfoV4Flag_UnwindMap) {
|
||||
U64 unwind_map_foff = coff_foff_from_voff(sections, section_count, func_info.unwind_map_voff);
|
||||
mscrt_parse_unwind_map_v4(arena, raw_data, unwind_map_foff, &unwind_map);
|
||||
}
|
||||
|
||||
MSCRT_TryBlockMapV4Array try_block_map = {0};
|
||||
if (func_info.header & MSCRT_FuncInfoV4Flag_TryBlockMap) {
|
||||
U64 try_block_map_foff = coff_foff_from_voff(sections, section_count, func_info.try_block_map_voff);
|
||||
mscrt_parse_try_block_map_array_v4(arena, raw_data, try_block_map_foff, section_count, sections, func_voff, &try_block_map);
|
||||
}
|
||||
|
||||
MSCRT_IP2State32V4 ip2state_map = {0};
|
||||
if (func_info.header & MSCRT_FuncInfoV4Flag_IsSeparated) {
|
||||
Assert(!"TODO: separated ip2state map");
|
||||
} else {
|
||||
U64 ip_to_state_map_foff = coff_foff_from_voff(sections, section_count, func_info.ip_to_state_map_voff);
|
||||
mscrt_parse_ip2state_map_v4(arena, raw_data, ip_to_state_map_foff, func_voff, &ip2state_map);
|
||||
}
|
||||
|
||||
func_info_out->header = func_info.header;
|
||||
func_info_out->bbt_flags = func_info.bbt_flags;
|
||||
func_info_out->try_block_map = try_block_map;
|
||||
func_info_out->unwind_map = unwind_map;
|
||||
func_info_out->ip2state_map = ip2state_map;
|
||||
|
||||
U64 read_size = cursor - off;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal Rng1U64List
|
||||
mscrt_catch_blocks_from_data_x8664(Arena *arena,
|
||||
String8 raw_data,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *sections,
|
||||
Rng1U64 except_frange)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
Rng1U64List result = {0};
|
||||
|
||||
String8 raw_pdata = str8_substr(raw_data, except_frange);
|
||||
U64 pdata_count = raw_pdata.size / sizeof(PE_IntelPdata);
|
||||
PE_IntelPdata *src_pdata = (PE_IntelPdata *)raw_pdata.str;
|
||||
PE_IntelPdata *opl_pdata = src_pdata + pdata_count;
|
||||
|
||||
for (PE_IntelPdata *pdata = src_pdata; pdata < opl_pdata; ++pdata) {
|
||||
U64 uwinfo_foff = coff_foff_from_voff(sections, section_count, pdata->voff_unwind_info);
|
||||
PE_UnwindInfo *uwinfo = str8_deserial_get_raw_ptr(raw_data, uwinfo_foff, sizeof(*uwinfo));
|
||||
|
||||
U8 flags = PE_UnwindInfo_FlagsFromHeader(uwinfo->header);
|
||||
B32 is_chained = !!(flags & PE_UnwindInfoFlag_CHAINED);
|
||||
B32 has_handler_data = !is_chained && ((flags & (PE_UnwindInfoFlag_EHANDLER | PE_UnwindInfoFlag_UHANDLER)) != 0);
|
||||
|
||||
if (has_handler_data) {
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
|
||||
U32 actual_code_count = PE_UNWIND_INFO_GET_CODE_COUNT(uwinfo->codes_num);
|
||||
U64 handler_data_foff = uwinfo_foff + sizeof(PE_UnwindInfo) + actual_code_count * sizeof(PE_UnwindCode);
|
||||
U32 handler_voff = *(U32 *)str8_deserial_get_raw_ptr(raw_data, handler_data_foff, sizeof(handler_voff));
|
||||
|
||||
String8 handler_name = str8_zero();
|
||||
/* TODO:
|
||||
{
|
||||
SYMS_UnitID uid = syms_group_uid_from_voff__accelerated(group, handler_voff);
|
||||
SYMS_UnitAccel *unit = syms_group_unit_from_uid(group, uid);
|
||||
SYMS_SymbolID sid = syms_group_proc_sid_from_uid_voff__accelerated(group, uid, handler_voff);
|
||||
handler_name = syms_group_symbol_name_from_sid(temp.arena, group, unit, sid);
|
||||
}
|
||||
*/
|
||||
|
||||
B32 is_handler_v3_or_below = str8_match(handler_name, str8_lit("__CxxFrameHandler3"), 0) ||
|
||||
str8_match(handler_name, str8_lit("__GSHandlerCheck_EH"), 0);
|
||||
if (is_handler_v3_or_below) {
|
||||
U64 func_info_foff = handler_data_foff + sizeof(handler_voff);
|
||||
MSCRT_FuncInfo func_info = {0};
|
||||
mscrt_parse_func_info(temp.arena, raw_data, section_count, sections, func_info_foff, &func_info);
|
||||
|
||||
for (U32 itry = 0; itry < func_info.try_block_map_count; ++itry) {
|
||||
MSCRT_TryMapBlock *try_block = &func_info.try_block_map[itry];
|
||||
for (U32 icatch = 0; icatch < try_block->catch_handlers_count; ++icatch) {
|
||||
MSCRT_EhHandlerType32 *catch_block = &try_block->catch_handlers[icatch];
|
||||
U64 catch_pdata_off = pe_pdata_off_from_voff__binary_search_x8664(raw_pdata, catch_block->catch_handler_voff);
|
||||
PE_IntelPdata *catch_pdata = str8_deserial_get_raw_ptr(raw_pdata, catch_pdata_off, sizeof(*catch_pdata));
|
||||
rng1u64_list_push(arena, &result, rng_1u64(catch_pdata->voff_first, catch_pdata->voff_one_past_last));
|
||||
}
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
|
||||
B32 is_handler_v4 = str8_match(handler_name, str8_lit("__CxxFrameHandler4"), 0) ||
|
||||
str8_match(handler_name, str8_lit("__GSHandlerCheck_EH4"), 0);
|
||||
if (is_handler_v4) {
|
||||
U32 func_info_voff = *(U32 *)str8_deserial_get_raw_ptr(raw_data, handler_data_foff + sizeof(handler_voff), sizeof(func_info_voff));
|
||||
U64 func_info_foff = coff_foff_from_voff(sections, section_count, func_info_voff);
|
||||
MSCRT_ParsedFuncInfoV4 func_info = {0};
|
||||
mscrt_parse_func_info_v4(temp.arena, raw_data, section_count, sections, func_info_foff, pdata->voff_first, &func_info);
|
||||
|
||||
for (U32 itry = 0; itry < func_info.try_block_map.count; ++itry) {
|
||||
MSCRT_TryBlockMapV4 *try_block = &func_info.try_block_map.v[itry];
|
||||
for (U32 icatch = 0; icatch < try_block->handlers.count; ++icatch) {
|
||||
MSCRT_EhHandlerTypeV4 *catch_block = &try_block->handlers.v[icatch];
|
||||
U64 catch_pdata_off = pe_pdata_off_from_voff__binary_search_x8664(raw_pdata, catch_block->catch_code_voff);
|
||||
PE_IntelPdata *catch_pdata = str8_deserial_get_raw_ptr(raw_pdata, catch_pdata_off, sizeof(*catch_pdata));
|
||||
rng1u64_list_push(arena, &result, rng_1u64(catch_pdata->voff_first, catch_pdata->voff_one_past_last));
|
||||
}
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
|
||||
next:;
|
||||
temp_end(temp);
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
// Copyright (c) 2024 Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef MSVC_CRT
|
||||
#define MSVC_CRT
|
||||
|
||||
////////////////////////////////
|
||||
// GS Handler
|
||||
|
||||
#define MSCRT_GSHandler_GetFlags(x) (((x) & 0x00000007) >> 0)
|
||||
#define MSCRT_GSHandler_GetCookieOffset(x) (((x) & 0xFFFFFFF8) >> 3)
|
||||
|
||||
typedef U8 MSCRT_GSHandlerFlags;
|
||||
enum
|
||||
{
|
||||
MSCRT_GSHandlerFlag_EHandler = (1 << 0),
|
||||
MSCRT_GSHandlerFlag_UHandler = (1 << 1),
|
||||
MSCRT_GSHandlerFlag_HasAlignment = (1 << 2)
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// Exceptions < v4
|
||||
|
||||
#define MSCRT_MAGIC_GET_CHECK(x) ((x) & 0x1FFFFFFF)
|
||||
#define MSCRT_MAGIC_GET_FLAGS(x) (((x) & 0xE0000000) >> 29)
|
||||
|
||||
// Magic numbers are incremented by one everytime there is a new version.
|
||||
// Top 3 bits are reserved for flags.
|
||||
enum
|
||||
{
|
||||
MSCRT_Magic1 = 0x19930520,
|
||||
MSCRT_Magic2 = 0x19930521,
|
||||
MSCRT_Magic3 = 0x19930522,
|
||||
|
||||
// pure magic indicates that exception cannot be caught in native or managed code.
|
||||
MSCRT_PureMagic1 = 0x1994000,
|
||||
};
|
||||
enum
|
||||
{
|
||||
MSCRT_MagicFlag_EHS = (1 << 0),
|
||||
MSCRT_MagicFlag_DYNSTALKING = (1 << 1),
|
||||
MSCRT_MagicFlag_EHNOEXCEPT = (1 << 2)
|
||||
};
|
||||
|
||||
typedef U32 MSCRT_Flags;
|
||||
enum
|
||||
{
|
||||
MSCRT_Flag_SynchronousExceptionOnly = (1 << 0),
|
||||
MSCRT_Flag_UNKNOWN = (1 << 1),
|
||||
MSCRT_Flag_StopUnwind = (1 << 2), // When set unwinding can't continue.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MSCRT_CatchableType_IsSimpleType = (1 << 0),
|
||||
MSCRT_CatchableType_ByRefOnly = (1 << 1),
|
||||
MSCRT_CatchableType_HasVirtualBase = (1 << 2), // type is a class with virtual base
|
||||
MSCRT_CatchableType_IsWinRTHandle = (1 << 3), // type is a WinRT handle
|
||||
MSCRT_CatchableType_IsStdBadAlloc = (1 << 4) // type is a std::bad_alloc
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MSCRT_ThrowInfo_IsConst = (1 << 0),
|
||||
MSCRT_ThrowInfo_IsVolatile = (1 << 1),
|
||||
MSCRT_ThrowInfo_IsUnaligned = (1 << 2),
|
||||
MSCRT_ThrowInfo_IsPure = (1 << 3), // thrown object is from pure module
|
||||
MSCRT_ThrowInfo_IsWinRT = (1 << 4) // thrown object is a WinRT exception
|
||||
};
|
||||
|
||||
typedef U32 MSCRT_EhHandlerTypeFlags;
|
||||
enum
|
||||
{
|
||||
MSCRT_EhHandlerTypeFlag_IsConst = (1 << 0), // referenced type is 'const'
|
||||
MSCRT_EhHandlerTypeFlag_IsVolatile = (1 << 1), // referenced type is 'volatile'
|
||||
MSCRT_EhHandlerTypeFlag_IsUnaligned = (1 << 2), // referenced type is 'unaligned'
|
||||
MSCRT_EhHandlerTypeFlag_IsReference = (1 << 3), // catch type is by reference
|
||||
MSCRT_EhHandlerTypeFlag_IsResumable = (1 << 4), // catch may choose to resume
|
||||
MSCRT_EhHandlerTypeFlag_IsStdDotDot = (1 << 6), // catch(...)
|
||||
MSCRT_EhHandlerTypeFlag_IsComplusEH = (1 << 31) // is handling EH in complus
|
||||
};
|
||||
|
||||
typedef struct MSCRT_FuncInfo32
|
||||
{
|
||||
U32 magic;
|
||||
U32 max_state;
|
||||
U32 unwind_map_voff;
|
||||
U32 try_block_map_count;
|
||||
U32 try_block_map_voff;
|
||||
U32 ip_map_count;
|
||||
U32 ip_map_voff;
|
||||
U32 frame_offset_unwind_helper;
|
||||
U32 es_type_list_voff; // llvm emits zero, not sure what this supposed to be
|
||||
MSCRT_Flags eh_flags;
|
||||
} MSCRT_FuncInfo32;
|
||||
|
||||
typedef struct MSCRT_IPState32
|
||||
{
|
||||
U32 ip;
|
||||
S32 state;
|
||||
} MSCRT_IPState32;
|
||||
|
||||
typedef struct MSCRT_UnwindMap32
|
||||
{
|
||||
S32 next_state;
|
||||
U32 action_virt_off;
|
||||
} MSCRT_UnwindMap32;
|
||||
|
||||
typedef struct MSCRT_EhHandlerType32
|
||||
{
|
||||
MSCRT_EhHandlerTypeFlags adjectives;
|
||||
U32 descriptor_voff;
|
||||
U32 catch_obj_frame_offset;
|
||||
U32 catch_handler_voff;
|
||||
U32 fp_distance;
|
||||
} MSCRT_EhHandlerType32;
|
||||
|
||||
typedef struct MSCRT_TryMapBlock32
|
||||
{
|
||||
S32 try_low;
|
||||
S32 try_high;
|
||||
S32 catch_high;
|
||||
S32 catch_handlers_count;
|
||||
U32 catch_handlers_voff;
|
||||
} MSCRT_TryMapBlock32;
|
||||
|
||||
typedef struct MSCRT_ExceptionSpecTypeList32
|
||||
{
|
||||
S32 count;
|
||||
U32 handlers_voff;
|
||||
} MSCRT_ExceptionSpecTypeList32;
|
||||
|
||||
typedef struct MSCRT_TryMapBlock
|
||||
{
|
||||
S32 try_low;
|
||||
S32 try_high;
|
||||
S32 catch_high;
|
||||
S32 catch_handlers_count;
|
||||
MSCRT_EhHandlerType32 *catch_handlers;
|
||||
} MSCRT_TryMapBlock;
|
||||
|
||||
typedef struct MSCRT_ExceptionSpecTypeList
|
||||
{
|
||||
S32 count;
|
||||
MSCRT_EhHandlerType32 *handlers;
|
||||
} MSCRT_ExceptionSpecTypeList;
|
||||
|
||||
typedef struct MSCRT_FuncInfo
|
||||
{
|
||||
U32 magic;
|
||||
U32 max_state;
|
||||
MSCRT_UnwindMap32 *unwind_map;
|
||||
U32 try_block_map_count;
|
||||
MSCRT_TryMapBlock *try_block_map;
|
||||
U32 ip_map_count;
|
||||
MSCRT_IPState32 *ip_map;
|
||||
U32 frame_offset_unwind_helper;
|
||||
MSCRT_ExceptionSpecTypeList es_type_list;
|
||||
MSCRT_Flags eh_flags;
|
||||
} MSCRT_FuncInfo;
|
||||
|
||||
////////////////////////////////
|
||||
// C++ Exceptions V4
|
||||
|
||||
typedef U8 MSCRT_FuncInfoV4Flags;
|
||||
enum
|
||||
{
|
||||
MSCRT_FuncInfoV4Flag_IsCatch = (1 << 0), // catch funclet
|
||||
MSCRT_FuncInfoV4Flag_IsSeparated = (1 << 1), // func has separate code segment
|
||||
MSCRT_FuncInfoV4Flag_IsBBT = (1 << 2), // flags set by basic block trasformations
|
||||
MSCRT_FuncInfoV4Flag_UnwindMap = (1 << 3), // unwind map is present
|
||||
MSCRT_FuncInfoV4Flag_TryBlockMap = (1 << 4), // try block map is present
|
||||
MSCRT_FuncInfoV4Flag_EHs = (1 << 5),
|
||||
MSCRT_FuncInfoV4Flag_NoExcept = (1 << 6),
|
||||
MSCRT_FuncInfoV4Flag_Reserved = (1 << 7)
|
||||
};
|
||||
|
||||
typedef U32 MSCRT_UnwindMapV4Type;
|
||||
enum
|
||||
{
|
||||
MSCRT_UnwindMapV4Type_NoUW = 0, // no unwind action associated with this state
|
||||
MSCRT_UnwindMapV4Type_DtorWithObj = 1, // dtor with an object offset
|
||||
MSCRT_UnwindMapV4Type_DtorWithPtrToObj = 2, // dtor with an offset that contains a pointer to the object to be destroyed
|
||||
MSCRT_UnwindMapV4Type_VOFF = 3, // dtor that has a direct function that is called that knows where the object is and can perform more exotic destruction
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MSCRT_ContV4Type_NoMetadata = 1, // no metadata use whatever funclet returns
|
||||
MSCRT_ContV4Type_OneFuncRelAddr = 2,
|
||||
MSCRT_ContV4Type_TwoFuncRelAddr = 3
|
||||
};
|
||||
|
||||
#define MSCRT__EH_HANDLER_V4_FLAGS_EXTRACT_CONT_TYPE(x) (((x) & MSCRT_EhHandlerV4Flag_ContVOffMask) >> MSVC_CRTHandlerV4Flag_ContVOffShift)
|
||||
typedef U8 MSCRT_EhHandlerV4Flags;
|
||||
enum
|
||||
{
|
||||
MSCRT_EhHandlerV4Flag_Adjectives = (1 << 0), // set if adjectives are present
|
||||
MSCRT_EhHandlerV4Flag_DispType = (1 << 1), // set if type descriptors are present
|
||||
MSCRT_EhHandlerV4Flag_DispCatchObj = (1 << 2), // set if catch object object is present
|
||||
MSCRT_EhHandlerV4Flag_ContIsVOff = (1 << 3), // continuantion addresses are VOFF rather than function relative
|
||||
|
||||
MSCRT_EhHandlerV4Flag_ContVOffMask = 0x30,
|
||||
MSCRT_EhHandlerV4Flag_ContVOffShift = 4,
|
||||
};
|
||||
|
||||
typedef struct MSCRT_EhHandlerTypeV4
|
||||
{
|
||||
MSCRT_EhHandlerV4Flags flags;
|
||||
MSCRT_EhHandlerTypeFlags adjectives;
|
||||
S32 type_voff;
|
||||
U32 catch_obj_voff;
|
||||
S32 catch_code_voff;
|
||||
U64 catch_funclet_cont_addr[2];
|
||||
U32 catch_funclet_cont_addr_count;
|
||||
} MSCRT_EhHandlerTypeV4;
|
||||
|
||||
typedef struct MSCRT_EhHandlerTypeV4Array
|
||||
{
|
||||
U64 count;
|
||||
MSCRT_EhHandlerTypeV4 *v;
|
||||
} MSCRT_EhHandlerTypeV4Array;
|
||||
|
||||
typedef struct MSCRT_TryBlockMap32V4
|
||||
{
|
||||
U32 try_low;
|
||||
U32 try_high;
|
||||
U32 catch_high;
|
||||
S32 handler_array_voff;
|
||||
} MSCRT_TryBlockMap32V4;
|
||||
|
||||
typedef struct MSCRT_IP2State32V4
|
||||
{
|
||||
U32 count;
|
||||
U32 *voffs;
|
||||
S32 *states;
|
||||
} MSCRT_IP2State32V4;
|
||||
|
||||
typedef struct MSCRT_SepIPState32V4
|
||||
{
|
||||
S32 func_start_voff;
|
||||
S32 ip_map_voff;
|
||||
} MSCRT_SepIPState32V4;
|
||||
|
||||
typedef struct MSCRT_FuncInfo32V4
|
||||
{
|
||||
MSCRT_FuncInfoV4Flags header;
|
||||
U32 bbt_flags;
|
||||
S32 unwind_map_voff;
|
||||
S32 try_block_map_voff;
|
||||
S32 ip_to_state_map_voff;
|
||||
S32 wrt_frame_establisher_voff; // used only in catch funclets
|
||||
} MSCRT_FuncInfo32V4;
|
||||
|
||||
typedef struct MSCRT_UnwindEntryV4
|
||||
{
|
||||
MSCRT_UnwindMapV4Type type;
|
||||
S32 action;
|
||||
U32 object;
|
||||
U32 next_off;
|
||||
} MSCRT_UnwindEntryV4;
|
||||
|
||||
typedef struct MSCRT_UnwindMapV4
|
||||
{
|
||||
U32 count;
|
||||
MSCRT_UnwindEntryV4 *v;
|
||||
} MSCRT_UnwindMapV4;
|
||||
|
||||
typedef struct MSCRT_TryBlockMapV4
|
||||
{
|
||||
U32 try_low;
|
||||
U32 try_high;
|
||||
U32 catch_high;
|
||||
MSCRT_EhHandlerTypeV4Array handlers;
|
||||
} MSCRT_TryBlockMapV4;
|
||||
|
||||
typedef struct MSCRT_TryBlockMapV4Array
|
||||
{
|
||||
U64 count;
|
||||
MSCRT_TryBlockMapV4 *v;
|
||||
} MSCRT_TryBlockMapV4Array;
|
||||
|
||||
typedef struct MSCRT_ParsedFuncInfoV4
|
||||
{
|
||||
MSCRT_FuncInfoV4Flags header;
|
||||
U32 bbt_flags;
|
||||
MSCRT_UnwindMapV4 unwind_map;
|
||||
MSCRT_TryBlockMapV4Array try_block_map;
|
||||
MSCRT_IP2State32V4 ip2state_map;
|
||||
} MSCRT_ParsedFuncInfoV4;
|
||||
|
||||
//- Exception info < v4
|
||||
|
||||
internal U64 mscrt_parse_func_info(Arena *arena, String8 raw_data, U64 section_count, COFF_SectionHeader *sections, U64 off, MSCRT_FuncInfo *func_info);
|
||||
|
||||
//- Exception info v4
|
||||
|
||||
internal U64 mscrt_parse_handler_type_v4 (String8 raw_data, U64 offset, U64 func_voff, MSCRT_EhHandlerTypeV4 *handler);
|
||||
internal U64 mscrt_parse_unwind_v4_entry (String8 raw_data, U64 offset, MSCRT_UnwindEntryV4 *entry_out);
|
||||
internal U64 mscrt_parse_handler_type_v4_array (Arena *arena, String8 raw_data, U64 offset, U64 func_voff, MSCRT_EhHandlerTypeV4Array *array_out);
|
||||
internal U64 mscrt_parse_unwind_map_v4 (Arena *arena, String8 raw_data, U64 off, MSCRT_UnwindMapV4 *map_out);
|
||||
internal U64 mscrt_parse_try_block_map_array_v4(Arena *arena, String8 raw_data, U64 off, U64 section_count, COFF_SectionHeader *sections, U64 func_voff, MSCRT_TryBlockMapV4Array *map_out);
|
||||
internal U64 mscrt_parse_ip2state_map_v4 (Arena *arena, String8 raw_data, U64 off, U64 func_voff, MSCRT_IP2State32V4 *ip2state_map_out);
|
||||
internal U64 mscrt_parse_func_info_v4 (Arena *arena, String8 raw_data, U64 section_count, COFF_SectionHeader *sections, U64 off, U64 func_voff, MSCRT_ParsedFuncInfoV4 *func_info_out);
|
||||
|
||||
#endif // MSVC_CRT
|
||||
|
||||
Reference in New Issue
Block a user