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
);
28 static void RegisterModule_ELF(const char *name
, BPTR segList
, struct elfheader
*eh
, struct sheader
*sections
,
29 struct Library
*DebugBase
);
31 /*****************************************************************************
34 #include <proto/debug.h>
36 AROS_LH4(void, RegisterModule
,
39 AROS_LHA(const char *, name
, A0
),
40 AROS_LHA(BPTR
, segList
, A1
),
41 AROS_LHA(ULONG
, debugType
, D0
),
42 AROS_LHA(APTR
, debugInfo
, A2
),
45 struct Library
*, DebugBase
, 5, Debug
)
48 Add information about the loaded executable module to the
49 debug information database
53 segList - DOS segment list for the module
54 debugType - Type of supplied debug information. The only currently
55 supported type is DEBUG_ELF.
56 debugInfo - Debug information data. For DEBUG_ELF type this should be
57 a pointer to struct ELF_DebugInfo, filled in as follows:
58 eh - a pointer to ELF file header.
59 sh - a pointer to an array of ELF section headers.
73 The function supposes that segments in DOS list are linked in the same
74 order in which corresponding sections are placed in the file
76 ******************************************************************************/
80 D(bug("[Debug] RegisterModule(%s, 0x%p, %d)\n", name
, segList
, debugType
));
82 if (debugType
== DEBUG_ELF
)
84 struct elfheader
*eh
= ((struct ELF_DebugInfo
*)debugInfo
)->eh
;
85 struct sheader
*sections
= ((struct ELF_DebugInfo
*)debugInfo
)->sh
;
87 RegisterModule_ELF(name
, segList
, eh
, sections
, DebugBase
);
89 } else if (debugType
== DEBUG_PARTHENOPE
) {
90 const struct Parthenope_ModuleInfo
*pm
;
92 ForeachNode(debugInfo
, pm
) {
95 seg
= AllocVec(sizeof(struct segment
) + sizeof(module_t
) + strlen(pm
->m_name
), MEMF_PUBLIC
|MEMF_CLEAR
);
100 const struct Parthenope_Symbol
*sym
;
101 APTR str_l
= (APTR
)~(uintptr_t)0, str_h
= (APTR
)(uintptr_t)0;
102 APTR seg_l
= (APTR
)~(uintptr_t)0, seg_h
= (APTR
)(uintptr_t)0;
103 module_t
*mod
= (module_t
*)(&seg
[1]);
105 DSYMS(bug("[Debug] Adding module @%p: %s\n", pm
, pm
->m_name
));
106 strcpy(mod
->m_name
, pm
->m_name
);
110 seg
->s_name
= mod
->m_name
;
117 /* Determine the size of the string table */
119 ForeachNode(&pm
->m_symbols
, sym
) {
122 APTR end
= (APTR
)sym
->s_name
+ strlen(sym
->s_name
) + 1 + 1;
123 if ((APTR
)sym
->s_name
< str_l
)
124 str_l
= (APTR
)sym
->s_name
;
128 if ((APTR
)(uintptr_t)sym
->s_lowest
< seg_l
)
129 seg_l
= (APTR
)(uintptr_t)sym
->s_lowest
;
130 if ((APTR
)(uintptr_t)sym
->s_highest
> seg_h
)
131 seg_h
= (APTR
)(uintptr_t)sym
->s_highest
;
135 DSYMS(bug("[Debug] String table %p-%p (%u bytes)\n", str_l
, str_h
, (unsigned int)(str_h
- str_l
)));
136 DSYMS(bug("[Debug] Symbols for %p-%p (%u symbols)\n", seg_l
, seg_h
, symbols
));
138 seg
->s_lowest
= (APTR
)seg_l
;
139 seg
->s_highest
= (APTR
)seg_h
;
141 mod
->m_symcnt
= symbols
;
142 mod
->m_str
= AllocVec(str_h
- str_l
, MEMF_PUBLIC
);
145 CopyMem(str_l
, mod
->m_str
, str_h
- str_l
);
147 mod
->m_symbols
= AllocVec(sizeof(*mod
->m_symbols
) * symbols
, MEMF_PUBLIC
);
148 if (mod
->m_symbols
) {
149 struct MinList tmplist
;
152 dsym
= mod
->m_symbols
;
153 ForeachNode(&pm
->m_symbols
, sym
) {
154 dsym
->s_name
= ((APTR
)sym
->s_name
- str_l
) + mod
->m_str
;
155 dsym
->s_lowest
= (APTR
)(uintptr_t)sym
->s_lowest
;
156 dsym
->s_highest
= (APTR
)(uintptr_t)sym
->s_highest
;
160 AddTail((struct List
*)&tmplist
, (struct Node
*)seg
);
162 ObtainSemaphore(&DBGBASE(DebugBase
)->db_ModSem
);
163 AddTail((struct List
*)&DBGBASE(DebugBase
)->db_LoadedModules
, (struct Node
*)mod
);
164 ReleaseSemaphore(&DBGBASE(DebugBase
)->db_ModSem
);
166 HandleModuleSegments(mod
, &tmplist
);
179 } else if (debugType
== DEBUG_HUNK
) {
180 RegisterModule_Hunk(name
, segList
, debugType
, debugInfo
, DebugBase
);
185 static inline char *getstrtab(struct sheader
*sh
)
189 str
= AllocVec(sh
->size
, MEMF_PUBLIC
);
191 CopyMem(sh
->addr
, str
, sh
->size
);
196 static void addsymbol(module_t
*mod
, dbg_sym_t
*sym
, struct symbol
*st
, APTR value
)
199 sym
->s_name
= &mod
->m_str
[st
->name
];
203 sym
->s_lowest
= value
;
205 sym
->s_highest
= value
+ st
->size
- 1;
207 /* For symbols with zero size KDL_SymbolEnd will give NULL */
208 sym
->s_highest
= NULL
;
210 /* We count symbols here because not all of them can be added */
214 static void HandleModuleSegments(module_t
*mod
, struct MinList
* list
)
217 struct Node
*tmpnode
;
218 LONG segidx
= 0, i
= 0;
219 #if AROS_MODULES_DEBUG
222 ULONG seggdbhlplen
= 0;
225 mod
->m_segments
= AllocVec(mod
->m_segcnt
* sizeof(struct segment
*), MEMF_PUBLIC
| MEMF_CLEAR
);
227 #if AROS_MODULES_DEBUG
228 ForeachNode(list
, seg
)
230 if (seg
->s_name
) seggdbhlplen
+= strlen(seg
->s_name
) + 5 + 2 + sizeof(APTR
) * 2;
234 ForeachNodeSafe(list
, seg
, tmpnode
)
236 Remove((struct Node
*)seg
);
238 /* Assign segment to module */
239 mod
->m_segments
[segidx
++] = seg
;
241 #if AROS_MODULES_DEBUG
242 /* This solution isn't pretty but it allows to actually load symbols of C++
243 * heavy programs in sane time. The original approach with generating
244 * this in .gdbinit script took about 3 minutes for binary with around 4000
245 * sections. Now loading symbols for such file takes 2-3 seconds.
247 if (seg
->s_name
) /* Only for segments which have a name */
249 if (mod
->m_seggdbhlp
== NULL
)
251 mod
->m_seggdbhlp
= AllocVec(seggdbhlplen
, MEMF_PUBLIC
| MEMF_CLEAR
);
252 __sprintf(mod
->m_seggdbhlp
, "0x%x ", seg
->s_lowest
);
253 last
= mod
->m_seggdbhlp
+ strlen(mod
->m_seggdbhlp
);
257 __sprintf(buffer
, "-s %s 0x%x ", seg
->s_name
, seg
->s_lowest
);
258 strcpy(last
, buffer
);
259 last
+= strlen(buffer
);
265 /* Sort the symbols by their address so that searching can be faster */
266 while(i
< mod
->m_segcnt
- 1)
268 if (mod
->m_segments
[i
]->s_lowest
> mod
->m_segments
[i
+ 1]->s_lowest
)
270 struct segment
*temp
= mod
->m_segments
[i
+ 1];
271 mod
->m_segments
[i
+ 1] = mod
->m_segments
[i
];
272 mod
->m_segments
[i
] = temp
;
273 if (i
> 0) i
-= 1; /* Repeat the check on previous element */
278 /* Set module address range information */
279 mod
->m_lowest
= mod
->m_segments
[0]->s_lowest
;
280 mod
->m_highest
= mod
->m_segments
[mod
->m_segcnt
- 1]->s_highest
;
283 static void RegisterModule_Hunk(const char *name
, BPTR segList
, ULONG DebugType
, APTR DebugInfo
, struct Library
*DebugBase
)
287 struct MinList tmplist
;
289 mod
= AllocVec(sizeof(module_t
) + strlen(name
), MEMF_PUBLIC
|MEMF_CLEAR
);
293 strcpy(mod
->m_name
, name
);
294 mod
->m_seg
= segList
;
297 ULONG
*segPtr
= BADDR(segList
);
298 struct segment
*seg
= AllocMem(sizeof(struct segment
), MEMF_PUBLIC
| MEMF_CLEAR
);
300 seg
->s_lowest
= (UBYTE
*)segPtr
- 4;
301 seg
->s_highest
= (UBYTE
*)segPtr
+ segPtr
[-1];
302 seg
->s_seg
= segList
;
307 AddTail((struct List
*)&tmplist
, (struct Node
*)seg
);
309 D(bug("[Debug] Adding segment %d 0x%p (%p-%p)\n", i
, segList
, seg
->s_lowest
, seg
->s_highest
));
311 segList
= *(BPTR
*)BADDR(segList
);
315 ObtainSemaphore(&DBGBASE(DebugBase
)->db_ModSem
);
316 AddTail((struct List
*)&DBGBASE(DebugBase
)->db_LoadedModules
, (struct Node
*)mod
);
317 ReleaseSemaphore(&DBGBASE(DebugBase
)->db_ModSem
);
319 HandleModuleSegments(mod
, &tmplist
);
322 static void RegisterModule_ELF(const char *name
, BPTR segList
, struct elfheader
*eh
, struct sheader
*sections
,
323 struct Library
*DebugBase
)
325 module_t
*mod
= AllocVec(sizeof(module_t
) + strlen(name
), MEMF_PUBLIC
|MEMF_CLEAR
);
329 ULONG int_shnum
= eh
->shnum
;
330 ULONG int_shstrndx
= eh
->shstrndx
;
333 struct MinList tmplist
;
337 /* Get wider versions of shnum and shstrndx from first section header if needed */
339 int_shnum
= sections
[0].size
;
340 if (int_shstrndx
== SHN_XINDEX
)
341 int_shstrndx
= sections
[0].link
;
343 D(bug("[Debug] %d sections at 0x%p\n", int_shnum
, sections
));
344 shstr
= SHINDEX(int_shstrndx
);
346 strcpy(mod
->m_name
, name
);
347 mod
->m_seg
= segList
;
348 if (sections
[shstr
].type
== SHT_STRTAB
)
349 mod
->m_shstr
= getstrtab(§ions
[shstr
]);
351 for (i
=0; i
< int_shnum
; i
++)
353 /* Ignore all empty segments */
354 if (sections
[i
].size
)
356 /* If we have string table, copy it */
357 if ((sections
[i
].type
== SHT_STRTAB
) && (!mod
->m_str
)) {
358 /* We are looking for .strtab, not .shstrtab or .stabstr */
359 if (mod
->m_shstr
&& (strcmp(&mod
->m_shstr
[sections
[i
].name
], ".strtab") == 0)) {
360 D(bug("[Debug] Symbol name table of length %d in section %d\n", sections
[i
].size
, i
));
361 mod
->m_str
= getstrtab(§ions
[i
]);
365 /* Every loadable section with nonzero size got a corresponding DOS segment */
366 if (segList
&& (sections
[i
].flags
& SHF_ALLOC
))
368 struct segment
*seg
= AllocMem(sizeof(struct segment
), MEMF_PUBLIC
);
371 D(bug("[Debug] Adding segment 0x%p\n", segList
));
373 seg
->s_lowest
= sections
[i
].addr
;
374 seg
->s_highest
= sections
[i
].addr
+ sections
[i
].size
- 1;
375 seg
->s_seg
= segList
; /* Note that this will differ from s_lowest */
379 seg
->s_name
= &mod
->m_shstr
[sections
[i
].name
];
385 AddTail((struct List
*)&tmplist
, (struct Node
*)seg
);
388 /* Advance to next DOS segment */
389 segList
= *(BPTR
*)BADDR(segList
);
394 /* If the module contains no loadable segments (hm, weird),
395 we actually got nothing linked in our base list. This means
396 that module handle is actually a garbage and we can deallocate
397 it right now, and do nothing more */
398 if (mod
->m_segcnt
== 0)
401 FreeVec(mod
->m_shstr
);
407 ObtainSemaphore(&DBGBASE(DebugBase
)->db_ModSem
);
408 AddTail((struct List
*)&DBGBASE(DebugBase
)->db_LoadedModules
, (struct Node
*)mod
);
409 ReleaseSemaphore(&DBGBASE(DebugBase
)->db_ModSem
);
411 HandleModuleSegments(mod
, &tmplist
);
413 /* Parse module's symbol table */
414 for (i
=0; i
< int_shnum
; i
++)
416 if (sections
[i
].addr
&& sections
[i
].type
== SHT_SYMTAB
)
418 struct symbol
*st
= (struct symbol
*)sections
[i
].addr
;
419 unsigned int symcnt
= sections
[i
].size
/ sizeof(struct symbol
);
420 dbg_sym_t
*sym
= AllocVec(sizeof(dbg_sym_t
) * symcnt
, MEMF_PUBLIC
);
423 mod
->m_symbols
= sym
;
426 for (j
=0; j
< symcnt
; j
++)
428 int idx
= st
[j
].shindex
;
430 /* Ignore these - they should not be here at all */
431 if ((idx
== SHN_UNDEF
) || (idx
== SHN_COMMON
))
433 /* TODO: perhaps XINDEX support is needed */
434 if (idx
== SHN_XINDEX
)
437 if (idx
== SHN_ABS
) {
438 addsymbol(mod
, sym
, &st
[j
], (APTR
)st
[j
].value
);
439 DSYMS(bug("[Debug] Added ABS symbol '%s' %08x-%08x\n", sym
->s_name
, sym
->s_lowest
, sym
->s_highest
));
441 } else if (sections
[idx
].addr
&& (sections
[idx
].flags
& SHF_ALLOC
)) {
442 addsymbol(mod
, sym
, &st
[j
], sections
[idx
].addr
+ st
[j
].value
);
443 DSYMS(bug("[Debug] Added symbol '%s' %08x-%08x\n", sym
->s_name
, sym
->s_lowest
, sym
->s_highest
));