Commit 01aa7137 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

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.
parent 13abcb0a
......@@ -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);
......
......@@ -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. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment