VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTLdrFlt.cpp@ 84273

Last change on this file since 84273 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 KB
Line 
1/* $Id: RTLdrFlt.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - Utility for translating addresses into symbols+offset.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. 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/mem.h>
32#include <iprt/assert.h>
33#include <iprt/ctype.h>
34#include <iprt/dbg.h>
35#include <iprt/err.h>
36#include <iprt/getopt.h>
37#include <iprt/initterm.h>
38#include <iprt/message.h>
39#include <iprt/path.h>
40#include <iprt/stream.h>
41#include <iprt/string.h>
42
43
44
45/**
46 * Tries to parse out an address at the head of the string.
47 *
48 * @returns true if found address, false if not.
49 * @param psz Where to start parsing.
50 * @param pcchAddress Where to store the address length.
51 * @param pu64Address Where to store the address value.
52 */
53static bool TryParseAddress(const char *psz, size_t *pcchAddress, uint64_t *pu64Address)
54{
55 const char *pszStart = psz;
56
57 /*
58 * Hex prefix?
59 */
60 if (psz[0] == '0' && (psz[1] == 'x' || psz[1] == 'X'))
61 psz += 2;
62
63 /*
64 * How many hex digits? We want at least 4 and at most 16.
65 */
66 size_t off = 0;
67 while (RT_C_IS_XDIGIT(psz[off]))
68 off++;
69 if (off < 4 || off > 16)
70 return false;
71
72 /*
73 * Check for separator (xxxxxxxx'yyyyyyyy).
74 */
75 bool fHave64bitSep = off <= 8
76 && psz[off] == '\''
77 && RT_C_IS_XDIGIT(psz[off + 1])
78 && RT_C_IS_XDIGIT(psz[off + 2])
79 && RT_C_IS_XDIGIT(psz[off + 3])
80 && RT_C_IS_XDIGIT(psz[off + 4])
81 && RT_C_IS_XDIGIT(psz[off + 5])
82 && RT_C_IS_XDIGIT(psz[off + 6])
83 && RT_C_IS_XDIGIT(psz[off + 7])
84 && RT_C_IS_XDIGIT(psz[off + 8])
85 && !RT_C_IS_XDIGIT(psz[off + 9]);
86 if (fHave64bitSep)
87 {
88 uint32_t u32High;
89 int rc = RTStrToUInt32Ex(psz, NULL, 16, &u32High);
90 if (rc != VWRN_TRAILING_CHARS)
91 return false;
92
93 uint32_t u32Low;
94 rc = RTStrToUInt32Ex(&psz[off + 1], NULL, 16, &u32Low);
95 if ( rc != VINF_SUCCESS
96 && rc != VWRN_TRAILING_SPACES
97 && rc != VWRN_TRAILING_CHARS)
98 return false;
99
100 *pu64Address = RT_MAKE_U64(u32Low, u32High);
101 off += 1 + 8;
102 }
103 else
104 {
105 int rc = RTStrToUInt64Ex(psz, NULL, 16, pu64Address);
106 if ( rc != VINF_SUCCESS
107 && rc != VWRN_TRAILING_SPACES
108 && rc != VWRN_TRAILING_CHARS)
109 return false;
110 }
111
112 *pcchAddress = psz + off - pszStart;
113 return true;
114}
115
116
117int main(int argc, char **argv)
118{
119 int rc = RTR3InitExe(argc, &argv, 0);
120 if (RT_FAILURE(rc))
121 return RTMsgInitFailure(rc);
122
123 /*
124 * Create an empty address space that we can load modules and stuff into
125 * as we parse the parameters.
126 */
127 RTDBGAS hDbgAs;
128 rc = RTDbgAsCreate(&hDbgAs, 0, RTUINTPTR_MAX, "");
129 if (RT_FAILURE(rc))
130 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDBgAsCreate -> %Rrc", rc);
131
132 /*
133 * Create a debugging configuration instance to work with so that we can
134 * make use of (i.e. test) path searching and such.
135 */
136 RTDBGCFG hDbgCfg;
137 rc = RTDbgCfgCreate(&hDbgCfg, "IPRT", true /*fNativePaths*/);
138 if (RT_FAILURE(rc))
139 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgCfgCreate -> %Rrc", rc);
140
141 /*
142 * Parse arguments.
143 */
144 static const RTGETOPTDEF s_aOptions[] =
145 {
146 { "--input", 'i', RTGETOPT_REQ_STRING },
147 { "--local-file", 'l', RTGETOPT_REQ_NOTHING },
148 { "--cache-file", 'c', RTGETOPT_REQ_NOTHING },
149 { "--pe-image", 'p', RTGETOPT_REQ_NOTHING },
150 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
151 { "--x86", '8', RTGETOPT_REQ_NOTHING },
152 { "--amd64", '6', RTGETOPT_REQ_NOTHING },
153 { "--whatever", '*', RTGETOPT_REQ_NOTHING },
154 };
155
156 PRTSTREAM pInput = g_pStdIn;
157 PRTSTREAM pOutput = g_pStdOut;
158 unsigned cVerbosityLevel = 0;
159 enum {
160 kOpenMethod_FromImage,
161 kOpenMethod_FromPeImage
162 } enmOpenMethod = kOpenMethod_FromImage;
163 bool fCacheFile = false;
164 RTLDRARCH enmArch = RTLDRARCH_WHATEVER;
165
166 RTGETOPTUNION ValueUnion;
167 RTGETOPTSTATE GetState;
168 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
169 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
170 {
171 switch (rc)
172 {
173 case 'i':
174 rc = RTStrmOpen(ValueUnion.psz, "r", &pInput);
175 if (RT_FAILURE(rc))
176 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to open '%s' for reading: %Rrc", ValueUnion.psz, rc);
177 break;
178
179 case 'c':
180 fCacheFile = true;
181 break;
182
183 case 'l':
184 fCacheFile = false;
185 break;
186
187 case 'p':
188 enmOpenMethod = kOpenMethod_FromPeImage;
189 break;
190
191 case 'v':
192 cVerbosityLevel++;
193 break;
194
195 case '8':
196 enmArch = RTLDRARCH_X86_32;
197 break;
198
199 case '6':
200 enmArch = RTLDRARCH_AMD64;
201 break;
202
203 case '*':
204 enmArch = RTLDRARCH_WHATEVER;
205 break;
206
207 case 'h':
208 RTPrintf("Usage: %s [options] <module> <address> [<module> <address> [..]]\n"
209 "\n"
210 "Options:\n"
211 " -i,--input=file\n"
212 " Specify a input file instead of standard input.\n"
213 " --pe-image\n"
214 " Use RTDbgModCreateFromPeImage to open the file."
215 " -v, --verbose\n"
216 " Display the address space before doing the filtering.\n"
217 " --amd64,--x86,--whatever\n"
218 " Selects the desired architecture.\n"
219 " -h, -?, --help\n"
220 " Display this help text and exit successfully.\n"
221 " -V, --version\n"
222 " Display the revision and exit successfully.\n"
223 , RTPathFilename(argv[0]));
224 return RTEXITCODE_SUCCESS;
225
226 case 'V':
227 RTPrintf("$Revision: 82968 $\n");
228 return RTEXITCODE_SUCCESS;
229
230 case VINF_GETOPT_NOT_OPTION:
231 {
232 /* <module> <address> */
233 const char *pszModule = ValueUnion.psz;
234
235 rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX);
236 if (RT_FAILURE(rc))
237 return RTGetOptPrintError(rc, &ValueUnion);
238 uint64_t u64Address = ValueUnion.u64;
239
240 uint32_t cbImage = 0;
241 uint32_t uTimestamp = 0;
242 if (fCacheFile)
243 {
244 rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX);
245 if (RT_FAILURE(rc))
246 return RTGetOptPrintError(rc, &ValueUnion);
247 cbImage = ValueUnion.u32;
248
249 rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX);
250 if (RT_FAILURE(rc))
251 return RTGetOptPrintError(rc, &ValueUnion);
252 uTimestamp = ValueUnion.u32;
253 }
254
255 RTDBGMOD hMod;
256 if (enmOpenMethod == kOpenMethod_FromImage)
257 rc = RTDbgModCreateFromImage(&hMod, pszModule, NULL, enmArch, hDbgCfg);
258 else
259 rc = RTDbgModCreateFromPeImage(&hMod, pszModule, NULL, NULL, cbImage, uTimestamp, hDbgCfg);
260 if (RT_FAILURE(rc))
261 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgModCreateFromImage(,%s,,) -> %Rrc", pszModule, rc);
262
263 rc = RTDbgAsModuleLink(hDbgAs, hMod, u64Address, 0 /* fFlags */);
264 if (RT_FAILURE(rc))
265 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTDbgAsModuleLink(,%s,%llx,) -> %Rrc", pszModule, u64Address, rc);
266 break;
267 }
268
269 default:
270 return RTGetOptPrintError(rc, &ValueUnion);
271 }
272 }
273
274 /*
275 * Display the address space.
276 */
277 if (cVerbosityLevel)
278 {
279 RTPrintf("*** Address Space Dump ***\n");
280 uint32_t cModules = RTDbgAsModuleCount(hDbgAs);
281 for (uint32_t iModule = 0; iModule < cModules; iModule++)
282 {
283 RTDBGMOD hDbgMod = RTDbgAsModuleByIndex(hDbgAs, iModule);
284 RTPrintf("Module #%u: %s\n", iModule, RTDbgModName(hDbgMod));
285
286 RTDBGASMAPINFO aMappings[128];
287 uint32_t cMappings = RT_ELEMENTS(aMappings);
288 rc = RTDbgAsModuleQueryMapByIndex(hDbgAs, iModule, &aMappings[0], &cMappings, 0 /*fFlags*/);
289 if (RT_SUCCESS(rc))
290 {
291 for (uint32_t iMapping = 0; iMapping < cMappings; iMapping++)
292 {
293 if (aMappings[iMapping].iSeg == NIL_RTDBGSEGIDX)
294 {
295 RTPrintf(" mapping #%u: %RTptr-%RTptr\n",
296 iMapping,
297 aMappings[iMapping].Address,
298 aMappings[iMapping].Address + RTDbgModImageSize(hDbgMod) - 1);
299 if (cVerbosityLevel > 2)
300 {
301 uint32_t cSegments = RTDbgModSegmentCount(hDbgMod);
302 for (uint32_t iSeg = 0; iSeg < cSegments; iSeg++)
303 {
304 RTDBGSEGMENT SegInfo;
305 rc = RTDbgModSegmentByIndex(hDbgMod, iSeg, &SegInfo);
306 if (RT_SUCCESS(rc))
307 RTPrintf(" seg #%u: %RTptr LB %RTptr '%s'\n",
308 iSeg, SegInfo.uRva, SegInfo.cb, SegInfo.szName);
309 else
310 RTPrintf(" seg #%u: %Rrc\n", iSeg, rc);
311 }
312 }
313 }
314 else
315 {
316 RTDBGSEGMENT SegInfo;
317 rc = RTDbgModSegmentByIndex(hDbgMod, aMappings[iMapping].iSeg, &SegInfo);
318 if (RT_SUCCESS(rc))
319 RTPrintf(" mapping #%u: %RTptr-%RTptr (segment #%u - '%s')\n",
320 iMapping,
321 aMappings[iMapping].Address,
322 aMappings[iMapping].Address + SegInfo.cb,
323 SegInfo.iSeg, SegInfo.szName);
324 else
325 RTPrintf(" mapping #%u: %RTptr-???????? (segment #%u) rc=%Rrc\n",
326 iMapping, aMappings[iMapping].Address, aMappings[iMapping].iSeg, rc);
327 }
328
329 if (cVerbosityLevel > 1)
330 {
331 uint32_t cSymbols = RTDbgModSymbolCount(hDbgMod);
332 RTPrintf(" %u symbols\n", cSymbols);
333 for (uint32_t iSymbol = 0; iSymbol < cSymbols; iSymbol++)
334 {
335 RTDBGSYMBOL SymInfo;
336 rc = RTDbgModSymbolByOrdinal(hDbgMod, iSymbol, &SymInfo);
337 if (RT_SUCCESS(rc))
338 RTPrintf(" #%04u at %08x:%RTptr (%RTptr) %05llx %s\n",
339 SymInfo.iOrdinal, SymInfo.iSeg, SymInfo.offSeg, SymInfo.Value,
340 (uint64_t)SymInfo.cb, SymInfo.szName);
341 }
342 }
343 }
344 }
345 else
346 RTMsgError("RTDbgAsModuleQueryMapByIndex failed: %Rrc", rc);
347 RTDbgModRelease(hDbgMod);
348 }
349 RTPrintf("*** End of Address Space Dump ***\n");
350 }
351
352 /*
353 * Read text from standard input and see if there is anything we can translate.
354 */
355 for (;;)
356 {
357 /* Get a line. */
358 char szLine[_64K];
359 rc = RTStrmGetLine(pInput, szLine, sizeof(szLine));
360 if (rc == VERR_EOF)
361 break;
362 if (RT_FAILURE(rc))
363 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTStrmGetLine() -> %Rrc\n", rc);
364
365 /*
366 * Search the line for potential addresses and replace them with
367 * symbols+offset.
368 */
369 const char *pszStart = szLine;
370 const char *psz = szLine;
371 char ch;
372 while ((ch = *psz) != '\0')
373 {
374 size_t cchAddress;
375 uint64_t u64Address;
376
377 if ( ( ch == '0'
378 && (psz[1] == 'x' || psz[1] == 'X')
379 && TryParseAddress(psz, &cchAddress, &u64Address))
380 || ( RT_C_IS_XDIGIT(ch)
381 && TryParseAddress(psz, &cchAddress, &u64Address))
382 )
383 {
384 /* Print. */
385 psz += cchAddress;
386 if (pszStart != psz)
387 RTStrmWrite(pOutput, pszStart, psz - pszStart);
388 pszStart = psz;
389
390 /* Try get the module. */
391 RTUINTPTR uAddr;
392 RTDBGSEGIDX iSeg;
393 RTDBGMOD hDbgMod;
394 rc = RTDbgAsModuleByAddr(hDbgAs, u64Address, &hDbgMod, &uAddr, &iSeg);
395 if (RT_SUCCESS(rc))
396 {
397 if (iSeg != UINT32_MAX)
398 RTStrmPrintf(pOutput, "=[%s:%u", RTDbgModName(hDbgMod), iSeg);
399 else
400 RTStrmPrintf(pOutput, "=[%s", RTDbgModName(hDbgMod));
401
402 /*
403 * Do we have symbols?
404 */
405 RTDBGSYMBOL Symbol;
406 RTINTPTR offSym;
407 rc = RTDbgAsSymbolByAddr(hDbgAs, u64Address, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, &offSym, &Symbol, NULL);
408 if (RT_SUCCESS(rc))
409 {
410 if (!offSym)
411 RTStrmPrintf(pOutput, "!%s", Symbol.szName);
412 else if (offSym > 0)
413 RTStrmPrintf(pOutput, "!%s+%#llx", Symbol.szName, offSym);
414 else
415 RTStrmPrintf(pOutput, "!%s-%#llx", Symbol.szName, -offSym);
416 }
417 else
418 RTStrmPrintf(pOutput, "+%#llx", u64Address - uAddr);
419
420 /*
421 * Do we have line numbers?
422 */
423 RTDBGLINE Line;
424 RTINTPTR offLine;
425 rc = RTDbgAsLineByAddr(hDbgAs, u64Address, &offLine, &Line, NULL);
426 if (RT_SUCCESS(rc))
427 RTStrmPrintf(pOutput, " %Rbn(%u)", Line.szFilename, Line.uLineNo);
428
429 RTStrmPrintf(pOutput, "]");
430 RTDbgModRelease(hDbgMod);
431 }
432 }
433 else
434 psz++;
435 }
436
437 if (pszStart != psz)
438 RTStrmWrite(pOutput, pszStart, psz - pszStart);
439 RTStrmPutCh(pOutput, '\n');
440
441 }
442
443 return RTEXITCODE_SUCCESS;
444}
445
Note: See TracBrowser for help on using the repository browser.

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