📄 stabs.c
字号:
/*
* File stabs.c - read stabs information from the modules
*
* Copyright (C) 1996, Eric Youngdale.
* 1999-2004, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Maintenance Information
* -----------------------
*
* For documentation on the stabs format see for example
* The "stabs" debug format
* by Julia Menapace, Jim Kingdon, David Mackenzie
* of Cygnus Support
* available (hopefully) from http:\\sources.redhat.com\gdb\onlinedocs
*/
#include "config.h"
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdio.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#include <assert.h>
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "dbghelp_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_stabs);
#ifndef N_UNDF
#define N_UNDF 0x00
#endif
#define N_GSYM 0x20
#define N_FUN 0x24
#define N_STSYM 0x26
#define N_LCSYM 0x28
#define N_MAIN 0x2a
#define N_ROSYM 0x2c
#define N_OPT 0x3c
#define N_RSYM 0x40
#define N_SLINE 0x44
#define N_SO 0x64
#define N_LSYM 0x80
#define N_BINCL 0x82
#define N_SOL 0x84
#define N_PSYM 0xa0
#define N_EINCL 0xa2
#define N_LBRAC 0xc0
#define N_EXCL 0xc2
#define N_RBRAC 0xe0
struct stab_nlist
{
union
{
char* n_name;
struct stab_nlist* n_next;
long n_strx;
} n_un;
unsigned char n_type;
char n_other;
short n_desc;
unsigned long n_value;
};
static void stab_strcpy(char* dest, int sz, const char* source)
{
/*
* A strcpy routine that stops when we hit the ':' character.
* Faster than copying the whole thing, and then nuking the
* ':'.
*/
while (*source != '\0' && *source != ':' && sz-- > 0)
*dest++ = *source++;
*dest-- = '\0';
/* GCC seems to emit, in some cases, a .<digit>+ suffix.
* This is used for static variable inside functions, so
* that we can have several such variables with same name in
* the same compilation unit
* We simply ignore that suffix when present (we also get rid
* of it in ELF symtab parsing)
*/
if (isdigit(*dest))
{
while (isdigit(*dest)) dest--;
if (*dest == '.') *dest = '\0';
}
assert(sz > 0);
}
typedef struct
{
char* name;
unsigned long value;
struct symt** vector;
int nrofentries;
} include_def;
#define MAX_INCLUDES 5120
static include_def* include_defs = NULL;
static int num_include_def = 0;
static int num_alloc_include_def = 0;
static int cu_include_stack[MAX_INCLUDES];
static int cu_include_stk_idx = 0;
static struct symt** cu_vector = NULL;
static int cu_nrofentries = 0;
static struct symt_basic* stabs_basic[36];
static int stabs_new_include(const char* file, unsigned long val)
{
if (num_include_def == num_alloc_include_def)
{
num_alloc_include_def += 256;
if (!include_defs)
include_defs = HeapAlloc(GetProcessHeap(), 0,
sizeof(include_defs[0]) * num_alloc_include_def);
else
include_defs = HeapReAlloc(GetProcessHeap(), 0, include_defs,
sizeof(include_defs[0]) * num_alloc_include_def);
memset(include_defs + num_include_def, 0, sizeof(include_defs[0]) * 256);
}
include_defs[num_include_def].name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(file) + 1), file);
include_defs[num_include_def].value = val;
include_defs[num_include_def].vector = NULL;
include_defs[num_include_def].nrofentries = 0;
return num_include_def++;
}
static int stabs_find_include(const char* file, unsigned long val)
{
int i;
for (i = 0; i < num_include_def; i++)
{
if (val == include_defs[i].value &&
strcmp(file, include_defs[i].name) == 0)
return i;
}
return -1;
}
static int stabs_add_include(int idx)
{
if (idx < 0) return -1;
cu_include_stk_idx++;
/* if this happens, just bump MAX_INCLUDES */
/* we could also handle this as another dynarray */
assert(cu_include_stk_idx < MAX_INCLUDES);
cu_include_stack[cu_include_stk_idx] = idx;
return cu_include_stk_idx;
}
static void stabs_reset_includes(void)
{
/*
* The struct symt:s that we would need to use are reset when
* we start a new file. (at least the ones in filenr == 0)
*/
cu_include_stk_idx = 0;/* keep 0 as index for the .c file itself */
memset(cu_vector, 0, sizeof(cu_vector[0]) * cu_nrofentries);
}
static void stabs_free_includes(void)
{
int i;
stabs_reset_includes();
for (i = 0; i < num_include_def; i++)
{
HeapFree(GetProcessHeap(), 0, include_defs[i].name);
HeapFree(GetProcessHeap(), 0, include_defs[i].vector);
}
HeapFree(GetProcessHeap(), 0, include_defs);
include_defs = NULL;
num_include_def = 0;
num_alloc_include_def = 0;
HeapFree(GetProcessHeap(), 0, cu_vector);
cu_vector = NULL;
cu_nrofentries = 0;
}
static struct symt** stabs_find_ref(long filenr, long subnr)
{
struct symt** ret;
/* FIXME: I could perhaps create a dummy include_def for each compilation
* unit which would allow not to handle those two cases separately
*/
if (filenr == 0)
{
if (cu_nrofentries <= subnr)
{
if (!cu_vector)
cu_vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(cu_vector[0]) * (subnr+1));
else
cu_vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
cu_vector, sizeof(cu_vector[0]) * (subnr+1));
cu_nrofentries = subnr + 1;
}
ret = &cu_vector[subnr];
}
else
{
include_def* idef;
assert(filenr <= cu_include_stk_idx);
idef = &include_defs[cu_include_stack[filenr]];
if (idef->nrofentries <= subnr)
{
if (!idef->vector)
idef->vector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(idef->vector[0]) * (subnr+1));
else
idef->vector = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
idef->vector, sizeof(idef->vector[0]) * (subnr+1));
idef->nrofentries = subnr + 1;
}
ret = &idef->vector[subnr];
}
TRACE("(%ld,%ld) => %p (%p)\n", filenr, subnr, ret, *ret);
return ret;
}
static struct symt** stabs_read_type_enum(const char** x)
{
long filenr, subnr;
if (**x == '(')
{
(*x)++; /* '(' */
filenr = strtol(*x, (char**)x, 10); /* <int> */
(*x)++; /* ',' */
subnr = strtol(*x, (char**)x, 10); /* <int> */
(*x)++; /* ')' */
}
else
{
filenr = 0;
subnr = strtol(*x, (char**)x, 10); /* <int> */
}
return stabs_find_ref(filenr, subnr);
}
#define PTS_DEBUG
struct ParseTypedefData
{
const char* ptr;
char buf[1024];
int idx;
struct module* module;
#ifdef PTS_DEBUG
struct PTS_Error
{
const char* ptr;
unsigned line;
} errors[16];
int err_idx;
#endif
};
#ifdef PTS_DEBUG
static void stabs_pts_push(struct ParseTypedefData* ptd, unsigned line)
{
assert(ptd->err_idx < sizeof(ptd->errors) / sizeof(ptd->errors[0]));
ptd->errors[ptd->err_idx].line = line;
ptd->errors[ptd->err_idx].ptr = ptd->ptr;
ptd->err_idx++;
}
#define PTS_ABORTIF(ptd, t) do { if (t) { stabs_pts_push((ptd), __LINE__); return -1;} } while (0)
#else
#define PTS_ABORTIF(ptd, t) do { if (t) return -1; } while (0)
#endif
static int stabs_get_basic(struct ParseTypedefData* ptd, unsigned basic, struct symt** symt)
{
PTS_ABORTIF(ptd, basic >= sizeof(stabs_basic) / sizeof(stabs_basic[0]));
if (!stabs_basic[basic])
{
switch (basic)
{
case 1: stabs_basic[basic] = symt_new_basic(ptd->module, btInt, "int", 4); break;
case 2: stabs_basic[basic] = symt_new_basic(ptd->module, btChar, "char", 1); break;
case 3: stabs_basic[basic] = symt_new_basic(ptd->module, btInt, "short int", 2); break;
case 4: stabs_basic[basic] = symt_new_basic(ptd->module, btInt, "long int", 4); break;
case 5: stabs_basic[basic] = symt_new_basic(ptd->module, btUInt, "unsigned char", 1); break;
case 6: stabs_basic[basic] = symt_new_basic(ptd->module, btInt, "signed char", 1); break;
case 7: stabs_basic[basic] = symt_new_basic(ptd->module, btUInt, "unsigned short int", 2); break;
case 8: stabs_basic[basic] = symt_new_basic(ptd->module, btUInt, "unsigned int", 4); break;
case 9: stabs_basic[basic] = symt_new_basic(ptd->module, btUInt, "unsigned", 2); break;
case 10: stabs_basic[basic] = symt_new_basic(ptd->module, btUInt, "unsigned long int", 2); break;
case 11: stabs_basic[basic] = symt_new_basic(ptd->module, btVoid, "void", 0); break;
case 12: stabs_basic[basic] = symt_new_basic(ptd->module, btFloat, "float", 4); break;
case 13: stabs_basic[basic] = symt_new_basic(ptd->module, btFloat, "double", 8); break;
case 14: stabs_basic[basic] = symt_new_basic(ptd->module, btFloat, "long double", 12); break;
case 15: stabs_basic[basic] = symt_new_basic(ptd->module, btInt, "integer", 4); break;
case 16: stabs_basic[basic] = symt_new_basic(ptd->module, btBool, "bool", 1); break;
/* case 17: short real */
/* case 18: real */
case 25: stabs_basic[basic] = symt_new_basic(ptd->module, btComplex, "float complex", 8); break;
case 26: stabs_basic[basic] = symt_new_basic(ptd->module, btComplex, "double complex", 16); break;
case 30: stabs_basic[basic] = symt_new_basic(ptd->module, btWChar, "wchar_t", 2); break;
case 31: stabs_basic[basic] = symt_new_basic(ptd->module, btInt, "long long int", 8); break;
case 32: stabs_basic[basic] = symt_new_basic(ptd->module, btUInt, "long long unsigned", 8); break;
/* starting at 35 are wine extensions (especially for R implementation) */
case 35: stabs_basic[basic] = symt_new_basic(ptd->module, btComplex, "long double complex", 24); break;
default: PTS_ABORTIF(ptd, 1);
}
}
*symt = &stabs_basic[basic]->symt;
return 0;
}
static int stabs_pts_read_type_def(struct ParseTypedefData* ptd,
const char* typename, struct symt** dt);
static int stabs_pts_read_id(struct ParseTypedefData* ptd)
{
const char* first = ptd->ptr;
unsigned int len;
PTS_ABORTIF(ptd, (ptd->ptr = strchr(ptd->ptr, ':')) == NULL);
len = ptd->ptr - first;
PTS_ABORTIF(ptd, len >= sizeof(ptd->buf) - ptd->idx);
memcpy(ptd->buf + ptd->idx, first, len);
ptd->buf[ptd->idx + len] = '\0';
ptd->idx += len + 1;
ptd->ptr++; /* ':' */
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -