source: trunk/kStuff/kDbg/kDbgModule.cpp

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

license update.

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