Memory consumption optimization while loading ELF debug info:
- don't map twice an ELF file for symbol lookup (in non deferred mode) - no longer entirely map an ELF file into memory, but only the sections we need. Added support for loading ELF modules thru SymLoadModule in a non life process. Factorisation of code for ELF module handling. Fixes to ELF symbol loading - drops symbols from symtab which are neither funcs nor global variables - fixes some incorrect size computation for latest GCC versions. Several cleanups and fixes.
This commit is contained in:
parent
13abcb0a26
commit
01aa71371b
|
@ -37,6 +37,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
|||
* but those values are not directly usable from a debugger (that's why, I
|
||||
* assume, that we have also to define constants for enum values, as
|
||||
* Codeview does BTW.
|
||||
* + SymGetType(TI_GET_LENGTH) takes a ULONG64 (yurk, ugly)
|
||||
* - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
|
||||
* functions, and even across function blocks...). Basically, for *Next* to work
|
||||
* it requires an address after the prolog of the func (the base address of the
|
||||
* func doesn't work)
|
||||
* - most options (dbghelp_options) are not used (loading lines...)
|
||||
* - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
|
||||
* we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
|
||||
|
@ -45,7 +50,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
|
|||
* - msc:
|
||||
* + we should add parameters' types to the function's signature
|
||||
* while processing a function's parameters
|
||||
* + get rid of MSC reading FIXME:s (lots of types are not defined)
|
||||
* + add support for function-less labels (as MSC seems to define them)
|
||||
* + C++ management
|
||||
* - stabs:
|
||||
* + when, in a same module, the same definition is used in several compilation
|
||||
|
@ -132,25 +137,10 @@ BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath,
|
|||
* SymInitialize helper: loads in dbghelp all known (and loaded modules)
|
||||
* this assumes that hProcess is a handle on a valid process
|
||||
*/
|
||||
static BOOL process_invade(HANDLE hProcess)
|
||||
static BOOL WINAPI process_invade_cb(char* name, DWORD base, DWORD size, void* user)
|
||||
{
|
||||
HMODULE hMods[256];
|
||||
char img[256];
|
||||
DWORD i, sz;
|
||||
MODULEINFO mi;
|
||||
|
||||
if (!EnumProcessModules(hProcess, hMods, sizeof(hMods), &sz))
|
||||
return FALSE; /* FIXME should grow hMods */
|
||||
|
||||
for (i = 0; i < sz / sizeof(HMODULE); i++)
|
||||
{
|
||||
if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
|
||||
!GetModuleFileNameExA(hProcess, hMods[i], img, sizeof(img)) ||
|
||||
!SymLoadModule(hProcess, 0, img, NULL, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return sz != 0;
|
||||
SymLoadModule((HANDLE)user, 0, name, NULL, base, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -235,9 +225,10 @@ BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProc
|
|||
SymCleanup(hProcess);
|
||||
return FALSE;
|
||||
}
|
||||
process_invade(hProcess);
|
||||
EnumerateLoadedModules(hProcess, process_invade_cb, (void*)hProcess);
|
||||
elf_synchronize_module_list(pcs);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -293,9 +293,12 @@ extern struct process* process_find_by_handle(HANDLE hProcess);
|
|||
extern HANDLE hMsvcrt;
|
||||
|
||||
/* elf_module.c */
|
||||
extern BOOL elf_load_debug_info(struct module* module);
|
||||
typedef BOOL (*elf_enum_modules_cb)(const char*, unsigned long addr, void* user);
|
||||
extern BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb, void*);
|
||||
struct elf_file_map;
|
||||
extern BOOL elf_load_debug_info(struct module* module, struct elf_file_map* fmap);
|
||||
extern struct module*
|
||||
elf_load_module(struct process* pcs, const char* name);
|
||||
elf_load_module(struct process* pcs, const char* name, unsigned long);
|
||||
extern BOOL elf_read_wine_loader_dbg_info(struct process* pcs);
|
||||
extern BOOL elf_synchronize_module_list(struct process* pcs);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -48,6 +48,10 @@ static void module_fill_module(const char* in, char* out, unsigned size)
|
|||
if (len > 4 &&
|
||||
(!strcasecmp(&out[len - 4], ".dll") || !strcasecmp(&out[len - 4], ".exe")))
|
||||
out[len - 4] = '\0';
|
||||
else if (((len > 12 && out[len - 13] == '/') || len == 12) &&
|
||||
(!strcasecmp(out + len - 12, "wine-pthread") ||
|
||||
!strcasecmp(out + len - 12, "wine-kthread")))
|
||||
strcpy(out, "<wine-loader>");
|
||||
else
|
||||
{
|
||||
if (len > 7 &&
|
||||
|
@ -134,14 +138,17 @@ struct module* module_find_by_name(const struct process* pcs,
|
|||
}
|
||||
else
|
||||
{
|
||||
char modname[MAX_PATH];
|
||||
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (type == module->type && !strcasecmp(name, module->module.LoadedImageName))
|
||||
return module;
|
||||
}
|
||||
module_fill_module(name, modname, sizeof(modname));
|
||||
for (module = pcs->lmodules; module; module = module->next)
|
||||
{
|
||||
if (type == module->type && !strcasecmp(name, module->module.ModuleName))
|
||||
if (type == module->type && !strcasecmp(modname, module->module.ModuleName))
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
@ -214,9 +221,9 @@ struct module* module_get_debug(const struct process* pcs, struct module* module
|
|||
|
||||
switch (module->type)
|
||||
{
|
||||
case DMT_ELF: ret = elf_load_debug_info(module); break;
|
||||
case DMT_PE: ret = pe_load_debug_info(pcs, module); break;
|
||||
default: ret = FALSE; break;
|
||||
case DMT_ELF: ret = elf_load_debug_info(module, NULL); break;
|
||||
case DMT_PE: ret = pe_load_debug_info(pcs, module); break;
|
||||
default: ret = FALSE; break;
|
||||
}
|
||||
if (!ret) module->module.SymType = SymNone;
|
||||
assert(module->module.SymType != SymDeferred);
|
||||
|
@ -277,6 +284,33 @@ static BOOL module_is_elf_container_loaded(struct process* pcs, const char* Imag
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL elf_is_shared_by_name(const char* name)
|
||||
{
|
||||
const char* ptr;
|
||||
int len = strlen(name);
|
||||
|
||||
/* check for terminating .so or .so.[digit]+ */
|
||||
while (len)
|
||||
{
|
||||
for (ptr = name + len - 1; ptr >= name; ptr--) if (*ptr == '.') break;
|
||||
if (ptr < name) break;
|
||||
if (ptr == name + len - 2 && isdigit(ptr[1]))
|
||||
{
|
||||
len -= 2;
|
||||
continue;
|
||||
}
|
||||
if (ptr == name + len - 3 && ptr[1] == 's' && ptr[2] == 'o')
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
/* wine-[kp]thread is valid too */
|
||||
if (((len > 12 && name[len - 13] == '/') || len == 12) &&
|
||||
(!strcasecmp(name + len - 12, "wine-pthread") ||
|
||||
!strcasecmp(name + len - 12, "wine-kthread")))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SymLoadModule (DBGHELP.@)
|
||||
*/
|
||||
|
@ -310,11 +344,11 @@ DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, char* ImageName,
|
|||
TRACE("Assuming %s as native DLL\n", ImageName);
|
||||
if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll)))
|
||||
{
|
||||
unsigned len = strlen(ImageName);
|
||||
|
||||
if (!strcmp(ImageName + len - 3, ".so") &&
|
||||
(module = elf_load_module(pcs, ImageName))) goto done;
|
||||
FIXME("should have successfully loaded some debug information for image %s\n", ImageName);
|
||||
if (elf_is_shared_by_name(ImageName) &&
|
||||
(module = elf_load_module(pcs, ImageName, BaseOfDll)))
|
||||
goto done;
|
||||
FIXME("Should have successfully loaded debug information for image %s\n",
|
||||
ImageName);
|
||||
if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
|
||||
goto done;
|
||||
WARN("Couldn't locate %s\n", ImageName);
|
||||
|
@ -418,7 +452,7 @@ BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess,
|
|||
DWORD i, sz;
|
||||
MODULEINFO mi;
|
||||
|
||||
hMods = HeapAlloc(GetProcessHeap(), 0, sz);
|
||||
hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
|
||||
if (!hMods) return FALSE;
|
||||
|
||||
if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
|
||||
|
|
|
@ -404,21 +404,25 @@ struct module* pe_load_module_from_pcs(struct process* pcs, const char* name,
|
|||
}
|
||||
}
|
||||
if (ptr && (module = module_find_by_name(pcs, ptr, DMT_PE))) return module;
|
||||
if (base && pcs->dbg_hdr_addr)
|
||||
if (base)
|
||||
{
|
||||
IMAGE_DOS_HEADER dos;
|
||||
IMAGE_NT_HEADERS nth;
|
||||
|
||||
if (ReadProcessMemory(pcs->handle, (char*)base, &dos, sizeof(dos), NULL) &&
|
||||
dos.e_magic == IMAGE_DOS_SIGNATURE &&
|
||||
ReadProcessMemory(pcs->handle, (char*)(base + dos.e_lfanew),
|
||||
&nth, sizeof(nth), NULL) &&
|
||||
nth.Signature == IMAGE_NT_SIGNATURE)
|
||||
if (pcs->dbg_hdr_addr)
|
||||
{
|
||||
if (!size) size = nth.OptionalHeader.SizeOfImage;
|
||||
module = module_new(pcs, name, DMT_PE, base, size,
|
||||
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum);
|
||||
}
|
||||
IMAGE_DOS_HEADER dos;
|
||||
IMAGE_NT_HEADERS nth;
|
||||
|
||||
if (ReadProcessMemory(pcs->handle, (char*)base, &dos, sizeof(dos), NULL) &&
|
||||
dos.e_magic == IMAGE_DOS_SIGNATURE &&
|
||||
ReadProcessMemory(pcs->handle, (char*)(base + dos.e_lfanew),
|
||||
&nth, sizeof(nth), NULL) &&
|
||||
nth.Signature == IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
if (!size) size = nth.OptionalHeader.SizeOfImage;
|
||||
module = module_new(pcs, name, DMT_PE, base, size,
|
||||
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum);
|
||||
}
|
||||
} else if (size)
|
||||
module = module_new(pcs, name, DMT_PE, base, size, 0 /* FIXME */, 0 /* FIXME */);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ struct stab_nlist
|
|||
|
||||
static void stab_strcpy(char* dest, int sz, const char* source)
|
||||
{
|
||||
char* ptr = dest;
|
||||
/*
|
||||
* A strcpy routine that stops when we hit the ':' character.
|
||||
* Faster than copying the whole thing, and then nuking the
|
||||
|
@ -108,28 +109,27 @@ static void stab_strcpy(char* dest, int sz, const char* source)
|
|||
*/
|
||||
while (*source != '\0')
|
||||
{
|
||||
if (source[0] != ':' && sz-- > 0) *dest++ = *source++;
|
||||
if (source[0] != ':' && sz-- > 0) *ptr++ = *source++;
|
||||
else if (source[1] == ':' && (sz -= 2) > 0)
|
||||
{
|
||||
*dest++ = *source++;
|
||||
*dest++ = *source++;
|
||||
*ptr++ = *source++;
|
||||
*ptr++ = *source++;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
*dest-- = '\0';
|
||||
/* GCC seems to emit, in some cases, a .<digit>+ suffix.
|
||||
*ptr-- = '\0';
|
||||
/* GCC emits, 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))
|
||||
if (ptr >= dest && isdigit(*ptr))
|
||||
{
|
||||
while (isdigit(*dest)) dest--;
|
||||
if (*dest == '.') *dest = '\0';
|
||||
while (ptr > dest && isdigit(*ptr)) ptr--;
|
||||
if (*ptr == '.') *ptr = '\0';
|
||||
}
|
||||
|
||||
assert(sz > 0);
|
||||
}
|
||||
|
||||
|
@ -1098,7 +1098,7 @@ struct pending_loc_var
|
|||
* 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)
|
||||
unsigned long size)
|
||||
{
|
||||
IMAGEHLP_LINE il;
|
||||
|
||||
|
@ -1113,7 +1113,7 @@ static void stabs_finalize_function(struct module* module, struct symt_function*
|
|||
symt_add_function_point(module, func, SymTagFuncDebugStart,
|
||||
il.Address - func->address, NULL);
|
||||
}
|
||||
if (end) func->size = end - func->address;
|
||||
if (size) func->size = size;
|
||||
}
|
||||
|
||||
BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
||||
|
@ -1389,10 +1389,6 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
}
|
||||
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
|
||||
|
@ -1409,6 +1405,17 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
if (*symname)
|
||||
{
|
||||
struct symt_function_signature* func_type;
|
||||
|
||||
if (curr_func)
|
||||
{
|
||||
/* First, clean up the previous function we were working on.
|
||||
* Assume size of the func is the delta between current offset
|
||||
* and offset of last function
|
||||
*/
|
||||
stabs_finalize_function(module, curr_func,
|
||||
stab_ptr->n_value ?
|
||||
(load_offset + stab_ptr->n_value - curr_func->address) : 0);
|
||||
}
|
||||
func_type = symt_new_function_signature(module,
|
||||
stabs_parse_type(ptr));
|
||||
curr_func = symt_new_function(module, compiland, symname,
|
||||
|
@ -1417,7 +1424,10 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* some GCC seem to use a N_FUN "" to mark the end of a function */
|
||||
/* some versions of GCC to use a N_FUN "" to mark the end of a function
|
||||
* and n_value contains the size of the func
|
||||
*/
|
||||
stabs_finalize_function(module, curr_func, stab_ptr->n_value);
|
||||
curr_func = NULL;
|
||||
}
|
||||
break;
|
||||
|
@ -1430,8 +1440,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
{
|
||||
/* Nuke old path. */
|
||||
srcpath[0] = '\0';
|
||||
stabs_finalize_function(module, curr_func,
|
||||
stab_ptr->n_value ? load_offset + stab_ptr->n_value : 0);
|
||||
stabs_finalize_function(module, curr_func, 0);
|
||||
curr_func = NULL;
|
||||
source_idx = -1;
|
||||
incl_stk = -1;
|
||||
|
@ -1467,9 +1476,12 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
|||
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;
|
||||
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. */
|
||||
|
|
Loading…
Reference in New Issue