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

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

Made build on VCC80 / amd64.

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