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
Eric Pouech 2005-03-01 10:39:49 +00:00 committed by Alexandre Julliard
parent 13abcb0a26
commit 01aa71371b
6 changed files with 546 additions and 302 deletions

View File

@ -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;
} }

View File

@ -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

View File

@ -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))

View File

@ -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;
} }

View File

@ -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. */