📄 stabs.c
字号:
/* ar<typeinfo_nodef>;<int>;<int>;<typeinfo> */
PTS_ABORTIF(ptd, *ptd->ptr++ != 'r');
/* FIXME: range type is lost, always assume int */
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &rdt) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &lo) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &hi) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &rdt) == -1);
*adt = &symt_new_array(ptd->module, lo, hi, rdt)->symt;
return 0;
}
static int stabs_pts_read_type_def(struct ParseTypedefData* ptd, const char* typename,
struct symt** ret_dt)
{
int idx;
long sz = -1;
struct symt* new_dt = NULL; /* newly created data type */
struct symt* ref_dt; /* referenced data type (pointer...) */
long filenr1, subnr1, tmp;
/* things are a bit complicated because of the way the typedefs are stored inside
* the file, because addresses can change when realloc is done, so we must call
* over and over stabs_find_ref() to keep the correct values around
*/
PTS_ABORTIF(ptd, stabs_pts_read_type_reference(ptd, &filenr1, &subnr1) == -1);
while (*ptd->ptr == '=')
{
ptd->ptr++;
PTS_ABORTIF(ptd, new_dt != btNoType);
/* first handle attribute if any */
switch (*ptd->ptr)
{
case '@':
if (*++ptd->ptr == 's')
{
ptd->ptr++;
if (stabs_pts_read_number(ptd, &sz) == -1)
{
ERR("Not an attribute... NIY\n");
ptd->ptr -= 2;
return -1;
}
PTS_ABORTIF(ptd, *ptd->ptr++ != ';');
}
break;
}
/* then the real definitions */
switch (*ptd->ptr++)
{
case '*':
case '&':
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref_dt) == -1);
new_dt = &symt_new_pointer(ptd->module, ref_dt)->symt;
break;
case 'k': /* 'const' modifier */
case 'B': /* 'volatile' modifier */
/* just kinda ignore the modifier, I guess -gmt */
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, typename, &new_dt) == -1);
break;
case '(':
ptd->ptr--;
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, typename, &new_dt) == -1);
break;
case 'a':
PTS_ABORTIF(ptd, stabs_pts_read_array(ptd, &new_dt) == -1);
break;
case 'r':
PTS_ABORTIF(ptd, stabs_pts_read_range(ptd, typename, &new_dt) == -1);
assert(!*stabs_find_ref(filenr1, subnr1));
*stabs_find_ref(filenr1, subnr1) = new_dt;
break;
case 'f':
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref_dt) == -1);
new_dt = &symt_new_function_signature(ptd->module, ref_dt)->symt;
break;
case 'e':
new_dt = &symt_new_enum(ptd->module, typename)->symt;
PTS_ABORTIF(ptd, stabs_pts_read_enum(ptd, (struct symt_enum*)new_dt) == -1);
break;
case 's':
case 'u':
{
struct symt_udt* udt;
enum UdtKind kind = (ptd->ptr[-1] == 's') ? UdtStruct : UdtUnion;
/* udt can have been already defined in a forward definition */
udt = (struct symt_udt*)*stabs_find_ref(filenr1, subnr1);
if (!udt)
{
udt = symt_new_udt(ptd->module, typename, 0, kind);
/* we need to set it here, because a struct can hold a pointer
* to itself
*/
new_dt = *stabs_find_ref(filenr1, subnr1) = &udt->symt;
}
else
{
if (udt->symt.tag != SymTagUDT)
{
ERR("Forward declaration (%p/%s) is not an aggregate (%u)\n",
udt, symt_get_name(&udt->symt), udt->symt.tag);
return -1;
}
if (strcmp(udt->hash_elt.name, typename))
ERR("Forward declaration name mismatch %s <> %s\n",
udt->hash_elt.name, typename);
/* should check typename is the same too */
new_dt = &udt->symt;
}
PTS_ABORTIF(ptd, stabs_pts_read_aggregate(ptd, udt) == -1);
}
break;
case 'x':
idx = ptd->idx;
tmp = *ptd->ptr++;
PTS_ABORTIF(ptd, stabs_pts_read_id(ptd) == -1);
switch (tmp)
{
case 'e':
new_dt = &symt_new_enum(ptd->module, ptd->buf + idx)->symt;
break;
case 's':
new_dt = &symt_new_udt(ptd->module, ptd->buf + idx, 0, UdtStruct)->symt;
break;
case 'u':
new_dt = &symt_new_udt(ptd->module, ptd->buf + idx, 0, UdtUnion)->symt;
break;
default:
return -1;
}
ptd->idx = idx;
break;
case '-':
{
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &tmp) == -1);
PTS_ABORTIF(ptd, stabs_get_basic(ptd, tmp, &new_dt) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';');
}
break;
case '#':
if (*ptd->ptr == '#')
{
ptd->ptr++;
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref_dt) == -1);
new_dt = &symt_new_function_signature(ptd->module, ref_dt)->symt;
}
else
{
struct symt* cls_dt;
struct symt* pmt_dt;
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &cls_dt) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ',');
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &ref_dt) == -1);
new_dt = &symt_new_function_signature(ptd->module, ref_dt)->symt;
while (*ptd->ptr == ',')
{
ptd->ptr++;
PTS_ABORTIF(ptd, stabs_pts_read_type_def(ptd, NULL, &pmt_dt) == -1);
}
}
break;
case 'R':
{
long type, len, unk;
int basic;
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &type) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &len) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
PTS_ABORTIF(ptd, stabs_pts_read_number(ptd, &unk) == -1);
PTS_ABORTIF(ptd, *ptd->ptr++ != ';'); /* ';' */
switch (type) /* see stabs_get_basic for the details */
{
case 1: basic = 12; break;
case 2: basic = 13; break;
case 3: basic = 25; break;
case 4: basic = 26; break;
case 5: basic = 35; break;
case 6: basic = 14; break;
default: PTS_ABORTIF(ptd, 1);
}
PTS_ABORTIF(ptd, stabs_get_basic(ptd, basic, &new_dt) == -1);
}
break;
default:
ERR("Unknown type '%c'\n", ptd->ptr[-1]);
return -1;
}
}
if (!new_dt)
{
/* is it a forward declaration that has been filled ? */
new_dt = *stabs_find_ref(filenr1, subnr1);
/* if not, this should be void (which is defined as a ref to itself, but we
* don't correctly catch it)
*/
if (!new_dt && typename)
{
new_dt = &symt_new_basic(ptd->module, btVoid, typename, 0)->symt;
PTS_ABORTIF(ptd, strcmp(typename, "void"));
}
}
*stabs_find_ref(filenr1, subnr1) = *ret_dt = new_dt;
TRACE("Adding (%ld,%ld) %s\n", filenr1, subnr1, typename);
return 0;
}
static int stabs_parse_typedef(struct module* module, const char* ptr,
const char* typename)
{
struct ParseTypedefData ptd;
struct symt* dt;
int ret = -1;
/* check for already existing definition */
TRACE("%s\n", debugstr_a(ptr));
ptd.module = module;
ptd.idx = 0;
#ifdef PTS_DEBUG
ptd.err_idx = 0;
#endif
for (ptd.ptr = ptr - 1; ;)
{
ptd.ptr = strchr(ptd.ptr + 1, ':');
if (ptd.ptr == NULL || *++ptd.ptr != ':') break;
}
if (ptd.ptr)
{
if (*ptd.ptr != '(') ptd.ptr++;
/* most of type definitions take one char, except Tt */
if (*ptd.ptr != '(') ptd.ptr++;
ret = stabs_pts_read_type_def(&ptd, typename, &dt);
}
if (ret == -1 || *ptd.ptr)
{
#ifdef PTS_DEBUG
int i;
TRACE("Failure on %s\n", debugstr_a(ptr));
if (ret == -1)
{
for (i = 0; i < ptd.err_idx; i++)
{
TRACE("[%d]: line %d => %s\n",
i, ptd.errors[i].line, debugstr_a(ptd.errors[i].ptr));
}
}
else
TRACE("[0]: => %s\n", debugstr_a(ptd.ptr));
#else
ERR("Failure on %s at %s\n", debugstr_a(ptr), debugstr_a(ptd.ptr));
#endif
return FALSE;
}
return TRUE;
}
static struct symt* stabs_parse_type(const char* stab)
{
const char* c = stab - 1;
/*
* Look through the stab definition, and figure out what struct symt
* this represents. If we have something we know about, assign the
* type.
* According to "The \"stabs\" debug format" (Rev 2.130) the name may be
* a C++ name and contain double colons e.g. foo::bar::baz:t5=*6.
*/
do
{
if ((c = strchr(c + 1, ':')) == NULL) return NULL;
} while (*++c == ':');
/*
* The next characters say more about the type (i.e. data, function, etc)
* of symbol. Skip them. (C++ for example may have Tt).
* Actually this is a very weak description; I think Tt is the only
* multiple combination we should see.
*/
while (*c && *c != '(' && !isdigit(*c))
c++;
/*
* The next is either an integer or a (integer,integer).
* The stabs_read_type_enum() takes care that stab_types is large enough.
*/
return *stabs_read_type_enum(&c);
}
struct pending_loc_var
{
char name[256];
struct symt* type;
unsigned offset;
unsigned regno;
};
/******************************************************************
* stabs_finalize_function
*
* Ends function creation: mainly:
* - cleans up line number information
* - tries to set up a debug-start tag (FIXME: heuristic to be enhanced)
* - for stabs which have abolute address in them, initializes the size of the
* function (assuming that current function ends where next function starts)
*/
static void stabs_finalize_function(struct module* module, struct symt_function* func,
unsigned long end)
{
IMAGEHLP_LINE il;
if (!func) return;
symt_normalize_function(module, func);
/* To define the debug-start of the function, we use the second line number.
* Not 100% bullet proof, but better than nothing
*/
if (symt_fill_func_line_info(module, func, func->address, &il) &&
symt_get_func_line_next(module, &il))
{
symt_add_function_point(module, func, SymTagFuncDebugStart,
il.Address - func->address, NULL);
}
if (end) func->size = end - func->address;
}
BOOL stabs_parse(struct module* module, unsigned long load_offset,
const void* pv_stab_ptr, int stablen,
const char* strs, int strtablen)
{
struct symt_function* curr_func = NULL;
struct symt_block* block = NULL;
struct symt_compiland* compiland = NULL;
char currpath[PATH_MAX]; /* path to current file */
char srcpath[PATH_MAX]; /* path to directory source file is in */
int i, j;
int nstab;
const char* ptr;
char* stabbuff;
unsigned int stabbufflen;
const struct stab_nlist* stab_ptr = pv_stab_ptr;
const char* strs_end;
int strtabinc;
char symname[4096];
unsigned incl[32];
int incl_stk = -1;
int source_idx = -1;
struct pending_loc_var* pending_vars = NULL;
unsigned num_pending_vars = 0;
unsigned num_allocated_pending_vars = 0;
BOOL ret = TRUE;
nstab = stablen / sizeof(struct stab_nlist);
strs_end = strs + strtablen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -