VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dbg/dbgmodghidra.cpp@ 89895

Last change on this file since 89895 was 89895, checked in by vboxsync, 4 years ago

Runtime/common/dbg/dbgmodghidra.cpp: Some fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.8 KB
Line 
1/* $Id: dbgmodghidra.cpp 89895 2021-06-24 18:24:12Z vboxsync $ */
2/** @file
3 * IPRT - Debug Info Reader for Ghidra XML files created with createPdbXmlFiles.bat/pdb.exe.
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/dbg.h>
32#include "internal/iprt.h"
33
34#include <iprt/err.h>
35#include <iprt/ctype.h>
36#include <iprt/mem.h>
37#include <iprt/sort.h>
38#include <iprt/stream.h>
39#include <iprt/string.h>
40#include <iprt/cpp/xml.h>
41#include "internal/dbgmod.h"
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47/**
48 * Temporary segment data.
49 */
50typedef struct RTDBGMODGHIDRASEG
51{
52 const char *pszNumber;
53 RTUINTPTR uRva;
54} RTDBGMODGHIDRASEG;
55typedef RTDBGMODGHIDRASEG *PRTDBGMODGHIDRASEG;
56typedef const RTDBGMODGHIDRASEG *PCRTDBGMODGHIDRASEG;
57
58
59/** @interface_method_impl{RTDBGMODVTDBG,pfnUnwindFrame} */
60static DECLCALLBACK(int) rtDbgModGhidra_UnwindFrame(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTDBGUNWINDSTATE pState)
61{
62 RT_NOREF(pMod, iSeg, off, pState);
63 return VERR_DBG_NO_UNWIND_INFO;
64}
65
66
67/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
68static DECLCALLBACK(int) rtDbgModGhidra_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
69 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
70{
71 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
72 return RTDbgModLineByAddr(hCnt, iSeg, off, poffDisp, pLineInfo);
73}
74
75
76/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
77static DECLCALLBACK(int) rtDbgModGhidra_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
78{
79 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
80 return RTDbgModLineByOrdinal(hCnt, iOrdinal, pLineInfo);
81}
82
83
84/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
85static DECLCALLBACK(uint32_t) rtDbgModGhidra_LineCount(PRTDBGMODINT pMod)
86{
87 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
88 return RTDbgModLineCount(hCnt);
89}
90
91
92/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
93static DECLCALLBACK(int) rtDbgModGhidra_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
94 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
95{
96 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
97 Assert(!pszFile[cchFile]); NOREF(cchFile);
98 return RTDbgModLineAdd(hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
99}
100
101
102/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
103static DECLCALLBACK(int) rtDbgModGhidra_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
104 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
105{
106 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
107 return RTDbgModSymbolByAddr(hCnt, iSeg, off, fFlags, poffDisp, pSymInfo);
108}
109
110
111/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
112static DECLCALLBACK(int) rtDbgModGhidra_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
113 PRTDBGSYMBOL pSymInfo)
114{
115 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
116 Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
117 return RTDbgModSymbolByName(hCnt, pszSymbol, pSymInfo);
118}
119
120
121/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
122static DECLCALLBACK(int) rtDbgModGhidra_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
123{
124 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
125 return RTDbgModSymbolByOrdinal(hCnt, iOrdinal, pSymInfo);
126}
127
128
129/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
130static DECLCALLBACK(uint32_t) rtDbgModGhidra_SymbolCount(PRTDBGMODINT pMod)
131{
132 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
133 return RTDbgModSymbolCount(hCnt);
134}
135
136
137/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
138static DECLCALLBACK(int) rtDbgModGhidra_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
139 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
140 uint32_t *piOrdinal)
141{
142 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
143 Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
144 return RTDbgModSymbolAdd(hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
145}
146
147
148/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
149static DECLCALLBACK(int) rtDbgModGhidra_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
150{
151 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
152 return RTDbgModSegmentByIndex(hCnt, iSeg, pSegInfo);
153}
154
155
156/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
157static DECLCALLBACK(RTDBGSEGIDX) rtDbgModGhidra_SegmentCount(PRTDBGMODINT pMod)
158{
159 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
160 return RTDbgModSegmentCount(hCnt);
161}
162
163
164/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
165static DECLCALLBACK(int) rtDbgModGhidra_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
166 size_t cchName, uint32_t fFlags, PRTDBGSEGIDX piSeg)
167{
168 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
169 Assert(!pszName[cchName]); NOREF(cchName);
170 return RTDbgModSegmentAdd(hCnt, uRva, cb, pszName, fFlags, piSeg);
171}
172
173
174/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
175static DECLCALLBACK(RTUINTPTR) rtDbgModGhidra_ImageSize(PRTDBGMODINT pMod)
176{
177 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
178 return RTDbgModImageSize(hCnt);
179}
180
181
182/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
183static DECLCALLBACK(RTDBGSEGIDX) rtDbgModGhidra_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
184{
185 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
186 return RTDbgModRvaToSegOff(hCnt, uRva, poffSeg);
187}
188
189
190/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
191static DECLCALLBACK(int) rtDbgModGhidra_Close(PRTDBGMODINT pMod)
192{
193 RTDBGMOD hCnt = (RTDBGMOD)pMod->pvDbgPriv;
194 RTDbgModRelease(hCnt);
195 pMod->pvDbgPriv = NULL;
196 return VINF_SUCCESS;
197}
198
199
200/**
201 * Returns the table with the given name from the given table list.
202 *
203 * @returns Pointer to the XML element node containing the given table or NULL if not found.
204 * @param pelmTables Pointer to the node containing the tables.
205 * @param pszName The table name to look for.
206 */
207static const xml::ElementNode *rtDbgModGhidraGetTableByName(const xml::ElementNode *pelmTables, const char *pszName)
208{
209 xml::NodesLoop nl1(*pelmTables, "table");
210 const xml::ElementNode *pelmTbl;
211 while ((pelmTbl = nl1.forAllNodes()))
212 {
213 const char *pszTblName = NULL;
214
215 if ( pelmTbl->getAttributeValue("name", &pszTblName)
216 && !strcmp(pszTblName, pszName))
217 return pelmTbl;
218 }
219
220 return NULL;
221}
222
223
224/**
225 * Adds the symbols from the given \"Symbols\" table.
226 *
227 * @returns IPRT status code.
228 * @param hCnt Debug module container handle.
229 * @param elmTbl Reference to the XML node containing the symbols.
230 */
231static int rtDbgModGhidraXmlParseSymbols(RTDBGMOD hCnt, const xml::ElementNode &elmTbl)
232{
233 xml::NodesLoop nlSym(elmTbl, "symbol");
234 const xml::ElementNode *pelmSym;
235 while ((pelmSym = nlSym.forAllNodes()))
236 {
237 /* Only parse Function and PublicSymbol tags. */
238 const char *pszTag = NULL;
239 if ( pelmSym->getAttributeValue("tag", &pszTag)
240 && ( !strcmp(pszTag, "PublicSymbol")
241 || !strcmp(pszTag, "Function")))
242 {
243 const char *pszSymName = NULL;
244 if ( !pelmSym->getAttributeValue("undecorated", &pszSymName)
245 || *pszSymName == '\0')
246 pelmSym->getAttributeValue("name", &pszSymName);
247
248 if ( pszSymName
249 && strlen(pszSymName) < RTDBG_SYMBOL_NAME_LENGTH)
250 {
251 uint64_t u64Addr = 0;
252 uint64_t u64Length = 0;
253 if ( pelmSym->getAttributeValue("address", &u64Addr)
254 && pelmSym->getAttributeValue("length", &u64Length))
255 {
256 int rc = RTDbgModSymbolAdd(hCnt, pszSymName, RTDBGSEGIDX_RVA, u64Addr, u64Length, 0 /*fFlags*/, NULL);
257 if ( RT_FAILURE(rc)
258 && rc != VERR_DBG_DUPLICATE_SYMBOL
259 && rc != VERR_DBG_ADDRESS_CONFLICT
260 && rc != VERR_DBG_INVALID_RVA) /* (don't be too strict) */
261 return rc;
262 }
263 }
264 }
265 }
266
267 return VINF_SUCCESS;
268}
269
270
271/**
272 * @copydoc FNRTSORTCMP
273 */
274static DECLCALLBACK(int) rtDbgModGhidraSegmentsSortCmp(void const *pvElement1, void const *pvElement2, void *pvUser)
275{
276 RT_NOREF(pvUser);
277 PCRTDBGMODGHIDRASEG pSeg1 = (PCRTDBGMODGHIDRASEG)pvElement1;
278 PCRTDBGMODGHIDRASEG pSeg2 = (PCRTDBGMODGHIDRASEG)pvElement2;
279
280 if (pSeg1->uRva > pSeg2->uRva)
281 return 1;
282 if (pSeg1->uRva < pSeg2->uRva)
283 return -1;
284
285 return 0;
286}
287
288
289/**
290 * Adds the segments in the given \"SegmentMap\" table.
291 *
292 * @returns IPRT status code.
293 * @param hCnt Debug module container handle.
294 * @param elmTblSeg Reference to the XML node containing the segments.
295 */
296static int rtDbgModGhidraSegmentsAdd(RTDBGMOD hCnt, const xml::ElementNode &elmTblSeg)
297{
298 RTDBGMODGHIDRASEG aSegments[32];
299 uint32_t idxSeg = 0;
300
301 xml::NodesLoop nl1(elmTblSeg, "segment");
302 const xml::ElementNode *pelmSeg;
303 while ( (pelmSeg = nl1.forAllNodes())
304 && idxSeg < RT_ELEMENTS(aSegments))
305 {
306 const char *pszNumber = NULL;
307 RTUINTPTR uRva = 0;
308
309 if ( pelmSeg->getAttributeValue("number", &pszNumber)
310 && pelmSeg->getAttributeValue("address", &uRva))
311 {
312 aSegments[idxSeg].pszNumber = pszNumber;
313 aSegments[idxSeg].uRva = uRva;
314 idxSeg++;
315 }
316 }
317
318 /* Sort the segments by RVA so it is possible to deduce segment sizes. */
319 RTSortShell(&aSegments[0], idxSeg, sizeof(aSegments[0]), rtDbgModGhidraSegmentsSortCmp, NULL);
320
321 for (uint32_t i = 0; i < idxSeg - 1; i++)
322 {
323 int rc = RTDbgModSegmentAdd(hCnt, aSegments[i].uRva, aSegments[i + 1].uRva - aSegments[i].uRva,
324 aSegments[i].pszNumber, 0 /*fFlags*/, NULL);
325 if (RT_FAILURE(rc))
326 return rc;
327 }
328
329 /* Last segment for which we assume a size of 0 right now. */
330 int rc = RTDbgModSegmentAdd(hCnt, aSegments[idxSeg - 1].uRva, 0,
331 aSegments[idxSeg - 1].pszNumber, 0 /*fFlags*/, NULL);
332 if (RT_FAILURE(rc))
333 return rc;
334
335 return rc;
336}
337
338
339/**
340 * Load the symbols from an XML document.
341 *
342 * @returns IPRT status code.
343 * @param hCnt Debug module container handle.
344 * @param a_pDoc Pointer to the XML document.
345 */
346static int rtDbgModGhidraXmlParse(RTDBGMOD hCnt, xml::Document *a_pDoc)
347{
348 /*
349 * Get the root element and check whether it looks like a valid Ghidra XML.
350 */
351 const xml::ElementNode *pelmRoot = a_pDoc->getRootElement();
352 if ( !pelmRoot
353 || strcmp(pelmRoot->getName(), "pdb") != 0)
354 return VERR_DBG_NO_MATCHING_INTERPRETER;
355
356 const xml::ElementNode *pelmTables = pelmRoot->findChildElement("tables");
357 if (!pelmTables)
358 return VERR_DBG_NO_MATCHING_INTERPRETER;
359
360 const xml::ElementNode *pelmTbl = rtDbgModGhidraGetTableByName(pelmTables, "SegmentMap");
361 if (pelmTbl)
362 {
363 int rc = rtDbgModGhidraSegmentsAdd(hCnt, *pelmTbl);
364 if (RT_SUCCESS(rc))
365 {
366 pelmTbl = rtDbgModGhidraGetTableByName(pelmTables, "Symbols");
367 if (pelmTbl)
368 return rtDbgModGhidraXmlParseSymbols(hCnt, *pelmTbl);
369 }
370 }
371
372 return VERR_DBG_NO_MATCHING_INTERPRETER;
373}
374
375
376/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
377static DECLCALLBACK(int) rtDbgModGhidra_TryOpen(PRTDBGMODINT pMod, RTLDRARCH enmArch)
378{
379 RT_NOREF(enmArch);
380
381 /*
382 * Fend off images.
383 */
384 if (!pMod->pszDbgFile)
385 return VERR_DBG_NO_MATCHING_INTERPRETER;
386 pMod->pvDbgPriv = NULL;
387
388 /*
389 * Try open the file and create an instance.
390 */
391 xml::Document Doc;
392 {
393 xml::XmlFileParser Parser;
394 try
395 {
396 Parser.read(pMod->pszDbgFile, Doc);
397 }
398 catch (xml::XmlError &rErr)
399 {
400 RT_NOREF(rErr);
401 return VERR_DBG_NO_MATCHING_INTERPRETER;
402 }
403 catch (xml::EIPRTFailure &rErr)
404 {
405 return rErr.rc();
406 }
407 }
408
409 RTDBGMOD hCnt;
410 int rc = RTDbgModCreate(&hCnt, pMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
411 if (RT_SUCCESS(rc))
412 {
413 /*
414 * Hand the xml doc over to the common code.
415 */
416 try
417 {
418 rc = rtDbgModGhidraXmlParse(hCnt, &Doc);
419 if (RT_SUCCESS(rc))
420 {
421 pMod->pvDbgPriv = hCnt;
422 return VINF_SUCCESS;
423 }
424 }
425 catch (RTCError &rXcpt) // includes all XML exceptions
426 {
427 RT_NOREF(rXcpt);
428 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
429 }
430 RTDbgModRelease(hCnt);
431 }
432
433 return rc;
434}
435
436
437
438/** Virtual function table for the Ghidra XML file reader. */
439DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgGhidra =
440{
441 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
442 /*.fSupports = */ RT_DBGTYPE_OTHER | RT_DBGTYPE_MAP,
443 /*.pszName = */ "ghidra",
444 /*.pfnTryOpen = */ rtDbgModGhidra_TryOpen,
445 /*.pfnClose = */ rtDbgModGhidra_Close,
446
447 /*.pfnRvaToSegOff = */ rtDbgModGhidra_RvaToSegOff,
448 /*.pfnImageSize = */ rtDbgModGhidra_ImageSize,
449
450 /*.pfnSegmentAdd = */ rtDbgModGhidra_SegmentAdd,
451 /*.pfnSegmentCount = */ rtDbgModGhidra_SegmentCount,
452 /*.pfnSegmentByIndex = */ rtDbgModGhidra_SegmentByIndex,
453
454 /*.pfnSymbolAdd = */ rtDbgModGhidra_SymbolAdd,
455 /*.pfnSymbolCount = */ rtDbgModGhidra_SymbolCount,
456 /*.pfnSymbolByOrdinal = */ rtDbgModGhidra_SymbolByOrdinal,
457 /*.pfnSymbolByName = */ rtDbgModGhidra_SymbolByName,
458 /*.pfnSymbolByAddr = */ rtDbgModGhidra_SymbolByAddr,
459
460 /*.pfnLineAdd = */ rtDbgModGhidra_LineAdd,
461 /*.pfnLineCount = */ rtDbgModGhidra_LineCount,
462 /*.pfnLineByOrdinal = */ rtDbgModGhidra_LineByOrdinal,
463 /*.pfnLineByAddr = */ rtDbgModGhidra_LineByAddr,
464
465 /*.pfnUnwindFrame = */ rtDbgModGhidra_UnwindFrame,
466
467 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
468};
469
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette