- now detecting Dwarf debug information in ELF modules (but don't load
[wine.git] / programs / winedbg / module.c
blob756fcfc188d8f241250a608604e4dc61ed8e43d9
1 /*
2 * File module.c - module handling for the wine debugger
4 * Copyright (C) 1993, Eric Youngdale.
5 * 2000, Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "debugger.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
32 /***********************************************************************
33 * Creates and links a new module to the current process
36 DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
37 void* mod_addr, unsigned long size, HMODULE hmodule)
39 DBG_MODULE* wmod;
41 if (!(wmod = (DBG_MODULE*)DBG_alloc(sizeof(*wmod))))
42 return NULL;
44 memset(wmod, 0, sizeof(*wmod));
46 wmod->dil = DIL_DEFERRED;
47 wmod->main = (DEBUG_CurrProcess->num_modules == 0);
48 wmod->type = type;
49 wmod->load_addr = mod_addr;
50 wmod->size = size;
51 wmod->handle = hmodule;
52 wmod->dbg_index = DEBUG_CurrProcess->next_index;
53 wmod->module_name = DBG_strdup(name);
54 DEBUG_CurrProcess->next_index++;
56 DEBUG_CurrProcess->modules = DBG_realloc(DEBUG_CurrProcess->modules,
57 ++DEBUG_CurrProcess->num_modules * sizeof(DBG_MODULE*));
58 DEBUG_CurrProcess->modules[DEBUG_CurrProcess->num_modules - 1] = wmod;
60 return wmod;
63 /***********************************************************************
64 * DEBUG_FindModuleByName
67 DBG_MODULE* DEBUG_FindModuleByName(const char* name, enum DbgModuleType type)
69 int i;
70 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
72 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
73 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
74 !strcasecmp(name, amod[i]->module_name))
75 return amod[i];
77 return NULL;
80 /***********************************************************************
81 * DEBUG_FindModuleByAddr
83 * either the addr where module is loaded, or any address inside the
84 * module
86 DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type)
88 int i;
89 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
90 DBG_MODULE* res = NULL;
92 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
93 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
94 (char *)addr >= (char *)amod[i]->load_addr &&
95 (char *)addr < (char *)amod[i]->load_addr + amod[i]->size) {
96 /* amod[i] contains it... check against res now */
97 if (!res || res->load_addr < amod[i]->load_addr)
98 res = amod[i];
101 return res;
104 /***********************************************************************
105 * DEBUG_FindModuleByHandle
107 DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type)
109 int i;
110 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
112 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
113 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
114 handle == amod[i]->handle)
115 return amod[i];
117 return NULL;
120 /***********************************************************************
121 * DEBUG_GetProcessMainModule
123 DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process)
125 if (!process || !process->num_modules) return NULL;
127 /* main module is the first to be loaded on a given process, so it's the first
128 * in the array */
129 assert(process->modules[0]->main);
130 return process->modules[0];
133 #if 0
134 /***********************************************************************
135 * DEBUG_RegisterNEModule
138 static DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr,
139 unsigned long size, const char *module_name)
141 DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_NE, load_addr, size, hModule);
143 if (!wmod) return NULL;
145 DEBUG_CurrProcess->next_index++;
146 return wmod;
149 /***********************************************************************
150 * DEBUG_GetEP16
152 * Helper function fo DEBUG_LoadModuleEPs16:
153 * finds the address of a given entry point from a given module
155 static BOOL DEBUG_GetEP16(char* moduleAddr, const NE_MODULE* module,
156 WORD ordinal, DBG_ADDR* addr)
158 void* idx;
159 ET_ENTRY entry;
160 ET_BUNDLE bundle;
161 SEGTABLEENTRY ste;
163 bundle.next = module->entry_table;
164 do {
165 if (!bundle.next)
166 return FALSE;
167 idx = moduleAddr + bundle.next;
168 if (!DEBUG_READ_MEM_VERBOSE(idx, &bundle, sizeof(bundle)))
169 return FALSE;
170 } while ((ordinal < bundle.first + 1) || (ordinal > bundle.last));
172 if (!DEBUG_READ_MEM_VERBOSE((char*)idx + sizeof(ET_BUNDLE) +
173 (ordinal - bundle.first - 1) * sizeof(ET_ENTRY),
174 &entry, sizeof(ET_ENTRY)))
175 return FALSE;
177 addr->seg = entry.segnum;
178 addr->off = entry.offs;
180 if (addr->seg == 0xfe) addr->seg = 0xffff; /* constant entry */
181 else {
182 if (!DEBUG_READ_MEM_VERBOSE(moduleAddr + module->seg_table +
183 sizeof(ste) * (addr->seg - 1),
184 &ste, sizeof(ste)))
185 return FALSE;
186 addr->seg = GlobalHandleToSel16(ste.hSeg);
188 return TRUE;
191 /***********************************************************************
192 * DEBUG_LoadModule16
194 * Load the entry points of a Win16 module into the hash table.
196 static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleAddr, const char* name)
198 DBG_VALUE value;
199 BYTE buf[1 + 256 + 2];
200 char epname[512];
201 char* cpnt;
202 DBG_MODULE* wmod;
204 wmod = DEBUG_RegisterNEModule(hModule, moduleAddr, name);
206 value.type = NULL;
207 value.cookie = DV_TARGET;
208 value.addr.seg = 0;
209 value.addr.off = 0;
211 cpnt = moduleAddr + module->name_table;
213 /* First search the resident names */
215 /* skip module name */
216 if (!DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) || !buf[0])
217 return;
218 cpnt += 1 + buf[0] + sizeof(WORD);
220 while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
221 snprintf(epname, sizeof(epname), "%s.%.*s", name, buf[0], &buf[1]);
222 if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
223 DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
225 cpnt += buf[0] + 1 + sizeof(WORD);
228 /* Now search the non-resident names table */
229 if (!module->nrname_handle) return; /* No non-resident table */
230 cpnt = (char *)GlobalLock16(module->nrname_handle);
231 while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
232 snprintf(epname, sizeof(epname), "%s.%.*s", name, buf[0], &buf[1]);
233 if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
234 DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
236 cpnt += buf[0] + 1 + sizeof(WORD);
238 GlobalUnlock16(module->nrname_handle);
240 #endif
242 /***********************************************************************
243 * DEBUG_LoadEntryPoints
245 * Load the entry points of all the modules into the hash table.
247 int DEBUG_LoadEntryPoints(const char* pfx)
249 int first = 0;
250 /* FIXME: with address space separation in space, this is plain wrong
251 * it requires the 16 bit WOW debugging interface...
253 #if 0
254 MODULEENTRY entry;
255 NE_MODULE module;
256 void* moduleAddr;
257 int rowcount = 0;
258 int len;
260 /* FIXME: we assume that a module is never removed from memory */
261 /* FIXME: this is (currently plain wrong when debugger is started by
262 * attaching to an existing program => the 16 bit modules will
263 * not be shared... not much to do on debugger side... sigh
265 if (ModuleFirst16(&entry)) do {
266 if (DEBUG_FindModuleByName(entry.szModule, DM_TYPE_UNKNOWN) ||
267 !(moduleAddr = NE_GetPtr(entry.hModule)) ||
268 !DEBUG_READ_MEM_VERBOSE(moduleAddr, &module, sizeof(module)) ||
269 (module.flags & NE_FFLAGS_WIN32) /* NE module */)
270 continue;
271 if (!first) {
272 if (pfx) DEBUG_Printf(pfx);
273 DEBUG_Printf(" ");
274 rowcount = 3 + (pfx ? strlen(pfx) : 0);
275 first = 1;
278 len = strlen(entry.szModule);
279 if ((rowcount + len) > 76) {
280 DEBUG_Printf("\n ");
281 rowcount = 3;
283 DEBUG_Printf(" %s", entry.szModule);
284 rowcount += len + 1;
286 DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
287 } while (ModuleNext16(&entry));
288 #endif
290 if (first) DEBUG_Printf("\n");
291 return first;
294 void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename, void *load_addr)
296 const char* fmt;
298 switch (dil) {
299 case DIL_DEFERRED:
300 fmt = "Deferring debug information loading for %s '%s' (%p)\n";
301 break;
302 case DIL_LOADED:
303 fmt = "Loaded debug information from %s '%s' (%p)\n";
304 break;
305 case DIL_NOINFO:
306 fmt = "No debug information in %s '%s' (%p)\n";
307 break;
308 case DIL_NOT_SUPPORTED:
309 fmt = "Unsupported debug information in %s '%s' (%p)\n";
310 break;
311 case DIL_ERROR:
312 fmt = "Can't find file for %s '%s' (%p)\n";
313 break;
314 default:
315 WINE_ERR("Oooocch (%d)\n", dil);
316 return;
319 DEBUG_Printf(fmt, pfx, filename, load_addr);
322 static const char* DEBUG_GetModuleType(enum DbgModuleType type)
324 switch (type) {
325 case DMT_NE: return "NE";
326 case DMT_PE: return "PE";
327 case DMT_ELF: return "ELF";
328 default: return "???";
332 static const char* DEBUG_GetDbgInfo(enum DbgInfoLoad dil)
334 switch (dil) {
335 case DIL_LOADED: return "loaded";
336 case DIL_DEFERRED: return "deferred";
337 case DIL_NOINFO: return "none";
338 case DIL_NOT_SUPPORTED: return "not supported";
339 case DIL_ERROR: return "error";
340 default: return "?";
344 /***********************************************************************
345 * DEBUG_ModuleCompare
347 * returns -1 is p1 < p2, 0 is p1 == p2, +1 if p1 > p2
348 * order used is order on load_addr of a module
350 static int DEBUG_ModuleCompare(const void* p1, const void* p2)
352 return (char*)(*((const DBG_MODULE**)p1))->load_addr -
353 (char*)(*((const DBG_MODULE**)p2))->load_addr;
356 /***********************************************************************
357 * DEBUG_IsContainer
359 * returns TRUE is wmod_child is contained (inside bounds) of wmod_cntnr
361 static inline BOOL DEBUG_IsContainer(const DBG_MODULE* wmod_cntnr,
362 const DBG_MODULE* wmod_child)
364 return wmod_cntnr->load_addr < wmod_child->load_addr &&
365 (DWORD)wmod_cntnr->load_addr + wmod_cntnr->size >
366 (DWORD)wmod_child->load_addr + wmod_child->size;
369 static void DEBUG_InfoShareModule(const DBG_MODULE* module, int ident)
371 if (ident) DEBUG_Printf(" \\-");
372 DEBUG_Printf("%s\t0x%08lx-%08lx\t%s\n",
373 DEBUG_GetModuleType(module->type),
374 (DWORD)module->load_addr, (DWORD)module->load_addr + module->size,
375 module->module_name);
378 /***********************************************************************
379 * DEBUG_InfoShare
381 * Display shared libarary information.
383 void DEBUG_InfoShare(void)
385 DBG_MODULE** ref;
386 int i, j;
388 ref = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
389 if (!ref) return;
391 DEBUG_Printf("Module\tAddress\t\t\tName\t%d modules\n",
392 DEBUG_CurrProcess->num_modules);
394 memcpy(ref, DEBUG_CurrProcess->modules,
395 sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
396 qsort(ref, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
397 DEBUG_ModuleCompare);
398 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
399 switch (ref[i]->type) {
400 case DMT_ELF:
401 DEBUG_InfoShareModule(ref[i], 0);
402 for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
403 if (ref[j]->type != DMT_ELF && DEBUG_IsContainer(ref[i], ref[j]))
404 DEBUG_InfoShareModule(ref[j], 1);
406 break;
407 case DMT_NE:
408 case DMT_PE:
409 /* check module is not in ELF */
410 for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
411 if (ref[j]->type == DMT_ELF &&
412 DEBUG_IsContainer(ref[j], ref[i]))
413 break;
415 if (j >= DEBUG_CurrProcess->num_modules)
416 DEBUG_InfoShareModule(ref[i], 0);
417 break;
418 default:
419 WINE_ERR("Unknown type (%d)\n", ref[i]->type);
422 DBG_free(ref);
425 /***********************************************************************
426 * DEBUG_DumpModule
427 * Display information about a given module (DLL or EXE)
429 void DEBUG_DumpModule(DWORD mod)
431 DBG_MODULE* wmod;
433 if (!(wmod = DEBUG_FindModuleByHandle((HANDLE)mod, DMT_UNKNOWN)) &&
434 !(wmod = DEBUG_FindModuleByAddr((void*)mod, DMT_UNKNOWN))) {
435 DEBUG_Printf("'0x%08lx' is not a valid module handle or address\n", mod);
436 return;
439 DEBUG_Printf("Module '%s' (handle=%p) 0x%08lx-0x%08lx (%s, debug info %s)\n",
440 wmod->module_name, wmod->handle, (DWORD)wmod->load_addr,
441 (DWORD)wmod->load_addr + wmod->size,
442 DEBUG_GetModuleType(wmod->type), DEBUG_GetDbgInfo(wmod->dil));
445 /***********************************************************************
446 * DEBUG_WalkModules
448 * Display information about all modules (DLLs and EXEs)
450 void DEBUG_WalkModules(void)
452 DBG_MODULE** amod;
453 int i;
455 if (!DEBUG_CurrProcess)
457 DEBUG_Printf("Cannot walk classes while no process is loaded\n");
458 return;
461 DEBUG_Printf("Address\t\t\tModule\tName\n");
463 amod = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
464 if (!amod) return;
466 memcpy(amod, DEBUG_CurrProcess->modules,
467 sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
468 qsort(amod, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
469 DEBUG_ModuleCompare);
470 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
471 if (amod[i]->type == DMT_ELF) continue;
473 DEBUG_Printf("0x%08lx-%08lx\t(%s)\t%s\n",
474 (DWORD)amod[i]->load_addr,
475 (DWORD)amod[i]->load_addr + amod[i]->size,
476 DEBUG_GetModuleType(amod[i]->type), amod[i]->module_name);
478 DBG_free(amod);