move delay code into separate function.
[AROS.git] / rom / debug / registermodule.c
blobe9a20a871ff21bed9dd9b4dc538ebdc38fe59440
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 */
8 #define DEBUG 0
9 #define DSYMS(x)
11 #include <aros/debug.h>
12 #include <aros/libcall.h>
13 #include <dos/dosextens.h>
14 #include <exec/lists.h>
15 #include <libraries/debug.h>
16 #include <proto/exec.h>
17 #include <clib/alib_protos.h>
19 #include <stdint.h>
20 #include <string.h>
22 #include "debug_intern.h"
24 static inline char *getstrtab(struct sheader *sh);
25 static void addsymbol(module_t *mod, dbg_sym_t *sym, struct symbol *st, APTR value);
26 static void HandleModuleSegments(module_t *mod, struct MinList * list);
27 static void RegisterModule_Hunk(const char *name, BPTR segList, ULONG DebugType, APTR DebugInfo, struct Library *DebugBase);
29 /*****************************************************************************
31 NAME */
32 #include <proto/debug.h>
34 AROS_LH4(void, RegisterModule,
36 /* SYNOPSIS */
37 AROS_LHA(const char *, name, A0),
38 AROS_LHA(BPTR, segList, A1),
39 AROS_LHA(ULONG, debugType, D0),
40 AROS_LHA(APTR, debugInfo, A2),
42 /* LOCATION */
43 struct Library *, DebugBase, 5, Debug)
45 /* FUNCTION
46 Add information about the loaded executable module to the
47 debug information database
49 INPUTS
50 name - Module name
51 segList - DOS segment list for the module
52 debugType - Type of supplied debug information. The only currently
53 supported type is DEBUG_ELF.
54 debugInfo - Debug information data. For DEBUG_ELF type this should be
55 a pointer to struct ELF_DebugInfo, filled in as follows:
56 eh - a pointer to ELF file header.
57 sh - a pointer to an array of ELF section headers.
59 RESULT
60 None
62 NOTES
64 EXAMPLE
66 BUGS
68 SEE ALSO
70 INTERNALS
71 The function supposes that segments in DOS list are linked in the same
72 order in which corresponding sections are placed in the file
74 ******************************************************************************/
76 AROS_LIBFUNC_INIT
78 D(bug("[Debug] RegisterModule(%s, 0x%p, %d)\n", name, segList, debugType));
80 if (debugType == DEBUG_ELF)
82 struct elfheader *eh = ((struct ELF_DebugInfo *)debugInfo)->eh;
83 struct sheader *sections = ((struct ELF_DebugInfo *)debugInfo)->sh;
85 RegisterModule_ELF(name, segList, eh, sections, DebugBase);
87 } else if (debugType == DEBUG_PARTHENOPE) {
88 const struct Parthenope_ModuleInfo *pm;
90 ForeachNode(debugInfo, pm) {
91 struct segment *seg;
93 seg = AllocVec(sizeof(struct segment) + sizeof(module_t) + strlen(pm->m_name), MEMF_PUBLIC|MEMF_CLEAR);
95 if (seg) {
96 unsigned int symbols;
97 dbg_sym_t *dsym;
98 const struct Parthenope_Symbol *sym;
99 APTR str_l = (APTR)~(uintptr_t)0, str_h = (APTR)(uintptr_t)0;
100 APTR seg_l = (APTR)~(uintptr_t)0, seg_h = (APTR)(uintptr_t)0;
101 module_t *mod = (module_t *)(&seg[1]);
103 DSYMS(bug("[Debug] Adding module @%p: %s\n", pm, pm->m_name));
104 strcpy(mod->m_name, pm->m_name);
106 seg->s_seg = BNULL;
107 seg->s_mod = mod;
108 seg->s_name = mod->m_name;
109 seg->s_num = 0;
111 mod->m_shstr = NULL;
112 mod->m_str = NULL;
113 mod->m_segcnt = 1;
115 /* Determine the size of the string table */
116 symbols = 0;
117 ForeachNode(&pm->m_symbols, sym) {
118 symbols++;
119 if (sym->s_name) {
120 APTR end = (APTR)sym->s_name + strlen(sym->s_name) + 1 + 1;
121 if ((APTR)sym->s_name < str_l)
122 str_l = (APTR)sym->s_name;
123 if (end > str_h)
124 str_h = end;
126 if ((APTR)(uintptr_t)sym->s_lowest < seg_l)
127 seg_l = (APTR)(uintptr_t)sym->s_lowest;
128 if ((APTR)(uintptr_t)sym->s_highest > seg_h)
129 seg_h = (APTR)(uintptr_t)sym->s_highest;
132 if (symbols) {
133 DSYMS(bug("[Debug] String table %p-%p (%u bytes)\n", str_l, str_h, (unsigned int)(str_h - str_l)));
134 DSYMS(bug("[Debug] Symbols for %p-%p (%u symbols)\n", seg_l, seg_h, symbols));
136 seg->s_lowest = (APTR)seg_l;
137 seg->s_highest = (APTR)seg_h;
139 mod->m_symcnt = symbols;
140 mod->m_str = AllocVec(str_h - str_l, MEMF_PUBLIC);
142 if (mod->m_str) {
143 CopyMem(str_l, mod->m_str, str_h - str_l);
145 mod->m_symbols = AllocVec(sizeof(*mod->m_symbols) * symbols, MEMF_PUBLIC);
146 if (mod->m_symbols) {
147 struct MinList tmplist;
148 NEWLIST(&tmplist);
150 dsym = mod->m_symbols;
151 ForeachNode(&pm->m_symbols, sym) {
152 dsym->s_name = ((APTR)sym->s_name - str_l) + mod->m_str;
153 dsym->s_lowest = (APTR)(uintptr_t)sym->s_lowest;
154 dsym->s_highest= (APTR)(uintptr_t)sym->s_highest;
155 dsym++;
158 AddTail((struct List *)&tmplist, (struct Node *)seg);
160 ObtainSemaphore(&DBGBASE(DebugBase)->db_ModSem);
161 AddTail((struct List *)&DBGBASE(DebugBase)->db_Modules, (struct Node *)mod);
162 ReleaseSemaphore(&DBGBASE(DebugBase)->db_ModSem);
164 HandleModuleSegments(mod, &tmplist);
166 continue;
169 FreeVec(mod->m_str);
172 FreeVec(seg);
177 } else if (debugType == DEBUG_HUNK) {
178 RegisterModule_Hunk(name, segList, debugType, debugInfo, DebugBase);
180 AROS_LIBFUNC_EXIT
183 static inline char *getstrtab(struct sheader *sh)
185 char *str;
187 str = AllocVec(sh->size, MEMF_PUBLIC);
188 if (str)
189 CopyMem(sh->addr, str, sh->size);
191 return str;
194 static void addsymbol(module_t *mod, dbg_sym_t *sym, struct symbol *st, APTR value)
196 if (mod->m_str)
197 sym->s_name = &mod->m_str[st->name];
198 else
199 sym->s_name = NULL;
201 sym->s_lowest = value;
202 if (st->size)
203 sym->s_highest = value + st->size - 1;
204 else
205 /* For symbols with zero size KDL_SymbolEnd will give NULL */
206 sym->s_highest = NULL;
208 /* We count symbols here because not all of them can be added */
209 mod->m_symcnt++;
212 /* quick sort */
213 #define SWAPIDX(a, b) \
214 do \
216 struct segment * tmp = segments[b]; \
217 segments[b] = segments[a]; \
218 segments[a] = tmp; \
220 while(0); \
222 static LONG partition(struct segment **segments, LONG left, LONG right, LONG pivotidx)
224 void * pivotval = segments[pivotidx]->s_lowest;
225 LONG storeidx = left;
226 LONG i;
227 SWAPIDX(right, pivotidx)
229 for (i = left; i < right; i++)
230 if (segments[i]->s_lowest < pivotval)
232 SWAPIDX(i, storeidx);
233 storeidx++;
235 SWAPIDX(storeidx, right);
236 return storeidx;
239 static VOID qsort(struct segment **segments, LONG left, LONG right)
241 if (left > right)
242 return;
244 LONG pivotidx = (right + left) / 2;
245 pivotidx = partition(segments, left, right, pivotidx);
246 qsort(segments, left, pivotidx - 1);
247 qsort(segments, pivotidx + 1, right);
250 static void HandleModuleSegments(module_t *mod, struct MinList * list)
252 struct segment *seg;
253 struct Node *tmpnode;
254 LONG segidx = 0, i = 0;
255 IPTR maxgapsize = 0;
256 #if AROS_MODULES_DEBUG
257 TEXT buffer[512];
258 STRPTR last = NULL;
259 ULONG seggdbhlplen = 0;
260 #endif
262 mod->m_segments = AllocVec(mod->m_segcnt * sizeof(struct segment *), MEMF_PUBLIC | MEMF_CLEAR);
264 #if AROS_MODULES_DEBUG
265 ForeachNode(list, seg)
267 if (seg->s_name) seggdbhlplen += strlen(seg->s_name) + 5 + 2 + sizeof(APTR) * 2;
269 #endif
271 ForeachNodeSafe(list, seg, tmpnode)
273 Remove((struct Node*)seg);
275 /* Assign segment to module */
276 mod->m_segments[segidx++] = seg;
278 #if AROS_MODULES_DEBUG
279 /* This solution isn't pretty but it allows to actually load symbols of C++
280 * heavy programs in sane time. The original approach with generating
281 * this in .gdbinit script took about 3 minutes for binary with around 4000
282 * sections. Now loading symbols for such file takes 2-3 seconds.
284 if (seg->s_name) /* Only for segments which have a name */
286 if (mod->m_seggdbhlp == NULL)
288 mod->m_seggdbhlp = AllocVec(seggdbhlplen, MEMF_PUBLIC | MEMF_CLEAR);
289 __sprintf(mod->m_seggdbhlp, "0x%lx ", seg->s_lowest);
290 last = mod->m_seggdbhlp + strlen(mod->m_seggdbhlp);
292 else
294 __sprintf(buffer, "-s %s 0x%lx ", seg->s_name, seg->s_lowest);
295 strcpy(last, buffer);
296 last += strlen(buffer);
299 #endif
303 /* Sort the symbols by their address so that searching can be faster */
304 qsort(mod->m_segments, 0, mod->m_segcnt - 1);
306 /* Set module address range information */
307 mod->m_lowest = mod->m_segments[0]->s_lowest;
308 mod->m_highest = mod->m_segments[mod->m_segcnt - 1]->s_highest;
310 /* Calculate biggest gap */
311 mod->m_gaplowest = (void *)-1;
312 mod->m_gaphighest = (void *)0;
314 for (i = 0; i < mod->m_segcnt - 1; i++)
316 IPTR gapsize = (IPTR)mod->m_segments[i + 1]->s_lowest - (IPTR)mod->m_segments[i]->s_highest - 1;
317 if (gapsize > maxgapsize)
319 maxgapsize = gapsize;
320 mod->m_gaplowest = (void *)((IPTR)mod->m_segments[i]->s_highest + 1);
321 mod->m_gaphighest = (void *)((IPTR)mod->m_segments[i + 1]->s_lowest - 1);
325 D(bug("[Debug] Module %s gap 0x%x - 0x%x\n", mod->m_name, mod->m_gaplowest, mod->m_gaphighest));
328 static void RegisterModule_Hunk(const char *name, BPTR segList, ULONG DebugType, APTR DebugInfo, struct Library *DebugBase)
330 module_t *mod;
331 int i = 0;
332 struct MinList tmplist;
334 mod = AllocVec(sizeof(module_t) + strlen(name), MEMF_PUBLIC|MEMF_CLEAR);
335 if (!mod)
336 return;
337 NEWLIST(&tmplist);
338 strcpy(mod->m_name, name);
339 mod->m_seg = segList;
341 while (segList) {
342 ULONG *segPtr = BADDR(segList);
343 struct segment *seg = AllocMem(sizeof(struct segment), MEMF_PUBLIC | MEMF_CLEAR);
344 if (seg) {
345 seg->s_lowest = (UBYTE*)segPtr - 4;
346 seg->s_highest = (UBYTE*)segPtr + segPtr[-1];
347 seg->s_seg = segList;
348 seg->s_num = i;
349 seg->s_mod = mod;
350 mod->m_segcnt++;
352 AddTail((struct List *)&tmplist, (struct Node *)seg);
354 D(bug("[Debug] Adding segment %d 0x%p (%p-%p)\n", i, segList, seg->s_lowest, seg->s_highest));
356 segList = *(BPTR *)BADDR(segList);
357 i++;
360 ObtainSemaphore(&DBGBASE(DebugBase)->db_ModSem);
361 AddTail((struct List *)&DBGBASE(DebugBase)->db_Modules, (struct Node *)mod);
362 ReleaseSemaphore(&DBGBASE(DebugBase)->db_ModSem);
364 HandleModuleSegments(mod, &tmplist);
367 void RegisterModule_ELF(const char *name, BPTR segList, struct elfheader *eh, struct sheader *sections,
368 struct Library *DebugBase)
370 module_t *mod = AllocVec(sizeof(module_t) + strlen(name), MEMF_PUBLIC|MEMF_CLEAR);
371 BOOL segListSkip = (segList == BNULL ? TRUE : FALSE);
373 D(bug("[Debug] RegisterModule_ELF(%s)\n", name));
375 if (mod)
377 ULONG int_shnum = eh->shnum;
378 ULONG int_shstrndx = eh->shstrndx;
379 ULONG shstr;
380 ULONG i;
381 struct MinList tmplist;
383 NEWLIST(&tmplist);
385 /* Get wider versions of shnum and shstrndx from first section header if needed */
386 if (int_shnum == 0)
387 int_shnum = sections[0].size;
388 if (int_shstrndx == SHN_XINDEX)
389 int_shstrndx = sections[0].link;
391 D(bug("[Debug] %d sections at 0x%p\n", int_shnum, sections));
392 shstr = int_shstrndx;
394 strcpy(mod->m_name, name);
395 mod->m_seg = segList;
396 if (sections[shstr].type == SHT_STRTAB)
397 mod->m_shstr = getstrtab(&sections[shstr]);
399 for (i=0; i < int_shnum; i++)
401 /* Ignore all empty segments */
402 if (sections[i].size)
404 /* If we have string table, copy it */
405 if ((sections[i].type == SHT_STRTAB) && (!mod->m_str)) {
406 /* We are looking for .strtab, not .shstrtab or .stabstr */
407 if (mod->m_shstr && (strcmp(&mod->m_shstr[sections[i].name], ".strtab") == 0)) {
408 D(bug("[Debug] Symbol name table of length %d in section %d\n", sections[i].size, i));
409 mod->m_str = getstrtab(&sections[i]);
413 /* Every loadable section with nonzero size got a corresponding DOS segment */
414 if ((segListSkip || segList) && (sections[i].flags & SHF_ALLOC))
416 struct segment *seg = AllocMem(sizeof(struct segment), MEMF_PUBLIC);
418 if (seg) {
419 D(bug("[Debug] Adding segment 0x%p\n", segList));
421 seg->s_lowest = sections[i].addr;
422 seg->s_highest = sections[i].addr + sections[i].size - 1;
423 seg->s_seg = segList; /* Note that this will differ from s_lowest */
424 seg->s_mod = mod;
425 seg->s_num = i;
426 if (mod->m_shstr)
427 seg->s_name = &mod->m_shstr[sections[i].name];
428 else
429 seg->s_name = NULL;
431 mod->m_segcnt++;
433 AddTail((struct List *)&tmplist, (struct Node *)seg);
436 /* Advance to next DOS segment */
437 if (!segListSkip) segList = *(BPTR *)BADDR(segList);
442 /* If the module contains no loadable segments (hm, weird),
443 we actually got nothing linked in our base list. This means
444 that module handle is actually a garbage and we can deallocate
445 it right now, and do nothing more */
446 if (mod->m_segcnt == 0)
448 FreeVec(mod->m_str);
449 FreeVec(mod->m_shstr);
450 FreeVec(mod);
452 return;
455 ObtainSemaphore(&DBGBASE(DebugBase)->db_ModSem);
456 AddTail((struct List *)&DBGBASE(DebugBase)->db_Modules, (struct Node *)mod);
457 ReleaseSemaphore(&DBGBASE(DebugBase)->db_ModSem);
459 HandleModuleSegments(mod, &tmplist);
460 D(bug("[Debug] Module %s, 0x%x - 0x%x added to list of modules\n", mod->m_name, mod->m_lowest, mod->m_highest));
462 /* Parse module's symbol table */
463 for (i=0; i < int_shnum; i++)
465 if (sections[i].addr && sections[i].type == SHT_SYMTAB)
467 struct symbol *st = (struct symbol *)sections[i].addr;
468 unsigned int symcnt = sections[i].size / sizeof(struct symbol);
469 dbg_sym_t *sym = AllocVec(sizeof(dbg_sym_t) * symcnt, MEMF_PUBLIC);
470 unsigned int j;
472 mod->m_symbols = sym;
474 if (sym) {
475 for (j=0; j < symcnt; j++)
477 int idx = st[j].shindex;
479 /* Ignore these - they should not be here at all */
480 if ((idx == SHN_UNDEF) || (idx == SHN_COMMON))
481 continue;
482 /* TODO: perhaps XINDEX support is needed */
483 if (idx == SHN_XINDEX)
484 continue;
486 if (idx == SHN_ABS) {
487 addsymbol(mod, sym, &st[j], (APTR)st[j].value);
488 DSYMS(bug("[Debug] Added ABS symbol '%s' %08x-%08x\n", sym->s_name, sym->s_lowest, sym->s_highest));
489 sym++;
490 } else if (sections[idx].addr && (sections[idx].flags & SHF_ALLOC)) {
491 addsymbol(mod, sym, &st[j], sections[idx].addr + st[j].value);
492 DSYMS(bug("[Debug] Added symbol '%s' %08x-%08x\n", sym->s_name, sym->s_lowest, sym->s_highest));
493 sym++;
497 break;