forked from Mirrors/wine-wine
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.oldstable
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
|
* 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
|
* assume, that we have also to define constants for enum values, as
|
||||||
* Codeview does BTW.
|
* 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...)
|
* - most options (dbghelp_options) are not used (loading lines...)
|
||||||
* - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
|
* - 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,
|
* 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:
|
* - msc:
|
||||||
* + we should add parameters' types to the function's signature
|
* + we should add parameters' types to the function's signature
|
||||||
* while processing a function's parameters
|
* 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
|
* + C++ management
|
||||||
* - stabs:
|
* - stabs:
|
||||||
* + when, in a same module, the same definition is used in several compilation
|
* + 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)
|
* SymInitialize helper: loads in dbghelp all known (and loaded modules)
|
||||||
* this assumes that hProcess is a handle on a valid process
|
* 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];
|
SymLoadModule((HANDLE)user, 0, name, NULL, base, size);
|
||||||
char img[256];
|
return TRUE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -235,9 +225,10 @@ BOOL WINAPI SymInitialize(HANDLE hProcess, PSTR UserSearchPath, BOOL fInvadeProc
|
||||||
SymCleanup(hProcess);
|
SymCleanup(hProcess);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
process_invade(hProcess);
|
EnumerateLoadedModules(hProcess, process_invade_cb, (void*)hProcess);
|
||||||
elf_synchronize_module_list(pcs);
|
elf_synchronize_module_list(pcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -293,9 +293,12 @@ extern struct process* process_find_by_handle(HANDLE hProcess);
|
||||||
extern HANDLE hMsvcrt;
|
extern HANDLE hMsvcrt;
|
||||||
|
|
||||||
/* elf_module.c */
|
/* 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*
|
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_read_wine_loader_dbg_info(struct process* pcs);
|
||||||
extern BOOL elf_synchronize_module_list(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 &&
|
if (len > 4 &&
|
||||||
(!strcasecmp(&out[len - 4], ".dll") || !strcasecmp(&out[len - 4], ".exe")))
|
(!strcasecmp(&out[len - 4], ".dll") || !strcasecmp(&out[len - 4], ".exe")))
|
||||||
out[len - 4] = '\0';
|
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
|
else
|
||||||
{
|
{
|
||||||
if (len > 7 &&
|
if (len > 7 &&
|
||||||
|
@ -134,14 +138,17 @@ struct module* module_find_by_name(const struct process* pcs,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
char modname[MAX_PATH];
|
||||||
|
|
||||||
for (module = pcs->lmodules; module; module = module->next)
|
for (module = pcs->lmodules; module; module = module->next)
|
||||||
{
|
{
|
||||||
if (type == module->type && !strcasecmp(name, module->module.LoadedImageName))
|
if (type == module->type && !strcasecmp(name, module->module.LoadedImageName))
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
module_fill_module(name, modname, sizeof(modname));
|
||||||
for (module = pcs->lmodules; module; module = module->next)
|
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;
|
return module;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,9 +221,9 @@ struct module* module_get_debug(const struct process* pcs, struct module* module
|
||||||
|
|
||||||
switch (module->type)
|
switch (module->type)
|
||||||
{
|
{
|
||||||
case DMT_ELF: ret = elf_load_debug_info(module); break;
|
case DMT_ELF: ret = elf_load_debug_info(module, NULL); break;
|
||||||
case DMT_PE: ret = pe_load_debug_info(pcs, module); break;
|
case DMT_PE: ret = pe_load_debug_info(pcs, module); break;
|
||||||
default: ret = FALSE; break;
|
default: ret = FALSE; break;
|
||||||
}
|
}
|
||||||
if (!ret) module->module.SymType = SymNone;
|
if (!ret) module->module.SymType = SymNone;
|
||||||
assert(module->module.SymType != SymDeferred);
|
assert(module->module.SymType != SymDeferred);
|
||||||
|
@ -277,6 +284,33 @@ static BOOL module_is_elf_container_loaded(struct process* pcs, const char* Imag
|
||||||
return FALSE;
|
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.@)
|
* SymLoadModule (DBGHELP.@)
|
||||||
*/
|
*/
|
||||||
|
@ -310,11 +344,11 @@ DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, char* ImageName,
|
||||||
TRACE("Assuming %s as native DLL\n", ImageName);
|
TRACE("Assuming %s as native DLL\n", ImageName);
|
||||||
if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll)))
|
if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll)))
|
||||||
{
|
{
|
||||||
unsigned len = strlen(ImageName);
|
if (elf_is_shared_by_name(ImageName) &&
|
||||||
|
(module = elf_load_module(pcs, ImageName, BaseOfDll)))
|
||||||
if (!strcmp(ImageName + len - 3, ".so") &&
|
goto done;
|
||||||
(module = elf_load_module(pcs, ImageName))) goto done;
|
FIXME("Should have successfully loaded debug information for image %s\n",
|
||||||
FIXME("should have successfully loaded some debug information for image %s\n", ImageName);
|
ImageName);
|
||||||
if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
|
if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
|
||||||
goto done;
|
goto done;
|
||||||
WARN("Couldn't locate %s\n", ImageName);
|
WARN("Couldn't locate %s\n", ImageName);
|
||||||
|
@ -418,7 +452,7 @@ BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess,
|
||||||
DWORD i, sz;
|
DWORD i, sz;
|
||||||
MODULEINFO mi;
|
MODULEINFO mi;
|
||||||
|
|
||||||
hMods = HeapAlloc(GetProcessHeap(), 0, sz);
|
hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
|
||||||
if (!hMods) return FALSE;
|
if (!hMods) return FALSE;
|
||||||
|
|
||||||
if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
|
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 (ptr && (module = module_find_by_name(pcs, ptr, DMT_PE))) return module;
|
||||||
if (base && pcs->dbg_hdr_addr)
|
if (base)
|
||||||
{
|
{
|
||||||
IMAGE_DOS_HEADER dos;
|
if (pcs->dbg_hdr_addr)
|
||||||
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;
|
IMAGE_DOS_HEADER dos;
|
||||||
module = module_new(pcs, name, DMT_PE, base, size,
|
IMAGE_NT_HEADERS nth;
|
||||||
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum);
|
|
||||||
}
|
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;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ struct stab_nlist
|
||||||
|
|
||||||
static void stab_strcpy(char* dest, int sz, const char* source)
|
static void stab_strcpy(char* dest, int sz, const char* source)
|
||||||
{
|
{
|
||||||
|
char* ptr = dest;
|
||||||
/*
|
/*
|
||||||
* A strcpy routine that stops when we hit the ':' character.
|
* A strcpy routine that stops when we hit the ':' character.
|
||||||
* Faster than copying the whole thing, and then nuking the
|
* 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')
|
while (*source != '\0')
|
||||||
{
|
{
|
||||||
if (source[0] != ':' && sz-- > 0) *dest++ = *source++;
|
if (source[0] != ':' && sz-- > 0) *ptr++ = *source++;
|
||||||
else if (source[1] == ':' && (sz -= 2) > 0)
|
else if (source[1] == ':' && (sz -= 2) > 0)
|
||||||
{
|
{
|
||||||
*dest++ = *source++;
|
*ptr++ = *source++;
|
||||||
*dest++ = *source++;
|
*ptr++ = *source++;
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
*dest-- = '\0';
|
*ptr-- = '\0';
|
||||||
/* GCC seems to emit, in some cases, a .<digit>+ suffix.
|
/* GCC emits, in some cases, a .<digit>+ suffix.
|
||||||
* This is used for static variable inside functions, so
|
* This is used for static variable inside functions, so
|
||||||
* that we can have several such variables with same name in
|
* that we can have several such variables with same name in
|
||||||
* the same compilation unit
|
* the same compilation unit
|
||||||
* We simply ignore that suffix when present (we also get rid
|
* We simply ignore that suffix when present (we also get rid
|
||||||
* of it in ELF symtab parsing)
|
* of it in ELF symtab parsing)
|
||||||
*/
|
*/
|
||||||
if (isdigit(*dest))
|
if (ptr >= dest && isdigit(*ptr))
|
||||||
{
|
{
|
||||||
while (isdigit(*dest)) dest--;
|
while (ptr > dest && isdigit(*ptr)) ptr--;
|
||||||
if (*dest == '.') *dest = '\0';
|
if (*ptr == '.') *ptr = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(sz > 0);
|
assert(sz > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1098,7 +1098,7 @@ struct pending_loc_var
|
||||||
* function (assuming that current function ends where next function starts)
|
* function (assuming that current function ends where next function starts)
|
||||||
*/
|
*/
|
||||||
static void stabs_finalize_function(struct module* module, struct symt_function* func,
|
static void stabs_finalize_function(struct module* module, struct symt_function* func,
|
||||||
unsigned long end)
|
unsigned long size)
|
||||||
{
|
{
|
||||||
IMAGEHLP_LINE il;
|
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,
|
symt_add_function_point(module, func, SymTagFuncDebugStart,
|
||||||
il.Address - func->address, NULL);
|
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,
|
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;
|
break;
|
||||||
case N_FUN:
|
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
|
* For now, just declare the various functions. Later
|
||||||
* on, we will add the line number information and the
|
* 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)
|
if (*symname)
|
||||||
{
|
{
|
||||||
struct symt_function_signature* func_type;
|
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,
|
func_type = symt_new_function_signature(module,
|
||||||
stabs_parse_type(ptr));
|
stabs_parse_type(ptr));
|
||||||
curr_func = symt_new_function(module, compiland, symname,
|
curr_func = symt_new_function(module, compiland, symname,
|
||||||
|
@ -1417,7 +1424,10 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
||||||
}
|
}
|
||||||
else
|
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;
|
curr_func = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1430,8 +1440,7 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
||||||
{
|
{
|
||||||
/* Nuke old path. */
|
/* Nuke old path. */
|
||||||
srcpath[0] = '\0';
|
srcpath[0] = '\0';
|
||||||
stabs_finalize_function(module, curr_func,
|
stabs_finalize_function(module, curr_func, 0);
|
||||||
stab_ptr->n_value ? load_offset + stab_ptr->n_value : 0);
|
|
||||||
curr_func = NULL;
|
curr_func = NULL;
|
||||||
source_idx = -1;
|
source_idx = -1;
|
||||||
incl_stk = -1;
|
incl_stk = -1;
|
||||||
|
@ -1467,9 +1476,12 @@ BOOL stabs_parse(struct module* module, unsigned long load_offset,
|
||||||
strs += strtabinc;
|
strs += strtabinc;
|
||||||
strtabinc = stab_ptr->n_value;
|
strtabinc = stab_ptr->n_value;
|
||||||
/* I'm not sure this is needed, so trace it before we obsolete it */
|
/* 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);
|
if (curr_func)
|
||||||
stabs_finalize_function(module, curr_func, 0); /* FIXME */
|
{
|
||||||
curr_func = NULL;
|
FIXME("UNDF: curr_func %s\n", curr_func->hash_elt.name);
|
||||||
|
stabs_finalize_function(module, curr_func, 0); /* FIXME */
|
||||||
|
curr_func = NULL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case N_OPT:
|
case N_OPT:
|
||||||
/* Ignore this. We don't care what it points to. */
|
/* Ignore this. We don't care what it points to. */
|
||||||
|
|
Loading…
Reference in New Issue