#include "dbghelp_private.h"
#include "psapi.h"
-#include "winreg.h"
#include "winternl.h"
#include "wine/debug.h"
const WCHAR S_ElfW[] = {'<','e','l','f','>','\0'};
const WCHAR S_WineLoaderW[] = {'<','w','i','n','e','-','l','o','a','d','e','r','>','\0'};
static const WCHAR S_DotSoW[] = {'.','s','o','\0'};
+static const WCHAR S_DotDylibW[] = {'.','d','y','l','i','b','\0'};
static const WCHAR S_DotPdbW[] = {'.','p','d','b','\0'};
-const WCHAR S_WinePThreadW[] = {'w','i','n','e','-','p','t','h','r','e','a','d','\0'};
-const WCHAR S_WineKThreadW[] = {'w','i','n','e','-','k','t','h','r','e','a','d','\0'};
+static const WCHAR S_DotDbgW[] = {'.','d','b','g','\0'};
const WCHAR S_SlashW[] = {'/','\0'};
static const WCHAR S_AcmW[] = {'.','a','c','m','\0'};
static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size)
{
+ const WCHAR *loader = get_wine_loader_name();
const WCHAR *ptr, *endptr;
size_t len, l;
out[len] = '\0';
if (len > 4 && (l = match_ext(out, len)))
out[len - l] = '\0';
- else if (len > 12 &&
- (!strcmpiW(out + len - 12, S_WinePThreadW) ||
- !strcmpiW(out + len - 12, S_WineKThreadW)))
+ else if (len > strlenW(loader) && !strcmpiW(out + len - strlenW(loader), loader))
lstrcpynW(out, S_WineLoaderW, size);
else
{
NULL, NULL);
}
+const WCHAR *get_wine_loader_name(void)
+{
+ static const int is_win64 = sizeof(void *) > sizeof(int); /* FIXME: should depend on target process */
+ static const WCHAR wineW[] = {'w','i','n','e',0};
+ static const WCHAR suffixW[] = {'6','4',0};
+ static const WCHAR *loader;
+
+ if (!loader)
+ {
+ WCHAR *p, *buffer;
+ const char *ptr;
+
+ /* All binaries are loaded with WINELOADER (if run from tree) or by the
+ * main executable
+ */
+ if ((ptr = getenv("WINELOADER")))
+ {
+ DWORD len = 2 + MultiByteToWideChar( CP_UNIXCP, 0, ptr, -1, NULL, 0 );
+ buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
+ MultiByteToWideChar( CP_UNIXCP, 0, ptr, -1, buffer, len );
+ }
+ else
+ {
+ buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(wineW) + 2 * sizeof(WCHAR) );
+ strcpyW( buffer, wineW );
+ }
+ p = buffer + strlenW( buffer ) - strlenW( suffixW );
+ if (p > buffer && !strcmpW( p, suffixW ))
+ {
+ if (!is_win64) *p = 0;
+ }
+ else if (is_win64) strcatW( buffer, suffixW );
+
+ TRACE( "returning %s\n", debugstr_w(buffer) );
+ loader = buffer;
+ }
+ return loader;
+}
+
static const char* get_module_type(enum module_type type, BOOL virtual)
{
switch (type)
{
case DMT_ELF: return virtual ? "Virtual ELF" : "ELF";
case DMT_PE: return virtual ? "Virtual PE" : "PE";
+ case DMT_MACHO: return virtual ? "Virtual Mach-O" : "Mach-O";
default: return "---";
}
}
*/
struct module* module_new(struct process* pcs, const WCHAR* name,
enum module_type type, BOOL virtual,
- unsigned long mod_addr, unsigned long size,
+ DWORD64 mod_addr, DWORD64 size,
unsigned long stamp, unsigned long checksum)
{
struct module* module;
+ unsigned i;
- assert(type == DMT_ELF || type == DMT_PE);
- if (!(module = HeapAlloc(GetProcessHeap(), 0, sizeof(*module))))
+ assert(type == DMT_ELF || type == DMT_PE || type == DMT_MACHO);
+ if (!(module = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*module))))
return NULL;
- memset(module, 0, sizeof(*module));
-
module->next = pcs->lmodules;
pcs->lmodules = module;
- TRACE("=> %s %08lx-%08lx %s\n",
- get_module_type(type, virtual), mod_addr, mod_addr + size,
+ TRACE("=> %s %s-%s %s\n",
+ get_module_type(type, virtual),
+ wine_dbgstr_longlong(mod_addr), wine_dbgstr_longlong(mod_addr + size),
debugstr_w(name));
pool_init(&module->pool, 65536);
+ module->process = pcs;
module->module.SizeOfStruct = sizeof(module->module);
module->module.BaseOfImage = mod_addr;
module->module.ImageSize = size;
module->module.SourceIndexed = FALSE;
module->module.Publics = FALSE;
+ module->reloc_delta = 0;
module->type = type;
module->is_virtual = virtual ? TRUE : FALSE;
+ for (i = 0; i < DFI_LAST; i++) module->format_info[i] = NULL;
module->sortlist_valid = FALSE;
+ module->sorttab_size = 0;
module->addr_sorttab = NULL;
+ module->num_sorttab = 0;
+ module->num_symbols = 0;
+
+ vector_init(&module->vsymt, sizeof(struct symt*), 128);
/* FIXME: this seems a bit too high (on a per module basis)
* need some statistics about this
*/
module->sources_used = 0;
module->sources_alloc = 0;
module->sources = 0;
+ wine_rb_init(&module->sources_offsets_tree, &source_rb_functions);
return module;
}
* module_find_by_name
*
*/
-struct module* module_find_by_name(const struct process* pcs, const WCHAR* name)
+static struct module* module_find_by_name(const struct process* pcs, const WCHAR* name)
{
struct module* module;
* module_get_container
*
*/
-struct module* module_get_container(const struct process* pcs,
+static struct module* module_get_container(const struct process* pcs,
const struct module* inner)
{
struct module* module;
else switch (pair->effective->type)
{
case DMT_ELF:
- ret = elf_load_debug_info(pair->effective, NULL);
+ ret = elf_load_debug_info(pair->effective);
break;
case DMT_PE:
idslW64.SizeOfStruct = sizeof(idslW64);
idslW64.CheckSum = pair->effective->module.CheckSum;
idslW64.TimeDateStamp = pair->effective->module.TimeDateStamp;
memcpy(idslW64.FileName, pair->effective->module.ImageName,
- sizeof(idslW64.FileName));
+ sizeof(pair->effective->module.ImageName));
idslW64.Reparse = FALSE;
idslW64.hFile = INVALID_HANDLE_VALUE;
ret ? CBA_DEFERRED_SYMBOL_LOAD_COMPLETE : CBA_DEFERRED_SYMBOL_LOAD_FAILURE,
&idslW64);
break;
+ case DMT_MACHO:
+ ret = macho_load_debug_info(pair->effective, NULL);
+ break;
default:
ret = FALSE;
break;
if (type == DMT_UNKNOWN)
{
if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
- (module = module_find_by_addr(pcs, addr, DMT_ELF)))
+ (module = module_find_by_addr(pcs, addr, DMT_ELF)) ||
+ (module = module_find_by_addr(pcs, addr, DMT_MACHO)))
return module;
}
else
}
/******************************************************************
- * module_is_elf_container_loaded
+ * module_is_container_loaded
*
- * checks whether the ELF container, for a (supposed) PE builtin is
+ * checks whether the native container, for a (supposed) PE builtin is
* already loaded
*/
-static BOOL module_is_elf_container_loaded(struct process* pcs,
- const WCHAR* ImageName, DWORD base)
+static BOOL module_is_container_loaded(const struct process* pcs,
+ const WCHAR* ImageName, DWORD64 base)
{
size_t len;
struct module* module;
- LPCWSTR filename, modname;
+ PCWSTR filename, modname;
if (!base) return FALSE;
filename = get_filename(ImageName, NULL);
for (module = pcs->lmodules; module; module = module->next)
{
- if (module->type == DMT_ELF &&
+ if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
base >= module->module.BaseOfImage &&
base < module->module.BaseOfImage + module->module.ImageSize)
{
*/
enum module_type module_get_type_by_name(const WCHAR* name)
{
- const WCHAR*ptr;
- int len = strlenW(name);
+ int loader_len, len = strlenW(name);
+ const WCHAR *loader;
- /* check for terminating .so or .so.[digit] */
- ptr = strrchrW(name, '.');
- if (ptr)
+ /* Skip all version extensions (.[digits]) regex: "(\.\d+)*$" */
+ do
{
- if (!strcmpW(ptr, S_DotSoW) ||
- (isdigit(ptr[1]) && !ptr[2] && ptr >= name + 3 && !memcmp(ptr - 3, S_DotSoW, 3)))
- return DMT_ELF;
- else if (!strcmpiW(ptr, S_DotPdbW))
- return DMT_PDB;
- }
- /* wine-[kp]thread is also an ELF module */
- else if (((len > 12 && name[len - 13] == '/') || len == 12) &&
- (!strcmpiW(name + len - 12, S_WinePThreadW) ||
- !strcmpiW(name + len - 12, S_WineKThreadW)))
+ int i = len;
+
+ while (i && isdigit(name[i - 1])) i--;
+
+ if (i && name[i - 1] == '.')
+ len = i - 1;
+ else
+ break;
+ } while (len);
+
+ /* check for terminating .so or .so.[digit] */
+ /* FIXME: Can't rely solely on extension; have to check magic or
+ * stop using .so on Mac OS X. For now, base on platform. */
+ if (len > 3 && !memcmp(name + len - 3, S_DotSoW, 3))
+#ifdef __APPLE__
+ return DMT_MACHO;
+#else
+ return DMT_ELF;
+#endif
+
+ if (len > 6 && !strncmpiW(name + len - 6, S_DotDylibW, 6))
+ return DMT_MACHO;
+
+ if (len > 4 && !strncmpiW(name + len - 4, S_DotPdbW, 4))
+ return DMT_PDB;
+
+ if (len > 4 && !strncmpiW(name + len - 4, S_DotDbgW, 4))
+ return DMT_DBG;
+
+ /* wine is also a native module (Mach-O on Mac OS X, ELF elsewhere) */
+ loader = get_wine_loader_name();
+ loader_len = strlenW( loader );
+ if ((len == loader_len || (len > loader_len && name[len - loader_len - 1] == '/')) &&
+ !strcmpiW(name + len - loader_len, loader))
{
+#ifdef __APPLE__
+ return DMT_MACHO;
+#else
return DMT_ELF;
+#endif
}
return DMT_PE;
}
+/******************************************************************
+ * refresh_module_list
+ */
+static BOOL refresh_module_list(struct process* pcs)
+{
+ /* force transparent ELF and Mach-O loading / unloading */
+ return elf_synchronize_module_list(pcs) || macho_synchronize_module_list(pcs);
+}
+
/***********************************************************************
* SymLoadModule (DBGHELP.@)
*/
-DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, const char* ImageName,
- const char* ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
+DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
+ PCSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
{
return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll,
SizeOfDll, NULL, 0);
PCSTR ModuleName, DWORD64 BaseOfDll, DWORD DllSize,
PMODLOAD_DATA Data, DWORD Flags)
{
- LPWSTR wImageName, wModuleName;
+ PWSTR wImageName, wModuleName;
unsigned len;
DWORD64 ret;
if (Flags & SLMFLAG_VIRTUAL)
{
+ if (!wImageName) return FALSE;
module = module_new(pcs, wImageName, module_get_type_by_name(wImageName),
- TRUE, (DWORD)BaseOfDll, SizeOfDll, 0, 0);
+ TRUE, BaseOfDll, SizeOfDll, 0, 0);
if (!module) return FALSE;
if (wModuleName) module_set_module(module, wModuleName);
module->module.SymType = SymVirtual;
if (Flags & ~(SLMFLAG_VIRTUAL))
FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName));
- /* force transparent ELF loading / unloading */
- elf_synchronize_module_list(pcs);
+ refresh_module_list(pcs);
/* this is a Wine extension to the API just to redo the synchronisation */
if (!wImageName && !hFile) return 0;
if (wImageName)
{
module = module_is_already_loaded(pcs, wImageName);
- if (!module && module_is_elf_container_loaded(pcs, wImageName, BaseOfDll))
+ if (!module && module_is_container_loaded(pcs, wImageName, BaseOfDll))
{
/* force the loading of DLL as builtin */
module = pe_load_builtin_module(pcs, wImageName, BaseOfDll, SizeOfDll);
if (!module)
{
/* otherwise, try a regular PE module */
- if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)))
+ if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)) &&
+ wImageName)
{
- /* and finally and ELF module */
- if (module_get_type_by_name(wImageName) == DMT_ELF)
- module = elf_load_module(pcs, wImageName, BaseOfDll);
+ /* and finally an ELF or Mach-O module */
+ switch (module_get_type_by_name(wImageName))
+ {
+ case DMT_ELF:
+ module = elf_load_module(pcs, wImageName, BaseOfDll);
+ break;
+ case DMT_MACHO:
+ module = macho_load_module(pcs, wImageName, BaseOfDll);
+ break;
+ default:
+ /* Ignored */
+ break;
+ }
}
}
if (!module)
*/
if (wModuleName)
module_set_module(module, wModuleName);
- lstrcpynW(module->module.ImageName, wImageName,
- sizeof(module->module.ImageName) / sizeof(CHAR));
+ if (wImageName)
+ lstrcpynW(module->module.ImageName, wImageName,
+ sizeof(module->module.ImageName) / sizeof(WCHAR));
return module->module.BaseOfImage;
}
*/
BOOL module_remove(struct process* pcs, struct module* module)
{
+ struct module_format*modfmt;
struct module** p;
+ unsigned i;
TRACE("%s (%p)\n", debugstr_w(module->module.ModuleName), module);
+
+ for (i = 0; i < DFI_LAST; i++)
+ {
+ if ((modfmt = module->format_info[i]) && modfmt->remove)
+ modfmt->remove(pcs, module->format_info[i]);
+ }
hash_table_destroy(&module->ht_symbols);
hash_table_destroy(&module->ht_types);
- HeapFree(GetProcessHeap(), 0, (char*)module->sources);
+ wine_rb_destroy(&module->sources_offsets_tree, NULL, NULL);
+ HeapFree(GetProcessHeap(), 0, module->sources);
HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
- HeapFree(GetProcessHeap(), 0, module->dwarf2_info);
pool_destroy(&module->pool);
/* native dbghelp doesn't invoke registered callback(,CBA_SYMBOLS_UNLOADED,) here
* so do we
char module[MAX_PATH];
};
-static BOOL CALLBACK enum_modW64_32(PWSTR name, DWORD64 base, PVOID user)
+static BOOL CALLBACK enum_modW64_32(PCWSTR name, DWORD64 base, PVOID user)
{
struct enum_modW64_32* x = user;
char module[MAX_PATH];
};
-static BOOL CALLBACK enum_modW64_64(PWSTR name, DWORD64 base, PVOID user)
+static BOOL CALLBACK enum_modW64_64(PCWSTR name, DWORD64 base, PVOID user)
{
struct enum_modW64_64* x = user;
for (module = pcs->lmodules; module; module = module->next)
{
- if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type == DMT_ELF)
+ if (!(dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) &&
+ (module->type == DMT_ELF || module->type == DMT_MACHO))
continue;
if (!EnumModulesCallback(module->module.ModuleName,
module->module.BaseOfImage, UserContext))
char module[MAX_PATH];
};
-static BOOL CALLBACK enum_load_modW64_64(PWSTR name, DWORD64 base, ULONG size,
+static BOOL CALLBACK enum_load_modW64_64(PCWSTR name, DWORD64 base, ULONG size,
PVOID user)
{
struct enum_load_modW64_64* x = user;
char module[MAX_PATH];
};
-static BOOL CALLBACK enum_load_modW64_32(PWSTR name, DWORD64 base, ULONG size,
+static BOOL CALLBACK enum_load_modW64_32(PCWSTR name, DWORD64 base, ULONG size,
PVOID user)
{
struct enum_load_modW64_32* x = user;
IMAGEHLP_MODULE64 mi64;
IMAGEHLP_MODULEW64 miw64;
- if (sizeof(mi64) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
+ if (sizeof(mi64) < ModuleInfo->SizeOfStruct)
+ {
+ SetLastError(ERROR_MOD_NOT_FOUND); /* NOTE: native returns this error */
+ WARN("Wrong size %u\n", ModuleInfo->SizeOfStruct);
+ return FALSE;
+ }
miw64.SizeOfStruct = sizeof(miw64);
if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
*/
DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
{
- struct process* pcs = process_find_by_handle(hProcess);
- struct module* module;
+ DWORD64 ret;
- if (!pcs) return 0;
- module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
- if (!module) return 0;
- return module->module.BaseOfImage;
+ ret = SymGetModuleBase64(hProcess, dwAddr);
+ return validate_addr64(ret) ? ret : 0;
}
/***********************************************************************
*/
DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr)
{
- if (!validate_addr64(dwAddr)) return 0;
- return SymGetModuleBase(hProcess, (DWORD)dwAddr);
+ struct process* pcs = process_find_by_handle(hProcess);
+ struct module* module;
+
+ if (!pcs) return 0;
+ module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
+ if (!module) return 0;
+ return module->module.BaseOfImage;
}
/******************************************************************
void module_reset_debug_info(struct module* module)
{
module->sortlist_valid = TRUE;
+ module->sorttab_size = 0;
module->addr_sorttab = NULL;
+ module->num_sorttab = module->num_symbols = 0;
hash_table_destroy(&module->ht_symbols);
module->ht_symbols.num_buckets = 0;
module->ht_symbols.buckets = NULL;
module->sources_used = module->sources_alloc = 0;
module->sources = NULL;
}
+
+/******************************************************************
+ * SymRefreshModuleList (DBGHELP.@)
+ */
+BOOL WINAPI SymRefreshModuleList(HANDLE hProcess)
+{
+ struct process* pcs;
+
+ TRACE("(%p)\n", hProcess);
+
+ if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
+
+ return refresh_module_list(pcs);
+}
+
+/***********************************************************************
+ * SymFunctionTableAccess (DBGHELP.@)
+ */
+PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
+{
+ return SymFunctionTableAccess64(hProcess, AddrBase);
+}
+
+/***********************************************************************
+ * SymFunctionTableAccess64 (DBGHELP.@)
+ */
+PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase)
+{
+ struct process* pcs = process_find_by_handle(hProcess);
+ struct module* module;
+
+ if (!pcs || !dbghelp_current_cpu->find_runtime_function) return NULL;
+ module = module_find_by_addr(pcs, AddrBase, DMT_UNKNOWN);
+ if (!module) return NULL;
+
+ return dbghelp_current_cpu->find_runtime_function(module, AddrBase);
+}