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
|
* 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);
|
||||||
|
|
||||||
|
@ -89,6 +89,25 @@ struct elf_info
|
|||||||
struct module* module; /* OUT loaded module (if ELF_INFO_MODULE is set) */
|
struct module* module; /* OUT loaded module (if ELF_INFO_MODULE is set) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NO_MAP ((const void*)0xffffffff)
|
||||||
|
/* structure holding information while handling an ELF image
|
||||||
|
* allows one by one section mapping for memory savings
|
||||||
|
*/
|
||||||
|
struct elf_file_map
|
||||||
|
{
|
||||||
|
Elf32_Ehdr elfhdr;
|
||||||
|
size_t elf_size;
|
||||||
|
size_t elf_start;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
Elf32_Shdr shdr;
|
||||||
|
const char* mapped;
|
||||||
|
}* sect;
|
||||||
|
int fd;
|
||||||
|
unsigned with_crc;
|
||||||
|
unsigned long crc;
|
||||||
|
};
|
||||||
|
|
||||||
struct symtab_elt
|
struct symtab_elt
|
||||||
{
|
{
|
||||||
struct hash_table_elt ht_elt;
|
struct hash_table_elt ht_elt;
|
||||||
@ -105,15 +124,128 @@ struct thunk_area
|
|||||||
unsigned long rva_end;
|
unsigned long rva_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* elf_map_section
|
||||||
|
*
|
||||||
|
* Maps a single section into memory from a ELF file
|
||||||
|
*/
|
||||||
|
static const char* elf_map_section(struct elf_file_map* fmap, int sidx)
|
||||||
|
{
|
||||||
|
unsigned pgsz = getpagesize();
|
||||||
|
unsigned ofst, size;
|
||||||
|
|
||||||
|
if (sidx >= fmap->elfhdr.e_shnum ||
|
||||||
|
fmap->sect[sidx].shdr.sh_type == SHT_NOBITS)
|
||||||
|
return NO_MAP;
|
||||||
|
/* align required information on page size (we assume pagesize is a power of 2) */
|
||||||
|
ofst = fmap->sect[sidx].shdr.sh_offset & ~(pgsz - 1);
|
||||||
|
size = (fmap->sect[sidx].shdr.sh_offset + fmap->sect[sidx].shdr.sh_size + pgsz - 1) & ~(pgsz - 1);
|
||||||
|
fmap->sect[sidx].mapped = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fmap->fd, ofst);
|
||||||
|
if (fmap->sect[sidx].mapped == NO_MAP) return NO_MAP;
|
||||||
|
return fmap->sect[sidx].mapped + (fmap->sect[sidx].shdr.sh_offset & (pgsz - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* elf_unmap_section
|
||||||
|
*
|
||||||
|
* Unmaps a single section from memory
|
||||||
|
*/
|
||||||
|
static void elf_unmap_section(struct elf_file_map* fmap, int sidx)
|
||||||
|
{
|
||||||
|
if (sidx < fmap->elfhdr.e_shnum && fmap->sect[sidx].mapped != NO_MAP)
|
||||||
|
{
|
||||||
|
munmap((char*)fmap->sect[sidx].mapped, fmap->sect[sidx].shdr.sh_size);
|
||||||
|
fmap->sect[sidx].mapped = NO_MAP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* elf_map_file
|
||||||
|
*
|
||||||
|
* Maps a ELF file into memory (and checks it's a real ELF file)
|
||||||
|
*/
|
||||||
|
static BOOL elf_map_file(const char* filename, struct elf_file_map* fmap)
|
||||||
|
{
|
||||||
|
static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
|
||||||
|
struct stat statbuf;
|
||||||
|
int i;
|
||||||
|
Elf32_Phdr phdr;
|
||||||
|
unsigned tmp, page_mask = getpagesize() - 1;
|
||||||
|
|
||||||
|
|
||||||
|
fmap->fd = -1;
|
||||||
|
fmap->with_crc = 0;
|
||||||
|
|
||||||
|
/* check that the file exists, and that the module hasn't been loaded yet */
|
||||||
|
if (stat(filename, &statbuf) == -1 || S_ISDIR(statbuf.st_mode)) return FALSE;
|
||||||
|
|
||||||
|
/* Now open the file, so that we can mmap() it. */
|
||||||
|
if ((fmap->fd = open(filename, O_RDONLY)) == -1) return FALSE;
|
||||||
|
|
||||||
|
if (read(fmap->fd, &fmap->elfhdr, sizeof(fmap->elfhdr)) != sizeof(fmap->elfhdr))
|
||||||
|
return FALSE;
|
||||||
|
/* and check for an ELF header */
|
||||||
|
if (memcmp(fmap->elfhdr.e_ident,
|
||||||
|
elf_signature, sizeof(elf_signature))) return FALSE;
|
||||||
|
|
||||||
|
fmap->sect = HeapAlloc(GetProcessHeap(), 0, fmap->elfhdr.e_shnum * sizeof(fmap->sect[0]));
|
||||||
|
if (!fmap->sect) return FALSE;
|
||||||
|
|
||||||
|
lseek(fmap->fd, fmap->elfhdr.e_shoff, SEEK_SET);
|
||||||
|
for (i = 0; i < fmap->elfhdr.e_shnum; i++)
|
||||||
|
{
|
||||||
|
read(fmap->fd, &fmap->sect[i].shdr, sizeof(fmap->sect[i].shdr));
|
||||||
|
fmap->sect[i].mapped = NO_MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* grab size of module once loaded in memory */
|
||||||
|
lseek(fmap->fd, fmap->elfhdr.e_phoff, SEEK_SET);
|
||||||
|
fmap->elf_size = 0;
|
||||||
|
fmap->elf_start = ~0L;
|
||||||
|
for (i = 0; i < fmap->elfhdr.e_phnum; i++)
|
||||||
|
{
|
||||||
|
if (read(fmap->fd, &phdr, sizeof(phdr)) == sizeof(phdr) &&
|
||||||
|
phdr.p_type == PT_LOAD)
|
||||||
|
{
|
||||||
|
tmp = (phdr.p_vaddr + phdr.p_memsz + page_mask) & ~page_mask;
|
||||||
|
if (fmap->elf_size < tmp) fmap->elf_size = tmp;
|
||||||
|
if (phdr.p_vaddr < fmap->elf_start) fmap->elf_start = phdr.p_vaddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if non relocatable ELF, then remove fixed address from computation
|
||||||
|
* otherwise, all addresses are zero based and start has no effect
|
||||||
|
*/
|
||||||
|
fmap->elf_size -= fmap->elf_start;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* elf_unmap_file
|
||||||
|
*
|
||||||
|
* Unmaps a ELF file from memory (previously mapped with elf_map_file)
|
||||||
|
*/
|
||||||
|
static void elf_unmap_file(struct elf_file_map* fmap)
|
||||||
|
{
|
||||||
|
if (fmap->fd != -1)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < fmap->elfhdr.e_shnum; i++)
|
||||||
|
{
|
||||||
|
elf_unmap_section(fmap, i);
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, fmap->sect);
|
||||||
|
close(fmap->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* elf_hash_symtab
|
* elf_hash_symtab
|
||||||
*
|
*
|
||||||
* creating an internal hash table to ease use ELF symtab information lookup
|
* creating an internal hash table to ease use ELF symtab information lookup
|
||||||
*/
|
*/
|
||||||
static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
||||||
struct hash_table* ht_symtab, const char* map_addr,
|
struct hash_table* ht_symtab, struct elf_file_map* fmap,
|
||||||
const Elf32_Shdr* symtab, const Elf32_Shdr* strtab,
|
int symtab_idx, struct thunk_area* thunks)
|
||||||
unsigned num_areas, struct thunk_area* thunks)
|
|
||||||
{
|
{
|
||||||
int i, j, nsym;
|
int i, j, nsym;
|
||||||
const char* strp;
|
const char* strp;
|
||||||
@ -123,11 +255,13 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
|||||||
const Elf32_Sym* symp;
|
const Elf32_Sym* symp;
|
||||||
struct symtab_elt* ste;
|
struct symtab_elt* ste;
|
||||||
|
|
||||||
symp = (const Elf32_Sym*)(map_addr + symtab->sh_offset);
|
symp = (const Elf32_Sym*)elf_map_section(fmap, symtab_idx);
|
||||||
nsym = symtab->sh_size / sizeof(*symp);
|
strp = elf_map_section(fmap, fmap->sect[symtab_idx].shdr.sh_link);
|
||||||
strp = (const char*)(map_addr + strtab->sh_offset);
|
if (symp == NO_MAP || strp == NO_MAP) return;
|
||||||
|
|
||||||
for (j = 0; j < num_areas; j++)
|
nsym = fmap->sect[symtab_idx].shdr.sh_size / sizeof(*symp);
|
||||||
|
|
||||||
|
for (j = 0; thunks[j].symname; j++)
|
||||||
thunks[j].rva_start = thunks[j].rva_end = 0;
|
thunks[j].rva_start = thunks[j].rva_end = 0;
|
||||||
|
|
||||||
for (i = 0; i < nsym; i++, symp++)
|
for (i = 0; i < nsym; i++, symp++)
|
||||||
@ -135,7 +269,10 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
|||||||
/* Ignore certain types of entries which really aren't of that much
|
/* Ignore certain types of entries which really aren't of that much
|
||||||
* interest.
|
* interest.
|
||||||
*/
|
*/
|
||||||
if (ELF32_ST_TYPE(symp->st_info) == STT_SECTION || symp->st_shndx == SHN_UNDEF)
|
if ((ELF32_ST_TYPE(symp->st_info) != STT_FILE &&
|
||||||
|
ELF32_ST_TYPE(symp->st_info) != STT_OBJECT &&
|
||||||
|
ELF32_ST_TYPE(symp->st_info) != STT_FUNC) ||
|
||||||
|
symp->st_shndx == SHN_UNDEF)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -147,7 +284,7 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
|||||||
filename = symname;
|
filename = symname;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (j = 0; j < num_areas; j++)
|
for (j = 0; thunks[j].symname; j++)
|
||||||
{
|
{
|
||||||
if (!strcmp(symname, thunks[j].symname))
|
if (!strcmp(symname, thunks[j].symname))
|
||||||
{
|
{
|
||||||
@ -156,7 +293,7 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (j < num_areas) continue;
|
if (thunks[j].symname) continue;
|
||||||
|
|
||||||
/* FIXME: we don't need to handle them (GCC internals)
|
/* FIXME: we don't need to handle them (GCC internals)
|
||||||
* Moreover, they screw up our symbol lookup :-/
|
* Moreover, they screw up our symbol lookup :-/
|
||||||
@ -165,7 +302,8 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
ste = pool_alloc(pool, sizeof(*ste));
|
ste = pool_alloc(pool, sizeof(*ste));
|
||||||
/* GCC seems to emit, in some cases, a .<digit>+ suffix.
|
ste->ht_elt.name = symname;
|
||||||
|
/* 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
|
||||||
@ -173,10 +311,9 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
|||||||
* of it in stabs parsing)
|
* of it in stabs parsing)
|
||||||
*/
|
*/
|
||||||
ptr = symname + strlen(symname) - 1;
|
ptr = symname + strlen(symname) - 1;
|
||||||
ste->ht_elt.name = symname;
|
|
||||||
if (isdigit(*ptr))
|
if (isdigit(*ptr))
|
||||||
{
|
{
|
||||||
while (*ptr >= '0' && *ptr <= '9' && ptr >= symname) ptr--;
|
while (isdigit(*ptr) && ptr >= symname) ptr--;
|
||||||
if (ptr > symname && *ptr == '.')
|
if (ptr > symname && *ptr == '.')
|
||||||
{
|
{
|
||||||
char* n = pool_alloc(pool, ptr - symname + 1);
|
char* n = pool_alloc(pool, ptr - symname + 1);
|
||||||
@ -190,6 +327,10 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
|
|||||||
ste->used = 0;
|
ste->used = 0;
|
||||||
hash_table_add(ht_symtab, &ste->ht_elt);
|
hash_table_add(ht_symtab, &ste->ht_elt);
|
||||||
}
|
}
|
||||||
|
/* as we added in the ht_symtab pointers to the symbols themselves,
|
||||||
|
* we cannot unmap yet the sections, it will be done when we're over
|
||||||
|
* with this ELF file
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
@ -253,7 +394,7 @@ static const Elf32_Sym* elf_lookup_symtab(const struct module* module,
|
|||||||
}
|
}
|
||||||
if (!result && !(result = weak_result))
|
if (!result && !(result = weak_result))
|
||||||
{
|
{
|
||||||
FIXME("Couldn't find symbol %s.%s in symtab\n",
|
FIXME("Couldn't find symbol %s!%s in symtab\n",
|
||||||
module->module.ModuleName, name);
|
module->module.ModuleName, name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -289,10 +430,20 @@ static void elf_finish_stabs_info(struct module* module, struct hash_table* symt
|
|||||||
((struct symt_function*)sym)->container);
|
((struct symt_function*)sym)->container);
|
||||||
if (symp)
|
if (symp)
|
||||||
{
|
{
|
||||||
|
if (((struct symt_function*)sym)->address != module->elf_info->elf_addr &&
|
||||||
|
((struct symt_function*)sym)->address != module->elf_info->elf_addr + symp->st_value)
|
||||||
|
FIXME("Changing address for %p/%s!%s from %08lx to %08lx\n",
|
||||||
|
sym, module->module.ModuleName, sym->hash_elt.name,
|
||||||
|
((struct symt_function*)sym)->address, module->elf_info->elf_addr + symp->st_value);
|
||||||
|
if (((struct symt_function*)sym)->size && ((struct symt_function*)sym)->size != symp->st_size)
|
||||||
|
FIXME("Changing size for %p/%s!%s from %08lx to %08x\n",
|
||||||
|
sym, module->module.ModuleName, sym->hash_elt.name,
|
||||||
|
((struct symt_function*)sym)->size, symp->st_size);
|
||||||
|
|
||||||
((struct symt_function*)sym)->address = module->elf_info->elf_addr +
|
((struct symt_function*)sym)->address = module->elf_info->elf_addr +
|
||||||
symp->st_value;
|
symp->st_value;
|
||||||
((struct symt_function*)sym)->size = symp->st_size;
|
((struct symt_function*)sym)->size = symp->st_size;
|
||||||
} else FIXME("Couldn't find %s\n", sym->hash_elt.name);
|
} else FIXME("Couldn't find %s!%s\n", module->module.ModuleName, sym->hash_elt.name);
|
||||||
break;
|
break;
|
||||||
case SymTagData:
|
case SymTagData:
|
||||||
switch (((struct symt_data*)sym)->kind)
|
switch (((struct symt_data*)sym)->kind)
|
||||||
@ -305,11 +456,16 @@ static void elf_finish_stabs_info(struct module* module, struct hash_table* symt
|
|||||||
((struct symt_data*)sym)->container);
|
((struct symt_data*)sym)->container);
|
||||||
if (symp)
|
if (symp)
|
||||||
{
|
{
|
||||||
|
if (((struct symt_data*)sym)->u.address != module->elf_info->elf_addr &&
|
||||||
|
((struct symt_data*)sym)->u.address != module->elf_info->elf_addr + symp->st_value)
|
||||||
|
FIXME("Changing address for %p/%s!%s from %08lx to %08lx\n",
|
||||||
|
sym, module->module.ModuleName, sym->hash_elt.name,
|
||||||
|
((struct symt_function*)sym)->address, module->elf_info->elf_addr + symp->st_value);
|
||||||
((struct symt_data*)sym)->u.address = module->elf_info->elf_addr +
|
((struct symt_data*)sym)->u.address = module->elf_info->elf_addr +
|
||||||
symp->st_value;
|
symp->st_value;
|
||||||
((struct symt_data*)sym)->kind = (ELF32_ST_BIND(symp->st_info) == STB_LOCAL) ?
|
((struct symt_data*)sym)->kind = (ELF32_ST_BIND(symp->st_info) == STB_LOCAL) ?
|
||||||
DataIsFileStatic : DataIsGlobal;
|
DataIsFileStatic : DataIsGlobal;
|
||||||
}
|
} else FIXME("Couldn't find %s!%s\n", module->module.ModuleName, sym->hash_elt.name);
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
@ -381,16 +537,20 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt
|
|||||||
* used yet (ie we have no debug information on them)
|
* used yet (ie we have no debug information on them)
|
||||||
* That's the case, for example, of the .spec.c files
|
* That's the case, for example, of the .spec.c files
|
||||||
*/
|
*/
|
||||||
if (ELF32_ST_TYPE(ste->symp->st_info) == STT_FUNC)
|
switch (ELF32_ST_TYPE(ste->symp->st_info))
|
||||||
{
|
{
|
||||||
|
case STT_FUNC:
|
||||||
symt_new_function(module, compiland, ste->ht_elt.name,
|
symt_new_function(module, compiland, ste->ht_elt.name,
|
||||||
addr, ste->symp->st_size, NULL);
|
addr, ste->symp->st_size, NULL);
|
||||||
}
|
break;
|
||||||
else
|
case STT_OBJECT:
|
||||||
{
|
|
||||||
symt_new_global_variable(module, compiland, ste->ht_elt.name,
|
symt_new_global_variable(module, compiland, ste->ht_elt.name,
|
||||||
ELF32_ST_BIND(ste->symp->st_info) == STB_LOCAL,
|
ELF32_ST_BIND(ste->symp->st_info) == STB_LOCAL,
|
||||||
addr, ste->symp->st_size, NULL);
|
addr, ste->symp->st_size, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FIXME("Shouldn't happen\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* FIXME: this is a hack !!!
|
/* FIXME: this is a hack !!!
|
||||||
* we are adding new symbols, but as we're parsing a symbol table
|
* we are adding new symbols, but as we're parsing a symbol table
|
||||||
@ -410,7 +570,6 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt
|
|||||||
symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_LENGTH, &xsize);
|
symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_LENGTH, &xsize);
|
||||||
symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_DATAKIND, &kind);
|
symt_get_info(&module->addr_sorttab[idx]->symt, TI_GET_DATAKIND, &kind);
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* If none of symbols has a correct size, we consider they are both markers
|
/* If none of symbols has a correct size, we consider they are both markers
|
||||||
* Hence, we can silence this warning
|
* Hence, we can silence this warning
|
||||||
* Also, we check that we don't have two symbols, one local, the other
|
* Also, we check that we don't have two symbols, one local, the other
|
||||||
@ -423,7 +582,6 @@ static int elf_new_wine_thunks(struct module* module, struct hash_table* ht_symt
|
|||||||
ste->ht_elt.name, addr, ste->symp->st_size,
|
ste->ht_elt.name, addr, ste->symp->st_size,
|
||||||
module->addr_sorttab[idx]->hash_elt.name,
|
module->addr_sorttab[idx]->hash_elt.name,
|
||||||
wine_dbgstr_longlong(xaddr), xsize);
|
wine_dbgstr_longlong(xaddr), xsize);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,7 +687,7 @@ static int elf_new_public_symbols(struct module* module, struct hash_table* symt
|
|||||||
/* using byte-swap instructions. */
|
/* using byte-swap instructions. */
|
||||||
|
|
||||||
|
|
||||||
static DWORD calc_crc32(const unsigned char *buf, size_t len)
|
static DWORD calc_crc32(struct elf_file_map* fmap)
|
||||||
{
|
{
|
||||||
#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
|
#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
|
||||||
static const DWORD crc_32_tab[] =
|
static const DWORD crc_32_tab[] =
|
||||||
@ -578,37 +736,38 @@ static DWORD calc_crc32(const unsigned char *buf, size_t len)
|
|||||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||||
};
|
};
|
||||||
size_t i;
|
int i, r;
|
||||||
|
unsigned char buffer[256];
|
||||||
DWORD crc = ~0;
|
DWORD crc = ~0;
|
||||||
for(i = 0; i < len; i++)
|
|
||||||
crc = UPDC32(buf[i], crc);
|
lseek(fmap->fd, 0, SEEK_SET);
|
||||||
|
while ((r = read(fmap->fd, buffer, sizeof(buffer))) > 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < r; i++) crc = UPDC32(buffer[i], crc);
|
||||||
|
}
|
||||||
return ~crc;
|
return ~crc;
|
||||||
#undef UPDC32
|
#undef UPDC32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* elf_load_debug_info_from_file
|
* elf_load_debug_info_from_map
|
||||||
*
|
*
|
||||||
* Loads the symbolic information from ELF module stored in 'file'
|
* Loads the symbolic information from ELF module which mapping is described
|
||||||
|
* in fmap
|
||||||
* the module has been loaded at 'load_offset' address, so symbols' address
|
* the module has been loaded at 'load_offset' address, so symbols' address
|
||||||
* relocation is performed. crc optionally points to the CRC of the debug file
|
* relocation is performed.
|
||||||
* to load.
|
* CRC is checked if fmap->with_crc is TRUE
|
||||||
* returns
|
* returns
|
||||||
* 0 if the file doesn't contain symbolic info (or this info cannot be
|
* 0 if the file doesn't contain symbolic info (or this info cannot be
|
||||||
* read or parsed)
|
* read or parsed)
|
||||||
* 1 on success
|
* 1 on success
|
||||||
*/
|
*/
|
||||||
static BOOL elf_load_debug_info_from_file(
|
static BOOL elf_load_debug_info_from_map(struct module* module,
|
||||||
struct module* module, const char* file, struct pool* pool,
|
struct elf_file_map* fmap,
|
||||||
struct hash_table* ht_symtab, const DWORD *crc)
|
struct pool* pool,
|
||||||
|
struct hash_table* ht_symtab)
|
||||||
{
|
{
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
char* addr = (char*)0xffffffff;
|
|
||||||
int fd = -1;
|
|
||||||
struct stat statbuf;
|
|
||||||
const Elf32_Ehdr* ehptr;
|
|
||||||
const Elf32_Shdr* spnt;
|
|
||||||
const char* shstrtab;
|
const char* shstrtab;
|
||||||
int i;
|
int i;
|
||||||
int symtab_sect, dynsym_sect, stab_sect, stabstr_sect, debug_sect, debuglink_sect;
|
int symtab_sect, dynsym_sect, stab_sect, stabstr_sect, debug_sect, debuglink_sect;
|
||||||
@ -622,35 +781,15 @@ static BOOL elf_load_debug_info_from_file(
|
|||||||
{"__wine_spec_thunk_data_16", -16, 0, 0}, /* 16 => 32 thunks */
|
{"__wine_spec_thunk_data_16", -16, 0, 0}, /* 16 => 32 thunks */
|
||||||
{"__wine_spec_thunk_text_32", -32, 0, 0}, /* 32 => 16 thunks */
|
{"__wine_spec_thunk_text_32", -32, 0, 0}, /* 32 => 16 thunks */
|
||||||
{"__wine_spec_thunk_data_32", -32, 0, 0}, /* 32 => 16 thunks */
|
{"__wine_spec_thunk_data_32", -32, 0, 0}, /* 32 => 16 thunks */
|
||||||
|
{NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (module->type != DMT_ELF || !module->elf_info)
|
if (fmap->with_crc && (fmap->crc != calc_crc32(fmap)))
|
||||||
{
|
{
|
||||||
ERR("Bad elf module '%s'\n", module->module.LoadedImageName);
|
ERR("Bad CRC for module %s (got %08lx while expecting %08lx)\n",
|
||||||
return FALSE;
|
module->module.ImageName, calc_crc32(fmap), fmap->crc);
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("%s\n", file);
|
|
||||||
/* check that the file exists, and that the module hasn't been loaded yet */
|
|
||||||
if (stat(file, &statbuf) == -1) goto leave;
|
|
||||||
if (S_ISDIR(statbuf.st_mode)) goto leave;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now open the file, so that we can mmap() it.
|
|
||||||
*/
|
|
||||||
if ((fd = open(file, O_RDONLY)) == -1) goto leave;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now mmap() the file.
|
|
||||||
*/
|
|
||||||
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
||||||
if (addr == (char*)0xffffffff) goto leave;
|
|
||||||
|
|
||||||
if (crc && (*crc != calc_crc32(addr, statbuf.st_size)))
|
|
||||||
{
|
|
||||||
ERR("Bad CRC for file %s\n", file);
|
|
||||||
/* we don't tolerate mis-matched files */
|
/* we don't tolerate mis-matched files */
|
||||||
goto leave;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -658,29 +797,30 @@ static BOOL elf_load_debug_info_from_file(
|
|||||||
* this thing. We need the main executable header, and the section
|
* this thing. We need the main executable header, and the section
|
||||||
* table.
|
* table.
|
||||||
*/
|
*/
|
||||||
ehptr = (Elf32_Ehdr*)addr;
|
shstrtab = elf_map_section(fmap, fmap->elfhdr.e_shstrndx);
|
||||||
spnt = (Elf32_Shdr*)(addr + ehptr->e_shoff);
|
if (shstrtab == NO_MAP) return FALSE;
|
||||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
|
||||||
|
|
||||||
symtab_sect = dynsym_sect = stab_sect = stabstr_sect = debug_sect = debuglink_sect = -1;
|
symtab_sect = dynsym_sect = stab_sect = stabstr_sect = debug_sect = debuglink_sect = -1;
|
||||||
|
|
||||||
for (i = 0; i < ehptr->e_shnum; i++)
|
for (i = 0; i < fmap->elfhdr.e_shnum; i++)
|
||||||
{
|
{
|
||||||
if (strcmp(shstrtab + spnt[i].sh_name, ".stab") == 0)
|
if (strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".stab") == 0)
|
||||||
stab_sect = i;
|
stab_sect = i;
|
||||||
if (strcmp(shstrtab + spnt[i].sh_name, ".stabstr") == 0)
|
if (strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".stabstr") == 0)
|
||||||
stabstr_sect = i;
|
stabstr_sect = i;
|
||||||
if (strcmp(shstrtab + spnt[i].sh_name, ".debug_info") == 0)
|
if (strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".debug_info") == 0)
|
||||||
debug_sect = i;
|
debug_sect = i;
|
||||||
if (strcmp(shstrtab + spnt[i].sh_name, ".gnu_debuglink") == 0)
|
if (strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".gnu_debuglink") == 0)
|
||||||
debuglink_sect = i;
|
debuglink_sect = i;
|
||||||
if ((strcmp(shstrtab + spnt[i].sh_name, ".symtab") == 0) &&
|
if ((strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".symtab") == 0) &&
|
||||||
(spnt[i].sh_type == SHT_SYMTAB))
|
(fmap->sect[i].shdr.sh_type == SHT_SYMTAB))
|
||||||
symtab_sect = i;
|
symtab_sect = i;
|
||||||
if ((strcmp(shstrtab + spnt[i].sh_name, ".dynsym") == 0) &&
|
if ((strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".dynsym") == 0) &&
|
||||||
(spnt[i].sh_type == SHT_DYNSYM))
|
(fmap->sect[i].shdr.sh_type == SHT_DYNSYM))
|
||||||
dynsym_sect = i;
|
dynsym_sect = i;
|
||||||
}
|
}
|
||||||
|
elf_unmap_section(fmap, fmap->elfhdr.e_shstrndx);
|
||||||
|
shstrtab = NULL;
|
||||||
|
|
||||||
if (symtab_sect == -1)
|
if (symtab_sect == -1)
|
||||||
{
|
{
|
||||||
@ -688,31 +828,38 @@ static BOOL elf_load_debug_info_from_file(
|
|||||||
* section instead. It'll contain less (relevant) information,
|
* section instead. It'll contain less (relevant) information,
|
||||||
* but it'll be better than nothing
|
* but it'll be better than nothing
|
||||||
*/
|
*/
|
||||||
if (dynsym_sect == -1) goto leave;
|
if (dynsym_sect == -1) return FALSE;
|
||||||
symtab_sect = dynsym_sect;
|
symtab_sect = dynsym_sect;
|
||||||
}
|
}
|
||||||
|
|
||||||
module->module.SymType = SymExport;
|
module->module.SymType = SymExport;
|
||||||
|
|
||||||
/* create a hash table for the symtab */
|
/* create a hash table for the symtab */
|
||||||
elf_hash_symtab(module, pool, ht_symtab, addr,
|
elf_hash_symtab(module, pool, ht_symtab, fmap, symtab_sect, thunks);
|
||||||
spnt + symtab_sect, spnt + spnt[symtab_sect].sh_link,
|
|
||||||
sizeof(thunks) / sizeof(thunks[0]), thunks);
|
|
||||||
|
|
||||||
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
|
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
|
||||||
{
|
{
|
||||||
if (stab_sect != -1 && stabstr_sect != -1)
|
if (stab_sect != -1 && stabstr_sect != -1)
|
||||||
|
{
|
||||||
|
const char* stab;
|
||||||
|
const char* stabstr;
|
||||||
|
|
||||||
|
stab = elf_map_section(fmap, stab_sect);
|
||||||
|
stabstr = elf_map_section(fmap, stabstr_sect);
|
||||||
|
if (stab != NO_MAP && stabstr != NO_MAP)
|
||||||
{
|
{
|
||||||
/* OK, now just parse all of the stabs. */
|
/* OK, now just parse all of the stabs. */
|
||||||
ret = stabs_parse(module, module->elf_info->elf_addr,
|
ret = stabs_parse(module, module->elf_info->elf_addr,
|
||||||
addr + spnt[stab_sect].sh_offset,
|
stab, fmap->sect[stab_sect].shdr.sh_size,
|
||||||
spnt[stab_sect].sh_size,
|
stabstr, fmap->sect[stabstr_sect].shdr.sh_size);
|
||||||
addr + spnt[stabstr_sect].sh_offset,
|
}
|
||||||
spnt[stabstr_sect].sh_size);
|
elf_unmap_section(fmap, stab_sect);
|
||||||
|
elf_unmap_section(fmap, stabstr_sect);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
WARN("Couldn't read correctly read stabs\n");
|
WARN("Couldn't correctly read stabs\n");
|
||||||
goto leave;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* and fill in the missing information for stabs */
|
/* and fill in the missing information for stabs */
|
||||||
elf_finish_stabs_info(module, ht_symtab);
|
elf_finish_stabs_info(module, ht_symtab);
|
||||||
@ -724,14 +871,25 @@ static BOOL elf_load_debug_info_from_file(
|
|||||||
}
|
}
|
||||||
else if (debuglink_sect != -1)
|
else if (debuglink_sect != -1)
|
||||||
{
|
{
|
||||||
DWORD crc;
|
const char* dbg_link;
|
||||||
const char * file = (const char *)(addr + spnt[debuglink_sect].sh_offset);
|
struct elf_file_map fmap_link;
|
||||||
/* crc is stored after the null terminated file string rounded
|
|
||||||
* up to the next 4 byte boundary */
|
dbg_link = elf_map_section(fmap, debuglink_sect);
|
||||||
crc = *(const DWORD *)(file + ((DWORD_PTR)(strlen(file) + 4) & ~3));
|
/* The content of a debug link section is:
|
||||||
ret = elf_load_debug_info_from_file(module, file, pool, ht_symtab, &crc);
|
* 1/ a NULL terminated string, containing the file name for the debug info
|
||||||
|
* 2/ padding on 4 byte boundary
|
||||||
|
* 3/ CRC of the linked ELF file
|
||||||
|
*/
|
||||||
|
if (dbg_link != NO_MAP && elf_map_file(dbg_link, &fmap_link))
|
||||||
|
{
|
||||||
|
fmap_link.crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3));
|
||||||
|
fmap_link.with_crc = 1;
|
||||||
|
ret = elf_load_debug_info_from_map(module, &fmap_link, pool, ht_symtab);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
WARN("Couldn't load linked debug file %s\n", file);
|
WARN("Couldn't load debug information from %s\n", dbg_link);
|
||||||
|
}
|
||||||
|
else WARN("Couldn't load linked debug file for %s\n", module->module.ModuleName);
|
||||||
|
elf_unmap_file(&fmap_link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strstr(module->module.ModuleName, "<elf>") ||
|
if (strstr(module->module.ModuleName, "<elf>") ||
|
||||||
@ -745,10 +903,6 @@ static BOOL elf_load_debug_info_from_file(
|
|||||||
/* add all the public symbols from symtab */
|
/* add all the public symbols from symtab */
|
||||||
if (elf_new_public_symbols(module, ht_symtab) && !ret) ret = TRUE;
|
if (elf_new_public_symbols(module, ht_symtab) && !ret) ret = TRUE;
|
||||||
|
|
||||||
leave:
|
|
||||||
if (addr != (char*)0xffffffff) munmap(addr, statbuf.st_size);
|
|
||||||
if (fd != -1) close(fd);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,20 +911,32 @@ leave:
|
|||||||
*
|
*
|
||||||
* Loads ELF debugging information from the module image file.
|
* Loads ELF debugging information from the module image file.
|
||||||
*/
|
*/
|
||||||
BOOL elf_load_debug_info(struct module* module)
|
BOOL elf_load_debug_info(struct module* module, struct elf_file_map* fmap)
|
||||||
{
|
{
|
||||||
BOOL ret;
|
BOOL ret = TRUE;
|
||||||
struct pool pool;
|
struct pool pool;
|
||||||
struct hash_table ht_symtab;
|
struct hash_table ht_symtab;
|
||||||
|
struct elf_file_map my_fmap;
|
||||||
|
|
||||||
|
if (module->type != DMT_ELF || !module->elf_info)
|
||||||
|
{
|
||||||
|
ERR("Bad elf module '%s'\n", module->module.LoadedImageName);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
pool_init(&pool, 65536);
|
pool_init(&pool, 65536);
|
||||||
hash_table_init(&pool, &ht_symtab, 256);
|
hash_table_init(&pool, &ht_symtab, 256);
|
||||||
|
|
||||||
ret = elf_load_debug_info_from_file(module,
|
if (!fmap)
|
||||||
module->module.LoadedImageName, &pool, &ht_symtab, NULL);
|
{
|
||||||
|
fmap = &my_fmap;
|
||||||
|
ret = elf_map_file(module->module.LoadedImageName, fmap);
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
ret = elf_load_debug_info_from_map(module, fmap, &pool, &ht_symtab);
|
||||||
|
|
||||||
pool_destroy(&pool);
|
pool_destroy(&pool);
|
||||||
|
if (fmap == &my_fmap) elf_unmap_file(fmap);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,63 +977,22 @@ static unsigned is_dt_flag_valid(unsigned d_tag)
|
|||||||
static BOOL elf_load_file(struct process* pcs, const char* filename,
|
static BOOL elf_load_file(struct process* pcs, const char* filename,
|
||||||
unsigned long load_offset, struct elf_info* elf_info)
|
unsigned long load_offset, struct elf_info* elf_info)
|
||||||
{
|
{
|
||||||
static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
|
|
||||||
BOOL ret = FALSE;
|
BOOL ret = FALSE;
|
||||||
const char* addr = (char*)0xffffffff;
|
struct elf_file_map fmap;
|
||||||
int fd = -1;
|
|
||||||
struct stat statbuf;
|
|
||||||
const Elf32_Ehdr* ehptr;
|
|
||||||
const Elf32_Shdr* spnt;
|
|
||||||
const Elf32_Phdr* ppnt;
|
|
||||||
const char* shstrtab;
|
|
||||||
int i;
|
int i;
|
||||||
DWORD size, start;
|
|
||||||
unsigned tmp, page_mask = getpagesize() - 1;
|
|
||||||
|
|
||||||
TRACE("Processing elf file '%s' at %08lx\n", filename, load_offset);
|
TRACE("Processing elf file '%s' at %08lx\n", filename, load_offset);
|
||||||
|
|
||||||
/* check that the file exists, and that the module hasn't been loaded yet */
|
if (!elf_map_file(filename, &fmap)) goto leave;
|
||||||
if (stat(filename, &statbuf) == -1) goto leave;
|
|
||||||
|
|
||||||
/* Now open the file, so that we can mmap() it. */
|
|
||||||
if ((fd = open(filename, O_RDONLY)) == -1) goto leave;
|
|
||||||
|
|
||||||
/* Now mmap() the file. */
|
|
||||||
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
||||||
if (addr == (char*)-1) goto leave;
|
|
||||||
|
|
||||||
/* Next, we need to find a few of the internal ELF headers within
|
/* Next, we need to find a few of the internal ELF headers within
|
||||||
* this thing. We need the main executable header, and the section
|
* this thing. We need the main executable header, and the section
|
||||||
* table.
|
* table.
|
||||||
*/
|
*/
|
||||||
ehptr = (const Elf32_Ehdr*)addr;
|
if (!fmap.elf_start && !load_offset)
|
||||||
if (memcmp(ehptr->e_ident, elf_signature, sizeof(elf_signature))) goto leave;
|
|
||||||
|
|
||||||
spnt = (const Elf32_Shdr*)(addr + ehptr->e_shoff);
|
|
||||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
|
||||||
|
|
||||||
/* grab size of module once loaded in memory */
|
|
||||||
ppnt = (const Elf32_Phdr*)(addr + ehptr->e_phoff);
|
|
||||||
size = 0; start = ~0L;
|
|
||||||
|
|
||||||
for (i = 0; i < ehptr->e_phnum; i++)
|
|
||||||
{
|
|
||||||
if (ppnt[i].p_type == PT_LOAD)
|
|
||||||
{
|
|
||||||
tmp = (ppnt[i].p_vaddr + ppnt[i].p_memsz + page_mask) & ~page_mask;
|
|
||||||
if (size < tmp) size = tmp;
|
|
||||||
if (ppnt[i].p_vaddr < start) start = ppnt[i].p_vaddr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if non relocatable ELF, then remove fixed address from computation
|
|
||||||
* otherwise, all addresses are zero based and start has no effect
|
|
||||||
*/
|
|
||||||
size -= start;
|
|
||||||
if (!start && !load_offset)
|
|
||||||
ERR("Relocatable ELF %s, but no load address. Loading at 0x0000000\n",
|
ERR("Relocatable ELF %s, but no load address. Loading at 0x0000000\n",
|
||||||
filename);
|
filename);
|
||||||
if (start && load_offset)
|
if (fmap.elf_start && load_offset)
|
||||||
{
|
{
|
||||||
WARN("Non-relocatable ELF %s, but load address of 0x%08lx supplied. "
|
WARN("Non-relocatable ELF %s, but load address of 0x%08lx supplied. "
|
||||||
"Assuming load address is corrupt\n", filename, load_offset);
|
"Assuming load address is corrupt\n", filename, load_offset);
|
||||||
@ -876,13 +1001,15 @@ static BOOL elf_load_file(struct process* pcs, const char* filename,
|
|||||||
|
|
||||||
if (elf_info->flags & ELF_INFO_DEBUG_HEADER)
|
if (elf_info->flags & ELF_INFO_DEBUG_HEADER)
|
||||||
{
|
{
|
||||||
for (i = 0; i < ehptr->e_shnum; i++)
|
const char* shstrtab = elf_map_section(&fmap, fmap.elfhdr.e_shstrndx);
|
||||||
|
if (shstrtab == NO_MAP) goto leave;
|
||||||
|
for (i = 0; i < fmap.elfhdr.e_shnum; i++)
|
||||||
{
|
{
|
||||||
if (strcmp(shstrtab + spnt[i].sh_name, ".dynamic") == 0 &&
|
if (strcmp(shstrtab + fmap.sect[i].shdr.sh_name, ".dynamic") == 0 &&
|
||||||
spnt[i].sh_type == SHT_DYNAMIC)
|
fmap.sect[i].shdr.sh_type == SHT_DYNAMIC)
|
||||||
{
|
{
|
||||||
Elf32_Dyn dyn;
|
Elf32_Dyn dyn;
|
||||||
char* ptr = (char*)spnt[i].sh_addr;
|
char* ptr = (char*)fmap.sect[i].shdr.sh_addr;
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -896,6 +1023,7 @@ static BOOL elf_load_file(struct process* pcs, const char* filename,
|
|||||||
elf_info->dbg_hdr_addr = dyn.d_un.d_ptr;
|
elf_info->dbg_hdr_addr = dyn.d_un.d_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
elf_unmap_section(&fmap, fmap.elfhdr.e_shstrndx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elf_info->flags & ELF_INFO_MODULE)
|
if (elf_info->flags & ELF_INFO_MODULE)
|
||||||
@ -904,8 +1032,8 @@ static BOOL elf_load_file(struct process* pcs, const char* filename,
|
|||||||
HeapAlloc(GetProcessHeap(), 0, sizeof(struct elf_module_info));
|
HeapAlloc(GetProcessHeap(), 0, sizeof(struct elf_module_info));
|
||||||
if (!elf_module_info) goto leave;
|
if (!elf_module_info) goto leave;
|
||||||
elf_info->module = module_new(pcs, filename, DMT_ELF,
|
elf_info->module = module_new(pcs, filename, DMT_ELF,
|
||||||
(load_offset) ? load_offset : start,
|
(load_offset) ? load_offset : fmap.elf_start,
|
||||||
size, 0, 0);
|
fmap.elf_size, 0, 0);
|
||||||
if (!elf_info->module)
|
if (!elf_info->module)
|
||||||
{
|
{
|
||||||
HeapFree(GetProcessHeap(), 0, elf_module_info);
|
HeapFree(GetProcessHeap(), 0, elf_module_info);
|
||||||
@ -919,15 +1047,14 @@ static BOOL elf_load_file(struct process* pcs, const char* filename,
|
|||||||
elf_info->module->module.SymType = SymDeferred;
|
elf_info->module->module.SymType = SymDeferred;
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
}
|
}
|
||||||
else ret = elf_load_debug_info(elf_info->module);
|
else ret = elf_load_debug_info(elf_info->module, &fmap);
|
||||||
|
|
||||||
elf_info->module->elf_info->elf_mark = 1;
|
elf_info->module->elf_info->elf_mark = 1;
|
||||||
elf_info->module->elf_info->elf_loader = 0;
|
elf_info->module->elf_info->elf_loader = 0;
|
||||||
} else ret = TRUE;
|
} else ret = TRUE;
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (addr != (char*)0xffffffff) munmap((void*)addr, statbuf.st_size);
|
elf_unmap_file(&fmap);
|
||||||
if (fd != -1) close(fd);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1005,33 +1132,23 @@ static BOOL elf_search_and_load_file(struct process* pcs, const char* filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* elf_synchronize_module_list
|
* elf_enum_modules_internal
|
||||||
*
|
*
|
||||||
* this functions rescans the debuggee module's list and synchronizes it with
|
* Enumerate ELF modules from a running process
|
||||||
* the one from 'pcs', ie:
|
|
||||||
* - if a module is in debuggee and not in pcs, it's loaded into pcs
|
|
||||||
* - if a module is in pcs and not in debuggee, it's unloaded from pcs
|
|
||||||
*/
|
*/
|
||||||
BOOL elf_synchronize_module_list(struct process* pcs)
|
static BOOL elf_enum_modules_internal(const struct process* pcs,
|
||||||
|
elf_enum_modules_cb cb, void* user)
|
||||||
{
|
{
|
||||||
struct r_debug dbg_hdr;
|
struct r_debug dbg_hdr;
|
||||||
void* lm_addr;
|
void* lm_addr;
|
||||||
struct link_map lm;
|
struct link_map lm;
|
||||||
char bufstr[256];
|
char bufstr[256];
|
||||||
struct elf_info elf_info;
|
|
||||||
struct module* module;
|
|
||||||
|
|
||||||
if (!pcs->dbg_hdr_addr ||
|
if (!pcs->dbg_hdr_addr ||
|
||||||
!ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
|
!ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
|
||||||
&dbg_hdr, sizeof(dbg_hdr), NULL))
|
&dbg_hdr, sizeof(dbg_hdr), NULL))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
for (module = pcs->lmodules; module; module = module->next)
|
|
||||||
{
|
|
||||||
if (module->type == DMT_ELF) module->elf_info->elf_mark = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
elf_info.flags = ELF_INFO_MODULE;
|
|
||||||
/* Now walk the linked list. In all known ELF implementations,
|
/* Now walk the linked list. In all known ELF implementations,
|
||||||
* the dynamic loader maintains this linked list for us. In some
|
* the dynamic loader maintains this linked list for us. In some
|
||||||
* cases the first entry doesn't appear with a name, in other cases it
|
* cases the first entry doesn't appear with a name, in other cases it
|
||||||
@ -1047,12 +1164,51 @@ BOOL elf_synchronize_module_list(struct process* pcs)
|
|||||||
ReadProcessMemory(pcs->handle, lm.l_name, bufstr, sizeof(bufstr), NULL))
|
ReadProcessMemory(pcs->handle, lm.l_name, bufstr, sizeof(bufstr), NULL))
|
||||||
{
|
{
|
||||||
bufstr[sizeof(bufstr) - 1] = '\0';
|
bufstr[sizeof(bufstr) - 1] = '\0';
|
||||||
elf_search_and_load_file(pcs, bufstr, (unsigned long)lm.l_addr,
|
if (!cb(bufstr, lm.l_addr, user)) break;
|
||||||
&elf_info);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct elf_sync
|
||||||
|
{
|
||||||
|
struct process* pcs;
|
||||||
|
struct elf_info elf_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
static BOOL elf_enum_sync_cb(const char* name, unsigned long addr, void* user)
|
||||||
|
{
|
||||||
|
struct elf_sync* es = user;
|
||||||
|
|
||||||
|
elf_search_and_load_file(es->pcs, name, addr, &es->elf_info);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* elf_synchronize_module_list
|
||||||
|
*
|
||||||
|
* this functions rescans the debuggee module's list and synchronizes it with
|
||||||
|
* the one from 'pcs', ie:
|
||||||
|
* - if a module is in debuggee and not in pcs, it's loaded into pcs
|
||||||
|
* - if a module is in pcs and not in debuggee, it's unloaded from pcs
|
||||||
|
*/
|
||||||
|
BOOL elf_synchronize_module_list(struct process* pcs)
|
||||||
|
{
|
||||||
|
struct module* module;
|
||||||
|
struct elf_sync es;
|
||||||
|
|
||||||
for (module = pcs->lmodules; module; module = module->next)
|
for (module = pcs->lmodules; module; module = module->next)
|
||||||
|
{
|
||||||
|
if (module->type == DMT_ELF) module->elf_info->elf_mark = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
es.pcs = pcs;
|
||||||
|
es.elf_info.flags = ELF_INFO_MODULE;
|
||||||
|
if (!elf_enum_modules_internal(pcs, elf_enum_sync_cb, &es))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
module = pcs->lmodules;
|
||||||
|
while (module)
|
||||||
{
|
{
|
||||||
if (module->type == DMT_ELF && !module->elf_info->elf_mark &&
|
if (module->type == DMT_ELF && !module->elf_info->elf_mark &&
|
||||||
!module->elf_info->elf_loader)
|
!module->elf_info->elf_loader)
|
||||||
@ -1061,10 +1217,39 @@ BOOL elf_synchronize_module_list(struct process* pcs)
|
|||||||
/* restart all over */
|
/* restart all over */
|
||||||
module = pcs->lmodules;
|
module = pcs->lmodules;
|
||||||
}
|
}
|
||||||
|
else module = module->next;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* elf_search_loader
|
||||||
|
*
|
||||||
|
* Lookup in a running ELF process the loader, and sets its ELF link
|
||||||
|
* address (for accessing the list of loaded .so libs) in pcs.
|
||||||
|
* If flags is ELF_INFO_MODULE, the module for the loader is also
|
||||||
|
* added as a module into pcs.
|
||||||
|
*/
|
||||||
|
static BOOL elf_search_loader(struct process* pcs, struct elf_info* elf_info)
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
const char* ptr;
|
||||||
|
|
||||||
|
/* All binaries are loaded with WINELOADER (if run from tree) or by the
|
||||||
|
* main executable (either wine-kthread or wine-pthread)
|
||||||
|
* FIXME: the heuristic used to know whether we need to load wine-pthread
|
||||||
|
* or wine-kthread is not 100% safe
|
||||||
|
*/
|
||||||
|
if ((ptr = getenv("WINELOADER")))
|
||||||
|
ret = elf_search_and_load_file(pcs, ptr, 0, elf_info);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = elf_search_and_load_file(pcs, "wine-kthread", 0, elf_info) ||
|
||||||
|
elf_search_and_load_file(pcs, "wine-pthread", 0, elf_info);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* elf_read_wine_loader_dbg_info
|
* elf_read_wine_loader_dbg_info
|
||||||
*
|
*
|
||||||
@ -1072,29 +1257,65 @@ BOOL elf_synchronize_module_list(struct process* pcs)
|
|||||||
*/
|
*/
|
||||||
BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
|
BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
|
||||||
{
|
{
|
||||||
const char* ptr;
|
|
||||||
struct elf_info elf_info;
|
struct elf_info elf_info;
|
||||||
BOOL ret;
|
|
||||||
|
|
||||||
elf_info.flags = ELF_INFO_DEBUG_HEADER | ELF_INFO_MODULE;
|
elf_info.flags = ELF_INFO_DEBUG_HEADER | ELF_INFO_MODULE;
|
||||||
/* All binaries are loaded with WINELOADER (if run from tree) or by the
|
if (!elf_search_loader(pcs, &elf_info)) return FALSE;
|
||||||
* main executable (either wine-kthread or wine-pthread)
|
|
||||||
* Note: the heuristic use to know whether we need to load wine-pthread or
|
|
||||||
* wine-kthread is not 100% safe
|
|
||||||
*/
|
|
||||||
if ((ptr = getenv("WINELOADER")))
|
|
||||||
ret = elf_search_and_load_file(pcs, ptr, 0, &elf_info);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = elf_search_and_load_file(pcs, "wine-kthread", 0, &elf_info) ||
|
|
||||||
elf_search_and_load_file(pcs, "wine-pthread", 0, &elf_info);
|
|
||||||
}
|
|
||||||
if (!ret) return FALSE;
|
|
||||||
elf_info.module->elf_info->elf_loader = 1;
|
elf_info.module->elf_info->elf_loader = 1;
|
||||||
strcpy(elf_info.module->module.ModuleName, "<wine-loader>");
|
strcpy(elf_info.module->module.ModuleName, "<wine-loader>");
|
||||||
return (pcs->dbg_hdr_addr = elf_info.dbg_hdr_addr) != 0;
|
return (pcs->dbg_hdr_addr = elf_info.dbg_hdr_addr) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* elf_enum_modules
|
||||||
|
*
|
||||||
|
* Enumerates the ELF loaded modules from a running target (hProc)
|
||||||
|
* This function doesn't require that someone has called SymInitialize
|
||||||
|
* on this very process.
|
||||||
|
*/
|
||||||
|
BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user)
|
||||||
|
{
|
||||||
|
struct process pcs;
|
||||||
|
struct elf_info elf_info;
|
||||||
|
|
||||||
|
pcs.handle = hProc;
|
||||||
|
elf_info.flags = ELF_INFO_DEBUG_HEADER;
|
||||||
|
if (!elf_search_loader(&pcs, &elf_info)) return FALSE;
|
||||||
|
return elf_enum_modules_internal(&pcs, cb, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct elf_load
|
||||||
|
{
|
||||||
|
struct process* pcs;
|
||||||
|
struct elf_info elf_info;
|
||||||
|
const char* name;
|
||||||
|
BOOL ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* elf_load_cb
|
||||||
|
*
|
||||||
|
* Callback for elf_load_module, used to walk the list of loaded
|
||||||
|
* modules.
|
||||||
|
*/
|
||||||
|
static BOOL elf_load_cb(const char* name, unsigned long addr, void* user)
|
||||||
|
{
|
||||||
|
struct elf_load* el = user;
|
||||||
|
const char* p;
|
||||||
|
|
||||||
|
/* memcmp is needed for matches when bufstr contains also version information
|
||||||
|
* el->name: libc.so, name: libc.so.6.0
|
||||||
|
*/
|
||||||
|
p = strrchr(name, '/');
|
||||||
|
if (!p++) p = name;
|
||||||
|
if (!memcmp(p, el->name, strlen(el->name)))
|
||||||
|
{
|
||||||
|
elf_search_and_load_file(el->pcs, name, addr, &el->elf_info);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* elf_load_module
|
* elf_load_module
|
||||||
*
|
*
|
||||||
@ -1102,56 +1323,35 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
|
|||||||
* Also, find module real name and load address from
|
* Also, find module real name and load address from
|
||||||
* the real loaded modules list in pcs address space
|
* the real loaded modules list in pcs address space
|
||||||
*/
|
*/
|
||||||
struct module* elf_load_module(struct process* pcs, const char* name)
|
struct module* elf_load_module(struct process* pcs, const char* name, DWORD addr)
|
||||||
{
|
{
|
||||||
struct elf_info elf_info;
|
struct elf_load el;
|
||||||
BOOL ret = FALSE;
|
|
||||||
const char* p;
|
|
||||||
const char* xname;
|
|
||||||
struct r_debug dbg_hdr;
|
|
||||||
void* lm_addr;
|
|
||||||
struct link_map lm;
|
|
||||||
char bufstr[256];
|
|
||||||
|
|
||||||
TRACE("(%p %s)\n", pcs, name);
|
TRACE("(%p %s)\n", pcs, name);
|
||||||
|
|
||||||
elf_info.flags = ELF_INFO_MODULE;
|
el.elf_info.flags = ELF_INFO_MODULE;
|
||||||
|
el.ret = FALSE;
|
||||||
|
|
||||||
|
if (pcs->dbg_hdr_addr) /* we're debugging a life target */
|
||||||
|
{
|
||||||
|
el.pcs = pcs;
|
||||||
/* do only the lookup from the filename, not the path (as we lookup module name
|
/* do only the lookup from the filename, not the path (as we lookup module name
|
||||||
* in the process' loaded module list)
|
* in the process' loaded module list)
|
||||||
*/
|
*/
|
||||||
xname = strrchr(name, '/');
|
el.name = strrchr(name, '/');
|
||||||
if (!xname++) xname = name;
|
if (!el.name++) el.name = name;
|
||||||
|
el.ret = FALSE;
|
||||||
|
|
||||||
if (!ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr), NULL))
|
if (!elf_enum_modules_internal(pcs, elf_load_cb, &el))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (lm_addr = (void*)dbg_hdr.r_map; lm_addr; lm_addr = (void*)lm.l_next)
|
|
||||||
{
|
|
||||||
if (!ReadProcessMemory(pcs->handle, lm_addr, &lm, sizeof(lm), NULL))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (lm.l_prev != NULL && /* skip first entry, normally debuggee itself */
|
|
||||||
lm.l_name != NULL &&
|
|
||||||
ReadProcessMemory(pcs->handle, lm.l_name, bufstr, sizeof(bufstr), NULL))
|
|
||||||
{
|
|
||||||
bufstr[sizeof(bufstr) - 1] = '\0';
|
|
||||||
/* memcmp is needed for matches when bufstr contains also version information
|
|
||||||
* name: libc.so, bufstr: libc.so.6.0
|
|
||||||
*/
|
|
||||||
p = strrchr(bufstr, '/');
|
|
||||||
if (!p++) p = bufstr;
|
|
||||||
if (!memcmp(p, xname, strlen(xname)))
|
|
||||||
{
|
|
||||||
ret = elf_search_and_load_file(pcs, bufstr,
|
|
||||||
(unsigned long)lm.l_addr, &elf_info);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else if (addr)
|
||||||
|
{
|
||||||
|
el.ret = elf_search_and_load_file(pcs, name, addr, &el.elf_info);
|
||||||
}
|
}
|
||||||
}
|
if (!el.ret) return NULL;
|
||||||
if (!lm_addr || !ret) return NULL;
|
assert(el.elf_info.module);
|
||||||
assert(elf_info.module);
|
return el.elf_info.module;
|
||||||
return elf_info.module;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* !__ELF__ */
|
#else /* !__ELF__ */
|
||||||
@ -1166,7 +1366,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct module* elf_load_module(struct process* pcs, const char* name)
|
struct module* elf_load_module(struct process* pcs, const char* name, DWORD addr)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -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,7 +221,7 @@ 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;
|
||||||
}
|
}
|
||||||
@ -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,7 +404,9 @@ 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)
|
||||||
|
{
|
||||||
|
if (pcs->dbg_hdr_addr)
|
||||||
{
|
{
|
||||||
IMAGE_DOS_HEADER dos;
|
IMAGE_DOS_HEADER dos;
|
||||||
IMAGE_NT_HEADERS nth;
|
IMAGE_NT_HEADERS nth;
|
||||||
@ -419,6 +421,8 @@ struct module* pe_load_module_from_pcs(struct process* pcs, const char* name,
|
|||||||
module = module_new(pcs, name, DMT_PE, base, size,
|
module = module_new(pcs, name, DMT_PE, base, size,
|
||||||
nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum);
|
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)
|
||||||
|
{
|
||||||
|
FIXME("UNDF: curr_func %s\n", curr_func->hash_elt.name);
|
||||||
stabs_finalize_function(module, curr_func, 0); /* FIXME */
|
stabs_finalize_function(module, curr_func, 0); /* FIXME */
|
||||||
curr_func = NULL;
|
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…
x
Reference in New Issue
Block a user