📄 stabs.c
字号:
memset(srcpath, 0, sizeof(srcpath));
memset(stabs_basic, 0, sizeof(stabs_basic));
/*
* Allocate a buffer into which we can build stab strings for cases
* where the stab is continued over multiple lines.
*/
stabbufflen = 65536;
stabbuff = HeapAlloc(GetProcessHeap(), 0, stabbufflen);
strtabinc = 0;
stabbuff[0] = '\0';
for (i = 0; i < nstab; i++, stab_ptr++)
{
ptr = strs + stab_ptr->n_un.n_strx;
if ((ptr > strs_end) || (ptr + strlen(ptr) > strs_end))
{
WARN("Bad stabs string %p\n", ptr);
continue;
}
if (ptr[strlen(ptr) - 1] == '\\')
{
/*
* Indicates continuation. Append this to the buffer, and go onto the
* next record. Repeat the process until we find a stab without the
* '/' character, as this indicates we have the whole thing.
*/
unsigned len = strlen(ptr);
if (strlen(stabbuff) + len > stabbufflen)
{
stabbufflen += 65536;
stabbuff = HeapReAlloc(GetProcessHeap(), 0, stabbuff, stabbufflen);
}
strncat(stabbuff, ptr, len - 1);
continue;
}
else if (stabbuff[0] != '\0')
{
strcat(stabbuff, ptr);
ptr = stabbuff;
}
/* only symbol entries contain a typedef */
switch (stab_ptr->n_type)
{
case N_GSYM:
case N_LCSYM:
case N_STSYM:
case N_RSYM:
case N_LSYM:
case N_ROSYM:
if (strchr(ptr, '=') != NULL)
{
/*
* The stabs aren't in writable memory, so copy it over so we are
* sure we can scribble on it.
*/
if (ptr != stabbuff)
{
strcpy(stabbuff, ptr);
ptr = stabbuff;
}
stab_strcpy(symname, sizeof(symname), ptr);
if (!stabs_parse_typedef(module, ptr, symname))
{
/* skip this definition */
stabbuff[0] = '\0';
continue;
}
}
}
#if 0
const char* defs[] = {"","","","", /* 00 */
"","","","", /* 08 */
"","","","", /* 10 */
"","","","", /* 18 */
"gsym","","fun","stsym", /* 20 */
"lcsym","main","rosym","", /* 28 */
"","","","", /* 30 */
"","","opt","", /* 38 */
"rsym","","sline","", /* 40 */
"","","","", /* 48 */
"","","","", /* 50 */
"","","","", /* 58 */
"","","so","", /* 60 */
"","","","", /* 68 */
"","","","", /* 70 */
"","","","", /* 78 */
"lsym","bincl","sol","", /* 80 */
"","","","", /* 88 */
"","","","", /* 90 */
"","","","", /* 98 */
"psym","eincl","","", /* a0 */
"","","","", /* a8 */
"","","","", /* b0 */
"","","","", /* b8 */
"lbrac","excl","","", /* c0 */
"","","","", /* c8 */
"","","","", /* d0 */
"","","","", /* d8 */
"rbrac","","","", /* e0 */
};
FIXME("Got %s<%u> %u/%lu (%s)\n",
defs[stab_ptr->n_type / 2], stab_ptr->n_type, stab_ptr->n_desc, stab_ptr->n_value, debugstr_a(ptr));
#endif
switch (stab_ptr->n_type)
{
case N_GSYM:
/*
* These are useless with ELF. They have no value, and you have to
* read the normal symbol table to get the address. Thus we
* ignore them, and when we process the normal symbol table
* we should do the right thing.
*
* With a.out or mingw, they actually do make some amount of sense.
*/
stab_strcpy(symname, sizeof(symname), ptr);
symt_new_global_variable(module, compiland, symname, TRUE /* FIXME */,
load_offset + stab_ptr->n_value, 0,
stabs_parse_type(ptr));
break;
case N_LCSYM:
case N_STSYM:
/* These are static symbols and BSS symbols. */
stab_strcpy(symname, sizeof(symname), ptr);
symt_new_global_variable(module, compiland, symname, TRUE /* FIXME */,
load_offset + stab_ptr->n_value, 0,
stabs_parse_type(ptr));
break;
case N_LBRAC:
block = symt_open_func_block(module, curr_func, block,
stab_ptr->n_value, 0);
for (j = 0; j < num_pending_vars; j++)
{
symt_add_func_local(module, curr_func, pending_vars[j].regno,
pending_vars[j].offset,
block, pending_vars[j].type, pending_vars[j].name);
}
num_pending_vars = 0;
break;
case N_RBRAC:
block = symt_close_func_block(module, curr_func, block,
stab_ptr->n_value);
break;
case N_PSYM:
/* These are function parameters. */
if (curr_func != NULL)
{
struct symt* param_type = stabs_parse_type(ptr);
stab_strcpy(symname, sizeof(symname), ptr);
symt_add_func_local(module, curr_func, 0, stab_ptr->n_value,
NULL, param_type, symname);
symt_add_function_signature_parameter(module,
(struct symt_function_signature*)curr_func->type,
param_type);
}
break;
case N_RSYM:
/* These are registers (as local variables) */
if (curr_func != NULL)
{
unsigned reg;
if (num_pending_vars == num_allocated_pending_vars)
{
num_allocated_pending_vars += 8;
if (!pending_vars)
pending_vars = HeapAlloc(GetProcessHeap(), 0,
num_allocated_pending_vars * sizeof(pending_vars[0]));
else
pending_vars = HeapReAlloc(GetProcessHeap(), 0, pending_vars,
num_allocated_pending_vars * sizeof(pending_vars[0]));
}
switch (stab_ptr->n_value)
{
case 0: reg = CV_REG_EAX; break;
case 1: reg = CV_REG_ECX; break;
case 2: reg = CV_REG_EDX; break;
case 3: reg = CV_REG_EBX; break;
case 4: reg = CV_REG_ESP; break;
case 5: reg = CV_REG_EBP; break;
case 6: reg = CV_REG_ESI; break;
case 7: reg = CV_REG_EDI; break;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19: reg = CV_REG_ST0 + stab_ptr->n_value - 12; break;
default:
FIXME("Unknown register value (%lu)\n", stab_ptr->n_value);
reg = CV_REG_NONE;
break;
}
stab_strcpy(pending_vars[num_pending_vars].name,
sizeof(pending_vars[num_pending_vars].name), ptr);
pending_vars[num_pending_vars].type = stabs_parse_type(ptr);
pending_vars[num_pending_vars].offset = 0;
pending_vars[num_pending_vars].regno = reg;
num_pending_vars++;
}
break;
case N_LSYM:
/* These are local variables */
if (curr_func != NULL)
{
if (num_pending_vars == num_allocated_pending_vars)
{
num_allocated_pending_vars += 8;
if (!pending_vars)
pending_vars = HeapAlloc(GetProcessHeap(), 0,
num_allocated_pending_vars * sizeof(pending_vars[0]));
else
pending_vars = HeapReAlloc(GetProcessHeap(), 0, pending_vars,
num_allocated_pending_vars * sizeof(pending_vars[0]));
}
stab_strcpy(pending_vars[num_pending_vars].name,
sizeof(pending_vars[num_pending_vars].name), ptr);
pending_vars[num_pending_vars].type = stabs_parse_type(ptr);
pending_vars[num_pending_vars].offset = stab_ptr->n_value;
pending_vars[num_pending_vars].regno = 0;
num_pending_vars++;
}
break;
case N_SLINE:
/*
* This is a line number. These are always relative to the start
* of the function (N_FUN), and this makes the lookup easier.
*/
if (curr_func != NULL)
{
assert(source_idx >= 0);
symt_add_func_line(module, curr_func, source_idx,
stab_ptr->n_desc, stab_ptr->n_value);
}
break;
case N_FUN:
/* First, clean up the previous function we were working on. */
stabs_finalize_function(module, curr_func,
stab_ptr->n_value ? load_offset + stab_ptr->n_value : 0);
/*
* For now, just declare the various functions. Later
* on, we will add the line number information and the
* local symbols.
*/
/*
* Copy the string to a temp buffer so we
* can kill everything after the ':'. We do
* it this way because otherwise we end up dirtying
* all of the pages related to the stabs, and that
* sucks up swap space like crazy.
*/
stab_strcpy(symname, sizeof(symname), ptr);
if (*symname)
{
struct symt_function_signature* func_type;
func_type = symt_new_function_signature(module,
stabs_parse_type(ptr));
curr_func = symt_new_function(module, compiland, symname,
load_offset + stab_ptr->n_value, 0,
&func_type->symt);
}
else
{
/* some GCC seem to use a N_FUN "" to mark the end of a function */
curr_func = NULL;
}
break;
case N_SO:
/*
* This indicates a new source file. Append the records
* together, to build the correct path name.
*/
if (*ptr == '\0') /* end of N_SO file */
{
/* Nuke old path. */
srcpath[0] = '\0';
stabs_finalize_function(module, curr_func,
stab_ptr->n_value ? load_offset + stab_ptr->n_value : 0);
curr_func = NULL;
source_idx = -1;
incl_stk = -1;
assert(block == NULL);
compiland = NULL;
}
else
{
int len = strlen(ptr);
if (ptr[len-1] != '/')
{
strcpy(currpath, srcpath);
strcat(currpath, ptr);
stabs_reset_includes();
compiland = symt_new_compiland(module, currpath);
source_idx = source_new(module, currpath);
}
else
strcpy(srcpath, ptr);
}
break;
case N_SOL:
if (*ptr != '/')
{
strcpy(currpath, srcpath);
strcat(currpath, ptr);
}
else
strcpy(currpath, ptr);
source_idx = source_new(module, currpath);
break;
case N_UNDF:
strs += strtabinc;
strtabinc = stab_ptr->n_value;
/* I'm not sure this is needed, so trace it before we obsolete it */
if (curr_func) FIXME("UNDF: curr_func %s\n", curr_func->hash_elt.name);
stabs_finalize_function(module, curr_func, 0); /* FIXME */
curr_func = NULL;
break;
case N_OPT:
/* Ignore this. We don't care what it points to. */
break;
case N_BINCL:
stabs_add_include(stabs_new_include(ptr, stab_ptr->n_value));
assert(incl_stk < (int)(sizeof(incl) / sizeof(incl[0])) - 1);
incl[++incl_stk] = source_idx;
source_idx = source_new(module, ptr);
break;
case N_EINCL:
assert(incl_stk >= 0);
source_idx = incl[incl_stk--];
break;
case N_EXCL:
if (stabs_add_include(stabs_find_include(ptr, stab_ptr->n_value)) < 0)
{
ERR("Excluded header not found (%s,%ld)\n", ptr, stab_ptr->n_value);
module_reset_debug_info(module);
ret = FALSE;
goto done;
}
break;
case N_MAIN:
/* Always ignore these. GCC doesn't even generate them. */
break;
default:
ERR("Unknown stab type 0x%02x\n", stab_ptr->n_type);
break;
}
stabbuff[0] = '\0';
TRACE("0x%02x %lx %s\n",
stab_ptr->n_type, stab_ptr->n_value, debugstr_a(strs + stab_ptr->n_un.n_strx));
}
module->module.SymType = SymDia;
done:
HeapFree(GetProcessHeap(), 0, stabbuff);
stabs_free_includes();
if (pending_vars) HeapFree(GetProcessHeap(), 0, pending_vars);
return ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -