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);
......
......@@ -89,6 +89,25 @@ struct elf_info
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 hash_table_elt ht_elt;
......@@ -106,14 +125,127 @@ struct thunk_area
};
/******************************************************************
* 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
*
* creating an internal hash table to ease use ELF symtab information lookup
*/
static void elf_hash_symtab(const struct module* module, struct pool* pool,
struct hash_table* ht_symtab, const char* map_addr,
const Elf32_Shdr* symtab, const Elf32_Shdr* strtab,
unsigned num_areas, struct thunk_area* thunks)
struct hash_table* ht_symtab, struct elf_file_map* fmap,
int symtab_idx, struct thunk_area* thunks)
{
int i, j, nsym;
const char* strp;
......@@ -123,11 +255,13 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
const Elf32_Sym* symp;
struct symtab_elt* ste;
symp = (const Elf32_Sym*)(map_addr + symtab->sh_offset);
nsym = symtab->sh_size / sizeof(*symp);
strp = (const char*)(map_addr + strtab->sh_offset);
symp = (const Elf32_Sym*)elf_map_section(fmap, symtab_idx);
strp = elf_map_section(fmap, fmap->sect[symtab_idx].shdr.sh_link);
if (symp == NO_MAP || strp == NO_MAP) return;
nsym = fmap->sect[symtab_idx].shdr.sh_size / sizeof(*symp);
for (j = 0; j < num_areas; j++)
for (j = 0; thunks[j].symname; j++)
thunks[j].rva_start = thunks[j].rva_end = 0;
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
* 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;
}
......@@ -147,7 +284,7 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
filename = symname;
continue;
}
for (j = 0; j < num_areas; j++)
for (j = 0; thunks[j].symname; j++)
{
if (!strcmp(symname, thunks[j].symname))
{
......@@ -156,7 +293,7 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
break;
}
}
if (j < num_areas) continue;
if (thunks[j].symname) continue;
/* FIXME: we don't need to handle them (GCC internals)
* Moreover, they screw up our symbol lookup :-/
......@@ -165,7 +302,8 @@ static void elf_hash_symtab(const struct module* module, struct pool* pool,
continue;
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
* that we can have several such variables with same name in
* 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)
*/
ptr = symname + strlen(symname) - 1;
ste->ht_elt.name = symname;
if (isdigit(*ptr))
{
while (*ptr >= '0' && *ptr <= '9' && ptr >= symname) ptr--;
while (isdigit(*ptr) && ptr >= symname) ptr--;
if (ptr > symname && *ptr == '.')
{
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;
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))
{
FIXME("Couldn't find symbol %s.%s in symtab\n",
FIXME("Couldn't find symbol %s!%s in symtab\n",
module->module.ModuleName, name);
return NULL;
}
......@@ -289,10 +430,20 @@ static void elf_finish_stabs_info(struct module* module, struct hash_table* symt
((struct symt_function*)sym)->container);
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 +
symp->st_value;
((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;
case SymTagData:
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);
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 +
symp->st_value;
((struct symt_data*)sym)->kind = (ELF32_ST_BIND(symp->st_info) == STB_LOCAL) ?
DataIsFileStatic : DataIsGlobal;
}
} else FIXME("Couldn't find %s!%s\n", module->module.ModuleName, sym->hash_elt.name);
break;
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)
* 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,
addr, ste->symp->st_size, NULL);
}
else
{
break;
case STT_OBJECT:
symt_new_global_variable(module, compiland, ste->ht_elt.name,
ELF32_ST_BIND(ste->symp->st_info) == STB_LOCAL,
addr, ste->symp->st_size, NULL);
break;
default:
FIXME("Shouldn't happen\n");
break;
}
/* FIXME: this is a hack !!!
* 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_DATAKIND, &kind);
#if 0
/* If none of symbols has a correct size, we consider they are both markers
* Hence, we can silence this warning
* 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,
module->addr_sorttab[idx]->hash_elt.name,
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. */
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))
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,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
size_t i;
DWORD crc = ~0;
for(i = 0; i < len; i++)
crc = UPDC32(buf[i], crc);
int i, r;
unsigned char buffer[256];
DWORD crc = ~0;
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;
#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
* relocation is performed. crc optionally points to the CRC of the debug file
* to load.
* relocation is performed.
* CRC is checked if fmap->with_crc is TRUE
* returns
* 0 if the file doesn't contain symbolic info (or this info cannot be
* read or parsed)
* 1 on success
*/
static BOOL elf_load_debug_info_from_file(
struct module* module, const char* file, struct pool* pool,
struct hash_table* ht_symtab, const DWORD *crc)
static BOOL elf_load_debug_info_from_map(struct module* module,
struct elf_file_map* fmap,
struct pool* pool,
struct hash_table* ht_symtab)
{
BOOL ret = FALSE;
char* addr = (char*)0xffffffff;
int fd = -1;
struct stat statbuf;
const Elf32_Ehdr* ehptr;
const Elf32_Shdr* spnt;
const char* shstrtab;
int i;
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_text_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)
{
ERR("Bad elf module '%s'\n", module->module.LoadedImageName);
return FALSE;
}
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)))
if (fmap->with_crc && (fmap->crc != calc_crc32(fmap)))
{
ERR("Bad CRC for file %s\n", file);
ERR("Bad CRC for module %s (got %08lx while expecting %08lx)\n",
module->module.ImageName, calc_crc32(fmap), fmap->crc);
/* 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
* table.
*/
ehptr = (Elf32_Ehdr*)addr;
spnt = (Elf32_Shdr*)(addr + ehptr->e_shoff);
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
shstrtab = elf_map_section(fmap, fmap->elfhdr.e_shstrndx);
if (shstrtab == NO_MAP) return FALSE;
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;
if (strcmp(shstrtab + spnt[i].sh_name, ".stabstr") == 0)
if (strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".stabstr") == 0)
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;
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;
if ((strcmp(shstrtab + spnt[i].sh_name, ".symtab") == 0) &&
(spnt[i].sh_type == SHT_SYMTAB))
if ((strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".symtab") == 0) &&
(fmap->sect[i].shdr.sh_type == SHT_SYMTAB))
symtab_sect = i;
if ((strcmp(shstrtab + spnt[i].sh_name, ".dynsym") == 0) &&
(spnt[i].sh_type == SHT_DYNSYM))
if ((strcmp(shstrtab + fmap->sect[i].shdr.sh_name, ".dynsym") == 0) &&
(fmap->sect[i].shdr.sh_type == SHT_DYNSYM))
dynsym_sect = i;
}
elf_unmap_section(fmap, fmap->elfhdr.e_shstrndx);
shstrtab = NULL;
if (symtab_sect == -1)
{
......@@ -688,31 +828,38 @@ static BOOL elf_load_debug_info_from_file(
* section instead. It'll contain less (relevant) information,
* but it'll be better than nothing
*/
if (dynsym_sect == -1) goto leave;
if (dynsym_sect == -1) return FALSE;
symtab_sect = dynsym_sect;
}
module->module.SymType = SymExport;
/* create a hash table for the symtab */
elf_hash_symtab(module, pool, ht_symtab, addr,
spnt + symtab_sect, spnt + spnt[symtab_sect].sh_link,
sizeof(thunks) / sizeof(thunks[0]), thunks);
elf_hash_symtab(module, pool, ht_symtab, fmap, symtab_sect, thunks);
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
{
if (stab_sect != -1 && stabstr_sect != -1)
{
/* OK, now just parse all of the stabs. */
ret = stabs_parse(module, module->elf_info->elf_addr,
addr + spnt[stab_sect].sh_offset,
spnt[stab_sect].sh_size,
addr + spnt[stabstr_sect].sh_offset,
spnt[stabstr_sect].sh_size);
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. */
ret = stabs_parse(module, module->elf_info->elf_addr,
stab, fmap->sect[stab_sect].shdr.sh_size,
stabstr, fmap->sect[stabstr_sect].shdr.sh_size);
}
elf_unmap_section(fmap, stab_sect);
elf_unmap_section(fmap, stabstr_sect);
if (!ret)
{
WARN("Couldn't read correctly read stabs\n");
goto leave;
WARN("Couldn't correctly read stabs\n");
return FALSE;
}
/* and fill in the missing information for stabs */
elf_finish_stabs_info(module, ht_symtab);
......@@ -724,14 +871,25 @@ static BOOL elf_load_debug_info_from_file(
}
else if (debuglink_sect != -1)
{
DWORD crc;
const char * file = (const char *)(addr + spnt[debuglink_sect].sh_offset);
/* crc is stored after the null terminated file string rounded
* up to the next 4 byte boundary */
crc = *(const DWORD *)(file + ((DWORD_PTR)(strlen(file) + 4) & ~3));
ret = elf_load_debug_info_from_file(module, file, pool, ht_symtab, &crc);
if (!ret)
WARN("Couldn't load linked debug file %s\n", file);
const char* dbg_link;
struct elf_file_map fmap_link;
dbg_link = elf_map_section(fmap, debuglink_sect);
/* The content of a debug link section is:
* 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)
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>") ||
......@@ -745,10 +903,6 @@ static BOOL elf_load_debug_info_from_file(
/* add all the public symbols from symtab */
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;
}
......@@ -757,20 +911,32 @@ leave:
*
* 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;
struct pool pool;
struct hash_table ht_symtab;
BOOL ret = TRUE;
struct pool pool;
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);
hash_table_init(&pool, &ht_symtab, 256);
ret = elf_load_debug_info_from_file(module,
module->module.LoadedImageName, &pool, &ht_symtab, NULL);
if (!fmap)
{
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);
if (fmap == &my_fmap) elf_unmap_file(fmap);
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,
unsigned long load_offset, struct elf_info* elf_info)
{
static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
BOOL ret = FALSE;
const char* addr = (char*)0xffffffff;
int fd = -1;
struct stat statbuf;
const Elf32_Ehdr* ehptr;
const Elf32_Shdr* spnt;
const Elf32_Phdr* ppnt;
const char* shstrtab;
struct elf_file_map fmap;
int i;
DWORD size, start;
unsigned tmp, page_mask = getpagesize() - 1;
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 (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;
if (!elf_map_file(filename, &fmap)) goto leave;
/* Next, we need to find a few of the internal ELF headers within
* this thing. We need the main executable header, and the section
* table.
*/
ehptr = (const Elf32_Ehdr*)addr;
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)
if (!fmap.elf_start && !load_offset)
ERR("Relocatable ELF %s, but no load address. Loading at 0x0000000\n",
filename);
if (start && load_offset)
if (fmap.elf_start && load_offset)
{
WARN("Non-relocatable ELF %s, but load address of 0x%08lx supplied. "
"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)
{
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 &&
spnt[i].sh_type == SHT_DYNAMIC)
if (strcmp(shstrtab + fmap.sect[i].shdr.sh_name, ".dynamic") == 0 &&
fmap.sect[i].shdr.sh_type == SHT_DYNAMIC)
{
Elf32_Dyn dyn;
char* ptr = (char*)spnt[i].sh_addr;
char* ptr = (char*)fmap.sect[i].shdr.sh_addr;
unsigned long len;
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_unmap_section(&fmap, fmap.elfhdr.e_shstrndx);
}
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));
if (!elf_module_info) goto leave;
elf_info->module = module_new(pcs, filename, DMT_ELF,
(load_offset) ? load_offset : start,
size, 0, 0);
(load_offset) ? load_offset : fmap.elf_start,
fmap.elf_size, 0, 0);
if (!elf_info->module)
{
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;
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_loader = 0;
} else ret = TRUE;
leave:
if (addr != (char*)0xffffffff) munmap((void*)addr, statbuf.st_size);
if (fd != -1) close(fd);
elf_unmap_file(&fmap);
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
* 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
* Enumerate ELF modules from a running process
*/
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;
void* lm_addr;
struct link_map lm;
char bufstr[256];
struct elf_info elf_info;
struct module* module;
if (!pcs->dbg_hdr_addr ||
!ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr,
&dbg_hdr, sizeof(dbg_hdr), NULL))
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,
* 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
......@@ -1047,13 +1164,52 @@ BOOL elf_synchronize_module_list(struct process* pcs)
ReadProcessMemory(pcs->handle, lm.l_name, bufstr, sizeof(bufstr), NULL))
{
bufstr[sizeof(bufstr) - 1] = '\0';
elf_search_and_load_file(pcs, bufstr, (unsigned long)lm.l_addr,
&elf_info);
if (!cb(bufstr, lm.l_addr, user)) break;
}
}
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)
{
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 &&
!module->elf_info->elf_loader)
{
......@@ -1061,97 +1217,141 @@ BOOL elf_synchronize_module_list(struct process* pcs)
/* restart all over */
module = pcs->lmodules;
}
else module = module->next;
}
return TRUE;
}
/******************************************************************
* elf_read_wine_loader_dbg_info
* elf_search_loader
*
* Try to find a decent wine executable which could have loaded the debuggee
* 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.
*/
BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
static BOOL elf_search_loader(struct process* pcs, struct elf_info* elf_info)
{
const char* ptr;
struct elf_info elf_info;
BOOL ret;
const char* ptr;
elf_info.flags = ELF_INFO_DEBUG_HEADER | ELF_INFO_MODULE;
/* All binaries are loaded with WINELOADER (if run from tree) or by the
* 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
* 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);
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);
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;
return ret;
}
/******************************************************************
* elf_read_wine_loader_dbg_info
*
* Try to find a decent wine executable which could have loaded the debuggee
*/
BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
{
struct elf_info elf_info;
elf_info.flags = ELF_INFO_DEBUG_HEADER | ELF_INFO_MODULE;
if (!elf_search_loader(pcs, &elf_info)) return FALSE;
elf_info.module->elf_info->elf_loader = 1;
strcpy(elf_info.module->module.ModuleName, "<wine-loader>");
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
*
* loads an ELF module and stores it in process' module list
* Also, find module real name and load address from
* 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;
BOOL ret = FALSE;
const char* p;
const char* xname;
struct r_debug dbg_hdr;
void* lm_addr;
struct link_map lm;
char bufstr[256];
struct elf_load el;
TRACE("(%p %s)\n", pcs, name);
elf_info.flags = ELF_INFO_MODULE;
/* do only the lookup from the filename, not the path (as we lookup module name
* in the process' loaded module list)
*/
xname = strrchr(name, '/');
if (!xname++) xname = name;
if (!ReadProcessMemory(pcs->handle, (void*)pcs->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr), NULL))
return NULL;
el.elf_info.flags = ELF_INFO_MODULE;
el.ret = FALSE;
for (lm_addr = (void*)dbg_hdr.r_map; lm_addr; lm_addr = (void*)lm.l_next)
if (pcs->dbg_hdr_addr) /* we're debugging a life target */
{
if (!ReadProcessMemory(pcs->handle, lm_addr, &lm, sizeof(lm), NULL))
return NULL;
el.pcs = pcs;
/* do only the lookup from the filename, not the path (as we lookup module name
* in the process' loaded module list)
*/
el.name = strrchr(name, '/');
if (!el.name++) el.name = name;
el.ret = FALSE;
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;
}
}
if (!elf_enum_modules_internal(pcs, elf_load_cb, &el))
return NULL;
}
else if (addr)
{
el.ret = elf_search_and_load_file(pcs, name, addr, &el.elf_info);
}
if (!lm_addr || !ret) return NULL;
assert(elf_info.module);
return elf_info.module;
if (!el.ret) return NULL;
assert(el.elf_info.module);
return el.elf_info.module;
}
#else /* !__ELF__ */
......@@ -1166,7 +1366,7 @@ BOOL elf_read_wine_loader_dbg_info(struct process* pcs)
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;
}
......
......@@ -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