1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * File module.c - module handling for the wine debugger
5 * Copyright (C) 1993, Eric Youngdale.
19 /***********************************************************************
20 * Creates and links a new module to the current process
23 DBG_MODULE
* DEBUG_AddModule(const char* name
, int type
,
24 void* mod_addr
, HMODULE hmodule
)
28 if (!(wmod
= (DBG_MODULE
*)DBG_alloc(sizeof(*wmod
))))
31 memset(wmod
, 0, sizeof(*wmod
));
33 wmod
->next
= DEBUG_CurrProcess
->modules
;
34 wmod
->status
= DM_STATUS_NEW
;
36 wmod
->load_addr
= mod_addr
;
37 wmod
->handle
= hmodule
;
38 wmod
->dbg_index
= DEBUG_CurrProcess
->next_index
;
39 wmod
->module_name
= DBG_strdup(name
);
40 DEBUG_CurrProcess
->modules
= wmod
;
45 /***********************************************************************
46 * DEBUG_FindModuleByName
49 DBG_MODULE
* DEBUG_FindModuleByName(const char* name
, int type
)
53 for (wmod
= DEBUG_CurrProcess
->modules
; wmod
; wmod
= wmod
->next
) {
54 if ((type
== DM_TYPE_UNKNOWN
|| type
== wmod
->type
) &&
55 !strcasecmp(name
, wmod
->module_name
)) break;
60 /***********************************************************************
61 * DEBUG_FindModuleByAddr
63 * either the addr where module is loaded, or any address inside the
66 DBG_MODULE
* DEBUG_FindModuleByAddr(void* addr
, int type
)
69 DBG_MODULE
* res
= NULL
;
71 for (wmod
= DEBUG_CurrProcess
->modules
; wmod
; wmod
= wmod
->next
) {
72 if ((type
== DM_TYPE_UNKNOWN
|| type
== wmod
->type
) &&
73 (u_long
)addr
>= (u_long
)wmod
->load_addr
&&
74 (!res
|| res
->load_addr
< wmod
->load_addr
))
80 /***********************************************************************
81 * DEBUG_FindModuleByHandle
83 DBG_MODULE
* DEBUG_FindModuleByHandle(HANDLE handle
, int type
)
87 for (wmod
= DEBUG_CurrProcess
->modules
; wmod
; wmod
= wmod
->next
) {
88 if ((type
== DM_TYPE_UNKNOWN
|| type
== wmod
->type
) && handle
== wmod
->handle
) break;
93 /***********************************************************************
94 * DEBUG_GetProcessMainModule
96 DBG_MODULE
* DEBUG_GetProcessMainModule(DBG_PROCESS
* process
)
100 if (!process
) return NULL
;
102 /* main module is the first to be loaded on a given process, so it's the last on
104 for (wmod
= process
->modules
; wmod
&& wmod
->next
; wmod
= wmod
->next
);
108 /***********************************************************************
109 * DEBUG_RegisterELFModule
111 * ELF modules are also entered into the list - this is so that we
112 * can make 'info shared' types of displays possible.
114 DBG_MODULE
* DEBUG_RegisterELFModule(u_long load_addr
, const char* name
)
116 DBG_MODULE
* wmod
= DEBUG_AddModule(name
, DM_TYPE_ELF
, (void*)load_addr
, 0);
118 if (!wmod
) return NULL
;
120 wmod
->status
= DM_STATUS_LOADED
;
121 DEBUG_CurrProcess
->next_index
++;
126 /***********************************************************************
127 * DEBUG_RegisterPEModule
130 DBG_MODULE
* DEBUG_RegisterPEModule(HMODULE hModule
, u_long load_addr
, const char *module_name
)
132 DBG_MODULE
* wmod
= DEBUG_AddModule(module_name
, DM_TYPE_PE
, (void*)load_addr
, hModule
);
134 if (!wmod
) return NULL
;
136 DEBUG_CurrProcess
->next_index
++;
141 /***********************************************************************
142 * DEBUG_RegisterNEModule
145 DBG_MODULE
* DEBUG_RegisterNEModule(HMODULE hModule
, void* load_addr
, const char *module_name
)
147 DBG_MODULE
* wmod
= DEBUG_AddModule(module_name
, DM_TYPE_NE
, load_addr
, hModule
);
149 if (!wmod
) return NULL
;
151 wmod
->status
= DM_STATUS_LOADED
;
152 DEBUG_CurrProcess
->next_index
++;
157 /***********************************************************************
160 * Helper function fo DEBUG_LoadModuleEPs16:
161 * finds the address of a given entry point from a given module
163 static BOOL
DEBUG_GetEP16(char* moduleAddr
, const NE_MODULE
* module
,
164 WORD ordinal
, DBG_ADDR
* addr
)
171 bundle
.next
= module
->entry_table
;
175 idx
= moduleAddr
+ bundle
.next
;
176 if (!DEBUG_READ_MEM_VERBOSE(idx
, &bundle
, sizeof(bundle
)))
178 } while ((ordinal
< bundle
.first
+ 1) || (ordinal
> bundle
.last
));
180 if (!DEBUG_READ_MEM_VERBOSE((char*)idx
+ sizeof(ET_BUNDLE
) +
181 (ordinal
- bundle
.first
- 1) * sizeof(ET_ENTRY
),
182 &entry
, sizeof(ET_ENTRY
)))
185 addr
->seg
= entry
.segnum
;
186 addr
->off
= entry
.offs
;
188 if (addr
->seg
== 0xfe) addr
->seg
= 0xffff; /* constant entry */
190 if (!DEBUG_READ_MEM_VERBOSE(moduleAddr
+ module
->seg_table
+
191 sizeof(ste
) * (addr
->seg
- 1),
194 addr
->seg
= GlobalHandleToSel16(ste
.hSeg
);
199 /***********************************************************************
202 * Load the entry points of a Win16 module into the hash table.
204 static void DEBUG_LoadModule16(HMODULE hModule
, NE_MODULE
* module
, char* moduleAddr
, const char* name
)
207 BYTE buf
[1 + 256 + 2];
212 wmod
= DEBUG_RegisterNEModule(hModule
, moduleAddr
, name
);
215 value
.cookie
= DV_TARGET
;
219 cpnt
= moduleAddr
+ module
->name_table
;
221 /* First search the resident names */
223 /* skip module name */
224 if (!DEBUG_READ_MEM_VERBOSE(cpnt
, buf
, sizeof(buf
)) || !buf
[0])
226 cpnt
+= 1 + buf
[0] + sizeof(WORD
);
228 while (DEBUG_READ_MEM_VERBOSE(cpnt
, buf
, sizeof(buf
)) && buf
[0]) {
229 sprintf(epname
, "%s.%.*s", name
, buf
[0], &buf
[1]);
230 if (DEBUG_GetEP16(moduleAddr
, module
, *(WORD
*)&buf
[1 + buf
[0]], &value
.addr
)) {
231 DEBUG_AddSymbol(epname
, &value
, NULL
, SYM_WIN32
| SYM_FUNC
);
233 cpnt
+= buf
[0] + 1 + sizeof(WORD
);
236 /* Now search the non-resident names table */
237 if (!module
->nrname_handle
) return; /* No non-resident table */
238 cpnt
= (char *)GlobalLock16(module
->nrname_handle
);
239 while (DEBUG_READ_MEM_VERBOSE(cpnt
, buf
, sizeof(buf
)) && buf
[0]) {
240 sprintf(epname
, "%s.%.*s", name
, buf
[0], &buf
[1]);
241 if (DEBUG_GetEP16(moduleAddr
, module
, *(WORD
*)&buf
[1 + buf
[0]], &value
.addr
)) {
242 DEBUG_AddSymbol(epname
, &value
, NULL
, SYM_WIN32
| SYM_FUNC
);
244 cpnt
+= buf
[0] + 1 + sizeof(WORD
);
246 GlobalUnlock16(module
->nrname_handle
);
250 /***********************************************************************
253 void DEBUG_LoadModule32(const char* name
, HANDLE hFile
, DWORD base
)
259 IMAGE_NT_HEADERS pe_header
;
261 IMAGE_SECTION_HEADER pe_seg
;
263 IMAGE_DATA_DIRECTORY dir
;
268 /* FIXME: we make the assumption that hModule == base */
269 wmod
= DEBUG_RegisterPEModule((HMODULE
)base
, base
, name
);
271 DEBUG_Printf(DBG_CHN_TRACE
, "Registring 32bit DLL '%s' at %08lx\n", name
, base
);
274 value
.cookie
= DV_TARGET
;
279 if (!DEBUG_READ_MEM_VERBOSE((void*)(base
+ OFFSET_OF(IMAGE_DOS_HEADER
, e_lfanew
)),
280 &pe_header_ofs
, sizeof(pe_header_ofs
)) ||
281 !DEBUG_READ_MEM_VERBOSE((void*)(base
+ pe_header_ofs
),
282 &pe_header
, sizeof(pe_header
)))
286 DEBUG_RegisterStabsDebugInfo(wmod
, hFile
, &pe_header
, pe_header_ofs
);
287 DEBUG_RegisterMSCDebugInfo(wmod
, hFile
, &pe_header
, pe_header_ofs
);
290 /* Add start of DLL */
291 value
.addr
.off
= base
;
292 if ((prefix
= strrchr( name
, '\\' ))) prefix
++;
295 DEBUG_AddSymbol(prefix
, &value
, NULL
, SYM_WIN32
| SYM_FUNC
);
297 /* Add entry point */
298 wsnprintf(buffer
, sizeof(buffer
), "%s.EntryPoint", prefix
);
299 value
.addr
.off
= base
+ pe_header
.OptionalHeader
.AddressOfEntryPoint
;
300 DEBUG_AddSymbol(buffer
, &value
, NULL
, SYM_WIN32
| SYM_FUNC
);
302 /* Add start of sections */
303 pe_seg_ofs
= pe_header_ofs
+ OFFSET_OF(IMAGE_NT_HEADERS
, OptionalHeader
) +
304 pe_header
.FileHeader
.SizeOfOptionalHeader
;
306 for (i
= 0; i
< pe_header
.FileHeader
.NumberOfSections
; i
++, pe_seg_ofs
+= sizeof(pe_seg
)) {
307 if (!DEBUG_READ_MEM_VERBOSE((void*)(base
+ pe_seg_ofs
), &pe_seg
, sizeof(pe_seg
)))
309 wsnprintf(buffer
, sizeof(buffer
), "%s.%s", prefix
, pe_seg
.Name
);
310 value
.addr
.off
= base
+ pe_seg
.VirtualAddress
;
311 DEBUG_AddSymbol(buffer
, &value
, NULL
, SYM_WIN32
| SYM_FUNC
);
314 /* Add exported functions */
315 dir_ofs
= pe_header_ofs
+
316 OFFSET_OF(IMAGE_NT_HEADERS
,
317 OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_EXPORT
]);
318 if (DEBUG_READ_MEM_VERBOSE((void*)(base
+ dir_ofs
), &dir
, sizeof(dir
)) && dir
.Size
) {
319 IMAGE_EXPORT_DIRECTORY exports
;
320 WORD
* ordinals
= NULL
;
321 void** functions
= NULL
;
325 if (DEBUG_READ_MEM_VERBOSE((void*)(base
+ dir
.VirtualAddress
),
326 &exports
, sizeof(exports
)) &&
328 ((functions
= DBG_alloc(sizeof(functions
[0]) * exports
.NumberOfFunctions
))) &&
329 DEBUG_READ_MEM_VERBOSE((void*)(base
+ (DWORD
)exports
.AddressOfFunctions
),
330 functions
, sizeof(functions
[0]) * exports
.NumberOfFunctions
) &&
332 ((ordinals
= DBG_alloc(sizeof(ordinals
[0]) * exports
.NumberOfNames
))) &&
333 DEBUG_READ_MEM_VERBOSE((void*)(base
+ (DWORD
)exports
.AddressOfNameOrdinals
),
334 ordinals
, sizeof(ordinals
[0]) * exports
.NumberOfNames
) &&
336 ((names
= DBG_alloc(sizeof(names
[0]) * exports
.NumberOfNames
))) &&
337 DEBUG_READ_MEM_VERBOSE((void*)(base
+ (DWORD
)exports
.AddressOfNames
),
338 names
, sizeof(names
[0]) * exports
.NumberOfNames
)) {
340 for (i
= 0; i
< exports
.NumberOfNames
; i
++) {
342 !DEBUG_READ_MEM_VERBOSE((void*)(base
+ names
[i
]), bufstr
, sizeof(bufstr
)))
344 bufstr
[sizeof(bufstr
) - 1] = 0;
345 wsnprintf(buffer
, sizeof(buffer
), "%s.%s", prefix
, bufstr
);
346 value
.addr
.off
= base
+ (DWORD
)functions
[ordinals
[i
]];
347 DEBUG_AddSymbol(buffer
, &value
, NULL
, SYM_WIN32
| SYM_FUNC
);
350 for (i
= 0; i
< exports
.NumberOfFunctions
; i
++) {
351 if (!functions
[i
]) continue;
352 /* Check if we already added it with a name */
353 for (j
= 0; j
< exports
.NumberOfNames
; j
++)
354 if ((ordinals
[j
] == i
) && names
[j
]) break;
355 if (j
< exports
.NumberOfNames
) continue;
356 wsnprintf(buffer
, sizeof(buffer
), "%s.%ld", prefix
, i
+ exports
.Base
);
357 value
.addr
.off
= base
+ (DWORD
)functions
[i
];
358 DEBUG_AddSymbol(buffer
, &value
, NULL
, SYM_WIN32
| SYM_FUNC
);
367 /***********************************************************************
368 * DEBUG_LoadEntryPoints
370 * Load the entry points of all the modules into the hash table.
372 int DEBUG_LoadEntryPoints(const char* pfx
)
375 /* FIXME: with address space separation in space, this is plain wrong
376 * it requires the 16 bit WOW debugging interface...
385 /* FIXME: we assume that a module is never removed from memory */
386 /* FIXME: this is (currently plain wrong when debugger is started by
387 * attaching to an existing program => the 16 bit modules will
388 * not be shared... not much to do on debugger side... sigh
390 if (ModuleFirst16(&entry
)) do {
391 if (DEBUG_FindModuleByName(entry
.szModule
, DM_TYPE_UNKNOWN
) ||
392 !(moduleAddr
= NE_GetPtr(entry
.hModule
)) ||
393 !DEBUG_READ_MEM_VERBOSE(moduleAddr
, &module
, sizeof(module
)) ||
394 (module
.flags
& NE_FFLAGS_WIN32
) /* NE module */)
397 if (pfx
) DEBUG_Printf(DBG_CHN_MESG
, pfx
);
398 DEBUG_Printf(DBG_CHN_MESG
, " ");
399 rowcount
= 3 + (pfx
? strlen(pfx
) : 0);
403 len
= strlen(entry
.szModule
);
404 if ((rowcount
+ len
) > 76) {
405 DEBUG_Printf(DBG_CHN_MESG
, "\n ");
408 DEBUG_Printf(DBG_CHN_MESG
, " %s", entry
.szModule
);
411 DEBUG_LoadModule16(entry
.hModule
, &module
, moduleAddr
, entry
.szModule
);
412 } while (ModuleNext16(&entry
));
415 if (first
) DEBUG_Printf(DBG_CHN_MESG
, "\n");
419 /***********************************************************************
422 * Display shared libarary information.
424 void DEBUG_InfoShare(void)
429 DEBUG_Printf(DBG_CHN_MESG
, "Address\t\tModule\tName\n");
431 for (wmod
= DEBUG_CurrProcess
->modules
; wmod
; wmod
= wmod
->next
) {
432 switch (wmod
->type
) {
433 case DM_TYPE_NE
: xtype
= "NE"; break;
434 case DM_TYPE_PE
: xtype
= "PE"; break;
435 case DM_TYPE_ELF
: xtype
= "ELF"; break;
436 default: xtype
= "???"; break;
438 DEBUG_Printf(DBG_CHN_MESG
, "0x%8.8x\t(%s)\t%s\n", (unsigned int)wmod
->load_addr
,
439 xtype
, wmod
->module_name
);
443 static const char* DEBUG_GetModuleType(int type
)
446 case DM_TYPE_NE
: return "NE";
447 case DM_TYPE_PE
: return "PE";
448 case DM_TYPE_ELF
: return "ELF";
449 default: return "???";;
453 static const char* DEBUG_GetModuleStatus(int status
)
456 case DM_STATUS_NEW
: return "deferred";
457 case DM_STATUS_LOADED
: return "ok";
458 case DM_STATUS_ERROR
: return "error";
459 default: return "???";
463 /***********************************************************************
465 * Display information about a given module (DLL or EXE)
467 void DEBUG_DumpModule(DWORD mod
)
471 if (!(wmod
= DEBUG_FindModuleByHandle(mod
, DM_TYPE_UNKNOWN
)) &&
472 !(wmod
= DEBUG_FindModuleByAddr((void*)mod
, DM_TYPE_UNKNOWN
))) {
473 DEBUG_Printf(DBG_CHN_MESG
, "'0x%08lx' is not a valid module handle or address\n", mod
);
477 DEBUG_Printf(DBG_CHN_MESG
, "Module '%s' (handle=0x%08x) at 0x%8.8x (%s/%s)\n",
478 wmod
->module_name
, wmod
->handle
, (unsigned int)wmod
->load_addr
,
479 DEBUG_GetModuleType(wmod
->type
), DEBUG_GetModuleStatus(wmod
->status
));
482 /***********************************************************************
485 * Display information about all modules (DLLs and EXEs)
487 void DEBUG_WalkModules(void)
492 DEBUG_Printf(DBG_CHN_MESG
, "Address\t\tModule\tName\n");
494 for (wmod
= DEBUG_CurrProcess
->modules
; wmod
; wmod
= wmod
->next
) {
495 switch (wmod
->type
) {
496 case DM_TYPE_NE
: xtype
= "NE"; break;
497 case DM_TYPE_PE
: xtype
= "PE"; break;
498 case DM_TYPE_ELF
: continue;
499 default: xtype
= "???"; break;
502 DEBUG_Printf(DBG_CHN_MESG
, "0x%8.8x\t(%s)\t%s\n",
503 (unsigned int)wmod
->load_addr
, DEBUG_GetModuleType(wmod
->type
),