2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
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>
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 /*****************************************************************************
32 #include <proto/debug.h>
34 AROS_LH4(void, RegisterModule
,
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
),
43 struct Library
*, DebugBase
, 5, Debug
)
46 Add information about the loaded executable module to the
47 debug information database
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.
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 ******************************************************************************/
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
) {
93 seg
= AllocVec(sizeof(struct segment
) + sizeof(module_t
) + strlen(pm
->m_name
), MEMF_PUBLIC
|MEMF_CLEAR
);
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
);
108 seg
->s_name
= mod
->m_name
;
115 /* Determine the size of the string table */
117 ForeachNode(&pm
->m_symbols
, sym
) {
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
;
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
;
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
);
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
;
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
;
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
);
177 } else if (debugType
== DEBUG_HUNK
) {
178 RegisterModule_Hunk(name
, segList
, debugType
, debugInfo
, DebugBase
);
183 static inline char *getstrtab(struct sheader
*sh
)
187 str
= AllocVec(sh
->size
, MEMF_PUBLIC
);
189 CopyMem(sh
->addr
, str
, sh
->size
);
194 static void addsymbol(module_t
*mod
, dbg_sym_t
*sym
, struct symbol
*st
, APTR value
)
197 sym
->s_name
= &mod
->m_str
[st
->name
];
201 sym
->s_lowest
= value
;
203 sym
->s_highest
= value
+ st
->size
- 1;
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 */
213 #define SWAPIDX(a, b) \
216 struct segment * tmp = segments[b]; \
217 segments[b] = segments[a]; \
222 static LONG partition(struct segment **segments, LONG left, LONG right, LONG pivotidx)
224 void * pivotval
= segments
[pivotidx
]->s_lowest
;
225 LONG storeidx
= left
;
227 SWAPIDX(right
, pivotidx
)
229 for (i
= left
; i
< right
; i
++)
230 if (segments
[i
]->s_lowest
< pivotval
)
232 SWAPIDX(i
, storeidx
);
235 SWAPIDX(storeidx
, right
);
239 static VOID
qsort(struct segment
**segments
, LONG left
, LONG right
)
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
)
253 struct Node
*tmpnode
;
254 LONG segidx
= 0, i
= 0;
256 #if AROS_MODULES_DEBUG
259 ULONG seggdbhlplen
= 0;
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;
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
);
294 __sprintf(buffer
, "-s %s 0x%lx ", seg
->s_name
, seg
->s_lowest
);
295 strcpy(last
, buffer
);
296 last
+= strlen(buffer
);
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
)
332 struct MinList tmplist
;
334 mod
= AllocVec(sizeof(module_t
) + strlen(name
), MEMF_PUBLIC
|MEMF_CLEAR
);
338 strcpy(mod
->m_name
, name
);
339 mod
->m_seg
= segList
;
342 ULONG
*segPtr
= BADDR(segList
);
343 struct segment
*seg
= AllocMem(sizeof(struct segment
), MEMF_PUBLIC
| MEMF_CLEAR
);
345 seg
->s_lowest
= (UBYTE
*)segPtr
- 4;
346 seg
->s_highest
= (UBYTE
*)segPtr
+ segPtr
[-1];
347 seg
->s_seg
= segList
;
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
);
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
));
377 ULONG int_shnum
= eh
->shnum
;
378 ULONG int_shstrndx
= eh
->shstrndx
;
381 struct MinList tmplist
;
385 /* Get wider versions of shnum and shstrndx from first section header if needed */
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(§ions
[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(§ions
[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
);
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 */
427 seg
->s_name
= &mod
->m_shstr
[sections
[i
].name
];
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)
449 FreeVec(mod
->m_shstr
);
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
);
472 mod
->m_symbols
= 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
))
482 /* TODO: perhaps XINDEX support is needed */
483 if (idx
== SHN_XINDEX
)
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
));
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
));