1 | /* $Id: DBGCDumpImage.cpp 106073 2024-09-17 14:47:42Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * DBGC - Debugger Console, Native Commands.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2006-2024 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
26 | */
|
---|
27 |
|
---|
28 |
|
---|
29 | /*********************************************************************************************************************************
|
---|
30 | * Header Files *
|
---|
31 | *********************************************************************************************************************************/
|
---|
32 | #define LOG_GROUP LOG_GROUP_DBGC
|
---|
33 | #include <VBox/dbg.h>
|
---|
34 | #include <VBox/vmm/dbgf.h>
|
---|
35 | #include <VBox/param.h>
|
---|
36 | #include <iprt/errcore.h>
|
---|
37 | #include <VBox/log.h>
|
---|
38 |
|
---|
39 | #include <iprt/assert.h>
|
---|
40 | #include <iprt/ctype.h>
|
---|
41 | #include <iprt/dir.h>
|
---|
42 | #include <iprt/env.h>
|
---|
43 | #include <iprt/ldr.h>
|
---|
44 | #include <iprt/mem.h>
|
---|
45 | #include <iprt/path.h>
|
---|
46 | #include <iprt/string.h>
|
---|
47 | #include <iprt/time.h>
|
---|
48 | #ifdef DBGC_DUMP_IMAGE_TOOL
|
---|
49 | # include <iprt/buildconfig.h>
|
---|
50 | # include <iprt/message.h>
|
---|
51 | # include <iprt/file.h>
|
---|
52 | # include <iprt/getopt.h>
|
---|
53 | # include <iprt/initterm.h>
|
---|
54 | # include <iprt/process.h>
|
---|
55 | # include <iprt/stream.h>
|
---|
56 | # include <iprt/vfs.h>
|
---|
57 | #endif
|
---|
58 | #include <iprt/formats/mz.h>
|
---|
59 | #include <iprt/formats/pecoff.h>
|
---|
60 | #include <iprt/formats/elf32.h>
|
---|
61 | #include <iprt/formats/elf64.h>
|
---|
62 | #include <iprt/formats/codeview.h>
|
---|
63 | #include <iprt/formats/mach-o.h>
|
---|
64 |
|
---|
65 | #include "DBGCInternal.h"
|
---|
66 |
|
---|
67 |
|
---|
68 | /*********************************************************************************************************************************
|
---|
69 | * Structures and Typedefs *
|
---|
70 | *********************************************************************************************************************************/
|
---|
71 | #ifdef DBGC_DUMP_IMAGE_TOOL
|
---|
72 | /** Command helper state for the image dumper tool. */
|
---|
73 | typedef struct CMDHLPSTATE
|
---|
74 | {
|
---|
75 | DBGCCMDHLP Core;
|
---|
76 | /** The exit code for the tool. */
|
---|
77 | RTEXITCODE rcExit;
|
---|
78 | /** The current input file. */
|
---|
79 | RTVFSFILE hVfsFile;
|
---|
80 | } CMDHLPSTATE;
|
---|
81 | typedef CMDHLPSTATE *PCMDHLPSTATE;
|
---|
82 | #endif
|
---|
83 |
|
---|
84 |
|
---|
85 | /** Helper for translating flags. */
|
---|
86 | typedef struct
|
---|
87 | {
|
---|
88 | uint32_t fFlag;
|
---|
89 | const char *pszNm;
|
---|
90 | } DBGCDUMPFLAGENTRY;
|
---|
91 | #define FLENT(a_Define) { a_Define, #a_Define }
|
---|
92 |
|
---|
93 |
|
---|
94 |
|
---|
95 | /*********************************************************************************************************************************
|
---|
96 | * DebugImageCmd *
|
---|
97 | *********************************************************************************************************************************/
|
---|
98 |
|
---|
99 | #define DUMPIMAGE_SELECT_HEADERS RT_BIT_64(0)
|
---|
100 | #define DUMPIMAGE_SELECT_SECTIONS RT_BIT_64(1)
|
---|
101 | #define DUMPIMAGE_SELECT_EXPORTS RT_BIT_64(2)
|
---|
102 | #define DUMPIMAGE_SELECT_IMPORTS RT_BIT_64(3)
|
---|
103 | #define DUMPIMAGE_SELECT_TLS RT_BIT_64(4)
|
---|
104 | #define DUMPIMAGE_SELECT_LOAD_CONFIG RT_BIT_64(5)
|
---|
105 | #define DUMPIMAGE_SELECT_RESOURCES RT_BIT_64(6)
|
---|
106 | #define DUMPIMAGE_SELECT_FIXUP RT_BIT_64(7)
|
---|
107 | #define DUMPIMAGE_SELECT_DEBUG RT_BIT_64(8)
|
---|
108 | #define DUMPIMAGE_SELECT_EVERYTHING UINT64_MAX
|
---|
109 | #define DUMPIMAGE_SELECT_DEFAULT DUMPIMAGE_SELECT_EVERYTHING
|
---|
110 |
|
---|
111 | static struct
|
---|
112 | {
|
---|
113 | const char *psz;
|
---|
114 | size_t cch;
|
---|
115 | uint64_t fSel;
|
---|
116 | const char *pszSummary;
|
---|
117 | const char *pszDesc;
|
---|
118 | } const g_aMnemonics[] =
|
---|
119 | {
|
---|
120 | { RT_STR_TUPLE("h"), DUMPIMAGE_SELECT_HEADERS, "h[d[r]],header[s]", "File headers" },
|
---|
121 | { RT_STR_TUPLE("hd"), DUMPIMAGE_SELECT_HEADERS, NULL, NULL },
|
---|
122 | { RT_STR_TUPLE("hdr"), DUMPIMAGE_SELECT_HEADERS, NULL, NULL },
|
---|
123 | { RT_STR_TUPLE("header"), DUMPIMAGE_SELECT_HEADERS, NULL, NULL },
|
---|
124 | { RT_STR_TUPLE("headers"), DUMPIMAGE_SELECT_HEADERS, NULL, NULL },
|
---|
125 | { RT_STR_TUPLE("s"), DUMPIMAGE_SELECT_SECTIONS, "s[e[ction[s]]]", "Section headers"},
|
---|
126 | { RT_STR_TUPLE("se"), DUMPIMAGE_SELECT_SECTIONS, NULL, NULL },
|
---|
127 | { RT_STR_TUPLE("sec"), DUMPIMAGE_SELECT_SECTIONS, NULL, NULL },
|
---|
128 | { RT_STR_TUPLE("section"), DUMPIMAGE_SELECT_SECTIONS, NULL, NULL },
|
---|
129 | { RT_STR_TUPLE("sections"), DUMPIMAGE_SELECT_SECTIONS, NULL, NULL },
|
---|
130 | { RT_STR_TUPLE("d"), DUMPIMAGE_SELECT_DEBUG, "d[b[g[info]]],db,debug", "Debug info headers" },
|
---|
131 | { RT_STR_TUPLE("db"), DUMPIMAGE_SELECT_DEBUG, NULL, NULL },
|
---|
132 | { RT_STR_TUPLE("dg"), DUMPIMAGE_SELECT_DEBUG, NULL, NULL },
|
---|
133 | { RT_STR_TUPLE("dbg"), DUMPIMAGE_SELECT_DEBUG, NULL, NULL },
|
---|
134 | { RT_STR_TUPLE("dbginfo"), DUMPIMAGE_SELECT_DEBUG, NULL, NULL },
|
---|
135 | { RT_STR_TUPLE("debug"), DUMPIMAGE_SELECT_DEBUG, NULL, NULL },
|
---|
136 | { RT_STR_TUPLE("f"), DUMPIMAGE_SELECT_FIXUP, "f[x],fix[up[s]]", "Fixups" },
|
---|
137 | { RT_STR_TUPLE("fx"), DUMPIMAGE_SELECT_FIXUP, NULL, NULL },
|
---|
138 | { RT_STR_TUPLE("fix"), DUMPIMAGE_SELECT_FIXUP, NULL, NULL },
|
---|
139 | { RT_STR_TUPLE("fixup"), DUMPIMAGE_SELECT_FIXUP, NULL, NULL },
|
---|
140 | { RT_STR_TUPLE("fixups"), DUMPIMAGE_SELECT_FIXUP, NULL, NULL },
|
---|
141 | { RT_STR_TUPLE("e"), DUMPIMAGE_SELECT_EXPORTS, "e[x[p[ort[s]]]]", "Exports" },
|
---|
142 | { RT_STR_TUPLE("ex"), DUMPIMAGE_SELECT_EXPORTS, NULL, NULL },
|
---|
143 | { RT_STR_TUPLE("exp"), DUMPIMAGE_SELECT_EXPORTS, NULL, NULL },
|
---|
144 | { RT_STR_TUPLE("export"), DUMPIMAGE_SELECT_EXPORTS, NULL, NULL },
|
---|
145 | { RT_STR_TUPLE("exports"), DUMPIMAGE_SELECT_EXPORTS, NULL, NULL },
|
---|
146 | { RT_STR_TUPLE("i"), DUMPIMAGE_SELECT_IMPORTS, "i[m[p[ort[s]]]]", "Imports" },
|
---|
147 | { RT_STR_TUPLE("im"), DUMPIMAGE_SELECT_IMPORTS, NULL, NULL },
|
---|
148 | { RT_STR_TUPLE("imp"), DUMPIMAGE_SELECT_IMPORTS, NULL, NULL },
|
---|
149 | { RT_STR_TUPLE("import"), DUMPIMAGE_SELECT_IMPORTS, NULL, NULL },
|
---|
150 | { RT_STR_TUPLE("imports"), DUMPIMAGE_SELECT_IMPORTS, NULL, NULL },
|
---|
151 | { RT_STR_TUPLE("l"), DUMPIMAGE_SELECT_LOAD_CONFIG, "l[c[fg],loadcfg", "Load configuration" },
|
---|
152 | { RT_STR_TUPLE("lc"), DUMPIMAGE_SELECT_LOAD_CONFIG, NULL, NULL },
|
---|
153 | { RT_STR_TUPLE("lcfg"), DUMPIMAGE_SELECT_LOAD_CONFIG, NULL, NULL },
|
---|
154 | { RT_STR_TUPLE("loadcfg"), DUMPIMAGE_SELECT_LOAD_CONFIG, NULL, NULL },
|
---|
155 | { RT_STR_TUPLE("rc"), DUMPIMAGE_SELECT_RESOURCES, "rc[s[rc]],resource[s]", "Resources" },
|
---|
156 | { RT_STR_TUPLE("rcs"), DUMPIMAGE_SELECT_RESOURCES, NULL, NULL },
|
---|
157 | { RT_STR_TUPLE("rcsrc"), DUMPIMAGE_SELECT_RESOURCES, NULL, NULL },
|
---|
158 | { RT_STR_TUPLE("resource"), DUMPIMAGE_SELECT_RESOURCES, NULL, NULL },
|
---|
159 | { RT_STR_TUPLE("resources"), DUMPIMAGE_SELECT_RESOURCES, NULL, NULL },
|
---|
160 | { RT_STR_TUPLE("t"), DUMPIMAGE_SELECT_TLS, "t[ls]", "Thread local storage" },
|
---|
161 | { RT_STR_TUPLE("tls"), DUMPIMAGE_SELECT_TLS, NULL, NULL },
|
---|
162 | /* masks: */
|
---|
163 | { RT_STR_TUPLE("all"), DUMPIMAGE_SELECT_EVERYTHING, "all,everything", "Everything" },
|
---|
164 | { RT_STR_TUPLE("everything"), DUMPIMAGE_SELECT_EVERYTHING, NULL, NULL },
|
---|
165 | { RT_STR_TUPLE("def"), DUMPIMAGE_SELECT_DEFAULT, "def[ault]", "Default selection" },
|
---|
166 | { RT_STR_TUPLE("default"), DUMPIMAGE_SELECT_DEFAULT, NULL, NULL },
|
---|
167 | };
|
---|
168 |
|
---|
169 | class DumpImageCmd
|
---|
170 | {
|
---|
171 | public:
|
---|
172 | /** Pointer to the command helpers. */
|
---|
173 | PDBGCCMDHLP const m_pCmdHlp;
|
---|
174 | /** The command descriptor (for failing the command). */
|
---|
175 | PCDBGCCMD const m_pCmd;
|
---|
176 | /** The command exit code. */
|
---|
177 | RTEXITCODE m_rcExit;
|
---|
178 | /** The first failure code. */
|
---|
179 | int m_rc;
|
---|
180 |
|
---|
181 | /** Current number of targets. */
|
---|
182 | unsigned m_cTargets;
|
---|
183 | /** The name of what's being dumped (for error messages). */
|
---|
184 | const char *m_pszName;
|
---|
185 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
186 | /** Debugger: Pointer to the image base address variable. */
|
---|
187 | PCDBGCVAR m_pImageBase;
|
---|
188 | #else
|
---|
189 | /** Command line tool: The file we're dumping. */
|
---|
190 | RTVFSFILE m_hVfsFile;
|
---|
191 | #endif
|
---|
192 |
|
---|
193 | public:
|
---|
194 | /** What to dump (DUMPIMAGE_SELECT_XXX). */
|
---|
195 | uint64_t m_fSelection;
|
---|
196 |
|
---|
197 | private:
|
---|
198 | DumpImageCmd();
|
---|
199 |
|
---|
200 | public:
|
---|
201 | DumpImageCmd(PDBGCCMDHLP a_pCmdHlp, PCDBGCCMD a_pCmd)
|
---|
202 | : m_pCmdHlp(a_pCmdHlp)
|
---|
203 | , m_pCmd(a_pCmd)
|
---|
204 | , m_rcExit(RTEXITCODE_SUCCESS)
|
---|
205 | , m_rc(VINF_SUCCESS)
|
---|
206 | , m_cTargets(0)
|
---|
207 | , m_pszName(NULL)
|
---|
208 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
209 | , m_pImageBase(NULL)
|
---|
210 | #else
|
---|
211 | , m_hVfsFile(NIL_RTVFSFILE)
|
---|
212 | #endif
|
---|
213 | , m_fSelection(DUMPIMAGE_SELECT_DEFAULT)
|
---|
214 | {
|
---|
215 | }
|
---|
216 |
|
---|
217 | ~DumpImageCmd()
|
---|
218 | {
|
---|
219 | clearTarget();
|
---|
220 | }
|
---|
221 |
|
---|
222 | /** @name Methods not requiring any target.
|
---|
223 | * @{ */
|
---|
224 |
|
---|
225 | void myPrintfV(const char *pszFormat, va_list va) const RT_NOEXCEPT
|
---|
226 | {
|
---|
227 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
228 | m_pCmdHlp->pfnPrintfV(m_pCmdHlp, NULL, pszFormat, va);
|
---|
229 | #else
|
---|
230 | RTPrintfV(pszFormat, va);
|
---|
231 | #endif
|
---|
232 | }
|
---|
233 |
|
---|
234 | void myPrintf(const char *pszFormat, ...) const RT_NOEXCEPT
|
---|
235 | {
|
---|
236 | va_list va;
|
---|
237 | va_start(va, pszFormat);
|
---|
238 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
239 | m_pCmdHlp->pfnPrintfV(m_pCmdHlp, NULL, pszFormat, va);
|
---|
240 | #else
|
---|
241 | RTPrintfV(pszFormat, va);
|
---|
242 | #endif
|
---|
243 | va_end(va);
|
---|
244 | }
|
---|
245 |
|
---|
246 | int myErrorV(const char *pszFormat, va_list va) RT_NOEXCEPT
|
---|
247 | {
|
---|
248 | int rc;
|
---|
249 | if (m_pszName)
|
---|
250 | {
|
---|
251 | va_list vaCopy;
|
---|
252 | va_copy(vaCopy, va);
|
---|
253 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
254 | rc = DBGCCmdHlpFail(m_pCmdHlp, m_pCmd, "%s: %N", m_pszName, pszFormat, &vaCopy);
|
---|
255 | #else
|
---|
256 | RTMsgError("%s: %N", m_pszName, pszFormat, &vaCopy);
|
---|
257 | #endif
|
---|
258 | va_end(va);
|
---|
259 | }
|
---|
260 | else
|
---|
261 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
262 | rc = m_pCmdHlp->pfnFailV(m_pCmdHlp, m_pCmd, pszFormat, va);
|
---|
263 | #else
|
---|
264 | RTMsgErrorV(pszFormat, va);
|
---|
265 | rc = VERR_GENERAL_FAILURE;
|
---|
266 | #endif
|
---|
267 |
|
---|
268 | m_rcExit = RTEXITCODE_FAILURE;
|
---|
269 | if (m_rc == VINF_SUCCESS)
|
---|
270 | m_rc = rc;
|
---|
271 | return rc;
|
---|
272 | }
|
---|
273 |
|
---|
274 | int myError(const char *pszFormat, ...) RT_NOEXCEPT
|
---|
275 | {
|
---|
276 | va_list va;
|
---|
277 | va_start(va, pszFormat);
|
---|
278 | int rc = myErrorV(pszFormat, va);
|
---|
279 | va_end(va);
|
---|
280 | return rc;
|
---|
281 | }
|
---|
282 |
|
---|
283 | int myErrorV(int rc, const char *pszFormat, va_list va) RT_NOEXCEPT
|
---|
284 | {
|
---|
285 | if (m_pszName)
|
---|
286 | {
|
---|
287 | va_list vaCopy;
|
---|
288 | va_copy(vaCopy, va);
|
---|
289 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
290 | rc = DBGCCmdHlpFailRc(m_pCmdHlp, m_pCmd, rc, "%s: %N", m_pszName, pszFormat, &vaCopy);
|
---|
291 | #else
|
---|
292 | RTMsgError("%s: %N: %Rrc", m_pszName, pszFormat, &vaCopy, rc);
|
---|
293 | #endif
|
---|
294 | va_end(vaCopy);
|
---|
295 | }
|
---|
296 | else
|
---|
297 | {
|
---|
298 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
299 | rc = m_pCmdHlp->pfnFailRcV(m_pCmdHlp, m_pCmd, rc, pszFormat, va);
|
---|
300 | #else
|
---|
301 | va_list vaCopy;
|
---|
302 | va_copy(vaCopy, va);
|
---|
303 | RTMsgError("%N: %Rrc", pszFormat, &vaCopy, rc);
|
---|
304 | va_end(vaCopy);
|
---|
305 | #endif
|
---|
306 | }
|
---|
307 |
|
---|
308 | m_rcExit = RTEXITCODE_FAILURE;
|
---|
309 | if (m_rc == VINF_SUCCESS)
|
---|
310 | m_rc = rc;
|
---|
311 | return rc;
|
---|
312 | }
|
---|
313 |
|
---|
314 | int myError(int rc, const char *pszFormat, ...) RT_NOEXCEPT
|
---|
315 | {
|
---|
316 | va_list va;
|
---|
317 | va_start(va, pszFormat);
|
---|
318 | rc = myErrorV(rc, pszFormat, va);
|
---|
319 | va_end(va);
|
---|
320 | return rc;
|
---|
321 | }
|
---|
322 |
|
---|
323 | int mySyntax(const char *pszFormat, ...) RT_NOEXCEPT
|
---|
324 | {
|
---|
325 | m_rcExit = RTEXITCODE_SYNTAX;
|
---|
326 | va_list va;
|
---|
327 | va_start(va, pszFormat);
|
---|
328 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
329 | int rc = DBGCCmdHlpFail(m_pCmdHlp, m_pCmd, "syntax: %N", pszFormat, &va);
|
---|
330 | #else
|
---|
331 | RTMsgSyntaxV(pszFormat, va);
|
---|
332 | int const rc = VERR_GENERAL_FAILURE;
|
---|
333 | #endif
|
---|
334 | va_end(va);
|
---|
335 |
|
---|
336 | m_rcExit = RTEXITCODE_SYNTAX;
|
---|
337 | if (m_rc == VINF_SUCCESS)
|
---|
338 | m_rc = rc;
|
---|
339 | return rc;
|
---|
340 | }
|
---|
341 |
|
---|
342 | void setFailure(int rc) RT_NOEXCEPT
|
---|
343 | {
|
---|
344 | m_rcExit = RTEXITCODE_FAILURE;
|
---|
345 | if (m_rc == VINF_SUCCESS)
|
---|
346 | m_rc = rc;
|
---|
347 | }
|
---|
348 |
|
---|
349 | RTEXITCODE getExitCode() const RT_NOEXCEPT
|
---|
350 | {
|
---|
351 | return m_rcExit;
|
---|
352 | }
|
---|
353 |
|
---|
354 | int getStatus() const RT_NOEXCEPT
|
---|
355 | {
|
---|
356 | return m_rc;
|
---|
357 | }
|
---|
358 |
|
---|
359 | private:
|
---|
360 | int parseSelection(const char *pszSelection, uint64_t *pfSel)
|
---|
361 | {
|
---|
362 | *pfSel = 0;
|
---|
363 | char ch;
|
---|
364 | do
|
---|
365 | {
|
---|
366 | /* Skip leading spaces and commas. */
|
---|
367 | while ((ch = *pszSelection) != '\0' && (RT_C_IS_BLANK(ch) || ch == ','))
|
---|
368 | pszSelection++;
|
---|
369 |
|
---|
370 | /* Find the end of the selection mnemonic. */
|
---|
371 | size_t cch = 0;
|
---|
372 | while (ch != '\0' && ch != ',' && !RT_C_IS_BLANK(ch))
|
---|
373 | ch = pszSelection[++cch];
|
---|
374 | if (!cch)
|
---|
375 | {
|
---|
376 | if (*pfSel)
|
---|
377 | break;
|
---|
378 | mySyntax("No selection");
|
---|
379 | return VERR_INVALID_PARAMETER;
|
---|
380 | }
|
---|
381 |
|
---|
382 | /* Look it up. */
|
---|
383 | uint32_t i;
|
---|
384 | for (i = 0; i < RT_ELEMENTS(g_aMnemonics); i++)
|
---|
385 | if (cch == g_aMnemonics[i].cch && memcmp(g_aMnemonics[i].psz, pszSelection, cch) == 0)
|
---|
386 | {
|
---|
387 | *pfSel = g_aMnemonics[i].fSel;
|
---|
388 | break;
|
---|
389 | }
|
---|
390 | if (i >= RT_ELEMENTS(g_aMnemonics))
|
---|
391 | {
|
---|
392 | mySyntax("Unknown selection '%.*s'", cch, pszSelection);
|
---|
393 | return VERR_INVALID_PARAMETER;
|
---|
394 | }
|
---|
395 | } while (ch != '\0');
|
---|
396 | return VINF_SUCCESS;
|
---|
397 | }
|
---|
398 |
|
---|
399 | public:
|
---|
400 | int optSelectionInclude(const char *pszSelection) RT_NOEXCEPT
|
---|
401 | {
|
---|
402 | uint64_t fSel = 0;
|
---|
403 | int rc = parseSelection(pszSelection, &fSel);
|
---|
404 | if (RT_SUCCESS(rc))
|
---|
405 | m_fSelection |= fSel;
|
---|
406 | return rc;
|
---|
407 | }
|
---|
408 |
|
---|
409 | int optSelectionOnly(const char *pszSelection) RT_NOEXCEPT
|
---|
410 | {
|
---|
411 | uint64_t fSel = 0;
|
---|
412 | int rc = parseSelection(pszSelection, &fSel);
|
---|
413 | if (RT_SUCCESS(rc))
|
---|
414 | {
|
---|
415 | if (m_fSelection == DUMPIMAGE_SELECT_DEFAULT)
|
---|
416 | m_fSelection = 0;
|
---|
417 | m_fSelection |= fSel;
|
---|
418 | }
|
---|
419 | return rc;
|
---|
420 | }
|
---|
421 |
|
---|
422 | int optSelectionSkip(const char *pszSelection) RT_NOEXCEPT
|
---|
423 | {
|
---|
424 | uint64_t fSel = 0;
|
---|
425 | int rc = parseSelection(pszSelection, &fSel);
|
---|
426 | if (RT_SUCCESS(rc))
|
---|
427 | m_fSelection &= ~fSel;
|
---|
428 | return rc;
|
---|
429 |
|
---|
430 | }
|
---|
431 |
|
---|
432 | /** @} */
|
---|
433 |
|
---|
434 |
|
---|
435 | /** @name Methods working on a target.
|
---|
436 | * @{ */
|
---|
437 |
|
---|
438 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
439 | void setTarget(const char *a_pszName, PCDBGCVAR a_pImageBase) RT_NOEXCEPT
|
---|
440 | #else
|
---|
441 | void setTarget(const char *a_pszName, RTVFSFILE a_hVfsFile) RT_NOEXCEPT
|
---|
442 | #endif
|
---|
443 | {
|
---|
444 | m_cTargets += 1;
|
---|
445 | m_pszName = a_pszName;
|
---|
446 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
447 | m_pImageBase = a_pImageBase;
|
---|
448 | #else
|
---|
449 | m_hVfsFile = a_hVfsFile;
|
---|
450 | #endif
|
---|
451 | }
|
---|
452 |
|
---|
453 | void clearTarget() RT_NOEXCEPT
|
---|
454 | {
|
---|
455 | m_pszName = NULL;
|
---|
456 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
457 | m_pImageBase = NULL;
|
---|
458 | #else
|
---|
459 | RTVfsFileRelease(m_hVfsFile);
|
---|
460 | m_hVfsFile = NIL_RTVFSFILE;
|
---|
461 | #endif
|
---|
462 | }
|
---|
463 |
|
---|
464 | bool isFirstTarget() const RT_NOEXCEPT
|
---|
465 | {
|
---|
466 | return m_cTargets == 1;
|
---|
467 | }
|
---|
468 |
|
---|
469 | /**
|
---|
470 | * Early read function.
|
---|
471 | *
|
---|
472 | * This kind of works on file offsets, though we all knows that it really
|
---|
473 | * depends on whether the stuff being dumped is in-memory or a file. However,
|
---|
474 | * in the latter case we do not have the ability to do any RVA translation, thus
|
---|
475 | * the input is treated as file offsets.
|
---|
476 | */
|
---|
477 | int readAt(size_t off, void *pvDst, size_t cbToRead, size_t *pcbRead) RT_NOEXCEPT
|
---|
478 | {
|
---|
479 | RT_BZERO(pvDst, cbToRead);
|
---|
480 | if (pcbRead)
|
---|
481 | *pcbRead = 0;
|
---|
482 | /** @todo introduce a buffer here? */
|
---|
483 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
484 | DBGCVAR AddrToReadAt;
|
---|
485 | int rc = DBGCCmdHlpEval(m_pCmdHlp, &AddrToReadAt, "%DV + %#zx", m_pImageBase, off);
|
---|
486 | if (RT_SUCCESS(rc))
|
---|
487 | {
|
---|
488 | rc = DBGCCmdHlpMemRead(m_pCmdHlp, pvDst, cbToRead, &AddrToReadAt, pcbRead);
|
---|
489 | if (RT_SUCCESS(rc))
|
---|
490 | return VINF_SUCCESS;
|
---|
491 | return myError(rc, "Failed to read %zu bytes at offset %Dv", cbToRead, &AddrToReadAt);
|
---|
492 | }
|
---|
493 | return myError(rc, "Failed to calculate address %Dv + #%zx for %#zx byte read", m_pImageBase, off, cbToRead);
|
---|
494 |
|
---|
495 | #else /* DBGC_DUMP_IMAGE_TOOL */
|
---|
496 | int rc = RTVfsFileReadAt(m_hVfsFile, off, pvDst, cbToRead, pcbRead);
|
---|
497 | if (RT_SUCCESS(rc))
|
---|
498 | return VINF_SUCCESS;
|
---|
499 | return myError(rc, "Failed to read %zu bytes at offset %#zx", cbToRead, off);
|
---|
500 | #endif /* DBGC_DUMP_IMAGE_TOOL */
|
---|
501 | }
|
---|
502 |
|
---|
503 | int dumpImage(const char *pszImageBaseAddr) RT_NOEXCEPT;
|
---|
504 |
|
---|
505 | /** @} */
|
---|
506 | };
|
---|
507 |
|
---|
508 |
|
---|
509 | /** Stringifies a 32-bit flag value. */
|
---|
510 | static void dbgcDumpImageFlags32(DumpImageCmd *pCmd, uint32_t fFlags, DBGCDUMPFLAGENTRY const *paEntries, size_t cEntries)
|
---|
511 | {
|
---|
512 | for (size_t i = 0; i < cEntries; i++)
|
---|
513 | if (fFlags & paEntries[i].fFlag)
|
---|
514 | pCmd->myPrintf(" %s", paEntries[i].pszNm);
|
---|
515 | }
|
---|
516 |
|
---|
517 |
|
---|
518 | /*********************************************************************************************************************************
|
---|
519 | * DumpImageBase *
|
---|
520 | *********************************************************************************************************************************/
|
---|
521 | /**
|
---|
522 | * Base class for the dumpers.
|
---|
523 | */
|
---|
524 | class DumpImageBase
|
---|
525 | {
|
---|
526 | protected:
|
---|
527 | DumpImageCmd *m_pCmd;
|
---|
528 |
|
---|
529 | private:
|
---|
530 | /** The Image base address. */
|
---|
531 | uint64_t m_uImageBaseAddr;
|
---|
532 | protected:
|
---|
533 | /** The full formatted address width. */
|
---|
534 | uint8_t m_cchAddr;
|
---|
535 | private:
|
---|
536 | /** The formatted address value width. */
|
---|
537 | uint8_t m_cchAddrValue;
|
---|
538 | /** The address prefix length. */
|
---|
539 | uint8_t m_cchAddrPfx;
|
---|
540 | /** The address prefix. */
|
---|
541 | char m_szAddrPfx[16 - 3];
|
---|
542 |
|
---|
543 | private:
|
---|
544 | DumpImageBase();
|
---|
545 |
|
---|
546 | void setupAddrFormatting(const char *a_pszImageBaseAddr) RT_NOEXCEPT
|
---|
547 | {
|
---|
548 | /*
|
---|
549 | * Expected inputs: %%12345678, %123456789abcdef, 0x12345678, 0008:12345678
|
---|
550 | *
|
---|
551 | * So, work backwards till be find the start of the address/offset value
|
---|
552 | * component, and treat what comes first as a prefix.
|
---|
553 | */
|
---|
554 | size_t const cch = strlen(a_pszImageBaseAddr);
|
---|
555 | size_t cchAddrPfx = cch;
|
---|
556 | while (cchAddrPfx > 0 && RT_C_IS_XDIGIT(a_pszImageBaseAddr[cchAddrPfx - 1]))
|
---|
557 | cchAddrPfx--;
|
---|
558 |
|
---|
559 | size_t cchLeadingZeros = 0;
|
---|
560 | while (a_pszImageBaseAddr[cchAddrPfx + cchLeadingZeros] == '0')
|
---|
561 | cchLeadingZeros++;
|
---|
562 |
|
---|
563 | int rc = RTStrToUInt64Full(&a_pszImageBaseAddr[cchAddrPfx], 16, &m_uImageBaseAddr);
|
---|
564 | AssertRCSuccess(rc);
|
---|
565 | m_cchAddrValue = (uint8_t)(cch - cchAddrPfx);
|
---|
566 | Assert(m_cchAddrValue == cch - cchAddrPfx);
|
---|
567 | if (m_cchAddrValue > 8 && cchLeadingZeros > 1)
|
---|
568 | m_cchAddrValue = RT_ALIGN_T(m_cchAddrValue - (uint8_t)(cchLeadingZeros - 1), 2, uint8_t);
|
---|
569 |
|
---|
570 | AssertStmt(cchAddrPfx < sizeof(m_szAddrPfx), cchAddrPfx = sizeof(m_szAddrPfx) - 1);
|
---|
571 | memcpy(m_szAddrPfx, a_pszImageBaseAddr, cchAddrPfx);
|
---|
572 | m_szAddrPfx[cchAddrPfx] = '\0';
|
---|
573 | m_cchAddrPfx = (uint8_t)cchAddrPfx;
|
---|
574 |
|
---|
575 | m_cchAddr = m_cchAddrPfx + m_cchAddrValue;
|
---|
576 | }
|
---|
577 |
|
---|
578 | public:
|
---|
579 | DumpImageBase(DumpImageCmd *a_pCmd, const char *a_pszImageBaseAddr) RT_NOEXCEPT
|
---|
580 | : m_pCmd(a_pCmd)
|
---|
581 | , m_uImageBaseAddr(0)
|
---|
582 | , m_cchAddr(0)
|
---|
583 | , m_cchAddrValue(12)
|
---|
584 | , m_cchAddrPfx(2)
|
---|
585 | , m_szAddrPfx("0x")
|
---|
586 | {
|
---|
587 | setupAddrFormatting(a_pszImageBaseAddr);
|
---|
588 | }
|
---|
589 |
|
---|
590 | virtual ~DumpImageBase() { }
|
---|
591 |
|
---|
592 | virtual size_t rvaToFileOffset(size_t uRva) const RT_NOEXCEPT = 0;
|
---|
593 | virtual size_t getEndRva(bool a_fAligned = true) const RT_NOEXCEPT = 0;
|
---|
594 |
|
---|
595 | char *rvaToStringWithAddr(size_t uRva, char *pszDst, size_t cbDst, bool fWide = false) const RT_NOEXCEPT
|
---|
596 | {
|
---|
597 | if (!fWide)
|
---|
598 | RTStrPrintf(pszDst, cbDst, "%#09zx/%s%0*RX64", uRva, m_szAddrPfx, m_cchAddrValue, m_uImageBaseAddr + uRva);
|
---|
599 | else
|
---|
600 | RTStrPrintf(pszDst, cbDst, "%#09zx / %s%0*RX64", uRva, m_szAddrPfx, m_cchAddrValue, m_uImageBaseAddr + uRva);
|
---|
601 | return pszDst;
|
---|
602 | }
|
---|
603 |
|
---|
604 | void myPrintf(const char *pszFormat, ...) const RT_NOEXCEPT
|
---|
605 | {
|
---|
606 | va_list va;
|
---|
607 | va_start(va, pszFormat);
|
---|
608 | m_pCmd->myPrintfV(pszFormat, va);
|
---|
609 | va_end(va);
|
---|
610 | }
|
---|
611 |
|
---|
612 | void myPrintHeader(size_t uRva, const char *pszFormat, ...) const RT_NOEXCEPT
|
---|
613 | {
|
---|
614 | char szTmp[64];
|
---|
615 | char szLine[128];
|
---|
616 | va_list va;
|
---|
617 | va_start(va, pszFormat);
|
---|
618 | size_t const cchLine = RTStrPrintf(szLine, sizeof(szLine), "%s - %N",
|
---|
619 | rvaToStringWithAddr(uRva, szTmp, sizeof(szTmp), true), pszFormat, &va);
|
---|
620 | va_end(va);
|
---|
621 | myPrintf("\n"
|
---|
622 | "%s\n"
|
---|
623 | "%.*s====\n",
|
---|
624 | szLine,
|
---|
625 | cchLine, "===============================================================================");
|
---|
626 | }
|
---|
627 |
|
---|
628 | int myError(const char *pszFormat, ...) const RT_NOEXCEPT
|
---|
629 | {
|
---|
630 | va_list va;
|
---|
631 | va_start(va, pszFormat);
|
---|
632 | int rc = m_pCmd->myErrorV(pszFormat, va);
|
---|
633 | va_end(va);
|
---|
634 | return rc;
|
---|
635 | }
|
---|
636 |
|
---|
637 | int myError(int rc, const char *pszFormat, ...) const RT_NOEXCEPT
|
---|
638 | {
|
---|
639 | va_list va;
|
---|
640 | va_start(va, pszFormat);
|
---|
641 | rc = m_pCmd->myErrorV(rc, pszFormat, va);
|
---|
642 | va_end(va);
|
---|
643 | return rc;
|
---|
644 | }
|
---|
645 |
|
---|
646 | int readBytesAtRva(size_t uRva, void *pvBuf, size_t cbToRead, size_t *pcbRead = NULL) RT_NOEXCEPT
|
---|
647 | {
|
---|
648 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
649 | /* RVA and offset is the same in this context. */
|
---|
650 | return m_pCmd->readAt(uRva, pvBuf, cbToRead, pcbRead);
|
---|
651 | #else
|
---|
652 | size_t const offFile = rvaToFileOffset(uRva);
|
---|
653 | if (offFile != ~(size_t)0)
|
---|
654 | return m_pCmd->readAt(offFile, pvBuf, cbToRead, pcbRead);
|
---|
655 | return myError(VERR_READ_ERROR, "Failed to convert RVA %#zx to file offset for %zu byte read!", uRva, cbToRead);
|
---|
656 | #endif
|
---|
657 | }
|
---|
658 | };
|
---|
659 |
|
---|
660 |
|
---|
661 | /**
|
---|
662 | * Buffered reading by relative virtual address (RVA).
|
---|
663 | */
|
---|
664 | class DumpImageBufferedReader
|
---|
665 | {
|
---|
666 | private:
|
---|
667 | /** Static sized buffer. */
|
---|
668 | uint8_t m_abBufFixed[4096];
|
---|
669 | /** Pointer to m_abBufFixed if that's sufficient, otherwise heap buffer. */
|
---|
670 | uint8_t *m_pbBuf;
|
---|
671 | /** The size of the buffer m_pbBuf points at. */
|
---|
672 | size_t m_cbBufAlloc;
|
---|
673 | /** Number of valid bytes in the buffer. */
|
---|
674 | size_t m_cbBuf;
|
---|
675 | /** The RVA of the first buffer byte, maximum value if empty. */
|
---|
676 | size_t m_uRvaBuf;
|
---|
677 | /** Pointer to the image dumper. */
|
---|
678 | DumpImageBase *m_pImage;
|
---|
679 |
|
---|
680 | int loadBuffer(size_t uRva) RT_NOEXCEPT
|
---|
681 | {
|
---|
682 | /* Check that the RVA is within the image. */
|
---|
683 | size_t const cbMaxRva = m_pImage->getEndRva();
|
---|
684 | if (uRva >= cbMaxRva)
|
---|
685 | return VERR_EOF;
|
---|
686 |
|
---|
687 | /* Adjust the RVA if we're reading beyond the end of the image. */
|
---|
688 | if (uRva + m_cbBufAlloc > RT_ALIGN_Z(cbMaxRva, 8))
|
---|
689 | uRva = m_cbBufAlloc < RT_ALIGN_Z(cbMaxRva, 8) ? RT_ALIGN_Z(cbMaxRva, 8) - m_cbBufAlloc : 0;
|
---|
690 |
|
---|
691 | /* Do the read. In case of failure readBytesAtRva will zero the buffer. */
|
---|
692 | m_uRvaBuf = uRva;
|
---|
693 | m_cbBuf = 0;
|
---|
694 | return m_pImage->readBytesAtRva(uRva, m_pbBuf, RT_MIN(cbMaxRva - uRva, m_cbBufAlloc), &m_cbBuf);
|
---|
695 | }
|
---|
696 |
|
---|
697 | /** Resizes the buffer if the current one can't hold @a cbNeeded bytes. */
|
---|
698 | int ensureBufferSpace(size_t cbNeeded) RT_NOEXCEPT
|
---|
699 | {
|
---|
700 | if (cbNeeded > m_cbBufAlloc)
|
---|
701 | {
|
---|
702 | cbNeeded = RT_ALIGN_Z(cbNeeded, 512);
|
---|
703 | void *pvNew = RTMemTmpAllocZ(cbNeeded);
|
---|
704 | if (!pvNew)
|
---|
705 | return m_pImage->myError(VERR_NO_TMP_MEMORY, "Failed to allocate %zu (%#zx) bytes", cbNeeded, cbNeeded);
|
---|
706 | memcpy(pvNew, m_pbBuf, RT_MIN(m_cbBuf, m_cbBufAlloc));
|
---|
707 |
|
---|
708 | if (m_pbBuf != &m_abBufFixed[0])
|
---|
709 | RTMemTmpFree(m_pbBuf);
|
---|
710 | m_pbBuf = (uint8_t *)pvNew;
|
---|
711 | m_cbBufAlloc = cbNeeded;
|
---|
712 | }
|
---|
713 | return VINF_SUCCESS;
|
---|
714 | }
|
---|
715 |
|
---|
716 | DumpImageBufferedReader();
|
---|
717 |
|
---|
718 | public:
|
---|
719 | DumpImageBufferedReader(DumpImageBase *a_pImage) RT_NOEXCEPT
|
---|
720 | : m_pbBuf(&m_abBufFixed[0])
|
---|
721 | , m_cbBufAlloc(sizeof(m_abBufFixed))
|
---|
722 | , m_cbBuf(0)
|
---|
723 | , m_uRvaBuf(~(size_t)0)
|
---|
724 | , m_pImage(a_pImage)
|
---|
725 | {
|
---|
726 | RT_ZERO(m_abBufFixed);
|
---|
727 | }
|
---|
728 |
|
---|
729 | /** Copy constructor. */
|
---|
730 | DumpImageBufferedReader(DumpImageBufferedReader const &a_rThat) RT_NOEXCEPT
|
---|
731 | : m_pbBuf(&m_abBufFixed[0])
|
---|
732 | , m_cbBufAlloc(sizeof(m_abBufFixed))
|
---|
733 | , m_cbBuf(RT_MIN(a_rThat.m_cbBuf, sizeof(m_abBufFixed)))
|
---|
734 | , m_uRvaBuf(a_rThat.m_uRvaBuf)
|
---|
735 | , m_pImage(a_rThat.m_pImage)
|
---|
736 | {
|
---|
737 | memcpy(m_abBufFixed, a_rThat.m_pbBuf, m_cbBuf);
|
---|
738 | if (m_cbBuf < sizeof(m_abBufFixed))
|
---|
739 | RT_BZERO(&m_abBufFixed[m_cbBuf], sizeof(m_abBufFixed) - m_cbBuf);
|
---|
740 | }
|
---|
741 |
|
---|
742 | ~DumpImageBufferedReader() RT_NOEXCEPT
|
---|
743 | {
|
---|
744 | if (m_pbBuf != &m_abBufFixed[0])
|
---|
745 | RTMemTmpFree(m_pbBuf);
|
---|
746 | m_pbBuf = NULL;
|
---|
747 | }
|
---|
748 |
|
---|
749 | /**
|
---|
750 | * Reads @a cbToRead bytes at @a uRva into @a pvDst.
|
---|
751 | *
|
---|
752 | * The buffer is entirely zeroed before reading anything, so it's okay to ignore
|
---|
753 | * the status code.
|
---|
754 | */
|
---|
755 | int readBytes(size_t uRva, void *pvDst, size_t cbToRead) RT_NOEXCEPT
|
---|
756 | {
|
---|
757 | RT_BZERO(pvDst, cbToRead);
|
---|
758 |
|
---|
759 | while (cbToRead)
|
---|
760 | {
|
---|
761 | /*
|
---|
762 | * Is the start of the request overlapping with the buffer?
|
---|
763 | */
|
---|
764 | if (uRva >= m_uRvaBuf)
|
---|
765 | {
|
---|
766 | size_t const offBuf = uRva - m_uRvaBuf;
|
---|
767 | if (offBuf < m_cbBuf)
|
---|
768 | {
|
---|
769 | size_t const cbThisRead = RT_MIN(m_cbBuf - offBuf, cbToRead);
|
---|
770 | memcpy(pvDst, &m_pbBuf[offBuf], cbThisRead);
|
---|
771 | if (cbToRead <= cbThisRead)
|
---|
772 | return VINF_SUCCESS;
|
---|
773 | uRva += cbThisRead;
|
---|
774 | cbToRead -= cbThisRead;
|
---|
775 | pvDst = (uint8_t *)pvDst + cbThisRead;
|
---|
776 | }
|
---|
777 | }
|
---|
778 |
|
---|
779 | /*
|
---|
780 | * Fill buffer.
|
---|
781 | */
|
---|
782 | int rc = loadBuffer(uRva);
|
---|
783 | if (RT_FAILURE(rc))
|
---|
784 | return rc;
|
---|
785 | }
|
---|
786 | return VINF_SUCCESS;
|
---|
787 | }
|
---|
788 |
|
---|
789 | /**
|
---|
790 | * Ensures @a cbItem at @a uRva is in the buffer and returns a pointer to it.
|
---|
791 | *
|
---|
792 | * The returned pointer is only valid till the next call to the reader instance.
|
---|
793 | *
|
---|
794 | * @returns NULL if failed to load the range into the buffer.
|
---|
795 | * @note Extra buffer space will be allocated if @a cbItem is larger than the
|
---|
796 | * internal buffer.
|
---|
797 | */
|
---|
798 | uint8_t const *bufferedBytes(size_t uRva, size_t cbItem) RT_NOEXCEPT
|
---|
799 | {
|
---|
800 | /* Do we need to load the item into the buffer? */
|
---|
801 | if ( uRva < m_uRvaBuf
|
---|
802 | || uRva + cbItem > m_uRvaBuf + m_cbBuf)
|
---|
803 | {
|
---|
804 | int rc = ensureBufferSpace(cbItem);
|
---|
805 | if (RT_SUCCESS(rc))
|
---|
806 | rc = loadBuffer(uRva);
|
---|
807 | if (RT_FAILURE(rc))
|
---|
808 | return NULL;
|
---|
809 | }
|
---|
810 |
|
---|
811 | Assert(uRva >= m_uRvaBuf && uRva + cbItem <= m_uRvaBuf + m_cbBuf);
|
---|
812 | return &m_pbBuf[uRva - m_uRvaBuf];
|
---|
813 | }
|
---|
814 |
|
---|
815 | /**
|
---|
816 | * Gets a buffered zero terminated string at @a uRva.
|
---|
817 | *
|
---|
818 | * @note The implied max length is the size of the internal buffer. No extra
|
---|
819 | * space will be allocated if the string doesn't terminate within the
|
---|
820 | * buffer size.
|
---|
821 | */
|
---|
822 | const char *bufferedString(size_t uRva) RT_NOEXCEPT
|
---|
823 | {
|
---|
824 | /* Do we need to reload the buffer? */
|
---|
825 | if ( uRva < m_uRvaBuf
|
---|
826 | || uRva >= m_uRvaBuf + m_cbBuf
|
---|
827 | || ( uRva != m_uRvaBuf
|
---|
828 | && !memchr(&m_pbBuf[uRva - m_uRvaBuf], '\0', m_cbBufAlloc - (uRva - m_uRvaBuf))))
|
---|
829 | {
|
---|
830 | int rc = loadBuffer(uRva);
|
---|
831 | AssertRCReturn(rc, NULL);
|
---|
832 | }
|
---|
833 |
|
---|
834 | /* The RVA is within the buffer now, just check that the string ends
|
---|
835 | before the end of the buffer. */
|
---|
836 | Assert(uRva >= m_uRvaBuf && uRva < m_uRvaBuf + m_cbBuf);
|
---|
837 | size_t const offString = uRva - m_uRvaBuf;
|
---|
838 | const char * const pszString = (const char *)&m_pbBuf[offString];
|
---|
839 | AssertReturn(memchr(pszString, '\0', m_cbBufAlloc - offString), NULL);
|
---|
840 | return pszString;
|
---|
841 | }
|
---|
842 |
|
---|
843 | /**
|
---|
844 | * Gets a simple integer value, with default in case of failure.
|
---|
845 | */
|
---|
846 | template<typename IntType>
|
---|
847 | IntType bufferedInt(size_t uRva, IntType Default = 0) RT_NOEXCEPT
|
---|
848 | {
|
---|
849 | AssertCompile(sizeof(IntType) <= 8);
|
---|
850 | AssertReturn(uRva < uRva + sizeof(IntType), Default);
|
---|
851 |
|
---|
852 | /* Do we need to reload the buffer? */
|
---|
853 | if ( uRva < m_uRvaBuf
|
---|
854 | || uRva + sizeof(IntType) > m_uRvaBuf + m_cbBuf)
|
---|
855 | {
|
---|
856 | int rc = loadBuffer(uRva);
|
---|
857 | AssertRCReturn(rc, Default);
|
---|
858 | }
|
---|
859 |
|
---|
860 | /* The RVA is within the buffer now. */
|
---|
861 | Assert(uRva >= m_uRvaBuf && uRva + sizeof(IntType) <= m_uRvaBuf + m_cbBuf);
|
---|
862 | return *(IntType *)&m_pbBuf[uRva - m_uRvaBuf];
|
---|
863 | }
|
---|
864 |
|
---|
865 | };
|
---|
866 |
|
---|
867 |
|
---|
868 | /*********************************************************************************************************************************
|
---|
869 | * PE *
|
---|
870 | *********************************************************************************************************************************/
|
---|
871 |
|
---|
872 | /**
|
---|
873 | * PE dumper class.
|
---|
874 | */
|
---|
875 | class DumpImagePe : public DumpImageBase
|
---|
876 | {
|
---|
877 | public:
|
---|
878 | /** Pointer to the file header. */
|
---|
879 | PCIMAGE_FILE_HEADER m_pFileHdr;
|
---|
880 | /** Pointer to the NT headers. */
|
---|
881 | union
|
---|
882 | {
|
---|
883 | PCIMAGE_NT_HEADERS32 pNt32;
|
---|
884 | PCIMAGE_NT_HEADERS64 pNt64;
|
---|
885 | void *pv;
|
---|
886 | } u;
|
---|
887 | /** The PE header RVA / file offset. */
|
---|
888 | uint32_t m_offPeHdr;
|
---|
889 | /** Section table RVA / file offset. */
|
---|
890 | uint32_t m_offShdrs;
|
---|
891 | /** Pointer to the section headers. */
|
---|
892 | PCIMAGE_SECTION_HEADER m_paShdrs;
|
---|
893 | /** Number of section headers. */
|
---|
894 | unsigned m_cShdrs;
|
---|
895 | /** Number of RVA and sizes (data directory entries). */
|
---|
896 | unsigned cDataDir;
|
---|
897 | /** Pointer to the data directory. */
|
---|
898 | PCIMAGE_DATA_DIRECTORY paDataDir;
|
---|
899 |
|
---|
900 | public:
|
---|
901 | DumpImagePe(DumpImageCmd *a_pCmd, const char *a_pszImageBaseAddr,
|
---|
902 | uint32_t a_offPeHdr, PCIMAGE_FILE_HEADER a_pFileHdr, void *a_pvNtHdrs,
|
---|
903 | uint32_t a_offShdrs, unsigned a_cShdrs, PCIMAGE_SECTION_HEADER a_paShdrs) RT_NOEXCEPT
|
---|
904 | : DumpImageBase(a_pCmd, a_pszImageBaseAddr)
|
---|
905 | , m_pFileHdr(a_pFileHdr)
|
---|
906 | , m_offPeHdr(a_offPeHdr)
|
---|
907 | , m_offShdrs(a_offShdrs)
|
---|
908 | , m_paShdrs(a_paShdrs)
|
---|
909 | , m_cShdrs(a_cShdrs)
|
---|
910 | , cDataDir(0)
|
---|
911 | , paDataDir(NULL)
|
---|
912 | {
|
---|
913 | u.pv = a_pvNtHdrs;
|
---|
914 | if (a_pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
|
---|
915 | {
|
---|
916 | paDataDir = u.pNt32->OptionalHeader.DataDirectory;
|
---|
917 | cDataDir = u.pNt32->OptionalHeader.NumberOfRvaAndSizes;
|
---|
918 | }
|
---|
919 | else
|
---|
920 | {
|
---|
921 | paDataDir = u.pNt64->OptionalHeader.DataDirectory;
|
---|
922 | cDataDir = u.pNt64->OptionalHeader.NumberOfRvaAndSizes;
|
---|
923 | }
|
---|
924 | }
|
---|
925 |
|
---|
926 | virtual size_t rvaToFileOffset(size_t uRva) const RT_NOEXCEPT RT_OVERRIDE
|
---|
927 | {
|
---|
928 | AssertReturn(m_paShdrs, uRva);
|
---|
929 | AssertReturn(u.pv, uRva);
|
---|
930 | if (uRva < m_paShdrs[0].VirtualAddress)
|
---|
931 | return uRva;
|
---|
932 | /** @todo handle uninitialized data. needs different return code or smth. */
|
---|
933 | unsigned iSh = m_cShdrs;
|
---|
934 | while (iSh-- > 0)
|
---|
935 | {
|
---|
936 | if (uRva >= m_paShdrs[iSh].VirtualAddress)
|
---|
937 | {
|
---|
938 | size_t offSection = uRva - m_paShdrs[iSh].VirtualAddress;
|
---|
939 | if (offSection < m_paShdrs[iSh].SizeOfRawData)
|
---|
940 | return m_paShdrs[iSh].PointerToRawData + offSection;
|
---|
941 | return ~(size_t)0;
|
---|
942 | }
|
---|
943 | }
|
---|
944 | return ~(size_t)0;
|
---|
945 | }
|
---|
946 |
|
---|
947 | virtual size_t getEndRva(bool a_fAligned = true) const RT_NOEXCEPT RT_OVERRIDE
|
---|
948 | {
|
---|
949 | AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage,
|
---|
950 | IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage);
|
---|
951 | if (a_fAligned)
|
---|
952 | {
|
---|
953 | uint32_t const cbAlignment = u.pNt32->OptionalHeader.SectionAlignment;
|
---|
954 | if (RT_IS_POWER_OF_TWO(cbAlignment))
|
---|
955 | return RT_ALIGN_Z((size_t)u.pNt32->OptionalHeader.SizeOfImage, cbAlignment);
|
---|
956 | }
|
---|
957 | return u.pNt32->OptionalHeader.SizeOfImage;
|
---|
958 | }
|
---|
959 |
|
---|
960 |
|
---|
961 | /** @name Helpers
|
---|
962 | * @{
|
---|
963 | */
|
---|
964 |
|
---|
965 | char *timestampToString(uint32_t uTimestamp, char *pszDst, size_t cbDst) RT_NOEXCEPT
|
---|
966 | {
|
---|
967 | /** @todo detect random numbers and skip formatting them. */
|
---|
968 | RTTIMESPEC TimeSpec;
|
---|
969 | RTTIME Time;
|
---|
970 | RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetDosSeconds(&TimeSpec, uTimestamp)),
|
---|
971 | pszDst, cbDst, 0 /*cFractionDigits*/);
|
---|
972 | return pszDst;
|
---|
973 | }
|
---|
974 |
|
---|
975 | /** @} */
|
---|
976 |
|
---|
977 | /** @name Constants naming
|
---|
978 | * @{ */
|
---|
979 |
|
---|
980 | static const char *machineToString(uint16_t uMachine) RT_NOEXCEPT
|
---|
981 | {
|
---|
982 | switch (uMachine)
|
---|
983 | {
|
---|
984 | case IMAGE_FILE_MACHINE_I386 : return "I386";
|
---|
985 | case IMAGE_FILE_MACHINE_AMD64 : return "AMD64";
|
---|
986 | case IMAGE_FILE_MACHINE_UNKNOWN : return "UNKNOWN";
|
---|
987 | case IMAGE_FILE_MACHINE_BASIC_16 : return "BASIC_16";
|
---|
988 | case IMAGE_FILE_MACHINE_BASIC_16_TV : return "BASIC_16_TV";
|
---|
989 | case IMAGE_FILE_MACHINE_IAPX16 : return "IAPX16";
|
---|
990 | case IMAGE_FILE_MACHINE_IAPX16_TV : return "IAPX16_TV";
|
---|
991 | //case IMAGE_FILE_MACHINE_IAPX20 : return "IAPX20";
|
---|
992 | //case IMAGE_FILE_MACHINE_IAPX20_TV : return "IAPX20_TV";
|
---|
993 | case IMAGE_FILE_MACHINE_I8086 : return "I8086";
|
---|
994 | case IMAGE_FILE_MACHINE_I8086_TV : return "I8086_TV";
|
---|
995 | case IMAGE_FILE_MACHINE_I286_SMALL : return "I286_SMALL";
|
---|
996 | case IMAGE_FILE_MACHINE_MC68 : return "MC68";
|
---|
997 | //case IMAGE_FILE_MACHINE_MC68_WR : return "MC68_WR";
|
---|
998 | case IMAGE_FILE_MACHINE_MC68_TV : return "MC68_TV";
|
---|
999 | case IMAGE_FILE_MACHINE_MC68_PG : return "MC68_PG";
|
---|
1000 | //case IMAGE_FILE_MACHINE_I286_LARGE : return "I286_LARGE";
|
---|
1001 | case IMAGE_FILE_MACHINE_U370_WR : return "U370_WR";
|
---|
1002 | case IMAGE_FILE_MACHINE_AMDAHL_470_WR: return "AMDAHL_470_WR";
|
---|
1003 | case IMAGE_FILE_MACHINE_AMDAHL_470_RO: return "AMDAHL_470_RO";
|
---|
1004 | case IMAGE_FILE_MACHINE_U370_RO : return "U370_RO";
|
---|
1005 | case IMAGE_FILE_MACHINE_R4000 : return "R4000";
|
---|
1006 | case IMAGE_FILE_MACHINE_WCEMIPSV2 : return "WCEMIPSV2";
|
---|
1007 | case IMAGE_FILE_MACHINE_VAX_WR : return "VAX_WR";
|
---|
1008 | case IMAGE_FILE_MACHINE_VAX_RO : return "VAX_RO";
|
---|
1009 | case IMAGE_FILE_MACHINE_SH3 : return "SH3";
|
---|
1010 | case IMAGE_FILE_MACHINE_SH3DSP : return "SH3DSP";
|
---|
1011 | case IMAGE_FILE_MACHINE_SH4 : return "SH4";
|
---|
1012 | case IMAGE_FILE_MACHINE_SH5 : return "SH5";
|
---|
1013 | case IMAGE_FILE_MACHINE_ARM : return "ARM";
|
---|
1014 | case IMAGE_FILE_MACHINE_THUMB : return "THUMB";
|
---|
1015 | case IMAGE_FILE_MACHINE_ARMNT : return "ARMNT";
|
---|
1016 | case IMAGE_FILE_MACHINE_AM33 : return "AM33";
|
---|
1017 | case IMAGE_FILE_MACHINE_POWERPC : return "POWERPC";
|
---|
1018 | case IMAGE_FILE_MACHINE_POWERPCFP : return "POWERPCFP";
|
---|
1019 | case IMAGE_FILE_MACHINE_IA64 : return "IA64";
|
---|
1020 | case IMAGE_FILE_MACHINE_MIPS16 : return "MIPS16";
|
---|
1021 | case IMAGE_FILE_MACHINE_MIPSFPU : return "MIPSFPU";
|
---|
1022 | case IMAGE_FILE_MACHINE_MIPSFPU16 : return "MIPSFPU16";
|
---|
1023 | case IMAGE_FILE_MACHINE_EBC : return "EBC";
|
---|
1024 | case IMAGE_FILE_MACHINE_M32R : return "M32R";
|
---|
1025 | case IMAGE_FILE_MACHINE_ARM64 : return "ARM64";
|
---|
1026 | }
|
---|
1027 | return "??";
|
---|
1028 | }
|
---|
1029 |
|
---|
1030 | static const char *dataDirectoryToString(unsigned iDir) RT_NOEXCEPT
|
---|
1031 | {
|
---|
1032 | switch (iDir)
|
---|
1033 | {
|
---|
1034 | case IMAGE_DIRECTORY_ENTRY_EXPORT: return "EXPORT";
|
---|
1035 | case IMAGE_DIRECTORY_ENTRY_IMPORT: return "IMPORT";
|
---|
1036 | case IMAGE_DIRECTORY_ENTRY_RESOURCE: return "RESOURCE";
|
---|
1037 | case IMAGE_DIRECTORY_ENTRY_EXCEPTION: return "EXCEPTION";
|
---|
1038 | case IMAGE_DIRECTORY_ENTRY_SECURITY: return "SECURITY";
|
---|
1039 | case IMAGE_DIRECTORY_ENTRY_BASERELOC: return "BASERELOC";
|
---|
1040 | case IMAGE_DIRECTORY_ENTRY_DEBUG: return "DEBUG";
|
---|
1041 | case IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: return "ARCHITECTURE";
|
---|
1042 | case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: return "GLOBALPTR";
|
---|
1043 | case IMAGE_DIRECTORY_ENTRY_TLS: return "TLS";
|
---|
1044 | case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: return "LOAD_CONFIG";
|
---|
1045 | case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: return "BOUND_IMPORT";
|
---|
1046 | case IMAGE_DIRECTORY_ENTRY_IAT: return "IAT";
|
---|
1047 | case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: return "DELAY_IMPORT";
|
---|
1048 | case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: return "COM_DESCRIPTOR";
|
---|
1049 | }
|
---|
1050 | return "??";
|
---|
1051 | }
|
---|
1052 |
|
---|
1053 | static const char *debugTypeToString(uint32_t uType, char *pszTmp, size_t cchTmp) RT_NOEXCEPT
|
---|
1054 | {
|
---|
1055 | switch (uType)
|
---|
1056 | {
|
---|
1057 | case IMAGE_DEBUG_TYPE_UNKNOWN: return "UNKNOWN";
|
---|
1058 | case IMAGE_DEBUG_TYPE_COFF: return "COFF";
|
---|
1059 | case IMAGE_DEBUG_TYPE_CODEVIEW: return "CODEVIEW";
|
---|
1060 | case IMAGE_DEBUG_TYPE_FPO: return "FPO";
|
---|
1061 | case IMAGE_DEBUG_TYPE_MISC: return "MISC";
|
---|
1062 | case IMAGE_DEBUG_TYPE_EXCEPTION: return "EXCEPTION";
|
---|
1063 | case IMAGE_DEBUG_TYPE_FIXUP: return "FIXUP";
|
---|
1064 | case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: return "OMAP_TO_SRC";
|
---|
1065 | case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: return "OMAP_FROM_SRC";
|
---|
1066 | case IMAGE_DEBUG_TYPE_BORLAND: return "BORLAND";
|
---|
1067 | case IMAGE_DEBUG_TYPE_RESERVED10: return "RESERVED10";
|
---|
1068 | case IMAGE_DEBUG_TYPE_CLSID: return "CLSID";
|
---|
1069 | case IMAGE_DEBUG_TYPE_VC_FEATURE: return "VC_FEATURE";
|
---|
1070 | case IMAGE_DEBUG_TYPE_POGO: return "POGO";
|
---|
1071 | case IMAGE_DEBUG_TYPE_ILTCG: return "ILTCG";
|
---|
1072 | case IMAGE_DEBUG_TYPE_MPX: return "MPX";
|
---|
1073 | case IMAGE_DEBUG_TYPE_REPRO: return "REPRO";
|
---|
1074 | }
|
---|
1075 | RTStrPrintf(pszTmp, cchTmp, "%#RX32", uType);
|
---|
1076 | return pszTmp;
|
---|
1077 | }
|
---|
1078 |
|
---|
1079 | /** @} */
|
---|
1080 |
|
---|
1081 |
|
---|
1082 | /** @name Dumpers
|
---|
1083 | * @{
|
---|
1084 | */
|
---|
1085 |
|
---|
1086 | int dumpPeHdr(void) RT_NOEXCEPT
|
---|
1087 | {
|
---|
1088 | if (!(m_pCmd->m_fSelection & DUMPIMAGE_SELECT_HEADERS))
|
---|
1089 | return VINF_SUCCESS;
|
---|
1090 | myPrintHeader(m_offPeHdr, "PE & File Header - %s", m_pCmd->m_pszName);
|
---|
1091 |
|
---|
1092 | char szTmp[64];
|
---|
1093 | myPrintf("Signature: %#010RX32\n", u.pNt32->Signature);
|
---|
1094 | PCIMAGE_FILE_HEADER const pFileHdr = &u.pNt32->FileHeader;
|
---|
1095 | myPrintf("Machine: %s (%#06RX16)\n", machineToString(pFileHdr->Machine), pFileHdr->Machine);
|
---|
1096 | myPrintf("Number of sections: %#06RX16\n", pFileHdr->NumberOfSections);
|
---|
1097 | myPrintf("Timestamp: %#010RX32\n",
|
---|
1098 | pFileHdr->TimeDateStamp, timestampToString(pFileHdr->TimeDateStamp, szTmp, sizeof(szTmp)));
|
---|
1099 | if (pFileHdr->PointerToSymbolTable || pFileHdr->NumberOfSymbols)
|
---|
1100 | myPrintf("Symbol table: %#010RX32 L %#06RX16\n",
|
---|
1101 | pFileHdr->PointerToSymbolTable, pFileHdr->NumberOfSymbols);
|
---|
1102 | myPrintf("Size of optional header: %#06RX16\n", pFileHdr->SizeOfOptionalHeader);
|
---|
1103 |
|
---|
1104 | myPrintf("Characteristics: %#06RX16", pFileHdr->Characteristics);
|
---|
1105 | if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) myPrintf(" RELOCS_STRIPPED");
|
---|
1106 | if (pFileHdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) myPrintf(" EXECUTABLE_IMAGE");
|
---|
1107 | if (pFileHdr->Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED) myPrintf(" LINE_NUMS_STRIPPED");
|
---|
1108 | if (pFileHdr->Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED) myPrintf(" LOCAL_SYMS_STRIPPED");
|
---|
1109 | if (pFileHdr->Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM) myPrintf(" AGGRESIVE_WS_TRIM");
|
---|
1110 | if (pFileHdr->Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) myPrintf(" LARGE_ADDRESS_AWARE");
|
---|
1111 | if (pFileHdr->Characteristics & IMAGE_FILE_16BIT_MACHINE) myPrintf(" 16BIT_MACHINE");
|
---|
1112 | if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_LO) myPrintf(" BYTES_REVERSED_LO");
|
---|
1113 | if (pFileHdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) myPrintf(" 32BIT_MACHINE");
|
---|
1114 | if (pFileHdr->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) myPrintf(" DEBUG_STRIPPED");
|
---|
1115 | if (pFileHdr->Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) myPrintf(" REMOVABLE_RUN_FROM_SWAP");
|
---|
1116 | if (pFileHdr->Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) myPrintf(" NET_RUN_FROM_SWAP");
|
---|
1117 | if (pFileHdr->Characteristics & IMAGE_FILE_SYSTEM) myPrintf(" SYSTEM");
|
---|
1118 | if (pFileHdr->Characteristics & IMAGE_FILE_DLL) myPrintf(" DLL");
|
---|
1119 | if (pFileHdr->Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) myPrintf(" UP_SYSTEM_ONLY");
|
---|
1120 | if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI) myPrintf(" BYTES_REVERSED_HI");
|
---|
1121 | myPrintf("\n");
|
---|
1122 | return VINF_SUCCESS;
|
---|
1123 | }
|
---|
1124 |
|
---|
1125 | template<typename OptHdrType, bool const a_f32Bit>
|
---|
1126 | int dumpOptHdr(OptHdrType const *pOptHdr, uint32_t uBaseOfData = 0) RT_NOEXCEPT
|
---|
1127 | {
|
---|
1128 | if (!(m_pCmd->m_fSelection & DUMPIMAGE_SELECT_HEADERS))
|
---|
1129 | return VINF_SUCCESS;
|
---|
1130 | myPrintHeader(m_offPeHdr + RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader), "Optional Header");
|
---|
1131 |
|
---|
1132 | char szTmp[64];
|
---|
1133 | myPrintf("Optional header magic: %#06RX16\n", pOptHdr->Magic);
|
---|
1134 | myPrintf("Linker version: %u.%02u\n", pOptHdr->MajorLinkerVersion, pOptHdr->MinorLinkerVersion);
|
---|
1135 | if (a_f32Bit)
|
---|
1136 | myPrintf("Image base: %#010RX32\n", pOptHdr->ImageBase);
|
---|
1137 | else
|
---|
1138 | myPrintf("Image base: %#018RX64\n", pOptHdr->ImageBase);
|
---|
1139 | myPrintf("Entrypoint: %s\n", rvaToStringWithAddr(pOptHdr->AddressOfEntryPoint, szTmp, sizeof(szTmp)));
|
---|
1140 | myPrintf("Base of code: %s\n", rvaToStringWithAddr(pOptHdr->BaseOfCode, szTmp, sizeof(szTmp)));
|
---|
1141 | if (a_f32Bit)
|
---|
1142 | myPrintf("Base of data: %s\n", rvaToStringWithAddr(uBaseOfData, szTmp, sizeof(szTmp)));
|
---|
1143 | myPrintf("Size of image: %#010RX32\n", pOptHdr->SizeOfImage);
|
---|
1144 | myPrintf("Size of headers: %#010RX32\n", pOptHdr->SizeOfHeaders);
|
---|
1145 | myPrintf("Size of code: %#010RX32\n", pOptHdr->SizeOfCode);
|
---|
1146 | myPrintf("Size of initialized data: %#010RX32\n", pOptHdr->SizeOfInitializedData);
|
---|
1147 | myPrintf("Size of uninitialized data: %#010RX32\n", pOptHdr->SizeOfUninitializedData);
|
---|
1148 | myPrintf("Section alignment: %#010RX32\n", pOptHdr->SectionAlignment);
|
---|
1149 | myPrintf("File alignment: %#010RX32\n", pOptHdr->FileAlignment);
|
---|
1150 | myPrintf("Image version: %u.%02u\n", pOptHdr->MajorImageVersion, pOptHdr->MinorImageVersion);
|
---|
1151 | myPrintf("Operating system version: %u.%02u\n", pOptHdr->MajorOperatingSystemVersion, pOptHdr->MinorOperatingSystemVersion);
|
---|
1152 | myPrintf("Windows version value: %#010RX32\n", pOptHdr->Win32VersionValue);
|
---|
1153 | const char *pszSubSys;
|
---|
1154 | switch (pOptHdr->Subsystem)
|
---|
1155 | {
|
---|
1156 | case IMAGE_SUBSYSTEM_UNKNOWN: pszSubSys = "Unknown"; break;
|
---|
1157 | case IMAGE_SUBSYSTEM_NATIVE: pszSubSys = "Native"; break;
|
---|
1158 | case IMAGE_SUBSYSTEM_WINDOWS_GUI: pszSubSys = "Windows GUI"; break;
|
---|
1159 | case IMAGE_SUBSYSTEM_WINDOWS_CUI: pszSubSys = "Windows char"; break;
|
---|
1160 | case IMAGE_SUBSYSTEM_OS2_GUI: pszSubSys = "OS/2 GUI"; break;
|
---|
1161 | case IMAGE_SUBSYSTEM_OS2_CUI: pszSubSys = "OS/2 char"; break;
|
---|
1162 | case IMAGE_SUBSYSTEM_POSIX_CUI: pszSubSys = "POSIX"; break;
|
---|
1163 | case IMAGE_SUBSYSTEM_NATIVE_WINDOWS: pszSubSys = "Native Windows 9x"; break;
|
---|
1164 | case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: pszSubSys = "Windows CE GUI"; break;
|
---|
1165 | case IMAGE_SUBSYSTEM_EFI_APPLICATION: pszSubSys = "EFI Application"; break;
|
---|
1166 | case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: pszSubSys = "EFI Boot Service Driver"; break;
|
---|
1167 | case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: pszSubSys = "EFI Runtime Driver"; break;
|
---|
1168 | case IMAGE_SUBSYSTEM_EFI_ROM: pszSubSys = "EFI ROM"; break;
|
---|
1169 | case IMAGE_SUBSYSTEM_XBOX: pszSubSys = "XBox"; break;
|
---|
1170 | case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: pszSubSys = "Windows Boot Application"; break;
|
---|
1171 | default: pszSubSys = "dunno"; break;
|
---|
1172 | }
|
---|
1173 | myPrintf("Subsystem: %s (%#x)\n", pszSubSys, pOptHdr->Subsystem);
|
---|
1174 | myPrintf("Subsystem version: %u.%02u\n", pOptHdr->MajorSubsystemVersion, pOptHdr->MinorSubsystemVersion);
|
---|
1175 | myPrintf("DLL characteristics: %#06RX16\n", pOptHdr->DllCharacteristics);
|
---|
1176 | myPrintf("Loader flags: %#010RX32\n", pOptHdr->LoaderFlags);
|
---|
1177 |
|
---|
1178 | myPrintf("File checksum: %#010RX32\n", pOptHdr->CheckSum);
|
---|
1179 | myPrintf("Size of stack reserve: %#010RX64\n", (uint64_t)pOptHdr->SizeOfStackReserve);
|
---|
1180 | myPrintf("Size of stack commit: %#010RX64\n", (uint64_t)pOptHdr->SizeOfStackReserve);
|
---|
1181 | myPrintf("Size of heap reserve: %#010RX64\n", (uint64_t)pOptHdr->SizeOfHeapReserve);
|
---|
1182 | myPrintf("Size of heap commit: %#010RX64\n", (uint64_t)pOptHdr->SizeOfHeapReserve);
|
---|
1183 |
|
---|
1184 | myPrintf("Number of data directories: %#010RX32%s\n", pOptHdr->NumberOfRvaAndSizes,
|
---|
1185 | pOptHdr->NumberOfRvaAndSizes <= RT_ELEMENTS(pOptHdr->DataDirectory) ? "" : " - bogus!");
|
---|
1186 |
|
---|
1187 | for (uint32_t i = 0; i < RT_ELEMENTS(pOptHdr->DataDirectory); i++)
|
---|
1188 | if (pOptHdr->DataDirectory[i].Size || pOptHdr->DataDirectory[i].VirtualAddress)
|
---|
1189 | {
|
---|
1190 | const char * const pszName = dataDirectoryToString(i);
|
---|
1191 | rvaToStringWithAddr(pOptHdr->DataDirectory[i].VirtualAddress, szTmp, sizeof(szTmp));
|
---|
1192 | if (i == IMAGE_DIRECTORY_ENTRY_SECURITY)
|
---|
1193 | {
|
---|
1194 | size_t const cchWidth = strlen(szTmp);
|
---|
1195 | size_t cch = RTStrPrintf(szTmp, sizeof(szTmp), "%#09RX32 (file off)",
|
---|
1196 | pOptHdr->DataDirectory[i].VirtualAddress);
|
---|
1197 | while (cch < cchWidth)
|
---|
1198 | szTmp[cch++] = ' ';
|
---|
1199 | szTmp[cch] = '\0';
|
---|
1200 | }
|
---|
1201 | myPrintf("DataDirectory[%#x]: %s LB %#07RX32 %s\n", i, szTmp, pOptHdr->DataDirectory[i].Size, pszName);
|
---|
1202 | }
|
---|
1203 | return VINF_SUCCESS;
|
---|
1204 | }
|
---|
1205 |
|
---|
1206 | int dumpSectionHdrs(void) RT_NOEXCEPT
|
---|
1207 | {
|
---|
1208 | if (!(m_pCmd->m_fSelection & DUMPIMAGE_SELECT_SECTIONS))
|
---|
1209 | return VINF_SUCCESS;
|
---|
1210 | myPrintHeader(m_offShdrs, "Section Table");
|
---|
1211 |
|
---|
1212 | for (unsigned i = 0; i < m_cShdrs; i++)
|
---|
1213 | {
|
---|
1214 | char szTmp[64];
|
---|
1215 | myPrintf("Section[%02u]: %s LB %08RX32 %.8s\n",
|
---|
1216 | i, rvaToStringWithAddr(m_paShdrs[i].VirtualAddress, szTmp, sizeof(szTmp)),
|
---|
1217 | m_paShdrs[i].Misc.VirtualSize, m_paShdrs[i].Name);
|
---|
1218 | }
|
---|
1219 | return VINF_SUCCESS;
|
---|
1220 | }
|
---|
1221 |
|
---|
1222 | int dumpExportDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData) RT_NOEXCEPT
|
---|
1223 | {
|
---|
1224 | if (!(m_pCmd->m_fSelection & DUMPIMAGE_SELECT_EXPORTS))
|
---|
1225 | return VINF_SUCCESS;
|
---|
1226 | myPrintHeader(uRvaData, "Export Table");
|
---|
1227 |
|
---|
1228 | RT_NOREF(cbData);
|
---|
1229 | char szTmp[64];
|
---|
1230 |
|
---|
1231 | /* Use dedicated readers for each array, but saving one by using pBufRdr
|
---|
1232 | for function addresses. */
|
---|
1233 | DumpImageBufferedReader NmAddrRdr(*pBufRdr), OrdRdr(*pBufRdr), NameRdr(*pBufRdr);
|
---|
1234 |
|
---|
1235 | /*
|
---|
1236 | * Read the entry into memory.
|
---|
1237 | */
|
---|
1238 | IMAGE_EXPORT_DIRECTORY ExpDir;
|
---|
1239 | int rc = pBufRdr->readBytes(uRvaData, &ExpDir, sizeof(ExpDir));
|
---|
1240 | if (RT_FAILURE(rc))
|
---|
1241 | return rc;
|
---|
1242 |
|
---|
1243 | /*
|
---|
1244 | * Dump the directory.
|
---|
1245 | */
|
---|
1246 | myPrintf(" Name: %s %s\n",
|
---|
1247 | rvaToStringWithAddr(ExpDir.Name, szTmp, sizeof(szTmp)), NmAddrRdr.bufferedString(ExpDir.Name));
|
---|
1248 | myPrintf(" Address table: %s L %u\n",
|
---|
1249 | rvaToStringWithAddr(ExpDir.AddressOfFunctions, szTmp, sizeof(szTmp)), ExpDir.NumberOfFunctions);
|
---|
1250 | myPrintf(" Name table: %s L %u\n",
|
---|
1251 | rvaToStringWithAddr(ExpDir.AddressOfNames, szTmp, sizeof(szTmp)), ExpDir.NumberOfNames);
|
---|
1252 | myPrintf(" Name index table: %s L ditto\n",
|
---|
1253 | rvaToStringWithAddr(ExpDir.AddressOfNameOrdinals, szTmp, sizeof(szTmp)), ExpDir.NumberOfNames);
|
---|
1254 | myPrintf(" Ordinal base: %u\n", ExpDir.Base);
|
---|
1255 | if (ExpDir.Characteristics)
|
---|
1256 | myPrintf(" Characteristics: %#RX32\n", ExpDir.Characteristics);
|
---|
1257 | if (ExpDir.TimeDateStamp && ExpDir.TimeDateStamp != UINT32_MAX)
|
---|
1258 | myPrintf(" TimeDateStamp: %#RX32 %s\n",
|
---|
1259 | ExpDir.TimeDateStamp, timestampToString(ExpDir.TimeDateStamp, szTmp, sizeof(szTmp)));
|
---|
1260 | if (ExpDir.MajorVersion || ExpDir.MinorVersion)
|
---|
1261 | myPrintf(" Version: %u.%u\n", ExpDir.MajorVersion, ExpDir.MinorVersion);
|
---|
1262 |
|
---|
1263 | uint32_t const cExports = ExpDir.NumberOfNames;
|
---|
1264 | if (cExports > _16K)
|
---|
1265 | {
|
---|
1266 | myPrintf(" Exports: Too many addresses! (%#x)\n", cExports);
|
---|
1267 | return VINF_SUCCESS;
|
---|
1268 | }
|
---|
1269 | uint32_t const cNames = ExpDir.NumberOfNames;
|
---|
1270 | if (cNames > _32K)
|
---|
1271 | {
|
---|
1272 | myPrintf(" Exports: Too many names! (%#x)\n", cNames);
|
---|
1273 | return VINF_SUCCESS;
|
---|
1274 | }
|
---|
1275 | if (cExports == 0)
|
---|
1276 | {
|
---|
1277 | myPrintf(" Exports: No exports!\n");
|
---|
1278 | return VINF_SUCCESS;
|
---|
1279 | }
|
---|
1280 |
|
---|
1281 | /*
|
---|
1282 | * Read the export addresses and name tables into memory.
|
---|
1283 | */
|
---|
1284 | uint32_t const *pauExportRvas = (uint32_t const *)pBufRdr->bufferedBytes(ExpDir.AddressOfFunctions,
|
---|
1285 | sizeof(pauExportRvas[0])* cExports);
|
---|
1286 | uint16_t const *pau16Ordinals = NULL;
|
---|
1287 | uint32_t const *pauNameRvas = NULL;
|
---|
1288 | bool fOrderedOrdinals = true;
|
---|
1289 | if (cNames)
|
---|
1290 | {
|
---|
1291 | pauNameRvas = (uint32_t const *)NmAddrRdr.bufferedBytes(ExpDir.AddressOfNames, sizeof(pauNameRvas[0]) * cNames);
|
---|
1292 | if (!pauNameRvas)
|
---|
1293 | return VINF_SUCCESS;
|
---|
1294 | pau16Ordinals = (uint16_t const *)OrdRdr.bufferedBytes(ExpDir.AddressOfNameOrdinals,
|
---|
1295 | sizeof(pau16Ordinals[0]) * cNames);
|
---|
1296 | if (!pau16Ordinals)
|
---|
1297 | return VINF_SUCCESS;
|
---|
1298 |
|
---|
1299 | /* Check if the name ordinals are ordered. */
|
---|
1300 | uint16_t iPrev = pau16Ordinals[0];
|
---|
1301 | for (uint32_t iOrd = 1; iOrd < cNames; iOrd++)
|
---|
1302 | {
|
---|
1303 | uint16_t const iCur = pau16Ordinals[iOrd];
|
---|
1304 | if (iCur > iPrev)
|
---|
1305 | iPrev = iCur;
|
---|
1306 | else
|
---|
1307 | {
|
---|
1308 | fOrderedOrdinals = false;
|
---|
1309 | break;
|
---|
1310 | }
|
---|
1311 | }
|
---|
1312 |
|
---|
1313 | }
|
---|
1314 |
|
---|
1315 | /*
|
---|
1316 | * Dump the exports by named exports.
|
---|
1317 | */
|
---|
1318 | static const char s_szAddr[] = "Export RVA/Address";
|
---|
1319 | unsigned cchAddr = (unsigned)strlen(rvaToStringWithAddr(uRvaData, szTmp, sizeof(szTmp)));
|
---|
1320 | cchAddr = RT_MAX(cchAddr, sizeof(s_szAddr) - 1);
|
---|
1321 | myPrintf("\n"
|
---|
1322 | "Ordinal %*s%s%*s Name RVA Name\n"
|
---|
1323 | "------- %*.*s --------- --------------------------------\n",
|
---|
1324 | (cchAddr - sizeof(s_szAddr) + 1) / 2, "", s_szAddr, (cchAddr - sizeof(s_szAddr) + 1 + 1) / 2, "",
|
---|
1325 | cchAddr, cchAddr, "--------------------------------------");
|
---|
1326 |
|
---|
1327 | for (uint32_t iExp = 0, iName = 0; iExp < cExports; iExp++)
|
---|
1328 | {
|
---|
1329 | if (cNames > 0)
|
---|
1330 | {
|
---|
1331 | if (fOrderedOrdinals)
|
---|
1332 | {
|
---|
1333 | if (iName < cNames && pau16Ordinals[iName] == iExp)
|
---|
1334 | {
|
---|
1335 | uint32_t const uRvaName = pauNameRvas[iExp];
|
---|
1336 | const char * const pszName = NameRdr.bufferedString(uRvaName);
|
---|
1337 | myPrintf("%7u %s %#09RX32 %s\n", iExp + ExpDir.Base,
|
---|
1338 | rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)),
|
---|
1339 | uRvaName, pszName ? pszName : "");
|
---|
1340 | iName++;
|
---|
1341 | continue;
|
---|
1342 | }
|
---|
1343 | }
|
---|
1344 | else
|
---|
1345 | {
|
---|
1346 | /* Search the entire name ordinal table, not stopping on a hit
|
---|
1347 | as there could in theory be different names for the same entry. */
|
---|
1348 | uint32_t cPrinted = 0;
|
---|
1349 | for (iName = 0; iName < cNames; iName++)
|
---|
1350 | if (pau16Ordinals[iName] == iExp)
|
---|
1351 | {
|
---|
1352 | uint32_t const uRvaName = pauNameRvas[iExp];
|
---|
1353 | const char * const pszName = NameRdr.bufferedString(uRvaName);
|
---|
1354 | myPrintf("%7u %s %#09RX32 %s\n", iExp + ExpDir.Base,
|
---|
1355 | rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)),
|
---|
1356 | uRvaName, pszName ? pszName : "");
|
---|
1357 | cPrinted++;
|
---|
1358 | }
|
---|
1359 | if (cPrinted)
|
---|
1360 | continue;
|
---|
1361 | }
|
---|
1362 | }
|
---|
1363 | /* Ordinal only. */
|
---|
1364 | myPrintf("%7u %s %#09RX32\n", iExp + ExpDir.Base,
|
---|
1365 | rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)), UINT32_MAX);
|
---|
1366 | }
|
---|
1367 | return VINF_SUCCESS;
|
---|
1368 | }
|
---|
1369 |
|
---|
1370 | template<typename ThunkType, bool const a_f32Bit, ThunkType const a_fOrdinalConst>
|
---|
1371 | int dumpImportDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData) RT_NOEXCEPT
|
---|
1372 | {
|
---|
1373 | if (!(m_pCmd->m_fSelection & DUMPIMAGE_SELECT_IMPORTS))
|
---|
1374 | return VINF_SUCCESS;
|
---|
1375 | myPrintHeader(uRvaData, "Import table");
|
---|
1376 |
|
---|
1377 | char szTmp[64];
|
---|
1378 | char szTmp2[64];
|
---|
1379 | size_t const cchRvaWithAddr = strlen(rvaToStringWithAddr(uRvaData, szTmp, sizeof(szTmp)));
|
---|
1380 |
|
---|
1381 | /* Use dedicated readers for each array and names */
|
---|
1382 | DumpImageBufferedReader NameRdr(*pBufRdr), Thunk1stRdr(*pBufRdr), ThunkOrgRdr(*pBufRdr);
|
---|
1383 |
|
---|
1384 | int rcRet = VINF_SUCCESS;
|
---|
1385 | uint32_t const cEntries = cbData / sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
---|
1386 | for (uint32_t i = 0; i < cEntries; i += 1, uRvaData += sizeof(IMAGE_IMPORT_DESCRIPTOR))
|
---|
1387 | {
|
---|
1388 | /*
|
---|
1389 | * Read the entry into memory.
|
---|
1390 | */
|
---|
1391 | IMAGE_IMPORT_DESCRIPTOR ImpDir;
|
---|
1392 | int rc = pBufRdr->readBytes(uRvaData, &ImpDir, sizeof(ImpDir));
|
---|
1393 | if (RT_FAILURE(rc))
|
---|
1394 | return rc;
|
---|
1395 |
|
---|
1396 | if (ImpDir.Name == 0)
|
---|
1397 | continue;
|
---|
1398 |
|
---|
1399 | /*
|
---|
1400 | * Dump it.
|
---|
1401 | */
|
---|
1402 | if (i > 0)
|
---|
1403 | myPrintf("\n");
|
---|
1404 | myPrintf(" Entry #: %u\n", i);
|
---|
1405 | myPrintf(" Name: %s - %s\n", rvaToStringWithAddr(ImpDir.Name, szTmp, sizeof(szTmp)),
|
---|
1406 | ImpDir.Name ? NameRdr.bufferedString(ImpDir.Name) : "");
|
---|
1407 | if (ImpDir.TimeDateStamp && ImpDir.TimeDateStamp != UINT32_MAX)
|
---|
1408 | myPrintf(" Timestamp: %#010RX32 %s\n",
|
---|
1409 | ImpDir.TimeDateStamp, timestampToString(ImpDir.TimeDateStamp, szTmp, sizeof(szTmp)));
|
---|
1410 | myPrintf(" First thunk: %s\n", rvaToStringWithAddr(ImpDir.FirstThunk, szTmp, sizeof(szTmp)));
|
---|
1411 | myPrintf(" Original thunk: %s\n", rvaToStringWithAddr(ImpDir.u.OriginalFirstThunk, szTmp, sizeof(szTmp)));
|
---|
1412 | if (ImpDir.ForwarderChain)
|
---|
1413 | myPrintf(" Forwarder chain: %s\n", rvaToStringWithAddr(ImpDir.ForwarderChain, szTmp, sizeof(szTmp)));
|
---|
1414 |
|
---|
1415 | /*
|
---|
1416 | * Try process the arrays.
|
---|
1417 | */
|
---|
1418 | static char const s_szDashes[] = "-----------------------------------------------";
|
---|
1419 | static char const s_szHdr1[] = "Thunk RVA/Addr";
|
---|
1420 | uint32_t uRvaNames = ImpDir.u.OriginalFirstThunk;
|
---|
1421 | uint32_t uRvaThunk = ImpDir.FirstThunk;
|
---|
1422 | if (uRvaThunk == 0)
|
---|
1423 | uRvaThunk = uRvaNames;
|
---|
1424 | if (uRvaNames != 0 && uRvaNames != uRvaThunk)
|
---|
1425 | {
|
---|
1426 | static char const s_szHdr2[] = "Thunk";
|
---|
1427 | static char const s_szHdr4[] = "Hint+Name RVA/Addr";
|
---|
1428 | size_t const cchCol1 = RT_MAX(sizeof(s_szHdr1) - 1, cchRvaWithAddr);
|
---|
1429 | size_t const cchCol2 = RT_MAX(sizeof(s_szHdr2) - 1, 2 + sizeof(ThunkType) * 2);
|
---|
1430 | size_t const cchCol4 = RT_MAX(sizeof(s_szHdr4) - 1, cchRvaWithAddr);
|
---|
1431 |
|
---|
1432 | myPrintf(" No. %-*s %-*s Ord/Hint %-*s Name\n"
|
---|
1433 | "---- %.*s %.*s -------- %.*s ----------------\n",
|
---|
1434 | cchCol1, s_szHdr1, cchCol2, s_szHdr2, cchCol4, s_szHdr4,
|
---|
1435 | cchCol1, s_szDashes, cchCol2, s_szDashes, cchCol4, s_szDashes);
|
---|
1436 | for (uint32_t iEntry = 0;; iEntry += 1, uRvaThunk += sizeof(ThunkType), uRvaNames += sizeof(ThunkType))
|
---|
1437 | {
|
---|
1438 | ThunkType const uName = ThunkOrgRdr.bufferedInt<ThunkType>(uRvaNames, 0);
|
---|
1439 | ThunkType const uThunk = Thunk1stRdr.bufferedInt<ThunkType>(uRvaThunk, 0);
|
---|
1440 | if (!uName || !uThunk)
|
---|
1441 | break;
|
---|
1442 |
|
---|
1443 | if (!(uName & a_fOrdinalConst))
|
---|
1444 | {
|
---|
1445 | uint16_t const uHint = NameRdr.bufferedInt<uint16_t>(uName);
|
---|
1446 | const char * const pszName = NameRdr.bufferedString(uName + 2);
|
---|
1447 | if (a_f32Bit)
|
---|
1448 | myPrintf("%4u: %s %#010RX32 %8RU16 %s %s\n",
|
---|
1449 | iEntry, rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uHint,
|
---|
1450 | rvaToStringWithAddr(uName, szTmp2, sizeof(szTmp2)), pszName);
|
---|
1451 | else
|
---|
1452 | myPrintf("%4u: %s %#018RX64 %8RU16 %s %s\n",
|
---|
1453 | iEntry, rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uHint,
|
---|
1454 | rvaToStringWithAddr(uName, szTmp2, sizeof(szTmp2)), pszName);
|
---|
1455 | }
|
---|
1456 | else
|
---|
1457 | {
|
---|
1458 | if (a_f32Bit)
|
---|
1459 | myPrintf("%4u: %s %#010RX32 %8RU32\n", iEntry,
|
---|
1460 | rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uName & ~a_fOrdinalConst);
|
---|
1461 | else
|
---|
1462 | myPrintf("%4u: %s %#018RX64 %8RU64\n", iEntry,
|
---|
1463 | rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uName & ~a_fOrdinalConst);
|
---|
1464 | }
|
---|
1465 | }
|
---|
1466 | }
|
---|
1467 | /** @todo */
|
---|
1468 | //else if (uRvaThunk)
|
---|
1469 | // for (;;)
|
---|
1470 | // {
|
---|
1471 | // ThunkType const *pThunk = (ThunkType const *)Thunk1stRdr.bufferedBytes(uRvaThunk, sizeof(*pThunk));
|
---|
1472 | // if (!pThunk->u1.AddressOfData == 0)
|
---|
1473 | // break;
|
---|
1474 | // }
|
---|
1475 | }
|
---|
1476 | return rcRet;
|
---|
1477 | }
|
---|
1478 |
|
---|
1479 | int dumpDebugDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData) RT_NOEXCEPT
|
---|
1480 | {
|
---|
1481 | if (!(m_pCmd->m_fSelection & DUMPIMAGE_SELECT_DEBUG))
|
---|
1482 | return VINF_SUCCESS;
|
---|
1483 | myPrintHeader(uRvaData, "Debug Directory");
|
---|
1484 |
|
---|
1485 | int rcRet = VINF_SUCCESS;
|
---|
1486 | uint32_t const cEntries = cbData / sizeof(IMAGE_DEBUG_DIRECTORY);
|
---|
1487 | for (uint32_t i = 0; i < cEntries; i += 1, uRvaData += sizeof(IMAGE_DEBUG_DIRECTORY))
|
---|
1488 | {
|
---|
1489 | /*
|
---|
1490 | * Read the entry into memory.
|
---|
1491 | */
|
---|
1492 | IMAGE_DEBUG_DIRECTORY DbgDir;
|
---|
1493 | int rc = pBufRdr->readBytes(uRvaData, &DbgDir, sizeof(DbgDir));
|
---|
1494 | if (RT_FAILURE(rc))
|
---|
1495 | return rc;
|
---|
1496 |
|
---|
1497 | /*
|
---|
1498 | * Dump it.
|
---|
1499 | * (longest type is 13 chars:'OMAP_FROM_SRC')
|
---|
1500 | */
|
---|
1501 | char szTmp[64];
|
---|
1502 | char szTmp2[64];
|
---|
1503 | myPrintf("%u: %s LB %06RX32 %#09RX32 %13s",
|
---|
1504 | i, rvaToStringWithAddr(DbgDir.AddressOfRawData, szTmp, sizeof(szTmp)), DbgDir.SizeOfData,
|
---|
1505 | DbgDir.PointerToRawData,
|
---|
1506 | debugTypeToString(DbgDir.Type, szTmp2, sizeof(szTmp2)));
|
---|
1507 | if (DbgDir.MajorVersion || DbgDir.MinorVersion)
|
---|
1508 | myPrintf(" v%u.%u", DbgDir.MajorVersion, DbgDir.MinorVersion);
|
---|
1509 | if (DbgDir.Characteristics)
|
---|
1510 | myPrintf(" flags=%#RX32", DbgDir.Characteristics);
|
---|
1511 | myPrintf(" %s (%#010RX32)\n", timestampToString(DbgDir.TimeDateStamp, szTmp, sizeof(szTmp)), DbgDir.TimeDateStamp);
|
---|
1512 |
|
---|
1513 | union
|
---|
1514 | {
|
---|
1515 | uint8_t abPage[0x1000];
|
---|
1516 | CVPDB20INFO Pdb20;
|
---|
1517 | CVPDB70INFO Pdb70;
|
---|
1518 | IMAGE_DEBUG_MISC Misc;
|
---|
1519 | } uBuf;
|
---|
1520 | RT_ZERO(uBuf);
|
---|
1521 |
|
---|
1522 | if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
|
---|
1523 | {
|
---|
1524 | if ( DbgDir.SizeOfData < sizeof(uBuf)
|
---|
1525 | && DbgDir.SizeOfData > 16
|
---|
1526 | && DbgDir.AddressOfRawData > 0
|
---|
1527 | && RT_SUCCESS(rc))
|
---|
1528 | {
|
---|
1529 | rc = pBufRdr->readBytes(DbgDir.AddressOfRawData, &uBuf, DbgDir.SizeOfData);
|
---|
1530 | if (RT_SUCCESS(rc))
|
---|
1531 | {
|
---|
1532 | if ( uBuf.Pdb20.u32Magic == CVPDB20INFO_MAGIC
|
---|
1533 | && uBuf.Pdb20.offDbgInfo == 0
|
---|
1534 | && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
|
---|
1535 | myPrintf(" PDB2.0: ts=%08RX32 age=%RX32 %s\n",
|
---|
1536 | uBuf.Pdb20.uTimestamp, uBuf.Pdb20.uAge, uBuf.Pdb20.szPdbFilename);
|
---|
1537 | else if ( uBuf.Pdb20.u32Magic == CVPDB70INFO_MAGIC
|
---|
1538 | && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
|
---|
1539 | myPrintf(" PDB7.0: %RTuuid age=%u %s\n",
|
---|
1540 | &uBuf.Pdb70.PdbUuid, uBuf.Pdb70.uAge, uBuf.Pdb70.szPdbFilename);
|
---|
1541 | else
|
---|
1542 | myPrintf(" Unknown PDB/codeview magic: %.8Rhxs\n", uBuf.abPage);
|
---|
1543 | }
|
---|
1544 | else
|
---|
1545 | rcRet = rc;
|
---|
1546 | }
|
---|
1547 | }
|
---|
1548 | else if (DbgDir.Type == IMAGE_DEBUG_TYPE_MISC)
|
---|
1549 | {
|
---|
1550 | if ( DbgDir.SizeOfData < sizeof(uBuf)
|
---|
1551 | && DbgDir.SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data)
|
---|
1552 | && DbgDir.AddressOfRawData > 0)
|
---|
1553 | {
|
---|
1554 | rc = pBufRdr->readBytes(DbgDir.AddressOfRawData, &uBuf, DbgDir.SizeOfData);
|
---|
1555 | if (RT_SUCCESS(rc))
|
---|
1556 | {
|
---|
1557 | if ( uBuf.Misc.DataType == IMAGE_DEBUG_MISC_EXENAME
|
---|
1558 | && uBuf.Misc.Length == DbgDir.SizeOfData)
|
---|
1559 | {
|
---|
1560 | if (!uBuf.Misc.Unicode)
|
---|
1561 | myPrintf(" Misc DBG: ts=%RX32 %s\n", DbgDir.TimeDateStamp, (const char *)&uBuf.Misc.Data[0]);
|
---|
1562 | else
|
---|
1563 | myPrintf(" Misc DBG: ts=%RX32 %ls\n", DbgDir.TimeDateStamp, (PCRTUTF16)&uBuf.Misc.Data[0]);
|
---|
1564 | }
|
---|
1565 | }
|
---|
1566 | else
|
---|
1567 | rcRet = rc;
|
---|
1568 | }
|
---|
1569 | }
|
---|
1570 | }
|
---|
1571 | return rcRet;
|
---|
1572 | }
|
---|
1573 |
|
---|
1574 | int dumpDataDirs(DumpImageBufferedReader *pBufRdr, unsigned cDataDirs, PCIMAGE_DATA_DIRECTORY paDataDirs) RT_NOEXCEPT
|
---|
1575 | {
|
---|
1576 | int rcRet = VINF_SUCCESS;
|
---|
1577 | for (unsigned i = 0; i < cDataDirs; i++)
|
---|
1578 | if (paDataDirs[i].Size > 0 && paDataDirs[i].VirtualAddress)
|
---|
1579 | {
|
---|
1580 | int rc;
|
---|
1581 | if ( i == IMAGE_DIRECTORY_ENTRY_EXPORT
|
---|
1582 | && paDataDirs[i].Size >= sizeof(IMAGE_EXPORT_DIRECTORY))
|
---|
1583 | rc = dumpExportDir(pBufRdr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size);
|
---|
1584 | else if ( i == IMAGE_DIRECTORY_ENTRY_IMPORT
|
---|
1585 | && paDataDirs[i].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR))
|
---|
1586 | {
|
---|
1587 | if (m_pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
|
---|
1588 | rc = dumpImportDir<uint32_t, true, IMAGE_ORDINAL_FLAG32>(pBufRdr, paDataDirs[i].VirtualAddress,
|
---|
1589 | paDataDirs[i].Size);
|
---|
1590 | else
|
---|
1591 | rc = dumpImportDir<uint64_t, false, IMAGE_ORDINAL_FLAG64>(pBufRdr, paDataDirs[i].VirtualAddress,
|
---|
1592 | paDataDirs[i].Size);
|
---|
1593 | }
|
---|
1594 | else if ( i == IMAGE_DIRECTORY_ENTRY_DEBUG
|
---|
1595 | && paDataDirs[i].Size >= sizeof(IMAGE_DEBUG_DIRECTORY))
|
---|
1596 | rc = dumpDebugDir(pBufRdr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size);
|
---|
1597 | else
|
---|
1598 | continue;
|
---|
1599 | if (RT_FAILURE(rc))
|
---|
1600 | rcRet = rc;
|
---|
1601 | }
|
---|
1602 | return rcRet;
|
---|
1603 | }
|
---|
1604 |
|
---|
1605 | /** @} */
|
---|
1606 |
|
---|
1607 | static int dumpImage(DumpImageCmd *pCmd, const char *pszImageBaseAddr,
|
---|
1608 | uint32_t offPeHdr, PCIMAGE_FILE_HEADER pFileHdr) RT_NOEXCEPT
|
---|
1609 | {
|
---|
1610 | pCmd->myPrintf("%s: PE image - %#x (%s), %u sections\n", pCmd->m_pszName, pFileHdr->Machine,
|
---|
1611 | machineToString(pFileHdr->Machine), pFileHdr->NumberOfSections);
|
---|
1612 |
|
---|
1613 | /* Is it a supported optional header size? */
|
---|
1614 | uint8_t cBits;
|
---|
1615 | if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
|
---|
1616 | cBits = 32;
|
---|
1617 | else if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
|
---|
1618 | cBits = 64;
|
---|
1619 | else
|
---|
1620 | return pCmd->myError("Unsupported optional header size: %#x", pFileHdr->SizeOfOptionalHeader);
|
---|
1621 |
|
---|
1622 | /*
|
---|
1623 | * Allocate memory for all the headers, including section headers, and read them into memory.
|
---|
1624 | */
|
---|
1625 | size_t const offShdrs = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + sizeof(uint32_t);
|
---|
1626 | size_t const cbHdrs = offShdrs + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
|
---|
1627 | if (cbHdrs > _2M)
|
---|
1628 | return pCmd->myError("headers too big: %zu.\n", cbHdrs);
|
---|
1629 |
|
---|
1630 | void *pvBuf = RTMemTmpAllocZ(cbHdrs);
|
---|
1631 | if (!pvBuf)
|
---|
1632 | return pCmd->myError("failed to allocate %zu bytes for headers.", cbHdrs);
|
---|
1633 |
|
---|
1634 | int rc = pCmd->readAt(offPeHdr, pvBuf, cbHdrs, NULL);
|
---|
1635 | if (RT_SUCCESS(rc))
|
---|
1636 | {
|
---|
1637 | /* Format the image base value from the header if one isn't specified. */
|
---|
1638 | char szTmp[32];
|
---|
1639 | if (!pszImageBaseAddr)
|
---|
1640 | {
|
---|
1641 | if (cBits == 32)
|
---|
1642 | RTStrPrintf(szTmp, sizeof(szTmp), "%#010RX32", ((PIMAGE_NT_HEADERS32)pvBuf)->OptionalHeader.ImageBase);
|
---|
1643 | else
|
---|
1644 | RTStrPrintf(szTmp, sizeof(szTmp), "%#018RX64", ((PIMAGE_NT_HEADERS64)pvBuf)->OptionalHeader.ImageBase);
|
---|
1645 | pszImageBaseAddr = szTmp;
|
---|
1646 | }
|
---|
1647 |
|
---|
1648 | /* Finally, instantiate dumper now that we've got the section table
|
---|
1649 | loaded, and let it contiue. */
|
---|
1650 | DumpImagePe This(pCmd, pszImageBaseAddr, offPeHdr, pFileHdr, pvBuf, (uint32_t)offShdrs,
|
---|
1651 | pFileHdr->NumberOfSections, (PCIMAGE_SECTION_HEADER)((uintptr_t)pvBuf + offShdrs));
|
---|
1652 |
|
---|
1653 | This.dumpPeHdr();
|
---|
1654 | if (cBits == 32)
|
---|
1655 | rc = This.dumpOptHdr<IMAGE_OPTIONAL_HEADER32, true>(&This.u.pNt32->OptionalHeader,
|
---|
1656 | This.u.pNt32->OptionalHeader.BaseOfData);
|
---|
1657 | else
|
---|
1658 | rc = This.dumpOptHdr<IMAGE_OPTIONAL_HEADER64, false>(&This.u.pNt64->OptionalHeader);
|
---|
1659 |
|
---|
1660 | int rc2 = This.dumpSectionHdrs();
|
---|
1661 | if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
|
---|
1662 | rc = rc2;
|
---|
1663 |
|
---|
1664 | DumpImageBufferedReader BufRdr(&This);
|
---|
1665 | rc2 = This.dumpDataDirs(&BufRdr, This.cDataDir, This.paDataDir);
|
---|
1666 | if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
|
---|
1667 | rc = rc2;
|
---|
1668 | }
|
---|
1669 | RTMemTmpFree(pvBuf);
|
---|
1670 | return rc;
|
---|
1671 | }
|
---|
1672 |
|
---|
1673 | };
|
---|
1674 |
|
---|
1675 |
|
---|
1676 | /*********************************************************************************************************************************
|
---|
1677 | * ELF *
|
---|
1678 | *********************************************************************************************************************************/
|
---|
1679 |
|
---|
1680 | static int dbgcDumpImageElf(DumpImageCmd *pCmd)
|
---|
1681 | {
|
---|
1682 | pCmd->myPrintf("%s: ELF image dumping not implemented yet.\n", pCmd->m_pszName);
|
---|
1683 | return VINF_SUCCESS;
|
---|
1684 | }
|
---|
1685 |
|
---|
1686 |
|
---|
1687 | /*********************************************************************************************************************************
|
---|
1688 | * Mach-O *
|
---|
1689 | *********************************************************************************************************************************/
|
---|
1690 |
|
---|
1691 | static const char *dbgcMachoFileType(uint32_t uType)
|
---|
1692 | {
|
---|
1693 | switch (uType)
|
---|
1694 | {
|
---|
1695 | case MH_OBJECT: return "MH_OBJECT";
|
---|
1696 | case MH_EXECUTE: return "MH_EXECUTE";
|
---|
1697 | case MH_FVMLIB: return "MH_FVMLIB";
|
---|
1698 | case MH_CORE: return "MH_CORE";
|
---|
1699 | case MH_PRELOAD: return "MH_PRELOAD";
|
---|
1700 | case MH_DYLIB: return "MH_DYLIB";
|
---|
1701 | case MH_DYLINKER: return "MH_DYLINKER";
|
---|
1702 | case MH_BUNDLE: return "MH_BUNDLE";
|
---|
1703 | case MH_DYLIB_STUB: return "MH_DYLIB_STUB";
|
---|
1704 | case MH_DSYM: return "MH_DSYM";
|
---|
1705 | case MH_KEXT_BUNDLE: return "MH_KEXT_BUNDLE";
|
---|
1706 | }
|
---|
1707 | return "??";
|
---|
1708 | }
|
---|
1709 |
|
---|
1710 |
|
---|
1711 | static const char *dbgcMachoCpuType(int32_t iType, int32_t iSubType)
|
---|
1712 | {
|
---|
1713 | switch (iType)
|
---|
1714 | {
|
---|
1715 | case CPU_TYPE_ANY: return "CPU_TYPE_ANY";
|
---|
1716 | case CPU_TYPE_VAX: return "VAX";
|
---|
1717 | case CPU_TYPE_MC680x0: return "MC680x0";
|
---|
1718 | case CPU_TYPE_X86: return "X86";
|
---|
1719 | case CPU_TYPE_X86_64:
|
---|
1720 | switch (iSubType)
|
---|
1721 | {
|
---|
1722 | case CPU_SUBTYPE_X86_64_ALL: return "X86_64/ALL64";
|
---|
1723 | }
|
---|
1724 | return "X86_64";
|
---|
1725 | case CPU_TYPE_MC98000: return "MC98000";
|
---|
1726 | case CPU_TYPE_HPPA: return "HPPA";
|
---|
1727 | case CPU_TYPE_MC88000: return "MC88000";
|
---|
1728 | case CPU_TYPE_SPARC: return "SPARC";
|
---|
1729 | case CPU_TYPE_I860: return "I860";
|
---|
1730 | case CPU_TYPE_POWERPC: return "POWERPC";
|
---|
1731 | case CPU_TYPE_POWERPC64: return "POWERPC64";
|
---|
1732 |
|
---|
1733 | }
|
---|
1734 | return "??";
|
---|
1735 | }
|
---|
1736 |
|
---|
1737 |
|
---|
1738 | static const char *dbgcMachoLoadCommand(uint32_t uCmd)
|
---|
1739 | {
|
---|
1740 | switch (uCmd)
|
---|
1741 | {
|
---|
1742 | RT_CASE_RET_STR(LC_SEGMENT_32);
|
---|
1743 | RT_CASE_RET_STR(LC_SYMTAB);
|
---|
1744 | RT_CASE_RET_STR(LC_SYMSEG);
|
---|
1745 | RT_CASE_RET_STR(LC_THREAD);
|
---|
1746 | RT_CASE_RET_STR(LC_UNIXTHREAD);
|
---|
1747 | RT_CASE_RET_STR(LC_LOADFVMLIB);
|
---|
1748 | RT_CASE_RET_STR(LC_IDFVMLIB);
|
---|
1749 | RT_CASE_RET_STR(LC_IDENT);
|
---|
1750 | RT_CASE_RET_STR(LC_FVMFILE);
|
---|
1751 | RT_CASE_RET_STR(LC_PREPAGE);
|
---|
1752 | RT_CASE_RET_STR(LC_DYSYMTAB);
|
---|
1753 | RT_CASE_RET_STR(LC_LOAD_DYLIB);
|
---|
1754 | RT_CASE_RET_STR(LC_ID_DYLIB);
|
---|
1755 | RT_CASE_RET_STR(LC_LOAD_DYLINKER);
|
---|
1756 | RT_CASE_RET_STR(LC_ID_DYLINKER);
|
---|
1757 | RT_CASE_RET_STR(LC_PREBOUND_DYLIB);
|
---|
1758 | RT_CASE_RET_STR(LC_ROUTINES);
|
---|
1759 | RT_CASE_RET_STR(LC_SUB_FRAMEWORK);
|
---|
1760 | RT_CASE_RET_STR(LC_SUB_UMBRELLA);
|
---|
1761 | RT_CASE_RET_STR(LC_SUB_CLIENT);
|
---|
1762 | RT_CASE_RET_STR(LC_SUB_LIBRARY);
|
---|
1763 | RT_CASE_RET_STR(LC_TWOLEVEL_HINTS);
|
---|
1764 | RT_CASE_RET_STR(LC_PREBIND_CKSUM);
|
---|
1765 | RT_CASE_RET_STR(LC_LOAD_WEAK_DYLIB);
|
---|
1766 | RT_CASE_RET_STR(LC_SEGMENT_64);
|
---|
1767 | RT_CASE_RET_STR(LC_ROUTINES_64);
|
---|
1768 | RT_CASE_RET_STR(LC_UUID);
|
---|
1769 | RT_CASE_RET_STR(LC_RPATH);
|
---|
1770 | RT_CASE_RET_STR(LC_CODE_SIGNATURE);
|
---|
1771 | RT_CASE_RET_STR(LC_SEGMENT_SPLIT_INFO);
|
---|
1772 | RT_CASE_RET_STR(LC_REEXPORT_DYLIB);
|
---|
1773 | RT_CASE_RET_STR(LC_LAZY_LOAD_DYLIB);
|
---|
1774 | RT_CASE_RET_STR(LC_ENCRYPTION_INFO);
|
---|
1775 | RT_CASE_RET_STR(LC_DYLD_INFO);
|
---|
1776 | RT_CASE_RET_STR(LC_DYLD_INFO_ONLY);
|
---|
1777 | RT_CASE_RET_STR(LC_LOAD_UPWARD_DYLIB);
|
---|
1778 | RT_CASE_RET_STR(LC_VERSION_MIN_MACOSX);
|
---|
1779 | RT_CASE_RET_STR(LC_VERSION_MIN_IPHONEOS);
|
---|
1780 | RT_CASE_RET_STR(LC_FUNCTION_STARTS);
|
---|
1781 | RT_CASE_RET_STR(LC_DYLD_ENVIRONMENT);
|
---|
1782 | RT_CASE_RET_STR(LC_MAIN);
|
---|
1783 | RT_CASE_RET_STR(LC_DATA_IN_CODE);
|
---|
1784 | RT_CASE_RET_STR(LC_SOURCE_VERSION);
|
---|
1785 | RT_CASE_RET_STR(LC_DYLIB_CODE_SIGN_DRS);
|
---|
1786 | RT_CASE_RET_STR(LC_ENCRYPTION_INFO_64);
|
---|
1787 | RT_CASE_RET_STR(LC_LINKER_OPTION);
|
---|
1788 | RT_CASE_RET_STR(LC_LINKER_OPTIMIZATION_HINT);
|
---|
1789 | RT_CASE_RET_STR(LC_VERSION_MIN_TVOS);
|
---|
1790 | RT_CASE_RET_STR(LC_VERSION_MIN_WATCHOS);
|
---|
1791 | RT_CASE_RET_STR(LC_NOTE);
|
---|
1792 | RT_CASE_RET_STR(LC_BUILD_VERSION);
|
---|
1793 | }
|
---|
1794 | return "??";
|
---|
1795 | }
|
---|
1796 |
|
---|
1797 |
|
---|
1798 | static const char *dbgcMachoProt(uint32_t fProt)
|
---|
1799 | {
|
---|
1800 | switch (fProt)
|
---|
1801 | {
|
---|
1802 | case VM_PROT_NONE: return "---";
|
---|
1803 | case VM_PROT_READ: return "r--";
|
---|
1804 | case VM_PROT_READ | VM_PROT_WRITE: return "rw-";
|
---|
1805 | case VM_PROT_READ | VM_PROT_EXECUTE: return "r-x";
|
---|
1806 | case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: return "rwx";
|
---|
1807 | case VM_PROT_WRITE: return "-w-";
|
---|
1808 | case VM_PROT_WRITE | VM_PROT_EXECUTE: return "-wx";
|
---|
1809 | case VM_PROT_EXECUTE: return "-w-";
|
---|
1810 | }
|
---|
1811 | return "???";
|
---|
1812 | }
|
---|
1813 |
|
---|
1814 |
|
---|
1815 | static int dbgcDumpImageMachO(DumpImageCmd *pCmd, mach_header_64_t const *pHdr)
|
---|
1816 | {
|
---|
1817 | #define ENTRY(a_Define) { a_Define, #a_Define }
|
---|
1818 | RT_NOREF_PV(pCmd);
|
---|
1819 |
|
---|
1820 | /*
|
---|
1821 | * Header:
|
---|
1822 | */
|
---|
1823 | pCmd->myPrintf("%s: Mach-O image (%s bit) - %s (%u) - %s (%#x / %#x)\n",
|
---|
1824 | pCmd->m_pszName, pHdr->magic == IMAGE_MACHO64_SIGNATURE ? "64" : "32",
|
---|
1825 | dbgcMachoFileType(pHdr->filetype), pHdr->filetype,
|
---|
1826 | dbgcMachoCpuType(pHdr->cputype, pHdr->cpusubtype), pHdr->cputype, pHdr->cpusubtype);
|
---|
1827 |
|
---|
1828 | pCmd->myPrintf("%s: Flags: %#x", pCmd->m_pszName, pHdr->flags);
|
---|
1829 | static DBGCDUMPFLAGENTRY const s_aHdrFlags[] =
|
---|
1830 | {
|
---|
1831 | FLENT(MH_NOUNDEFS), FLENT(MH_INCRLINK),
|
---|
1832 | FLENT(MH_DYLDLINK), FLENT(MH_BINDATLOAD),
|
---|
1833 | FLENT(MH_PREBOUND), FLENT(MH_SPLIT_SEGS),
|
---|
1834 | FLENT(MH_LAZY_INIT), FLENT(MH_TWOLEVEL),
|
---|
1835 | FLENT(MH_FORCE_FLAT), FLENT(MH_NOMULTIDEFS),
|
---|
1836 | FLENT(MH_NOFIXPREBINDING), FLENT(MH_PREBINDABLE),
|
---|
1837 | FLENT(MH_ALLMODSBOUND), FLENT(MH_SUBSECTIONS_VIA_SYMBOLS),
|
---|
1838 | FLENT(MH_CANONICAL), FLENT(MH_WEAK_DEFINES),
|
---|
1839 | FLENT(MH_BINDS_TO_WEAK), FLENT(MH_ALLOW_STACK_EXECUTION),
|
---|
1840 | FLENT(MH_ROOT_SAFE), FLENT(MH_SETUID_SAFE),
|
---|
1841 | FLENT(MH_NO_REEXPORTED_DYLIBS), FLENT(MH_PIE),
|
---|
1842 | FLENT(MH_DEAD_STRIPPABLE_DYLIB), FLENT(MH_HAS_TLV_DESCRIPTORS),
|
---|
1843 | FLENT(MH_NO_HEAP_EXECUTION),
|
---|
1844 | };
|
---|
1845 | dbgcDumpImageFlags32(pCmd, pHdr->flags, s_aHdrFlags, RT_ELEMENTS(s_aHdrFlags));
|
---|
1846 | pCmd->myPrintf("\n");
|
---|
1847 | if (pHdr->reserved != 0 && pHdr->magic == IMAGE_MACHO64_SIGNATURE)
|
---|
1848 | pCmd->myPrintf("%s: Reserved header field: %#x\n", pCmd->m_pszName, pHdr->reserved);
|
---|
1849 |
|
---|
1850 | /*
|
---|
1851 | * And now the load commands.
|
---|
1852 | */
|
---|
1853 | const uint32_t cCmds = pHdr->ncmds;
|
---|
1854 | const uint32_t cbCmds = pHdr->sizeofcmds;
|
---|
1855 | pCmd->myPrintf("%s: %u load commands covering %#x bytes:\n", pCmd->m_pszName, cCmds, cbCmds);
|
---|
1856 | if (cbCmds > _16M)
|
---|
1857 | return pCmd->myError(VERR_OUT_OF_RANGE, "%s: Commands too big: %#x bytes, max 16MiB", pCmd->m_pszName, cbCmds);
|
---|
1858 |
|
---|
1859 |
|
---|
1860 | /* Read the commands into a temp buffer: */
|
---|
1861 | const uint32_t cbHdr = pHdr->magic == IMAGE_MACHO64_SIGNATURE ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t);
|
---|
1862 | uint8_t *pbCmds = (uint8_t *)RTMemTmpAllocZ(cbCmds);
|
---|
1863 | if (!pbCmds)
|
---|
1864 | return VERR_NO_TMP_MEMORY;
|
---|
1865 |
|
---|
1866 | int rc = pCmd->readAt(cbHdr, pbCmds, cbCmds, NULL);
|
---|
1867 | if (RT_SUCCESS(rc))
|
---|
1868 | {
|
---|
1869 | static const DBGCDUMPFLAGENTRY s_aSegFlags[] =
|
---|
1870 | { FLENT(SG_HIGHVM), FLENT(SG_FVMLIB), FLENT(SG_NORELOC), FLENT(SG_PROTECTED_VERSION_1), };
|
---|
1871 |
|
---|
1872 | /*
|
---|
1873 | * Iterate the commands.
|
---|
1874 | */
|
---|
1875 | uint32_t offCmd = 0;
|
---|
1876 | for (uint32_t iCmd = 0; iCmd < cCmds; iCmd++)
|
---|
1877 | {
|
---|
1878 | load_command_t const *pCurCmd = (load_command_t const *)&pbCmds[offCmd];
|
---|
1879 | const uint32_t cbCurCmd = offCmd + sizeof(*pCurCmd) <= cbCmds ? pCurCmd->cmdsize : sizeof(*pCurCmd);
|
---|
1880 | if (offCmd + cbCurCmd > cbCmds)
|
---|
1881 | {
|
---|
1882 | rc = pCmd->myError(VERR_OUT_OF_RANGE,
|
---|
1883 | "%s: Load command #%u (offset %#x + %#x) is out of bounds! cmdsize=%u (%#x) cmd=%u\n",
|
---|
1884 | pCmd->m_pszName, iCmd, offCmd, cbHdr, cbCurCmd, cbCurCmd,
|
---|
1885 | offCmd + RT_UOFFSET_AFTER(load_command_t, cmd) <= cbCmds ? pCurCmd->cmd : UINT32_MAX);
|
---|
1886 | break;
|
---|
1887 | }
|
---|
1888 |
|
---|
1889 | pCmd->myPrintf("%s: Load command #%u (offset %#x + %#x): %s (%u) LB %u\n",
|
---|
1890 | pCmd->m_pszName, iCmd, offCmd, cbHdr, dbgcMachoLoadCommand(pCurCmd->cmd), pCurCmd->cmd, cbCurCmd);
|
---|
1891 | switch (pCurCmd->cmd)
|
---|
1892 | {
|
---|
1893 | case LC_SEGMENT_64:
|
---|
1894 | if (cbCurCmd < sizeof(segment_command_64_t))
|
---|
1895 | rc = pCmd->myError(VERR_LDRMACHO_BAD_LOAD_COMMAND, "LC_SEGMENT64 is too short!");
|
---|
1896 | else
|
---|
1897 | {
|
---|
1898 | segment_command_64_t const *pSeg = (segment_command_64_t const *)pCurCmd;
|
---|
1899 | pCmd->myPrintf("%s: vmaddr: %016RX64 LB %08RX64 prot: %s(%x) maxprot: %s(%x) name: %.16s\n",
|
---|
1900 | pCmd->m_pszName, pSeg->vmaddr, pSeg->vmsize, dbgcMachoProt(pSeg->initprot), pSeg->initprot,
|
---|
1901 | dbgcMachoProt(pSeg->maxprot), pSeg->maxprot, pSeg->segname);
|
---|
1902 | pCmd->myPrintf("%s: file: %016RX64 LB %08RX64 sections: %2u flags: %#x",
|
---|
1903 | pCmd->m_pszName, pSeg->fileoff, pSeg->filesize, pSeg->nsects, pSeg->flags);
|
---|
1904 | dbgcDumpImageFlags32(pCmd, pSeg->flags, s_aSegFlags, RT_ELEMENTS(s_aSegFlags));
|
---|
1905 | pCmd->myPrintf("\n");
|
---|
1906 | if ( pSeg->nsects > _64K
|
---|
1907 | || pSeg->nsects * sizeof(section_64_t) + sizeof(pSeg) > cbCurCmd)
|
---|
1908 | rc = pCmd->myError(VERR_LDRMACHO_BAD_LOAD_COMMAND, "LC_SEGMENT64 is too short for all the sections!");
|
---|
1909 | else
|
---|
1910 | {
|
---|
1911 | section_64_t const *paSec = (section_64_t const *)(pSeg + 1);
|
---|
1912 | for (uint32_t iSec = 0; iSec < pSeg->nsects; iSec++)
|
---|
1913 | {
|
---|
1914 | pCmd->myPrintf("%s: Section #%u: %016RX64 LB %08RX64 align: 2**%-2u name: %.16s",
|
---|
1915 | pCmd->m_pszName, iSec, paSec[iSec].addr, paSec[iSec].size, paSec[iSec].align,
|
---|
1916 | paSec[iSec].sectname);
|
---|
1917 | if (strncmp(pSeg->segname, paSec[iSec].segname, sizeof(pSeg->segname)))
|
---|
1918 | pCmd->myPrintf("(in %.16s)", paSec[iSec].segname);
|
---|
1919 | pCmd->myPrintf("\n");
|
---|
1920 |
|
---|
1921 | /// @todo Good night!
|
---|
1922 | /// uint32_t offset;
|
---|
1923 | /// uint32_t reloff;
|
---|
1924 | /// uint32_t nreloc;
|
---|
1925 | /// uint32_t flags;
|
---|
1926 | /// /** For S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS and S_SYMBOL_STUBS
|
---|
1927 | /// * this is the index into the indirect symbol table. */
|
---|
1928 | /// uint32_t reserved1;
|
---|
1929 | /// uint32_t reserved2;
|
---|
1930 | /// uint32_t reserved3;
|
---|
1931 | ///
|
---|
1932 | }
|
---|
1933 | }
|
---|
1934 | }
|
---|
1935 | break;
|
---|
1936 | }
|
---|
1937 |
|
---|
1938 | /* Advance: */
|
---|
1939 | offCmd += cbCurCmd;
|
---|
1940 | }
|
---|
1941 | }
|
---|
1942 | RTMemTmpFree(pbCmds);
|
---|
1943 | return rc;
|
---|
1944 | #undef ENTRY
|
---|
1945 | }
|
---|
1946 |
|
---|
1947 |
|
---|
1948 | /**
|
---|
1949 | * Common worker for the dumpimage command and the VBoxDumpImage tool.
|
---|
1950 | */
|
---|
1951 | int DumpImageCmd::dumpImage(const char *pszImageBaseAddr) RT_NOEXCEPT
|
---|
1952 | {
|
---|
1953 | if (!isFirstTarget())
|
---|
1954 | myPrintf("===================================================================\n"
|
---|
1955 | "\n"
|
---|
1956 | "\n");
|
---|
1957 | union
|
---|
1958 | {
|
---|
1959 | uint8_t ab[0x10];
|
---|
1960 | IMAGE_DOS_HEADER DosHdr;
|
---|
1961 | struct
|
---|
1962 | {
|
---|
1963 | uint32_t u32Magic;
|
---|
1964 | IMAGE_FILE_HEADER FileHdr;
|
---|
1965 | } Nt;
|
---|
1966 | mach_header_64_t MachO64;
|
---|
1967 | } uBuf;
|
---|
1968 | int rc = readAt(0, &uBuf.DosHdr, sizeof(uBuf.DosHdr), NULL);
|
---|
1969 | if (RT_SUCCESS(rc))
|
---|
1970 | {
|
---|
1971 | /*
|
---|
1972 | * MZ.
|
---|
1973 | */
|
---|
1974 | if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE)
|
---|
1975 | {
|
---|
1976 | uint32_t offNewHdr = uBuf.DosHdr.e_lfanew;
|
---|
1977 | if (offNewHdr < _256K && offNewHdr >= 16)
|
---|
1978 | {
|
---|
1979 | /* Look for new header. */
|
---|
1980 | rc = readAt(offNewHdr, &uBuf.Nt, sizeof(uBuf.Nt), NULL);
|
---|
1981 | if (RT_SUCCESS(rc))
|
---|
1982 | {
|
---|
1983 | /* PE: */
|
---|
1984 | if (uBuf.Nt.u32Magic == IMAGE_NT_SIGNATURE)
|
---|
1985 | rc = DumpImagePe::dumpImage(this, pszImageBaseAddr, offNewHdr, &uBuf.Nt.FileHdr);
|
---|
1986 | else
|
---|
1987 | return myError(rc, "Unknown new header magic: %.8Rhxs", uBuf.ab);
|
---|
1988 | }
|
---|
1989 | }
|
---|
1990 | else
|
---|
1991 | return myError(rc, "e_lfanew=%#RX32 is out of bounds (16..256K).", offNewHdr);
|
---|
1992 | }
|
---|
1993 | /*
|
---|
1994 | * ELF.
|
---|
1995 | */
|
---|
1996 | else if (uBuf.ab[0] == ELFMAG0 && uBuf.ab[1] == ELFMAG1 && uBuf.ab[2] == ELFMAG2 && uBuf.ab[3] == ELFMAG3)
|
---|
1997 | rc = dbgcDumpImageElf(this);
|
---|
1998 | /*
|
---|
1999 | * Mach-O.
|
---|
2000 | */
|
---|
2001 | else if ( uBuf.MachO64.magic == IMAGE_MACHO64_SIGNATURE
|
---|
2002 | || uBuf.MachO64.magic == IMAGE_MACHO32_SIGNATURE)
|
---|
2003 | rc = dbgcDumpImageMachO(this, &uBuf.MachO64);
|
---|
2004 | /*
|
---|
2005 | * Dunno.
|
---|
2006 | */
|
---|
2007 | else
|
---|
2008 | return myError(rc, "Unknown magic: %.8Rhxs", uBuf.ab);
|
---|
2009 |
|
---|
2010 | /* Make 100% sure the failure status is signalled. */
|
---|
2011 | if (RT_FAILURE(rc))
|
---|
2012 | setFailure(rc);
|
---|
2013 | }
|
---|
2014 | else
|
---|
2015 | rc = myError(rc, "Failed to read %zu", sizeof(uBuf.DosHdr));
|
---|
2016 | return rc;
|
---|
2017 | }
|
---|
2018 |
|
---|
2019 |
|
---|
2020 | #ifndef DBGC_DUMP_IMAGE_TOOL
|
---|
2021 |
|
---|
2022 | /**
|
---|
2023 | * @callback_method_impl{FNDBGCCMD, The 'dumpimage' command.}
|
---|
2024 | */
|
---|
2025 | DECLCALLBACK(int) dbgcCmdDumpImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
|
---|
2026 | {
|
---|
2027 | DumpImageCmd Cmd(pCmdHlp, pCmd);
|
---|
2028 | for (unsigned iArg = 0; iArg < cArgs; iArg++)
|
---|
2029 | {
|
---|
2030 | DBGCVAR const ImageBase = paArgs[iArg];
|
---|
2031 | char szImageBaseAddr[64];
|
---|
2032 | DBGCCmdHlpStrPrintf(pCmdHlp, szImageBaseAddr, sizeof(szImageBaseAddr), "%Dv", &ImageBase);
|
---|
2033 | Cmd.setTarget(szImageBaseAddr, &ImageBase);
|
---|
2034 | Cmd.dumpImage(szImageBaseAddr);
|
---|
2035 | Cmd.clearTarget();
|
---|
2036 | }
|
---|
2037 | RT_NOREF(pUVM);
|
---|
2038 | return Cmd.getStatus();
|
---|
2039 | }
|
---|
2040 |
|
---|
2041 | #else /* DBGC_DUMP_IMAGE_TOOL */
|
---|
2042 |
|
---|
2043 | int main(int argc, char **argv)
|
---|
2044 | {
|
---|
2045 | int rc = RTR3InitExe(argc, &argv, 0);
|
---|
2046 | if (RT_FAILURE(rc))
|
---|
2047 | return RTMsgInitFailure(rc);
|
---|
2048 |
|
---|
2049 | /*
|
---|
2050 | * Setup image helper code.
|
---|
2051 | */
|
---|
2052 | DumpImageCmd Cmd(NULL, NULL);
|
---|
2053 | char szImageBaseAddr[32] = {0};
|
---|
2054 | //uint64_t fSelect = DUMPIMAGE_SELECT_DEFAULT;
|
---|
2055 |
|
---|
2056 | static const RTGETOPTDEF s_aOptions[] =
|
---|
2057 | {
|
---|
2058 | { "--image-base", 'b', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX },
|
---|
2059 | { "--include", 'i', RTGETOPT_REQ_STRING },
|
---|
2060 | { "--only", 'o', RTGETOPT_REQ_STRING },
|
---|
2061 | { "--only", 'O', RTGETOPT_REQ_STRING },
|
---|
2062 | { "--skip", 's', RTGETOPT_REQ_STRING },
|
---|
2063 | { "--skip", 'S', RTGETOPT_REQ_STRING },
|
---|
2064 | };
|
---|
2065 |
|
---|
2066 | RTGETOPTSTATE GetState;
|
---|
2067 | rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
2068 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
2069 |
|
---|
2070 | RTGETOPTUNION ValueUnion;
|
---|
2071 | int chOpt;
|
---|
2072 | while ((chOpt = RTGetOpt(&GetState, &ValueUnion)) != 0)
|
---|
2073 | {
|
---|
2074 | switch (chOpt)
|
---|
2075 | {
|
---|
2076 | case 'b':
|
---|
2077 | if (ValueUnion.u64 >= UINT32_MAX - _16M)
|
---|
2078 | RTStrPrintf(szImageBaseAddr, sizeof(szImageBaseAddr), "%#018RX64", ValueUnion.u64);
|
---|
2079 | else
|
---|
2080 | RTStrPrintf(szImageBaseAddr, sizeof(szImageBaseAddr), "%#010RX64", ValueUnion.u64);
|
---|
2081 | break;
|
---|
2082 |
|
---|
2083 | case 'i':
|
---|
2084 | rc = Cmd.optSelectionInclude(ValueUnion.psz);
|
---|
2085 | if (RT_FAILURE(rc))
|
---|
2086 | return RTEXITCODE_SYNTAX;
|
---|
2087 | break;
|
---|
2088 |
|
---|
2089 | case 'o':
|
---|
2090 | case 'O':
|
---|
2091 | rc = Cmd.optSelectionOnly(ValueUnion.psz);
|
---|
2092 | if (RT_FAILURE(rc))
|
---|
2093 | return RTEXITCODE_SYNTAX;
|
---|
2094 | break;
|
---|
2095 |
|
---|
2096 | case 's':
|
---|
2097 | case 'S':
|
---|
2098 | rc = Cmd.optSelectionSkip(ValueUnion.psz);
|
---|
2099 | if (RT_FAILURE(rc))
|
---|
2100 | return RTEXITCODE_SYNTAX;
|
---|
2101 | break;
|
---|
2102 |
|
---|
2103 | case 'V':
|
---|
2104 | RTPrintf("%s\n", RTBldCfgRevision());
|
---|
2105 | return RTEXITCODE_SUCCESS;
|
---|
2106 |
|
---|
2107 | case 'h':
|
---|
2108 | {
|
---|
2109 | RTPrintf("usage: %s [options] <file> [file2..]\n"
|
---|
2110 | "\n"
|
---|
2111 | "Options:\n"
|
---|
2112 | " -b<address>, --image-base=<address>\n"
|
---|
2113 | " Pretend load address for the image.\n"
|
---|
2114 | " -i/--include <sel>, -o/-O/--only <sel>, -s/-S/--skip <sel>\n"
|
---|
2115 | " Select what to display. The selection is a comma or space separated\n"
|
---|
2116 | " list of any of the following:\n"
|
---|
2117 | , RTProcShortName());
|
---|
2118 | size_t cchWidth = 1;
|
---|
2119 | for (unsigned i = 0; i < RT_ELEMENTS(g_aMnemonics); i++)
|
---|
2120 | if (g_aMnemonics[i].pszSummary)
|
---|
2121 | {
|
---|
2122 | size_t cchSummary = strlen(g_aMnemonics[i].pszSummary);
|
---|
2123 | cchWidth = RT_MAX(cchWidth, cchSummary);
|
---|
2124 | }
|
---|
2125 | for (unsigned i = 0; i < RT_ELEMENTS(g_aMnemonics); i++)
|
---|
2126 | if (g_aMnemonics[i].pszSummary)
|
---|
2127 | RTPrintf(" %-*s - %s\n", cchWidth, g_aMnemonics[i].pszSummary, g_aMnemonics[i].pszDesc);
|
---|
2128 | return RTEXITCODE_SUCCESS;
|
---|
2129 | }
|
---|
2130 |
|
---|
2131 | case VINF_GETOPT_NOT_OPTION:
|
---|
2132 | {
|
---|
2133 | RTERRINFOSTATIC ErrInfo;
|
---|
2134 | uint32_t offError = 0;
|
---|
2135 | RTVFSFILE hVfsFile = NIL_RTVFSFILE;
|
---|
2136 | rc = RTVfsChainOpenFile(ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
|
---|
2137 | &hVfsFile, &offError, RTErrInfoInitStatic(&ErrInfo));
|
---|
2138 | if (RT_SUCCESS(rc))
|
---|
2139 | {
|
---|
2140 | Cmd.setTarget(ValueUnion.psz, hVfsFile);
|
---|
2141 | Cmd.dumpImage(szImageBaseAddr[0] ? szImageBaseAddr : NULL);
|
---|
2142 | Cmd.clearTarget();
|
---|
2143 | }
|
---|
2144 | else
|
---|
2145 | {
|
---|
2146 | RTVfsChainMsgErrorExitFailure("RTVfsChainOpenFile", ValueUnion.psz, rc, offError, &ErrInfo.Core);
|
---|
2147 | Cmd.setFailure(rc);
|
---|
2148 | }
|
---|
2149 | break;
|
---|
2150 | }
|
---|
2151 |
|
---|
2152 | default:
|
---|
2153 | return RTGetOptPrintError(chOpt, &ValueUnion);
|
---|
2154 | }
|
---|
2155 | }
|
---|
2156 |
|
---|
2157 | return Cmd.getExitCode();
|
---|
2158 | }
|
---|
2159 |
|
---|
2160 | #endif /* !DBGC_DUMP_IMAGE_TOOL */
|
---|
2161 |
|
---|