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