mirror of
https://github.com/astromaddie/HaloCE-VR.git
synced 2026-10-20 17:00:12 +02:00
862 lines
21 KiB
C
862 lines
21 KiB
C
/*
|
|
STACK_WALK_WINDOWS.C
|
|
|
|
symbols in this file:
|
|
000806A0 0020:
|
|
_stack_walk_global_function_offset (0000)
|
|
000806C0 0010:
|
|
_stack_walk_disregard_symbol_names (0000)
|
|
000806D0 0030:
|
|
_symbol_sort_proc (0000)
|
|
00080700 0080:
|
|
_free_symbol_table (0000)
|
|
00080780 00b0:
|
|
_symbol_name_from_address (0000)
|
|
00080830 0060:
|
|
_base_address_from_symbol_name (0000)
|
|
00080890 0020:
|
|
_is_valid_ebp (0000)
|
|
000808B0 0040:
|
|
_walk_up (0000)
|
|
000808F0 0020:
|
|
_initialize_stack_walk (0000)
|
|
00080910 00d0:
|
|
_walk_stack_context (0000)
|
|
000809E0 00d0:
|
|
_walk_stack (0000)
|
|
00080AB0 0020:
|
|
_stack_walk_dispose (0000)
|
|
00080AD0 02b0:
|
|
_stack_walk_with_context (0000)
|
|
00080D80 0620:
|
|
_load_symbol_table (0000)
|
|
000813A0 0030:
|
|
_stack_walk_initialize (0000)
|
|
000813D0 0020:
|
|
_stack_walk (0000)
|
|
002586B4 000d:
|
|
??_C@_0N@CNIOPMPL@symbol_table?$AA@ (0000)
|
|
002586C4 002c:
|
|
??_C@_0CM@LOAPPLNB@c?3?2halo?2SOURCE?2cseries?2stack_wal@ (0000)
|
|
002586F0 0010:
|
|
??_C@_0BA@OFOBHDCE@?$CFs?5?$CL?5?$CF04lX?5?3?5?$CFs?$AA@ (0000)
|
|
00258700 000a:
|
|
??_C@_09JLKGDFIH@?$CF08lX?5?$CFs?6?$AA@ (0000)
|
|
0025870C 0029:
|
|
??_C@_0CJ@POGHEDC@EIP?3?50x?$CF08lX?0?5?$CF02lX?5?$CF02lX?5?$CF02lX?5@ (0000)
|
|
00258738 000d:
|
|
??_C@_0N@DEGIIKCL@ESP?3?50x?$CF08lX?$AA@ (0000)
|
|
00258748 000d:
|
|
??_C@_0N@KDNFCLLI@EBP?3?50x?$CF08lX?$AA@ (0000)
|
|
00258758 000d:
|
|
??_C@_0N@OBNDHAGF@ESI?3?50x?$CF08lX?$AA@ (0000)
|
|
00258768 000d:
|
|
??_C@_0N@JJFDHEBG@EDI?3?50x?$CF08lX?$AA@ (0000)
|
|
00258778 000d:
|
|
??_C@_0N@PGCLGPBN@EDX?3?50x?$CF08lX?$AA@ (0000)
|
|
00258788 000d:
|
|
??_C@_0N@ICLDIGJC@ECX?3?50x?$CF08lX?$AA@ (0000)
|
|
00258798 000d:
|
|
??_C@_0N@BJBGMKPN@EBX?3?50x?$CF08lX?$AA@ (0000)
|
|
002587A8 000d:
|
|
??_C@_0N@GOIIBIAN@EAX?3?50x?$CF08lX?$AA@ (0000)
|
|
002587B8 0009:
|
|
??_C@_08CCCCNONO@?$CF08lX?5?$CFs?$AA@ (0000)
|
|
002587C4 0006:
|
|
??_C@_05EHMBKEBF@?$DP?$DP?$DP?$DP?$DP?$AA@ (0000)
|
|
002587CC 0025:
|
|
??_C@_0CF@JNHFBDOE@Printing?5stuff?5for?5Mat?8s?5edifica@ (0000)
|
|
002587F4 002e:
|
|
??_C@_0CO@DKHIBCJD@could?5not?5allocate?5enough?5memory@ (0000)
|
|
00258828 0051:
|
|
??_C@_0FB@FDLBMJMP@string_storage_used?5?$CL?5strlen?$CIlib@ (0000)
|
|
00258880 0044:
|
|
??_C@_0EE@HFHPDHDJ@string_storage_used?5?$CL?5strlen?$CIsym@ (0000)
|
|
002588C8 006b:
|
|
??_C@_0GL@HCCMEKIO@string_storage_used?5?$CL?5strlen?$CIsym@ (0000)
|
|
00258934 0013:
|
|
??_C@_0BD@IFIGKEIG@_load_symbol_table?$AA@ (0000)
|
|
00258948 000f:
|
|
??_C@_0P@JLHKGDG@Static?5symbols?$AA@ (0000)
|
|
00258958 000f:
|
|
??_C@_0P@BNEDFJAM@entry?5point?5at?$AA@ (0000)
|
|
00258968 0005:
|
|
??_C@_04DNCNJDPH@?5?7?6?$AN?$AA@ (0000)
|
|
00258970 0002:
|
|
??_C@_01JLIPDDHJ@?3?$AA@ (0000)
|
|
00258974 0008:
|
|
??_C@_07DFGIHOIL@nothing?$AA@ (0000)
|
|
0025897C 0019:
|
|
??_C@_0BJ@BLEJAHCK@map?5file?5appears?5corrupt?$AA@ (0000)
|
|
00258998 000a:
|
|
??_C@_09KDGENIOP@Timestamp?$AA@ (0000)
|
|
002589A4 000b:
|
|
??_C@_0L@CKIHAGIB@Lib?3Object?$AA@ (0000)
|
|
002589B0 001c:
|
|
??_C@_0BM@LBIFOOIP@Couldn?8t?5read?5map?5file?5?8?$CFs?8?$AA@ (0000)
|
|
002589CC 0011:
|
|
??_C@_0BB@LJHACKGC@d?3?2cachebeta?4map?$AA@ (0000)
|
|
002589E0 0019:
|
|
??_C@_0BJ@NNIPHMJN@Mon?5Dec?517?512?349?336?52001?$AA@ (0000)
|
|
002DCD40 0014:
|
|
_stack_walk_globals (0000)
|
|
00431C98 4008:
|
|
_walk_up_current_frame (0000)
|
|
_old_ebp (0004)
|
|
?symbol_buffer@?1??symbol_name_from_address@@9@9 (0008)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#define NOD3D
|
|
#define NODSOUND
|
|
#include "cseries_windows.h"
|
|
#include "errors.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
/* January calls the CRT isspace function rather than the multibyte ctype macro. */
|
|
#undef isspace
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
MAXIMUM_DEBUG_SYMBOL_NAME_LENGTH = 256,
|
|
MAXIMUM_LIBRARY_OBJECT_FILE_NAME_LENGTH = 256,
|
|
DEBUG_SYMBOL_ALLOCATION_COUNT = 4096,
|
|
DEBUG_SYMBOL_STRING_STORAGE_ALLOCATION_SIZE = 0x4000
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
struct debug_symbol_table
|
|
{
|
|
long number_of_symbols;
|
|
char *string_storage;
|
|
struct debug_symbol *symbols;
|
|
};
|
|
|
|
struct debug_symbol
|
|
{
|
|
unsigned long address;
|
|
unsigned long rva_base;
|
|
unsigned long name_string_offset;
|
|
unsigned long library_object_string_offset;
|
|
};
|
|
|
|
struct _stack_walk_globals
|
|
{
|
|
long fixup;
|
|
boolean disregard_symbol_names;
|
|
struct debug_symbol_table symbol_table;
|
|
};
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static boolean is_valid_ebp(
|
|
void);
|
|
|
|
static unsigned long walk_up(
|
|
void);
|
|
|
|
static void initialize_stack_walk(
|
|
CONTEXT *context);
|
|
|
|
static void walk_stack_context(
|
|
unsigned long *routine_addresses,
|
|
unsigned long number_of_levels,
|
|
unsigned long ignore_levels,
|
|
unsigned long *levels_dumped);
|
|
|
|
static void walk_stack(
|
|
unsigned long *routine_addresses,
|
|
unsigned long number_of_levels,
|
|
unsigned long ignore_levels,
|
|
unsigned long *levels_dumped);
|
|
|
|
static int symbol_sort_proc(
|
|
const void *elem1,
|
|
const void *elem2);
|
|
|
|
/* ---------- globals */
|
|
|
|
static struct _stack_walk_globals stack_walk_globals =
|
|
{
|
|
NONE,
|
|
FALSE
|
|
};
|
|
|
|
static unsigned long *old_ebp;
|
|
static unsigned long walk_up_current_frame;
|
|
|
|
/* ---------- public code */
|
|
|
|
long stack_walk_global_function_offset(
|
|
void)
|
|
{
|
|
return stack_walk_globals.fixup==NONE ? 0 : stack_walk_globals.fixup;
|
|
}
|
|
|
|
void stack_walk_disregard_symbol_names(
|
|
boolean disregard)
|
|
{
|
|
stack_walk_globals.disregard_symbol_names = disregard;
|
|
return;
|
|
}
|
|
|
|
void stack_walk(
|
|
short levels_to_ignore)
|
|
{
|
|
stack_walk_with_context(
|
|
NULL,
|
|
levels_to_ignore + 1,
|
|
NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
void free_symbol_table(
|
|
struct debug_symbol_table *symbol_table)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c", 549, symbol_table);
|
|
|
|
if (symbol_table->string_storage)
|
|
{
|
|
debug_free(symbol_table->string_storage, "c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c", 551);
|
|
}
|
|
|
|
if (symbol_table->symbols)
|
|
{
|
|
debug_free(symbol_table->symbols, "c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c", 552);
|
|
}
|
|
|
|
symbol_table->number_of_symbols = 0;
|
|
symbol_table->string_storage = NULL;
|
|
symbol_table->symbols = NULL;
|
|
return;
|
|
}
|
|
|
|
char *symbol_name_from_address(
|
|
unsigned long fake_address,
|
|
struct debug_symbol_table *symbol_table)
|
|
{
|
|
static char symbol_buffer[0x4000] = { 0 };
|
|
unsigned long address = stack_walk_globals.fixup + fake_address;
|
|
|
|
csstrcpy(symbol_buffer, "<unknown>");
|
|
if (symbol_table->number_of_symbols > 0)
|
|
{
|
|
if (address >= symbol_table->symbols[0].rva_base && address < symbol_table->symbols[symbol_table->number_of_symbols - 1].rva_base + 0xFFFF)
|
|
{
|
|
long symbol_index = 1;
|
|
|
|
if (symbol_table->number_of_symbols > 1)
|
|
{
|
|
while (symbol_table->symbols[symbol_index - 1].rva_base > address || address >= symbol_table->symbols[symbol_index].rva_base)
|
|
{
|
|
symbol_index++;
|
|
if (symbol_index >= symbol_table->number_of_symbols)
|
|
{
|
|
return symbol_buffer;
|
|
}
|
|
}
|
|
|
|
_snprintf(
|
|
symbol_buffer,
|
|
0x3FFF,
|
|
"%s + %04lX : %s",
|
|
symbol_table->string_storage + symbol_table->symbols[symbol_index - 1].name_string_offset,
|
|
address - symbol_table->symbols[symbol_index - 1].rva_base,
|
|
symbol_table->string_storage + symbol_table->symbols[symbol_index - 1].library_object_string_offset);
|
|
}
|
|
}
|
|
}
|
|
|
|
return symbol_buffer;
|
|
}
|
|
|
|
long base_address_from_symbol_name(
|
|
char const *name,
|
|
struct debug_symbol_table *symbol_table)
|
|
{
|
|
long base_address = NONE;
|
|
long symbol_index;
|
|
char const *symbol_name;
|
|
|
|
for (symbol_index = 1; symbol_index < symbol_table->number_of_symbols; symbol_index++)
|
|
{
|
|
symbol_name = symbol_table->string_storage + symbol_table->symbols[symbol_index].name_string_offset;
|
|
|
|
if (csstrcmp(name, symbol_name)==0)
|
|
{
|
|
base_address = symbol_table->symbols[symbol_index].rva_base;
|
|
}
|
|
}
|
|
|
|
return base_address;
|
|
}
|
|
|
|
void stack_walk_dispose(
|
|
void)
|
|
{
|
|
stack_walk_globals.fixup = NONE;
|
|
stack_walk_globals.disregard_symbol_names = FALSE;
|
|
free_symbol_table(&stack_walk_globals.symbol_table);
|
|
return;
|
|
}
|
|
|
|
void stack_walk_with_context(
|
|
FILE *error_stream,
|
|
short levels_to_ignore,
|
|
CONTEXT *context_pointer)
|
|
{
|
|
unsigned long routine_addresses[64] = { 0 };
|
|
unsigned long levels_dumped;
|
|
long frame_number;
|
|
|
|
if (context_pointer)
|
|
{
|
|
initialize_stack_walk(context_pointer);
|
|
walk_stack_context(
|
|
routine_addresses,
|
|
NUMBEROF(routine_addresses),
|
|
levels_to_ignore,
|
|
&levels_dumped);
|
|
}
|
|
else
|
|
{
|
|
walk_stack(
|
|
routine_addresses,
|
|
NUMBEROF(routine_addresses),
|
|
levels_to_ignore,
|
|
&levels_dumped);
|
|
}
|
|
|
|
if (!error_stream)
|
|
{
|
|
error(_error_silent, "Printing stuff for Mat's edification");
|
|
|
|
for (frame_number = levels_dumped - 1; frame_number >= levels_to_ignore; frame_number--)
|
|
{
|
|
#ifdef HALO_ANDROID
|
|
/* the call site (the BL before the return address), for
|
|
llvm-symbolizer --obj=build/android/halo_guest.elf */
|
|
unsigned long routine_address = routine_addresses[frame_number] - 4;
|
|
#else
|
|
unsigned long routine_address = routine_addresses[frame_number] + *(long *)(routine_addresses[frame_number] - sizeof(long));
|
|
#endif
|
|
char const *symbol_name;
|
|
|
|
if (stack_walk_globals.symbol_table.number_of_symbols && !stack_walk_globals.disregard_symbol_names)
|
|
{
|
|
symbol_name = symbol_name_from_address(routine_address, &stack_walk_globals.symbol_table);
|
|
}
|
|
else
|
|
{
|
|
symbol_name = "?????";
|
|
}
|
|
|
|
error(_error_silent, "%08lX %s", routine_address, symbol_name);
|
|
}
|
|
}
|
|
|
|
if (context_pointer)
|
|
{
|
|
unsigned long instruction = *(unsigned long *)context_pointer->Eip;
|
|
unsigned long instruction_byte0 = instruction & 0xFF;
|
|
unsigned long instruction_byte1 = (instruction >> 8) & 0xFF;
|
|
unsigned long instruction_byte2 = (instruction >> 16) & 0xFF;
|
|
unsigned long instruction_byte3 = (instruction >> 24) & 0xFF;
|
|
char const *symbol_name;
|
|
|
|
error(_error_silent, "EAX: 0x%08lX", context_pointer->Eax);
|
|
error(_error_silent, "EBX: 0x%08lX", context_pointer->Ebx);
|
|
error(_error_silent, "ECX: 0x%08lX", context_pointer->Ecx);
|
|
error(_error_silent, "EDX: 0x%08lX", context_pointer->Edx);
|
|
error(_error_silent, "EDI: 0x%08lX", context_pointer->Edi);
|
|
error(_error_silent, "ESI: 0x%08lX", context_pointer->Esi);
|
|
error(_error_silent, "EBP: 0x%08lX", context_pointer->Ebp);
|
|
error(_error_silent, "ESP: 0x%08lX", context_pointer->Esp);
|
|
|
|
if (stack_walk_globals.symbol_table.number_of_symbols && !stack_walk_globals.disregard_symbol_names)
|
|
{
|
|
symbol_name = symbol_name_from_address(context_pointer->Eip, &stack_walk_globals.symbol_table);
|
|
}
|
|
else
|
|
{
|
|
symbol_name = "?????";
|
|
}
|
|
|
|
error(
|
|
_error_silent,
|
|
"EIP: 0x%08lX, %02lX %02lX %02lX %02lX %s",
|
|
context_pointer->Eip,
|
|
instruction_byte0,
|
|
instruction_byte1,
|
|
instruction_byte2,
|
|
instruction_byte3,
|
|
symbol_name);
|
|
}
|
|
|
|
for (frame_number = levels_dumped - 1; frame_number >= levels_to_ignore; frame_number--)
|
|
{
|
|
if (!error_stream)
|
|
{
|
|
error(
|
|
_error_silent,
|
|
"%08lX %s",
|
|
routine_addresses[frame_number],
|
|
stack_walk_globals.symbol_table.number_of_symbols && !stack_walk_globals.disregard_symbol_names
|
|
? symbol_name_from_address(routine_addresses[frame_number], &stack_walk_globals.symbol_table)
|
|
: "?????");
|
|
}
|
|
else
|
|
{
|
|
fprintf(
|
|
error_stream,
|
|
"%08lX %s\n",
|
|
routine_addresses[frame_number],
|
|
stack_walk_globals.symbol_table.number_of_symbols && !stack_walk_globals.disregard_symbol_names
|
|
? symbol_name_from_address(routine_addresses[frame_number], &stack_walk_globals.symbol_table)
|
|
: "?????");
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int load_symbol_table(
|
|
char *filename,
|
|
struct debug_symbol_table *symbol_table,
|
|
char *timestamp_str)
|
|
{
|
|
FILE *map_file;
|
|
unsigned long string_storage_size;
|
|
unsigned long string_storage_used;
|
|
unsigned long symbols_size;
|
|
long previous_library_object_offset;
|
|
unsigned long symbol_address;
|
|
unsigned long rva_base;
|
|
char *segment;
|
|
char *token;
|
|
char *end_str;
|
|
char symbol_name[MAXIMUM_DEBUG_SYMBOL_NAME_LENGTH];
|
|
char library_object_file_name[MAXIMUM_LIBRARY_OBJECT_FILE_NAME_LENGTH];
|
|
char last_object_file_name[MAXIMUM_LIBRARY_OBJECT_FILE_NAME_LENGTH];
|
|
|
|
match_assert("c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c", 256, symbol_table);
|
|
csmemset(symbol_table, 0, sizeof(*symbol_table));
|
|
|
|
map_file = fopen(filename, "r");
|
|
if (!map_file)
|
|
{
|
|
error(_error_silent, "Couldn't read map file '%s'", filename);
|
|
goto finished;
|
|
}
|
|
|
|
{
|
|
char line[DEBUG_SYMBOL_STRING_STORAGE_ALLOCATION_SIZE] = "";
|
|
boolean found_symbols_section = FALSE;
|
|
|
|
if (!fgets(line, sizeof(line), map_file))
|
|
{
|
|
goto close_map_file;
|
|
}
|
|
|
|
while (!found_symbols_section)
|
|
{
|
|
if (!fgets(line, sizeof(line), map_file))
|
|
{
|
|
error(_error_silent, "map file appears corrupt");
|
|
goto close_map_file;
|
|
}
|
|
|
|
if (strstr(line, "Lib:Object"))
|
|
{
|
|
found_symbols_section = TRUE;
|
|
}
|
|
else if (strstr(line, "Timestamp"))
|
|
{
|
|
/* BUG (preserved for exact matching): January performs the
|
|
* timestamp search but ignores whether it succeeds. A corrected
|
|
* build should reject a map whose timestamp does not match. */
|
|
strstr(line, timestamp_str);
|
|
}
|
|
}
|
|
|
|
string_storage_size = 0;
|
|
string_storage_used = 0;
|
|
symbols_size = 0;
|
|
strcpy(last_object_file_name, "nothing");
|
|
previous_library_object_offset = NONE;
|
|
|
|
while (fgets(line, sizeof(line), map_file))
|
|
{
|
|
end_str = NULL;
|
|
segment = strtok(line, ":");
|
|
if (!segment || *segment!=' ')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
token = strtok(NULL, " \t\n\r");
|
|
if (!token)
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
symbol_address = strtoul(token, &end_str, 16);
|
|
|
|
token = strtok(NULL, " \t\n\r");
|
|
if (token)
|
|
{
|
|
strncpy(symbol_name, token, sizeof(symbol_name)-1);
|
|
symbol_name[sizeof(symbol_name)-1] = 0;
|
|
}
|
|
else
|
|
{
|
|
if (!strstr(line, "entry point at"))
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
|
|
/* BUG (preserved for exact matching): January consumes each of
|
|
* these continuation lines without checking whether fgets failed.
|
|
* A corrected build should reject EOF before reading line[0] or
|
|
* tokenizing the buffer. */
|
|
fgets(line, sizeof(line), map_file);
|
|
if (!isspace(line[0]))
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
|
|
fgets(line, sizeof(line), map_file);
|
|
if (!strstr(line, "Static symbols"))
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
|
|
fgets(line, sizeof(line), map_file);
|
|
if (!isspace(line[0]))
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
|
|
fgets(line, sizeof(line), map_file);
|
|
segment = strtok(line, ":");
|
|
if (!segment || *segment!=' ')
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
|
|
token = strtok(NULL, " \t\n\r");
|
|
if (!token)
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
symbol_address = strtoul(token, &end_str, 16);
|
|
|
|
/* BUG (preserved for exact matching): January leaves symbol_name
|
|
* unchanged if the continuation entry omits its name token, then
|
|
* continues parsing. A corrected build should reject that entry. */
|
|
token = strtok(NULL, " \t\n\r");
|
|
if (token)
|
|
{
|
|
strncpy(symbol_name, token, sizeof(symbol_name)-1);
|
|
symbol_name[sizeof(symbol_name)-1] = 0;
|
|
}
|
|
}
|
|
|
|
token = strtok(NULL, " \t\n\r");
|
|
if (!token)
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
rva_base = strtoul(token, &end_str, 16);
|
|
|
|
if (strcmp(symbol_name, "_load_symbol_table")==0)
|
|
{
|
|
stack_walk_globals.fixup = rva_base - (unsigned long)load_symbol_table;
|
|
}
|
|
|
|
/* BUG (preserved for exact matching): January checks only whether
|
|
* strtoul assigned an end pointer, then advances five bytes without
|
|
* validating the conversion or remaining field width. A corrected
|
|
* build should validate both before advancing. */
|
|
if (!end_str)
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
end_str += 5;
|
|
|
|
token = strtok(end_str, " \t\n\r");
|
|
if (!token)
|
|
{
|
|
goto corrupt_map_file;
|
|
}
|
|
strncpy(library_object_file_name, token, sizeof(library_object_file_name)-1);
|
|
library_object_file_name[sizeof(library_object_file_name)-1] = 0;
|
|
|
|
if ((unsigned long)symbol_table->number_of_symbols >= symbols_size)
|
|
{
|
|
struct debug_symbol *new_symbols;
|
|
|
|
symbols_size += DEBUG_SYMBOL_ALLOCATION_COUNT;
|
|
new_symbols = match_realloc(
|
|
"c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c",
|
|
454,
|
|
symbol_table->symbols,
|
|
symbols_size * sizeof(*symbol_table->symbols));
|
|
if (!new_symbols)
|
|
{
|
|
goto allocation_failed;
|
|
}
|
|
symbol_table->symbols = new_symbols;
|
|
}
|
|
|
|
if (string_storage_used + strlen(symbol_name) + 1 + strlen(library_object_file_name) + 1 >= string_storage_size)
|
|
{
|
|
char *new_string_storage;
|
|
|
|
string_storage_size += DEBUG_SYMBOL_STRING_STORAGE_ALLOCATION_SIZE;
|
|
new_string_storage = match_realloc(
|
|
"c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c",
|
|
471,
|
|
symbol_table->string_storage,
|
|
string_storage_size);
|
|
if (!new_string_storage)
|
|
{
|
|
goto allocation_failed;
|
|
}
|
|
symbol_table->string_storage = new_string_storage;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c",
|
|
482,
|
|
string_storage_used + strlen(symbol_name) + 1 + strlen(library_object_file_name) + 1 < string_storage_size);
|
|
}
|
|
|
|
{
|
|
struct debug_symbol *new_symbol = &symbol_table->symbols[symbol_table->number_of_symbols++];
|
|
|
|
new_symbol->address = symbol_address;
|
|
new_symbol->rva_base = rva_base;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c",
|
|
489,
|
|
string_storage_used + strlen(symbol_name) + 1 < string_storage_size);
|
|
strcpy(symbol_table->string_storage + string_storage_used, symbol_name);
|
|
new_symbol->name_string_offset = string_storage_used;
|
|
string_storage_used += strlen(symbol_name) + 1;
|
|
|
|
if (strcmp(last_object_file_name, library_object_file_name)==0)
|
|
{
|
|
new_symbol->library_object_string_offset = previous_library_object_offset;
|
|
}
|
|
else
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\cseries\\stack_walk_windows.c",
|
|
501,
|
|
string_storage_used + strlen(library_object_file_name) + 1 < string_storage_size);
|
|
strcpy(symbol_table->string_storage + string_storage_used, library_object_file_name);
|
|
new_symbol->library_object_string_offset = string_storage_used;
|
|
string_storage_used += strlen(library_object_file_name) + 1;
|
|
previous_library_object_offset = new_symbol->library_object_string_offset;
|
|
strcpy(last_object_file_name, library_object_file_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
goto close_map_file;
|
|
|
|
allocation_failed:
|
|
error(_error_silent, "could not allocate enough memory for map file");
|
|
free_symbol_table(symbol_table);
|
|
goto close_map_file;
|
|
|
|
corrupt_map_file:
|
|
error(_error_silent, "map file appears corrupt");
|
|
free_symbol_table(symbol_table);
|
|
|
|
close_map_file:
|
|
fclose(map_file);
|
|
}
|
|
|
|
finished:
|
|
if (symbol_table->number_of_symbols > 0)
|
|
{
|
|
qsort(
|
|
symbol_table->symbols,
|
|
symbol_table->number_of_symbols,
|
|
sizeof(*symbol_table->symbols),
|
|
symbol_sort_proc);
|
|
|
|
/* BUG (preserved for exact matching): January assumes at least one
|
|
* nonzero RVA while trimming sentinels. A corrected build should
|
|
* stop before number_of_symbols reaches zero. */
|
|
while (symbol_table->symbols[symbol_table->number_of_symbols-1].rva_base==0)
|
|
{
|
|
symbol_table->number_of_symbols--;
|
|
}
|
|
}
|
|
|
|
return symbol_table->number_of_symbols > 0;
|
|
}
|
|
|
|
void stack_walk_initialize(
|
|
void)
|
|
{
|
|
load_symbol_table(
|
|
"d:\\cachebeta.map",
|
|
&stack_walk_globals.symbol_table,
|
|
"Mon Dec 17 12:49:36 2001");
|
|
|
|
if (stack_walk_globals.fixup==NONE)
|
|
{
|
|
stack_walk_globals.fixup = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* ---------- private code */
|
|
|
|
static int symbol_sort_proc(
|
|
const void *elem1,
|
|
const void *elem2)
|
|
{
|
|
const struct debug_symbol *symbol1 = elem1;
|
|
const struct debug_symbol *symbol2 = elem2;
|
|
|
|
/* BUG (preserved for exact matching): January returns 1 when both RVAs
|
|
* are zero, violating comparator antisymmetry. A corrected build should
|
|
* return 0 for two equal zero-RVA sentinel records. */
|
|
if (symbol1->rva_base==0 || symbol1->rva_base > symbol2->rva_base)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if (symbol2->rva_base==0 || symbol1->rva_base < symbol2->rva_base)
|
|
{
|
|
return NONE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static boolean is_valid_ebp(
|
|
void)
|
|
{
|
|
return 0==(walk_up_current_frame & (sizeof(unsigned long) - 1)) && walk_up_current_frame >= (unsigned long)old_ebp;
|
|
}
|
|
|
|
static unsigned long walk_up(
|
|
void)
|
|
{
|
|
unsigned long routine_address = 0;
|
|
|
|
if (walk_up_current_frame)
|
|
{
|
|
#ifdef HALO_ANDROID
|
|
/* an AArch64 frame record: the caller's frame pointer, then the
|
|
return address, 8 bytes each (the upper halves are zero) */
|
|
routine_address = ((unsigned long *)walk_up_current_frame)[2];
|
|
#else
|
|
routine_address = ((unsigned long *)walk_up_current_frame)[1];
|
|
#endif
|
|
walk_up_current_frame = ((unsigned long *)walk_up_current_frame)[0];
|
|
if (!is_valid_ebp())
|
|
{
|
|
walk_up_current_frame = 0;
|
|
}
|
|
|
|
old_ebp = (unsigned long *)walk_up_current_frame;
|
|
}
|
|
|
|
return routine_address;
|
|
}
|
|
|
|
static void initialize_stack_walk(
|
|
CONTEXT *context)
|
|
{
|
|
old_ebp = (unsigned long *)context->Esp;
|
|
walk_up_current_frame = context->Ebp;
|
|
return;
|
|
}
|
|
|
|
static void walk_stack_context(
|
|
unsigned long *routine_addresses,
|
|
unsigned long number_of_levels,
|
|
unsigned long ignore_levels,
|
|
unsigned long *levels_dumped)
|
|
{
|
|
unsigned long level;
|
|
|
|
if (!is_valid_ebp())
|
|
{
|
|
walk_up_current_frame = 0;
|
|
}
|
|
|
|
if (ignore_levels)
|
|
{
|
|
while (--ignore_levels)
|
|
{
|
|
walk_up();
|
|
}
|
|
}
|
|
|
|
for (level = 0; level < number_of_levels; level++)
|
|
{
|
|
routine_addresses[level] = walk_up();
|
|
if (!routine_addresses[level])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
*levels_dumped = level;
|
|
return;
|
|
}
|
|
|
|
static void walk_stack(
|
|
unsigned long *routine_addresses,
|
|
unsigned long number_of_levels,
|
|
unsigned long ignore_levels,
|
|
unsigned long *levels_dumped)
|
|
{
|
|
unsigned long level;
|
|
|
|
walk_up_current_frame = (unsigned long)__builtin_frame_address(0);
|
|
old_ebp = (unsigned long *)walk_up_current_frame;
|
|
|
|
if (!is_valid_ebp())
|
|
{
|
|
walk_up_current_frame = 0;
|
|
}
|
|
|
|
if (ignore_levels)
|
|
{
|
|
while (--ignore_levels)
|
|
{
|
|
walk_up();
|
|
}
|
|
}
|
|
|
|
for (level = 0; level < number_of_levels; level++)
|
|
{
|
|
routine_addresses[level] = walk_up();
|
|
if (!routine_addresses[level])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
*levels_dumped = level;
|
|
return;
|
|
}
|