source: trunk/kStuff/kDbg/kDbgModule.cpp@ 3598

Last change on this file since 3598 was 3598, checked in by bird, 18 years ago

hacking darwin.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.2 KB
Line 
1/* $Id: kDbgModule.cpp 3598 2007-10-04 18:46:12Z bird $ */
2/** @file
3 * kDbg - The Debug Info Reader, Module API.
4 */
5
6/*
7 * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
8 *
9 * This file is part of kStuff.
10 *
11 * kStuff is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * kStuff is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with kStuff; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include "kDbgInternal.h"
31#include <k/kHlpString.h>
32#include <k/kHlpAlloc.h>
33
34
35/*******************************************************************************
36* Global Variables *
37*******************************************************************************/
38/**
39 * The built-in debug module readers.
40 */
41static PCKDBGMODOPS const g_aBuiltIns[] =
42{
43#if K_OS == K_OS_WINDOWS
44 &g_kDbgModWinDbgHelpOpen,
45#endif
46 &g_kDbgModLdr,
47// &g_kDbgModCv8,
48// &g_kDbgModDwarf,
49// &g_kDbgModHll,
50// &g_kDbgModStabs,
51// &g_kDbgModSym,
52// &g_kDbgModMapILink,
53// &g_kDbgModMapMSLink,
54// &g_kDbgModMapNm,
55// &g_kDbgModMapWLink
56};
57
58/**
59 * The debug module readers registered at runtime.
60 */
61static PKDBGMODOPS g_pHead = NULL;
62
63
64/**
65 * Register a debug module reader with the kDbgModule component.
66 *
67 * Dynamically registered readers are kept in FIFO order, and external
68 * readers will be tried after the builtin ones.
69 *
70 * Like all other kDbg APIs serializing is left to the caller.
71 *
72 * @returns 0 on success.
73 * @returns KERR_INVALID_POINTER if pOps is missing bits.
74 * @returns KERR_INVALID_PARAMETER if pOps is already in the list.
75 * @param pOps The reader method table, kDbg takes owner ship of
76 * this. This must be writeable as the pNext pointer
77 * will be update. It must also stick around for as
78 * long as kDbg is in use.
79 */
80KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps)
81{
82 /*
83 * Validate input.
84 */
85 kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER);
86 kDbgAssertPtrReturn(pOps->pszName, KERR_INVALID_POINTER);
87 kDbgAssertPtrReturn(pOps->pfnOpen, KERR_INVALID_POINTER);
88 kDbgAssertPtrReturn(pOps->pfnClose, KERR_INVALID_POINTER);
89 kDbgAssertPtrReturn(pOps->pfnQuerySymbol, KERR_INVALID_POINTER);
90 kDbgAssertPtrReturn(pOps->pfnQueryLine, KERR_INVALID_POINTER);
91 kDbgAssertPtrReturn(pOps->pszName2, KERR_INVALID_POINTER);
92 if (kHlpStrComp(pOps->pszName, pOps->pszName2))
93 return KERR_INVALID_PARAMETER;
94 kDbgAssertReturn(pOps->pNext == NULL, KERR_INVALID_PARAMETER);
95
96 /*
97 * Link it into the list.
98 */
99 if (!g_pHead)
100 g_pHead = pOps;
101 else
102 {
103 PKDBGMODOPS pPrev = g_pHead;
104 while (pPrev->pNext)
105 pPrev = pPrev->pNext;
106 kDbgAssertReturn(pPrev != pOps, KERR_INVALID_PARAMETER);
107 pPrev->pNext = pOps;
108 }
109 return 0;
110}
111
112
113/**
114 * Deregister a debug module reader previously registered using
115 * the kDbgModuleRegisterReader API.
116 *
117 * Deregistering a reader does not mean that non of its functions
118 * will be called after successful return, it only means that it
119 * will no longer be subjected to new module.
120 *
121 * @returns 0 on success.
122 * @returns KERR_INVALID_POINTER if pOps isn't a valid pointer.
123 * @returns KERR_INVALID_PARAMETER if pOps wasn't registered.
124 * @param pOps The debug module method table to deregister.
125 */
126KDBG_DECL(int) kDbgModuleDeregisterReader(PKDBGMODOPS pOps)
127{
128 /*
129 * Validate the pointer.
130 */
131 kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER);
132
133 /*
134 * Find it in the list and unlink it.
135 */
136 if (g_pHead == pOps)
137 g_pHead = pOps->pNext;
138 else
139 {
140 PKDBGMODOPS pPrev = g_pHead;
141 while (pPrev && pPrev->pNext != pOps)
142 pPrev = pPrev->pNext;
143 if (!pPrev)
144 return KERR_INVALID_PARAMETER;
145 pPrev->pNext = pOps->pNext;
146 }
147 pOps->pNext = NULL;
148 return 0;
149}
150
151
152
153/**
154 * Worker for the kDbgModuleOpen* APIs.
155 *
156 * This will make sure the reader is buffered. I will also take care of
157 * closing the reader opened by kDbgModuleOpen on failure.
158 *
159 * @returns 0 on success. An appropriate kErrors status code on failure.
160 * @param ppDbgMod Where to store the new debug module reader instance.
161 * @param pRdr The file provider.
162 * @param fCloseRdr Whether pRdr should be close or not. This applies both
163 * to the failure path and to the success path, where it'll
164 * be close when the module is closed by kDbgModuleClose().
165 * @param off The offset into the file where the debug info is supposed
166 * to be found.
167 * This is 0 if the entire file is the subject.
168 * @param cb The size of the debug info part of the file.
169 * This is KFOFF_MAX if the entire file is the subject.
170 * @param pLdrMod An optional kLdrMod association.
171 */
172static int kdbgModuleOpenWorker(PPKDBGMOD ppDbgMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
173{
174 /*
175 * If the reader isn't buffered create a buffered wrapper for it.
176 */
177 int rc;
178 PKRDR pRdrWrapped = NULL;
179 if (!kRdrBufIsBuffered(pRdr))
180 {
181 rc = kRdrBufWrap(&pRdrWrapped, pRdr, fCloseRdr);
182 if (rc)
183 {
184 if (fCloseRdr)
185 kRdrClose(pRdr);
186 return rc;
187 }
188 pRdr = pRdrWrapped;
189 }
190
191 /*
192 * Walk the built-in table and the list of registered readers
193 * and let each of them have a go at the file. Stop and return
194 * on the first one returning successfully.
195 */
196 rc = KDBG_ERR_UNKOWN_FORMAT;
197 for (KSIZE i = 0; i < K_ELEMENTS(g_aBuiltIns); i++)
198 if (g_aBuiltIns[i]->pfnOpen)
199 {
200 int rc2 = g_aBuiltIns[i]->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod);
201 if (!rc2)
202 return 0;
203 if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT)
204 rc = rc2;
205 }
206
207 for (PKDBGMODOPS pCur = g_pHead; pCur; pCur = pCur->pNext)
208 if (pCur->pfnOpen)
209 {
210 int rc2 = pCur->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod);
211 if (!rc2)
212 return 0;
213 if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT)
214 rc = rc2;
215 }
216
217 if (pRdrWrapped)
218 kRdrClose(pRdrWrapped);
219 else if (fCloseRdr)
220 kRdrClose(pRdr);
221 return rc;
222}
223
224
225/**
226 * Opens a debug module reader for the specified file or file section
227 *
228 * @returns kStuff status code.
229 * @param ppDbgMod Where to store the debug module reader handle.
230 * @param pRdr The file reader.
231 * @param off The offset of the file section. If the entire file, pass 0.
232 * @param cb The size of the file section. If the entire file, pass KFOFF_MAX.
233 * @param pLdrMod Associated kLdr module that the kDbg component can use to
234 * verify and suplement the debug info found in the file specified
235 * by pszFilename. The module will be used by kDbg for as long as
236 * the returned kDbg module remains open.
237 * This is an optional parameter, pass NULL if no kLdr module at hand.
238 */
239KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
240{
241 /*
242 * Validate input.
243 */
244 kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER);
245 kDbgAssertPtrReturn(pRdr, KERR_INVALID_POINTER);
246 kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER);
247 kDbgAssertMsgReturn(off >= 0 && off < KFOFF_MAX, (KFOFF_PRI "\n", off), KERR_INVALID_OFFSET);
248 kDbgAssertMsgReturn(cb >= 0 && cb <= KFOFF_MAX, (KFOFF_PRI "\n", cb), KERR_INVALID_SIZE);
249 kDbgAssertMsgReturn(off + cb > off, ("off=" KFOFF_PRI " cb=" KFOFF_PRI "\n", off, cb), KERR_INVALID_RANGE);
250 *ppDbgMod = NULL;
251
252 /*
253 * Hand it over to the internal worker.
254 */
255 return kdbgModuleOpenWorker(ppDbgMod, pRdr, K_FALSE /* fCloseRdr */, off, cb, pLdrMod);
256}
257
258
259/**
260 * Opens a debug module reader for the specified file.
261 *
262 * @returns kStuff status code.
263 * @param ppDbgMod Where to store the debug module reader handle.
264 * @param pRdr The file reader.
265 * @param pLdrMod Associated kLdr module that the kDbg component can use to
266 * verify and suplement the debug info found in the file specified
267 * by pszFilename. The module will be used by kDbg for as long as
268 * the returned kDbg module remains open.
269 * This is an optional parameter, pass NULL if no kLdr module at hand.
270 */
271KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod)
272{
273 return kDbgModuleOpenFilePart(ppDbgMod, pRdr, 0, KFOFF_MAX, pLdrMod);
274}
275
276
277/**
278 * Opens the debug info for a specified executable module.
279 *
280 * @returns kStuff status code.
281 * @param ppDbgMod Where to store the debug module handle.
282 * @param pszFilename The name of the file containing debug info and/or which
283 * debug info is wanted.
284 * @param pLdrMod Associated kLdr module that the kDbg component can use to
285 * verify and suplement the debug info found in the file specified
286 * by pszFilename. The module will be used by kDbg for as long as
287 * the returned kDbg module remains open.
288 * This is an optional parameter, pass NULL if no kLdr module at hand.
289 */
290KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod)
291{
292 /*
293 * Validate input.
294 */
295 kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER);
296 kDbgAssertPtrReturn(pszFilename, KERR_INVALID_POINTER);
297 kDbgAssertMsgReturn(*pszFilename, ("%p\n", pszFilename), KERR_INVALID_PARAMETER);
298 kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER);
299 *ppDbgMod = NULL;
300
301 /*
302 * Open the file and see if we can read it.
303 */
304 PKRDR pRdr;
305 int rc = kRdrBufOpen(&pRdr, pszFilename);
306 if (rc)
307 return rc;
308 rc = kdbgModuleOpenWorker(ppDbgMod, pRdr, K_TRUE /* fCloseRdr */, 0, KFOFF_MAX, pLdrMod);
309 return rc;
310}
311
312
313/**
314 * Closes the module.
315 *
316 * @returns IPRT status code.
317 * @param pMod The module handle.
318 */
319KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod)
320{
321 KDBGMOD_VALIDATE(pMod);
322 int rc = pMod->pOps->pfnClose(pMod);
323 if (!rc)
324 {
325 pMod->u32Magic++;
326 kHlpFree(pMod);
327 }
328 return rc;
329}
330
331
332/**
333 * Gets a symbol by segment:offset.
334 * This will be approximated to the nearest symbol if there is no exact match.
335 *
336 * @returns IPRT status code.
337 * @param pMod The module.
338 * @param iSegment The segment this offset is relative to.
339 * The -1 segment is special, it means that the addres is relative to
340 * the image base. The image base is where the first bit of the image
341 * is mapped during load.
342 * @param off The offset into the segment.
343 * @param pSym Where to store the symbol details.
344 */
345KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
346{
347 KDBGMOD_VALIDATE(pMod);
348 kDbgAssertPtrReturn(pSym, KERR_INVALID_POINTER);
349 return pMod->pOps->pfnQuerySymbol(pMod, iSegment, off, pSym);
350}
351
352
353/**
354 * Gets & allocates a symbol by segment:offset.
355 * This will be approximated to the nearest symbol if there is no exact match.
356 *
357 * @returns IPRT status code.
358 * @param pMod The module.
359 * @param iSegment The segment this offset is relative to.
360 * The -1 segment is special, it means that the addres is relative to
361 * the image base. The image base is where the first bit of the image
362 * is mapped during load.
363 * @param off The offset into the segment.
364 * @param ppSym Where to store the pointer to the symbol info.
365 * Free the returned symbol using kDbgSymbolFree().
366 */
367KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym)
368{
369 kDbgAssertPtrReturn(ppSym, KERR_INVALID_POINTER);
370
371 KDBGSYMBOL Sym;
372 int rc = kDbgModuleQuerySymbol(pMod, iSegment, off, &Sym);
373 if (!rc)
374 {
375 *ppSym = kDbgSymbolDup(&Sym);
376 if (!*ppSym)
377 rc = KERR_NO_MEMORY;
378 }
379 else
380 *ppSym = NULL;
381 return rc;
382}
383
384
385/**
386 * Gets a line number entry by segment:offset.
387 * This will be approximated to the nearest line number there is no exact match.
388 *
389 * @returns IPRT status code.
390 * @param pMod The module.
391 * @param iSegment The segment this offset is relative to.
392 * The -1 segment is special, it means that the addres is relative to
393 * the image base. The image base is where the first bit of the image
394 * is mapped during load.
395 * @param off The offset into the segment.
396 * @param pLine Where to store the line number details.
397 */
398KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine)
399{
400 KDBGMOD_VALIDATE(pMod);
401 kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER);
402 return pMod->pOps->pfnQueryLine(pMod, iSegment, off, pLine);
403}
404
405
406/**
407 * Gets & allocates a line number entry by segment:offset.
408 * This will be approximated to the nearest line number there is no exact match.
409 *
410 * @returns IPRT status code.
411 * @param pMod The module.
412 * @param iSegment The segment this offset is relative to.
413 * The -1 segment is special, it means that the addres is relative to
414 * the image base. The image base is where the first bit of the image
415 * is mapped during load.
416 * @param off The offset into the segment.
417 * @param ppLine Where to store the pointer to the line number info.
418 * Free the returned line number using kDbgLineFree().
419 */
420KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine)
421{
422 kDbgAssertPtrReturn(ppLine, KERR_INVALID_POINTER);
423
424 KDBGLINE Line;
425 int rc = kDbgModuleQueryLine(pMod, iSegment, off, &Line);
426 if (!rc)
427 {
428 *ppLine = kDbgLineDup(&Line);
429 if (!*ppLine)
430 rc = KERR_NO_MEMORY;
431 }
432 else
433 *ppLine = NULL;
434 return rc;
435}
436
Note: See TracBrowser for help on using the repository browser.