2 * File module.c - module handling for the wine debugger
4 * Copyright (C) 1993, Eric Youngdale.
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
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
)
41 if (!(wmod
= (DBG_MODULE
*)DBG_alloc(sizeof(*wmod
))))
44 memset(wmod
, 0, sizeof(*wmod
));
46 wmod
->dil
= DIL_DEFERRED
;
47 wmod
->main
= (DEBUG_CurrProcess
->num_modules
== 0);
49 wmod
->load_addr
= mod_addr
;
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
;
63 /***********************************************************************
64 * DEBUG_FindModuleByName
67 DBG_MODULE
* DEBUG_FindModuleByName(const char* name
, enum DbgModuleType type
)
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
))
80 /***********************************************************************
81 * DEBUG_FindModuleByAddr
83 * either the addr where module is loaded, or any address inside the
86 DBG_MODULE
* DEBUG_FindModuleByAddr(void* addr
, enum DbgModuleType type
)
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
)
104 /***********************************************************************
105 * DEBUG_FindModuleByHandle
107 DBG_MODULE
* DEBUG_FindModuleByHandle(HANDLE handle
, enum DbgModuleType type
)
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
)
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
129 assert(process
->modules
[0]->main
);
130 return process
->modules
[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
++;
149 /***********************************************************************
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
)
163 bundle
.next
= module
->entry_table
;
167 idx
= moduleAddr
+ bundle
.next
;
168 if (!DEBUG_READ_MEM_VERBOSE(idx
, &bundle
, sizeof(bundle
)))
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
)))
177 addr
->seg
= entry
.segnum
;
178 addr
->off
= entry
.offs
;
180 if (addr
->seg
== 0xfe) addr
->seg
= 0xffff; /* constant entry */
182 if (!DEBUG_READ_MEM_VERBOSE(moduleAddr
+ module
->seg_table
+
183 sizeof(ste
) * (addr
->seg
- 1),
186 addr
->seg
= GlobalHandleToSel16(ste
.hSeg
);
191 /***********************************************************************
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
)
199 BYTE buf
[1 + 256 + 2];
204 wmod
= DEBUG_RegisterNEModule(hModule
, moduleAddr
, name
);
207 value
.cookie
= DV_TARGET
;
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])
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
);
242 /***********************************************************************
243 * DEBUG_LoadEntryPoints
245 * Load the entry points of all the modules into the hash table.
247 int DEBUG_LoadEntryPoints(const char* pfx
)
250 /* FIXME: with address space separation in space, this is plain wrong
251 * it requires the 16 bit WOW debugging interface...
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 */)
272 if (pfx
) DEBUG_Printf(pfx
);
274 rowcount
= 3 + (pfx
? strlen(pfx
) : 0);
278 len
= strlen(entry
.szModule
);
279 if ((rowcount
+ len
) > 76) {
283 DEBUG_Printf(" %s", entry
.szModule
);
286 DEBUG_LoadModule16(entry
.hModule
, &module
, moduleAddr
, entry
.szModule
);
287 } while (ModuleNext16(&entry
));
290 if (first
) DEBUG_Printf("\n");
294 void DEBUG_ReportDIL(enum DbgInfoLoad dil
, const char* pfx
, const char* filename
, void *load_addr
)
300 fmt
= "Deferring debug information loading for %s '%s' (%p)\n";
303 fmt
= "Loaded debug information from %s '%s' (%p)\n";
306 fmt
= "No debug information in %s '%s' (%p)\n";
308 case DIL_NOT_SUPPORTED
:
309 fmt
= "Unsupported debug information in %s '%s' (%p)\n";
312 fmt
= "Can't find file for %s '%s' (%p)\n";
315 WINE_ERR("Oooocch (%d)\n", dil
);
319 DEBUG_Printf(fmt
, pfx
, filename
, load_addr
);
322 static const char* DEBUG_GetModuleType(enum DbgModuleType 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
)
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";
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 /***********************************************************************
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 /***********************************************************************
381 * Display shared libarary information.
383 void DEBUG_InfoShare(void)
388 ref
= DBG_alloc(sizeof(DBG_MODULE
*) * DEBUG_CurrProcess
->num_modules
);
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
) {
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);
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
]))
415 if (j
>= DEBUG_CurrProcess
->num_modules
)
416 DEBUG_InfoShareModule(ref
[i
], 0);
419 WINE_ERR("Unknown type (%d)\n", ref
[i
]->type
);
425 /***********************************************************************
427 * Display information about a given module (DLL or EXE)
429 void DEBUG_DumpModule(DWORD mod
)
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
);
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 /***********************************************************************
448 * Display information about all modules (DLLs and EXEs)
450 void DEBUG_WalkModules(void)
455 if (!DEBUG_CurrProcess
)
457 DEBUG_Printf("Cannot walk classes while no process is loaded\n");
461 DEBUG_Printf("Address\t\t\tModule\tName\n");
463 amod
= DBG_alloc(sizeof(DBG_MODULE
*) * DEBUG_CurrProcess
->num_modules
);
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
);