Changeset 105508 in vbox
- Timestamp:
- Jul 26, 2024 1:46:01 AM (8 months ago)
- svn:sync-xref-src-repo-rev:
- 164173
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGCDumpImage.cpp
r98103 r105508 45 45 #include <iprt/path.h> 46 46 #include <iprt/string.h> 47 #include <iprt/time.h> 48 #ifdef DBGC_DUMP_IMAGE_TOOL 49 # include <iprt/buildconfig.h> 50 # include <iprt/message.h> 51 # include <iprt/file.h> 52 # include <iprt/getopt.h> 53 # include <iprt/initterm.h> 54 # include <iprt/process.h> 55 # include <iprt/stream.h> 56 # include <iprt/vfs.h> 57 #endif 47 58 #include <iprt/formats/mz.h> 48 59 #include <iprt/formats/pecoff.h> … … 58 69 * Structures and Typedefs * 59 70 *********************************************************************************************************************************/ 60 /** 61 * PE dumper instance. 62 */ 63 typedef struct DUMPIMAGEPE 64 { 65 /** Pointer to the image base address variable. */ 66 PCDBGCVAR pImageBase; 67 /** Pointer to the file header. */ 68 PCIMAGE_FILE_HEADER pFileHdr; 69 /** Pointer to the NT headers. */ 70 union 71 { 72 PCIMAGE_NT_HEADERS32 pNt32; 73 PCIMAGE_NT_HEADERS64 pNt64; 74 void *pv; 75 } u; 76 /** Pointer to the section headers. */ 77 PCIMAGE_SECTION_HEADER paShdrs; 78 /** Number of section headers. */ 79 unsigned cShdrs; 80 /** Number of RVA and sizes (data directory entries). */ 81 unsigned cDataDir; 82 /** Pointer to the data directory. */ 83 PCIMAGE_DATA_DIRECTORY paDataDir; 84 85 /** The command descriptor (for failing the command). */ 86 PCDBGCCMD pCmd; 87 } DUMPIMAGEPE; 88 /** Pointer to a PE dumper instance. */ 89 typedef DUMPIMAGEPE *PDUMPIMAGEPE; 71 #ifdef DBGC_DUMP_IMAGE_TOOL 72 /** Command helper state for the image dumper tool. */ 73 typedef struct CMDHLPSTATE 74 { 75 DBGCCMDHLP Core; 76 /** The exit code for the tool. */ 77 RTEXITCODE rcExit; 78 /** The current input file. */ 79 RTVFSFILE hVfsFile; 80 } CMDHLPSTATE; 81 typedef CMDHLPSTATE *PCMDHLPSTATE; 82 #endif 90 83 91 84 … … 102 95 * Internal Functions * 103 96 *********************************************************************************************************************************/ 97 #ifndef DBGC_DUMP_IMAGE_TOOL 104 98 extern FNDBGCCMD dbgcCmdDumpImage; /* See DBGCCommands.cpp. */ 99 #endif 105 100 106 101 … … 112 107 DBGCCmdHlpPrintf(pCmdHlp, " %s", paEntries[i].pszNm); 113 108 } 109 110 111 /** 112 * Early read function. 113 * 114 * @todo refactor/abstract this somehow... 115 */ 116 static int dumpReadAt(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, PCDBGCVAR pImageBase, const char *pszName, 117 size_t off, void *pvDst, size_t cbToRead, size_t *pcbRead) 118 { 119 RT_BZERO(pvDst, cbToRead); 120 if (pcbRead) 121 *pcbRead = 0; 122 123 #ifndef DBGC_DUMP_IMAGE_TOOL 124 DBGCVAR AddrToReadAt; 125 int rc = DBGCCmdHlpEval(pCmdHlp, &AddrToReadAt, "%DV + %#zx", pImageBase, off); 126 if (RT_SUCCESS(rc)) 127 { 128 rc = DBGCCmdHlpMemRead(pCmdHlp, pvDst, cbToRead, &AddrToReadAt, pcbRead); 129 if (RT_SUCCESS(rc)) 130 return VINF_SUCCESS; 131 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%s: Failed to read %zu bytes at offset %Dv", pszName, cbToRead, &AddrToReadAt); 132 } 133 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%s: Failed to calculate address %Dv + #%zx for %#zx byte read", 134 pszName, pImageBase, off, cbToRead); 135 136 #else /* DBGC_DUMP_IMAGE_TOOL */ 137 CMDHLPSTATE * const pToolState = RT_FROM_MEMBER(pCmdHlp, CMDHLPSTATE, Core); 138 int rc = RTVfsFileReadAt(pToolState->hVfsFile, off, pvDst, cbToRead, pcbRead); 139 if (RT_SUCCESS(rc)) 140 return VINF_SUCCESS; 141 RT_NOREF(pImageBase); 142 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%s: Failed to read %zu bytes at offset %#zx", pszName, cbToRead, off); 143 #endif /* DBGC_DUMP_IMAGE_TOOL */ 144 } 145 146 147 /********************************************************************************************************************************* 148 * DumpImageBase * 149 *********************************************************************************************************************************/ 150 class DumpImageBase 151 { 152 public: 153 /** The name of what's being dumped (for error messages). */ 154 const char * const m_pszName; 155 /** Pointer to the image base address variable. */ 156 PCDBGCVAR const m_pImageBase; 157 /** Pointer to the command helpers. */ 158 PDBGCCMDHLP const m_pCmdHlp; 159 /** The command descriptor (for failing the command). */ 160 PCDBGCCMD const m_pCmd; 161 162 private: 163 /** The Image base address. */ 164 uint64_t m_uImageBaseAddr; 165 protected: 166 /** The full formatted address width. */ 167 uint8_t m_cchAddr; 168 private: 169 /** The formatted address value width. */ 170 uint8_t m_cchAddrValue; 171 /** The address prefix length. */ 172 uint8_t m_cchAddrPfx; 173 /** The address prefix. */ 174 char m_szAddrPfx[16 - 3]; 175 176 private: 177 DumpImageBase(); 178 179 void setupAddrFormatting(const char *a_pszImageBaseAddr) 180 { 181 /* 182 * Expected inputs: %%12345678, %123456789abcdef, 0x12345678, 0008:12345678 183 * 184 * So, work backwards till be find the start of the address/offset value 185 * component, and treat what comes first as a prefix. 186 */ 187 size_t const cch = strlen(a_pszImageBaseAddr); 188 size_t cchAddrPfx = cch; 189 while (cchAddrPfx > 0 && RT_C_IS_XDIGIT(a_pszImageBaseAddr[cchAddrPfx - 1])) 190 cchAddrPfx--; 191 192 size_t cchLeadingZeros = 0; 193 while (a_pszImageBaseAddr[cchAddrPfx + cchLeadingZeros] == '0') 194 cchLeadingZeros++; 195 196 int rc = RTStrToUInt64Full(&a_pszImageBaseAddr[cchAddrPfx], 16, &m_uImageBaseAddr); 197 AssertRCSuccess(rc); 198 m_cchAddrValue = (uint8_t)(cch - cchAddrPfx); 199 Assert(m_cchAddrValue == cch - cchAddrPfx); 200 if (m_cchAddrValue > 8 && cchLeadingZeros > 1) 201 m_cchAddrValue = RT_ALIGN_T(m_cchAddrValue - (uint8_t)(cchLeadingZeros - 1), 2, uint8_t); 202 203 AssertStmt(cchAddrPfx < sizeof(m_szAddrPfx), cchAddrPfx = sizeof(m_szAddrPfx) - 1); 204 memcpy(m_szAddrPfx, a_pszImageBaseAddr, cchAddrPfx); 205 m_szAddrPfx[cchAddrPfx] = '\0'; 206 m_cchAddrPfx = (uint8_t)cchAddrPfx; 207 208 m_cchAddr = m_cchAddrPfx + m_cchAddrValue; 209 } 210 211 public: 212 DumpImageBase(PDBGCCMDHLP a_pCmdHlp, PCDBGCCMD a_pCmd, PCDBGCVAR a_pImageBase, 213 const char *a_pszImageBaseAddr, const char *a_pszName) 214 : m_pszName(a_pszName) 215 , m_pImageBase(a_pImageBase) 216 , m_pCmdHlp(a_pCmdHlp) 217 , m_pCmd(a_pCmd) 218 , m_uImageBaseAddr(0) 219 , m_cchAddr(0) 220 , m_cchAddrValue(12) 221 , m_cchAddrPfx(2) 222 , m_szAddrPfx("0x") 223 { 224 setupAddrFormatting(a_pszImageBaseAddr); 225 } 226 227 virtual ~DumpImageBase() { } 228 229 virtual size_t rvaToFileOffset(size_t uRva) const = 0; 230 virtual size_t getEndRva(bool a_fAligned = true) const = 0; 231 232 char *rvaToStringWithAddr(size_t uRva, char *pszDst, size_t cbDst, bool fWide = false) 233 { 234 if (!fWide) 235 RTStrPrintf(pszDst, cbDst, "%#09zx/%s%0*RX64", uRva, m_szAddrPfx, m_cchAddrValue, m_uImageBaseAddr + uRva); 236 else 237 RTStrPrintf(pszDst, cbDst, "%#09zx / %s%0*RX64", uRva, m_szAddrPfx, m_cchAddrValue, m_uImageBaseAddr + uRva); 238 return pszDst; 239 } 240 241 virtual void myPrintf(const char *pszFormat, ...) 242 { 243 va_list va; 244 va_start(va, pszFormat); 245 m_pCmdHlp->pfnPrintfV(m_pCmdHlp, NULL, pszFormat, va); 246 va_end(va); 247 } 248 249 void myPrintHeader(size_t uRva, const char *pszFormat, ...) 250 { 251 char szTmp[64]; 252 char szLine[128]; 253 va_list va; 254 va_start(va, pszFormat); 255 size_t const cchLine = RTStrPrintf(szLine, sizeof(szLine), "%s - %N", 256 rvaToStringWithAddr(uRva, szTmp, sizeof(szTmp), true), pszFormat, &va); 257 va_end(va); 258 myPrintf("\n" 259 "%s\n" 260 "%.*s====\n", 261 szLine, 262 cchLine, "==============================================================================="); 263 } 264 265 virtual int myError(const char *pszFormat, ...) 266 { 267 va_list va; 268 va_start(va, pszFormat); 269 int rc = DBGCCmdHlpFail(m_pCmdHlp, m_pCmd, "%s: %N", m_pszName, pszFormat, &va); 270 va_end(va); 271 return rc; 272 } 273 274 virtual int myError(int rc, const char *pszFormat, ...) 275 { 276 va_list va; 277 va_start(va, pszFormat); 278 rc = DBGCCmdHlpFailRc(m_pCmdHlp, m_pCmd, rc, "%s: %N", m_pszName, pszFormat, &va); 279 va_end(va); 280 return rc; 281 } 282 283 int readBytesAtRva(size_t uRva, void *pvBuf, size_t cbToRead, size_t *pcbRead = NULL) 284 { 285 /* Ensure buffer and return size is zero before we do anything. */ 286 if (pcbRead) 287 *pcbRead = 0; 288 RT_BZERO(pvBuf, cbToRead); 289 290 #ifndef DBGC_DUMP_IMAGE_TOOL 291 /* Calc the read address. */ 292 DBGCVAR AddrToReadAt; 293 int rc = DBGCCmdHlpEval(m_pCmdHlp, &AddrToReadAt, "%DV + %#zx", m_pImageBase, uRva); 294 if (RT_SUCCESS(rc)) 295 { 296 rc = DBGCCmdHlpMemRead(m_pCmdHlp, pvBuf, cbToRead, &AddrToReadAt, pcbRead); 297 if (RT_FAILURE(rc)) 298 rc = myError(rc, "Failed to read %zu bytes at %Dv", cbToRead, &AddrToReadAt); 299 } 300 #else /* DBGC_DUMP_IMAGE_TOOL */ 301 int rc; 302 size_t const offFile = rvaToFileOffset(uRva); 303 if (offFile != ~(size_t)0) 304 { 305 CMDHLPSTATE * const pToolState = RT_FROM_MEMBER(m_pCmdHlp, CMDHLPSTATE, Core); 306 rc = RTVfsFileReadAt(pToolState->hVfsFile, offFile, pvBuf, cbToRead, pcbRead); 307 if (RT_FAILURE(rc)) 308 rc = myError(rc, "Failed to read %zu bytes at %#zx (RVA %#zx)", cbToRead, offFile, uRva); 309 } 310 else 311 rc = myError(VERR_READ_ERROR, "Failed to convert RVA %#zx to file offset for %zu byte read!", uRva, cbToRead); 312 #endif /* DBGC_DUMP_IMAGE_TOOL */ 313 return rc; 314 } 315 }; 316 317 318 /** 319 * Buffered reading by relative virtual address (RVA). 320 */ 321 class DumpImageBufferedReader 322 { 323 private: 324 /** Static sized buffer. */ 325 uint8_t m_abBufFixed[4096]; 326 /** Pointer to m_abBufFixed if that's sufficient, otherwise heap buffer. */ 327 uint8_t *m_pbBuf; 328 /** The size of the buffer m_pbBuf points at. */ 329 size_t m_cbBufAlloc; 330 /** Number of valid bytes in the buffer. */ 331 size_t m_cbBuf; 332 /** The RVA of the first buffer byte, maximum value if empty. */ 333 size_t m_uRvaBuf; 334 /** Pointer to the image dumper. */ 335 DumpImageBase *m_pImage; 336 337 int loadBuffer(size_t uRva) 338 { 339 /* Check that the RVA is within the image. */ 340 size_t const cbMaxRva = m_pImage->getEndRva(); 341 if (uRva >= cbMaxRva) 342 return VERR_EOF; 343 344 /* Adjust the RVA if we're reading beyond the end of the image. */ 345 if (uRva + m_cbBufAlloc > RT_ALIGN_Z(cbMaxRva, 8)) 346 uRva = m_cbBufAlloc > RT_ALIGN_Z(cbMaxRva, 8) ? RT_ALIGN_Z(cbMaxRva, 8) - m_cbBufAlloc : 0; 347 348 /* Do the read. In case of failure readBytesAtRva will zero the buffer. */ 349 m_uRvaBuf = uRva; 350 m_cbBuf = 0; 351 return m_pImage->readBytesAtRva(uRva, m_pbBuf, RT_MIN(cbMaxRva - uRva, m_cbBufAlloc), &m_cbBuf); 352 } 353 354 /** Resizes the buffer if the current one can't hold @a cbNeeded bytes. */ 355 int ensureBufferSpace(size_t cbNeeded) 356 { 357 if (cbNeeded > m_cbBufAlloc) 358 { 359 cbNeeded = RT_ALIGN_Z(cbNeeded, 512); 360 void *pvNew = RTMemTmpAllocZ(cbNeeded); 361 if (!pvNew) 362 return DBGCCmdHlpFailRc(m_pImage->m_pCmdHlp, m_pImage->m_pCmd, VERR_NO_TMP_MEMORY, 363 "Failed to allocate %zu (%#zx) bytes", cbNeeded, cbNeeded); 364 memcpy(pvNew, m_pbBuf, RT_MIN(m_cbBuf, m_cbBufAlloc)); 365 366 if (m_pbBuf != &m_abBufFixed[0]) 367 RTMemTmpFree(m_pbBuf); 368 m_pbBuf = (uint8_t *)pvNew; 369 m_cbBufAlloc = cbNeeded; 370 } 371 return VINF_SUCCESS; 372 } 373 374 DumpImageBufferedReader(); 375 376 public: 377 DumpImageBufferedReader(DumpImageBase *a_pImage) 378 : m_pbBuf(&m_abBufFixed[0]) 379 , m_cbBufAlloc(sizeof(m_abBufFixed)) 380 , m_cbBuf(0) 381 , m_uRvaBuf(~(size_t)0) 382 , m_pImage(a_pImage) 383 { 384 RT_ZERO(m_abBufFixed); 385 } 386 387 /** Copy constructor. */ 388 DumpImageBufferedReader(DumpImageBufferedReader const &a_rThat) 389 : m_pbBuf(&m_abBufFixed[0]) 390 , m_cbBufAlloc(sizeof(m_abBufFixed)) 391 , m_cbBuf(RT_MIN(a_rThat.m_cbBuf, sizeof(m_abBufFixed))) 392 , m_uRvaBuf(a_rThat.m_uRvaBuf) 393 , m_pImage(a_rThat.m_pImage) 394 { 395 memcpy(m_abBufFixed, a_rThat.m_pbBuf, m_cbBuf); 396 if (m_cbBuf < sizeof(m_abBufFixed)) 397 RT_BZERO(&m_abBufFixed[m_cbBuf], sizeof(m_abBufFixed) - m_cbBuf); 398 } 399 400 ~DumpImageBufferedReader() 401 { 402 if (m_pbBuf != &m_abBufFixed[0]) 403 RTMemTmpFree(m_pbBuf); 404 m_pbBuf = NULL; 405 } 406 407 /** 408 * Reads @a cbToRead bytes at @a uRva into @a pvDst. 409 * 410 * The buffer is entirely zeroed before reading anything, so it's okay to ignore 411 * the status code. 412 */ 413 int readBytes(size_t uRva, void *pvDst, size_t cbToRead) 414 { 415 RT_BZERO(pvDst, cbToRead); 416 417 while (cbToRead) 418 { 419 /* 420 * Is the start of the request overlapping with the buffer? 421 */ 422 if (uRva >= m_uRvaBuf) 423 { 424 size_t const offBuf = uRva - m_uRvaBuf; 425 if (offBuf < m_cbBuf) 426 { 427 size_t const cbThisRead = RT_MIN(m_cbBuf - offBuf, cbToRead); 428 memcpy(pvDst, &m_pbBuf[offBuf], cbThisRead); 429 if (cbToRead <= cbThisRead) 430 return VINF_SUCCESS; 431 uRva += cbThisRead; 432 cbToRead -= cbThisRead; 433 pvDst = (uint8_t *)pvDst + cbThisRead; 434 } 435 } 436 437 /* 438 * Fill buffer. 439 */ 440 int rc = loadBuffer(uRva); 441 if (RT_FAILURE(rc)) 442 return rc; 443 } 444 return VINF_SUCCESS; 445 } 446 447 /** 448 * Ensures @a cbItem at @a uRva is in the buffer and returns a pointer to it. 449 * 450 * The returned pointer is only valid till the next call to the reader instance. 451 * 452 * @returns NULL if failed to load the range into the buffer. 453 * @note Extra buffer space will be allocated if @a cbItem is larger than the 454 * internal buffer. 455 */ 456 uint8_t const *bufferedBytes(size_t uRva, size_t cbItem) 457 { 458 /* Do we need to load the item into the buffer? */ 459 if ( uRva < m_uRvaBuf 460 || uRva + cbItem > m_uRvaBuf + m_cbBuf) 461 { 462 int rc = ensureBufferSpace(cbItem); 463 if (RT_SUCCESS(rc)) 464 rc = loadBuffer(uRva); 465 if (RT_FAILURE(rc)) 466 return NULL; 467 } 468 469 Assert(uRva >= m_uRvaBuf && uRva + cbItem <= m_uRvaBuf + m_cbBuf); 470 return &m_pbBuf[uRva - m_uRvaBuf]; 471 } 472 473 /** 474 * Gets a buffered zero terminated string at @a uRva. 475 * 476 * @note The implied max length is the size of the internal buffer. No extra 477 * space will be allocated if the string doesn't terminate within the 478 * buffer size. 479 */ 480 const char *bufferedString(size_t uRva) 481 { 482 /* Do we need to reload the buffer? */ 483 if ( uRva < m_uRvaBuf 484 || uRva >= m_uRvaBuf + m_cbBuf 485 || ( uRva != m_uRvaBuf 486 && !memchr(&m_pbBuf[uRva - m_uRvaBuf], '\0', m_cbBufAlloc - (uRva - m_uRvaBuf)))) 487 { 488 int rc = loadBuffer(uRva); 489 AssertRCReturn(rc, NULL); 490 } 491 492 /* The RVA is within the buffer now, just check that the string ends 493 before the end of the buffer. */ 494 Assert(uRva >= m_uRvaBuf && uRva < m_uRvaBuf + m_cbBuf); 495 size_t const offString = uRva - m_uRvaBuf; 496 const char * const pszString = (const char *)&m_pbBuf[offString]; 497 AssertReturn(memchr(pszString, '\0', m_cbBufAlloc - offString), NULL); 498 return pszString; 499 } 500 501 /** 502 * Gets a simple integer value, with default in case of failure. 503 */ 504 template<typename IntType> 505 IntType bufferedInt(size_t uRva, IntType Default = 0) 506 { 507 AssertCompile(sizeof(IntType) <= 8); 508 AssertReturn(uRva < uRva + sizeof(IntType), Default); 509 510 /* Do we need to reload the buffer? */ 511 if ( uRva < m_uRvaBuf 512 || uRva + sizeof(IntType) > m_uRvaBuf + m_cbBuf) 513 { 514 int rc = loadBuffer(uRva); 515 AssertRCReturn(rc, Default); 516 } 517 518 /* The RVA is within the buffer now. */ 519 Assert(uRva >= m_uRvaBuf && uRva + sizeof(IntType) <= m_uRvaBuf + m_cbBuf); 520 return *(IntType *)&m_pbBuf[uRva - m_uRvaBuf]; 521 } 522 523 }; 114 524 115 525 … … 193 603 194 604 195 static const char *dbgPeDebugTypeName(uint32_t uType )605 static const char *dbgPeDebugTypeName(uint32_t uType, char *pszTmp, size_t cchTmp) 196 606 { 197 607 switch (uType) … … 215 625 case IMAGE_DEBUG_TYPE_REPRO: return "REPRO"; 216 626 } 217 return "??"; 627 RTStrPrintf(pszTmp, cchTmp, "%#RX32", uType); 628 return pszTmp; 218 629 } 219 630 220 631 221 static int dbgcDumpImagePeDebugDir(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pDataAddr, uint32_t cbData) 222 { 223 uint32_t cEntries = cbData / sizeof(IMAGE_DEBUG_DIRECTORY); 224 for (uint32_t i = 0; i < cEntries; i++) 225 { 632 /** 633 * PE dumper class. 634 */ 635 class DumpImagePe : public DumpImageBase 636 { 637 public: 638 /** Pointer to the file header. */ 639 PCIMAGE_FILE_HEADER m_pFileHdr; 640 /** Pointer to the NT headers. */ 641 union 642 { 643 PCIMAGE_NT_HEADERS32 pNt32; 644 PCIMAGE_NT_HEADERS64 pNt64; 645 void *pv; 646 } u; 647 /** The PE header RVA / file offset. */ 648 uint32_t m_offPeHdr; 649 /** Section table RVA / file offset. */ 650 uint32_t m_offShdrs; 651 /** Pointer to the section headers. */ 652 PCIMAGE_SECTION_HEADER m_paShdrs; 653 /** Number of section headers. */ 654 unsigned m_cShdrs; 655 /** Number of RVA and sizes (data directory entries). */ 656 unsigned cDataDir; 657 /** Pointer to the data directory. */ 658 PCIMAGE_DATA_DIRECTORY paDataDir; 659 660 public: 661 DumpImagePe(PDBGCCMDHLP a_pCmdHlp, PCDBGCCMD a_pCmd, PCDBGCVAR a_pImageBase, 662 const char *a_pszImageBaseAddr, const char *a_pszName, 663 uint32_t a_offPeHdr, PCIMAGE_FILE_HEADER a_pFileHdr, void *a_pvNtHdrs, 664 uint32_t a_offShdrs, unsigned a_cShdrs, PCIMAGE_SECTION_HEADER a_paShdrs) 665 : DumpImageBase(a_pCmdHlp, a_pCmd, a_pImageBase, a_pszImageBaseAddr, a_pszName) 666 , m_pFileHdr(a_pFileHdr) 667 , m_offPeHdr(a_offPeHdr) 668 , m_offShdrs(a_offShdrs) 669 , m_paShdrs(a_paShdrs) 670 , m_cShdrs(a_cShdrs) 671 , cDataDir(0) 672 , paDataDir(NULL) 673 { 674 u.pv = a_pvNtHdrs; 675 if (a_pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) 676 { 677 paDataDir = u.pNt32->OptionalHeader.DataDirectory; 678 cDataDir = u.pNt32->OptionalHeader.NumberOfRvaAndSizes; 679 } 680 else 681 { 682 paDataDir = u.pNt64->OptionalHeader.DataDirectory; 683 cDataDir = u.pNt64->OptionalHeader.NumberOfRvaAndSizes; 684 } 685 } 686 687 virtual size_t rvaToFileOffset(size_t uRva) const RT_OVERRIDE 688 { 689 AssertReturn(m_paShdrs, uRva); 690 AssertReturn(u.pv, uRva); 691 if (uRva < m_paShdrs[0].VirtualAddress) 692 return uRva; 693 unsigned iSh = m_cShdrs; 694 while (iSh-- > 0) 695 { 696 if (uRva >= m_paShdrs[iSh].VirtualAddress) 697 { 698 size_t offSection = uRva - m_paShdrs[iSh].VirtualAddress; 699 if (offSection < m_paShdrs[iSh].SizeOfRawData) 700 return m_paShdrs[iSh].PointerToRawData + offSection; 701 return ~(size_t)0; 702 } 703 } 704 return ~(size_t)0; 705 } 706 707 virtual size_t getEndRva(bool a_fAligned = true) const RT_OVERRIDE 708 { 709 AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage, 710 IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage); 711 if (a_fAligned) 712 { 713 uint32_t const cbAlignment = u.pNt32->OptionalHeader.SectionAlignment; 714 if (RT_IS_POWER_OF_TWO(cbAlignment)) 715 return RT_ALIGN_Z((size_t)u.pNt32->OptionalHeader.SizeOfImage, cbAlignment); 716 } 717 return u.pNt32->OptionalHeader.SizeOfImage; 718 } 719 720 721 /** @name Helpers 722 * @{ 723 */ 724 725 char *timestampToString(uint32_t uTimestamp, char *pszDst, size_t cbDst) RT_NOEXCEPT 726 { 727 /** @todo detect random numbers and skip formatting them. */ 728 RTTIMESPEC TimeSpec; 729 RTTIME Time; 730 RTTimeToStringEx(RTTimeExplode(&Time, RTTimeSpecSetDosSeconds(&TimeSpec, uTimestamp)), 731 pszDst, cbDst, 0 /*cFractionDigits*/); 732 return pszDst; 733 } 734 735 /** @} */ 736 737 /** @name Dumpers 738 * @{ 739 */ 740 741 int dumpPeHdr(void) 742 { 743 char szTmp[64]; 744 myPrintHeader(m_offPeHdr, "PE & File Header - %s", m_pszName); 745 myPrintf("Signature: %#010RX32\n", u.pNt32->Signature); 746 PCIMAGE_FILE_HEADER const pFileHdr = &u.pNt32->FileHeader; 747 myPrintf("Machine: %s (%#06RX16)\n", dbgcPeMachineName(pFileHdr->Machine), pFileHdr->Machine); 748 myPrintf("Number of sections: %#06RX16\n", pFileHdr->NumberOfSections); 749 myPrintf("Timestamp: %#010RX32\n", 750 pFileHdr->TimeDateStamp, timestampToString(pFileHdr->TimeDateStamp, szTmp, sizeof(szTmp))); 751 if (pFileHdr->PointerToSymbolTable || pFileHdr->NumberOfSymbols) 752 myPrintf("Symbol table: %#010RX32 L %#06RX16\n", 753 pFileHdr->PointerToSymbolTable, pFileHdr->NumberOfSymbols); 754 myPrintf("Size of optional header: %#06RX16\n", pFileHdr->SizeOfOptionalHeader); 755 756 myPrintf("Characteristics: %#06RX16", pFileHdr->Characteristics); 757 if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) myPrintf(" RELOCS_STRIPPED"); 758 if (pFileHdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) myPrintf(" EXECUTABLE_IMAGE"); 759 if (pFileHdr->Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED) myPrintf(" LINE_NUMS_STRIPPED"); 760 if (pFileHdr->Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED) myPrintf(" LOCAL_SYMS_STRIPPED"); 761 if (pFileHdr->Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM) myPrintf(" AGGRESIVE_WS_TRIM"); 762 if (pFileHdr->Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) myPrintf(" LARGE_ADDRESS_AWARE"); 763 if (pFileHdr->Characteristics & IMAGE_FILE_16BIT_MACHINE) myPrintf(" 16BIT_MACHINE"); 764 if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_LO) myPrintf(" BYTES_REVERSED_LO"); 765 if (pFileHdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) myPrintf(" 32BIT_MACHINE"); 766 if (pFileHdr->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) myPrintf(" DEBUG_STRIPPED"); 767 if (pFileHdr->Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) myPrintf(" REMOVABLE_RUN_FROM_SWAP"); 768 if (pFileHdr->Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) myPrintf(" NET_RUN_FROM_SWAP"); 769 if (pFileHdr->Characteristics & IMAGE_FILE_SYSTEM) myPrintf(" SYSTEM"); 770 if (pFileHdr->Characteristics & IMAGE_FILE_DLL) myPrintf(" DLL"); 771 if (pFileHdr->Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) myPrintf(" UP_SYSTEM_ONLY"); 772 if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI) myPrintf(" BYTES_REVERSED_HI"); 773 myPrintf("\n"); 774 return VINF_SUCCESS; 775 } 776 777 template<typename OptHdrType, bool const a_f32Bit> 778 int dumpOptHdr(OptHdrType const *pOptHdr, uint32_t uBaseOfData = 0) 779 { 780 myPrintHeader(m_offPeHdr + RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader), "Optional Header"); 781 char szTmp[64]; 782 myPrintf("Optional header magic: %#06RX16\n", pOptHdr->Magic); 783 myPrintf("Linker version: %u.%02u\n", pOptHdr->MajorLinkerVersion, pOptHdr->MinorLinkerVersion); 784 if (a_f32Bit) 785 myPrintf("Image base: %#010RX32\n", pOptHdr->ImageBase); 786 else 787 myPrintf("Image base: %#018RX64\n", pOptHdr->ImageBase); 788 myPrintf("Entrypoint: %s\n", rvaToStringWithAddr(pOptHdr->AddressOfEntryPoint, szTmp, sizeof(szTmp))); 789 myPrintf("Base of code: %s\n", rvaToStringWithAddr(pOptHdr->BaseOfCode, szTmp, sizeof(szTmp))); 790 if (a_f32Bit) 791 myPrintf("Base of data: %s\n", rvaToStringWithAddr(uBaseOfData, szTmp, sizeof(szTmp))); 792 myPrintf("Size of image: %#010RX32\n", pOptHdr->SizeOfImage); 793 myPrintf("Size of headers: %#010RX32\n", pOptHdr->SizeOfHeaders); 794 myPrintf("Size of code: %#010RX32\n", pOptHdr->SizeOfCode); 795 myPrintf("Size of initialized data: %#010RX32\n", pOptHdr->SizeOfInitializedData); 796 myPrintf("Size of uninitialized data: %#010RX32\n", pOptHdr->SizeOfUninitializedData); 797 myPrintf("Section alignment: %#010RX32\n", pOptHdr->SectionAlignment); 798 myPrintf("File alignment: %#010RX32\n", pOptHdr->FileAlignment); 799 myPrintf("Image version: %u.%02u\n", pOptHdr->MajorImageVersion, pOptHdr->MinorImageVersion); 800 myPrintf("Operating system version: %u.%02u\n", pOptHdr->MajorOperatingSystemVersion, pOptHdr->MinorOperatingSystemVersion); 801 myPrintf("Windows version value: %#010RX32\n", pOptHdr->Win32VersionValue); 802 const char *pszSubSys; 803 switch (pOptHdr->Subsystem) 804 { 805 case IMAGE_SUBSYSTEM_UNKNOWN: pszSubSys = "Unknown"; break; 806 case IMAGE_SUBSYSTEM_NATIVE: pszSubSys = "Native"; break; 807 case IMAGE_SUBSYSTEM_WINDOWS_GUI: pszSubSys = "Windows GUI"; break; 808 case IMAGE_SUBSYSTEM_WINDOWS_CUI: pszSubSys = "Windows char"; break; 809 case IMAGE_SUBSYSTEM_OS2_GUI: pszSubSys = "OS/2 GUI"; break; 810 case IMAGE_SUBSYSTEM_OS2_CUI: pszSubSys = "OS/2 char"; break; 811 case IMAGE_SUBSYSTEM_POSIX_CUI: pszSubSys = "POSIX"; break; 812 case IMAGE_SUBSYSTEM_NATIVE_WINDOWS: pszSubSys = "Native Windows 9x"; break; 813 case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: pszSubSys = "Windows CE GUI"; break; 814 case IMAGE_SUBSYSTEM_EFI_APPLICATION: pszSubSys = "EFI Application"; break; 815 case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: pszSubSys = "EFI Boot Service Driver"; break; 816 case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: pszSubSys = "EFI Runtime Driver"; break; 817 case IMAGE_SUBSYSTEM_EFI_ROM: pszSubSys = "EFI ROM"; break; 818 case IMAGE_SUBSYSTEM_XBOX: pszSubSys = "XBox"; break; 819 case IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: pszSubSys = "Windows Boot Application"; break; 820 default: pszSubSys = "dunno"; break; 821 } 822 myPrintf("Subsystem: %s (%#x)\n", pszSubSys, pOptHdr->Subsystem); 823 myPrintf("Subsystem version: %u.%02u\n", pOptHdr->MajorSubsystemVersion, pOptHdr->MinorSubsystemVersion); 824 myPrintf("DLL characteristics: %#06RX16\n", pOptHdr->DllCharacteristics); 825 myPrintf("Loader flags: %#010RX32\n", pOptHdr->LoaderFlags); 826 827 myPrintf("File checksum: %#010RX32\n", pOptHdr->CheckSum); 828 myPrintf("Size of stack reserve: %#010RX64\n", (uint64_t)pOptHdr->SizeOfStackReserve); 829 myPrintf("Size of stack commit: %#010RX64\n", (uint64_t)pOptHdr->SizeOfStackReserve); 830 myPrintf("Size of heap reserve: %#010RX64\n", (uint64_t)pOptHdr->SizeOfHeapReserve); 831 myPrintf("Size of heap commit: %#010RX64\n", (uint64_t)pOptHdr->SizeOfHeapReserve); 832 833 myPrintf("Number of data directories: %#010RX32%s\n", pOptHdr->NumberOfRvaAndSizes, 834 pOptHdr->NumberOfRvaAndSizes <= RT_ELEMENTS(pOptHdr->DataDirectory) ? "" : " - bogus!"); 835 836 for (uint32_t i = 0; i < RT_ELEMENTS(pOptHdr->DataDirectory); i++) 837 if (pOptHdr->DataDirectory[i].Size || pOptHdr->DataDirectory[i].VirtualAddress) 838 { 839 const char * const pszName = dbgcPeDataDirName(i); 840 rvaToStringWithAddr(pOptHdr->DataDirectory[i].VirtualAddress, szTmp, sizeof(szTmp)); 841 if (i == IMAGE_DIRECTORY_ENTRY_SECURITY) 842 { 843 size_t const cchWidth = strlen(szTmp); 844 size_t cch = RTStrPrintf(szTmp, sizeof(szTmp), "%#09RX32 (file off)", 845 pOptHdr->DataDirectory[i].VirtualAddress); 846 while (cch < cchWidth) 847 szTmp[cch++] = ' '; 848 szTmp[cch] = '\0'; 849 } 850 myPrintf("DataDirectory[%#x]: %s LB %#07RX32 %s\n", i, szTmp, pOptHdr->DataDirectory[i].Size, pszName); 851 } 852 return VINF_SUCCESS; 853 } 854 855 int dumpSectionHdrs(void) RT_NOEXCEPT 856 { 857 myPrintHeader(m_offShdrs, "Section Table"); 858 for (unsigned i = 0; i < m_cShdrs; i++) 859 { 860 char szTmp[64]; 861 myPrintf("Section[%02u]: %s LB %08RX32 %.8s\n", 862 i, rvaToStringWithAddr(m_paShdrs[i].VirtualAddress, szTmp, sizeof(szTmp)), 863 m_paShdrs[i].Misc.VirtualSize, m_paShdrs[i].Name); 864 } 865 return VINF_SUCCESS; 866 } 867 868 int dumpExportDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData) 869 { 870 myPrintHeader(uRvaData, "Export Table"); 871 RT_NOREF(cbData); 872 char szTmp[64]; 873 874 /* Use dedicated readers for each array, but saving one by using pBufRdr 875 for function addresses. */ 876 DumpImageBufferedReader NmAddrRdr(*pBufRdr), OrdRdr(*pBufRdr), NameRdr(*pBufRdr); 877 226 878 /* 227 879 * Read the entry into memory. 228 880 */ 229 DBGCVAR DbgDirAddr;230 int rc = DBGCCmdHlpEval(pCmdHlp, &DbgDirAddr, "%DV + %#RX32", pDataAddr, i * sizeof(IMAGE_DEBUG_DIRECTORY));881 IMAGE_EXPORT_DIRECTORY ExpDir; 882 int rc = pBufRdr->readBytes(uRvaData, &ExpDir, sizeof(ExpDir)); 231 883 if (RT_FAILURE(rc)) 232 return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "DBGCCmdHlpEval failed on debug entry %u", i); 233 234 IMAGE_DEBUG_DIRECTORY DbgDir; 235 rc = DBGCCmdHlpMemRead(pCmdHlp, &DbgDir, sizeof(DbgDir), &DbgDirAddr, NULL); 236 if (RT_FAILURE(rc)) 237 return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv", sizeof(DbgDir), &DbgDirAddr); 884 return rc; 238 885 239 886 /* 240 * Dump it.887 * Dump the directory. 241 888 */ 242 DBGCVAR DebugDataAddr = *pThis->pImageBase; 243 rc = DBGCCmdHlpEval(pCmdHlp, &DebugDataAddr, "%DV + %#RX32", pThis->pImageBase, DbgDir.AddressOfRawData); 244 DBGCCmdHlpPrintf(pCmdHlp, " Debug[%u]: %Dv/%08RX32 LB %06RX32 %u (%s) v%u.%u file=%RX32 ts=%08RX32 fl=%RX32\n", 245 i, &DebugDataAddr, DbgDir.AddressOfRawData, DbgDir.SizeOfData, DbgDir.Type, 246 dbgPeDebugTypeName(DbgDir.Type), DbgDir.MajorVersion, DbgDir.MinorVersion, DbgDir.PointerToRawData, 247 DbgDir.TimeDateStamp, DbgDir.Characteristics); 248 union 249 { 250 uint8_t abPage[0x1000]; 251 CVPDB20INFO Pdb20; 252 CVPDB70INFO Pdb70; 253 IMAGE_DEBUG_MISC Misc; 254 } uBuf; 255 RT_ZERO(uBuf); 256 257 if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW) 258 { 259 if ( DbgDir.SizeOfData < sizeof(uBuf) 260 && DbgDir.SizeOfData > 16 261 && DbgDir.AddressOfRawData > 0 262 && RT_SUCCESS(rc)) 889 myPrintf(" Name: %s %s\n", 890 rvaToStringWithAddr(ExpDir.Name, szTmp, sizeof(szTmp)), NmAddrRdr.bufferedString(ExpDir.Name)); 891 myPrintf(" Address table: %s L %u\n", 892 rvaToStringWithAddr(ExpDir.AddressOfFunctions, szTmp, sizeof(szTmp)), ExpDir.NumberOfFunctions); 893 myPrintf(" Name table: %s L %u\n", 894 rvaToStringWithAddr(ExpDir.AddressOfNames, szTmp, sizeof(szTmp)), ExpDir.NumberOfNames); 895 myPrintf(" Name index table: %s L ditto\n", 896 rvaToStringWithAddr(ExpDir.AddressOfNameOrdinals, szTmp, sizeof(szTmp)), ExpDir.NumberOfNames); 897 myPrintf(" Ordinal base: %u\n", ExpDir.Base); 898 if (ExpDir.Characteristics) 899 myPrintf(" Characteristics: %#RX32\n", ExpDir.Characteristics); 900 if (ExpDir.TimeDateStamp && ExpDir.TimeDateStamp != UINT32_MAX) 901 myPrintf(" TimeDateStamp: %#RX32 %s\n", 902 ExpDir.TimeDateStamp, timestampToString(ExpDir.TimeDateStamp, szTmp, sizeof(szTmp))); 903 if (ExpDir.MajorVersion || ExpDir.MinorVersion) 904 myPrintf(" Version: %u.%u\n", ExpDir.MajorVersion, ExpDir.MinorVersion); 905 906 uint32_t const cExports = ExpDir.NumberOfNames; 907 if (cExports > _16K) 908 { 909 myPrintf(" Exports: Too many addresses! (%#x)\n", cExports); 910 return VINF_SUCCESS; 911 } 912 uint32_t const cNames = ExpDir.NumberOfNames; 913 if (cNames > _32K) 914 { 915 myPrintf(" Exports: Too many names! (%#x)\n", cNames); 916 return VINF_SUCCESS; 917 } 918 if (cExports == 0) 919 { 920 myPrintf(" Exports: No exports!\n"); 921 return VINF_SUCCESS; 922 } 923 924 /* 925 * Read the export addresses and name tables into memory. 926 */ 927 uint32_t const *pauExportRvas = (uint32_t const *)pBufRdr->bufferedBytes(ExpDir.AddressOfFunctions, 928 sizeof(pauExportRvas[0])* cExports); 929 uint16_t const *pau16Ordinals = NULL; 930 uint32_t const *pauNameRvas = NULL; 931 bool fOrderedOrdinals = true; 932 if (cNames) 933 { 934 pauNameRvas = (uint32_t const *)NmAddrRdr.bufferedBytes(ExpDir.AddressOfNames, sizeof(pauNameRvas[0]) * cNames); 935 if (!pauNameRvas) 936 return VINF_SUCCESS; 937 pau16Ordinals = (uint16_t const *)OrdRdr.bufferedBytes(ExpDir.AddressOfNameOrdinals, 938 sizeof(pau16Ordinals[0]) * cNames); 939 if (!pau16Ordinals) 940 return VINF_SUCCESS; 941 942 /* Check if the name ordinals are ordered. */ 943 uint16_t iPrev = pau16Ordinals[0]; 944 for (uint32_t iOrd = 1; iOrd < cNames; iOrd++) 263 945 { 264 rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf, DbgDir.SizeOfData, &DebugDataAddr, NULL); 265 if (RT_FAILURE(rc)) 266 return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv", 267 DbgDir.SizeOfData, &DebugDataAddr); 268 269 if ( uBuf.Pdb20.u32Magic == CVPDB20INFO_MAGIC 270 && uBuf.Pdb20.offDbgInfo == 0 271 && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) ) 272 DBGCCmdHlpPrintf(pCmdHlp, " PDB2.0: ts=%08RX32 age=%RX32 %s\n", 273 uBuf.Pdb20.uTimestamp, uBuf.Pdb20.uAge, uBuf.Pdb20.szPdbFilename); 274 else if ( uBuf.Pdb20.u32Magic == CVPDB70INFO_MAGIC 275 && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) ) 276 DBGCCmdHlpPrintf(pCmdHlp, " PDB7.0: %RTuuid age=%u %s\n", 277 &uBuf.Pdb70.PdbUuid, uBuf.Pdb70.uAge, uBuf.Pdb70.szPdbFilename); 946 uint16_t const iCur = pau16Ordinals[iOrd]; 947 if (iCur > iPrev) 948 iPrev = iCur; 278 949 else 279 DBGCCmdHlpPrintf(pCmdHlp, " Unknown PDB/codeview magic: %.8Rhxs\n", uBuf.abPage);280 }281 }282 else if (DbgDir.Type == IMAGE_DEBUG_TYPE_MISC)283 {284 if ( DbgDir.SizeOfData < sizeof(uBuf)285 && DbgDir.SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data)286 && DbgDir.AddressOfRawData > 0287 && RT_SUCCESS(rc) )288 {289 rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf, DbgDir.SizeOfData, &DebugDataAddr, NULL);290 if (RT_FAILURE(rc))291 return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv",292 DbgDir.SizeOfData, &DebugDataAddr);293 294 if ( uBuf.Misc.DataType == IMAGE_DEBUG_MISC_EXENAME295 && uBuf.Misc.Length == DbgDir.SizeOfData)296 950 { 297 if (!uBuf.Misc.Unicode) 298 DBGCCmdHlpPrintf(pCmdHlp, " Misc DBG: ts=%RX32 %s\n", 299 DbgDir.TimeDateStamp, (const char *)&uBuf.Misc.Data[0]); 300 else 301 DBGCCmdHlpPrintf(pCmdHlp, " Misc DBG: ts=%RX32 %ls\n", 302 DbgDir.TimeDateStamp, (PCRTUTF16)&uBuf.Misc.Data[0]); 951 fOrderedOrdinals = false; 952 break; 303 953 } 304 954 } 305 } 306 } 307 return VINF_SUCCESS; 308 } 309 310 311 static int dbgcDumpImagePeDataDirs(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, unsigned cDataDirs, PCIMAGE_DATA_DIRECTORY paDataDirs) 312 { 313 int rcRet = VINF_SUCCESS; 314 for (unsigned i = 0; i < cDataDirs; i++) 315 { 316 if (paDataDirs[i].Size || paDataDirs[i].VirtualAddress) 317 { 318 DBGCVAR DataAddr = *pThis->pImageBase; 319 DBGCCmdHlpEval(pCmdHlp, &DataAddr, "%DV + %#RX32", pThis->pImageBase, paDataDirs[i].VirtualAddress); 320 DBGCCmdHlpPrintf(pCmdHlp, "DataDir[%02u]: %Dv/%08RX32 LB %08RX32 %s\n", 321 i, &DataAddr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size, dbgcPeDataDirName(i)); 322 int rc = VINF_SUCCESS; 323 if ( i == IMAGE_DIRECTORY_ENTRY_DEBUG 324 && paDataDirs[i].Size >= sizeof(IMAGE_DEBUG_DIRECTORY)) 325 rc = dbgcDumpImagePeDebugDir(pThis, pCmdHlp, &DataAddr, paDataDirs[i].Size); 326 if (RT_FAILURE(rc) && RT_SUCCESS(rcRet)) 327 rcRet = rc; 328 } 329 } 330 return rcRet; 331 } 332 333 334 static int dbgcDumpImagePeSectionHdrs(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, unsigned cShdrs, PCIMAGE_SECTION_HEADER paShdrs) 335 { 336 for (unsigned i = 0; i < cShdrs; i++) 337 { 338 DBGCVAR SectAddr = *pThis->pImageBase; 339 DBGCCmdHlpEval(pCmdHlp, &SectAddr, "%DV + %#RX32", pThis->pImageBase, paShdrs[i].VirtualAddress); 340 DBGCCmdHlpPrintf(pCmdHlp, "Section[%02u]: %Dv/%08RX32 LB %08RX32 %.8s\n", 341 i, &SectAddr, paShdrs[i].VirtualAddress, paShdrs[i].Misc.VirtualSize, paShdrs[i].Name); 342 } 343 return VINF_SUCCESS; 344 } 345 346 347 static int dbgcDumpImagePeOptHdr32(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCIMAGE_NT_HEADERS32 pNtHdrs) 348 { 349 RT_NOREF(pThis, pCmdHlp, pNtHdrs); 350 return VINF_SUCCESS; 351 } 352 353 static int dbgcDumpImagePeOptHdr64(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCIMAGE_NT_HEADERS64 pNtHdrs) 354 { 355 RT_NOREF(pThis, pCmdHlp, pNtHdrs); 356 return VINF_SUCCESS; 357 } 358 359 360 static int dbgcDumpImagePe(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, 361 PCDBGCVAR pPeHdrAddr, PCIMAGE_FILE_HEADER pFileHdr) 362 { 363 /* 364 * Dump file header fields. 365 */ 366 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: PE image - %#x (%s), %u sections\n", pImageBase, pFileHdr->Machine, 955 956 } 957 958 /* 959 * Dump the exports by named exports. 960 */ 961 static const char s_szAddr[] = "Export RVA/Address"; 962 unsigned cchAddr = (unsigned)strlen(rvaToStringWithAddr(uRvaData, szTmp, sizeof(szTmp))); 963 cchAddr = RT_MAX(cchAddr, sizeof(s_szAddr) - 1); 964 myPrintf("\n" 965 "Ordinal %*s%s%*s Name RVA Name\n" 966 "------- %*.*s --------- --------------------------------\n", 967 (cchAddr - sizeof(s_szAddr) + 1) / 2, "", s_szAddr, (cchAddr - sizeof(s_szAddr) + 1 + 1) / 2, "", 968 cchAddr, cchAddr, "--------------------------------------"); 969 970 for (uint32_t iExp = 0, iName = 0; iExp < cExports; iExp++) 971 { 972 if (cNames > 0) 973 { 974 if (fOrderedOrdinals) 975 { 976 if (iName < cNames && pau16Ordinals[iName] == iExp) 977 { 978 uint32_t const uRvaName = pauNameRvas[iExp]; 979 const char * const pszName = NameRdr.bufferedString(uRvaName); 980 myPrintf("%7u %s %#09RX32 %s\n", iExp + ExpDir.Base, 981 rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)), 982 uRvaName, pszName ? pszName : ""); 983 iName++; 984 continue; 985 } 986 } 987 else 988 { 989 /* Search the entire name ordinal table, not stopping on a hit 990 as there could in theory be different names for the same entry. */ 991 uint32_t cPrinted = 0; 992 for (iName = 0; iName < cNames; iName++) 993 if (pau16Ordinals[iName] == iExp) 994 { 995 uint32_t const uRvaName = pauNameRvas[iExp]; 996 const char * const pszName = NameRdr.bufferedString(uRvaName); 997 myPrintf("%7u %s %#09RX32 %s\n", iExp + ExpDir.Base, 998 rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)), 999 uRvaName, pszName ? pszName : ""); 1000 cPrinted++; 1001 } 1002 if (cPrinted) 1003 continue; 1004 } 1005 } 1006 /* Ordinal only. */ 1007 myPrintf("%7u %s %#09RX32\n", iExp + ExpDir.Base, 1008 rvaToStringWithAddr(pauExportRvas[iExp], szTmp, sizeof(szTmp)), UINT32_MAX); 1009 } 1010 return VINF_SUCCESS; 1011 } 1012 1013 template<typename ThunkType, bool const a_f32Bit, ThunkType const a_fOrdinalConst> 1014 int dumpImportDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData) 1015 { 1016 char szTmp[64]; 1017 char szTmp2[64]; 1018 size_t const cchRvaWithAddr = strlen(rvaToStringWithAddr(uRvaData, szTmp, sizeof(szTmp))); 1019 1020 /* Use dedicated readers for each array and names */ 1021 DumpImageBufferedReader NameRdr(*pBufRdr), Thunk1stRdr(*pBufRdr), ThunkOrgRdr(*pBufRdr); 1022 1023 myPrintHeader(uRvaData, "Import table"); 1024 int rcRet = VINF_SUCCESS; 1025 uint32_t const cEntries = cbData / sizeof(IMAGE_IMPORT_DESCRIPTOR); 1026 for (uint32_t i = 0; i < cEntries; i += 1, uRvaData += sizeof(IMAGE_IMPORT_DESCRIPTOR)) 1027 { 1028 /* 1029 * Read the entry into memory. 1030 */ 1031 IMAGE_IMPORT_DESCRIPTOR ImpDir; 1032 int rc = pBufRdr->readBytes(uRvaData, &ImpDir, sizeof(ImpDir)); 1033 if (RT_FAILURE(rc)) 1034 return rc; 1035 1036 if (ImpDir.Name == 0) 1037 continue; 1038 1039 /* 1040 * Dump it. 1041 */ 1042 if (i > 0) 1043 myPrintf("\n"); 1044 myPrintf(" Entry #: %u\n", i); 1045 myPrintf(" Name: %s - %s\n", rvaToStringWithAddr(ImpDir.Name, szTmp, sizeof(szTmp)), 1046 ImpDir.Name ? NameRdr.bufferedString(ImpDir.Name) : ""); 1047 if (ImpDir.TimeDateStamp && ImpDir.TimeDateStamp != UINT32_MAX) 1048 myPrintf(" Timestamp: %#010RX32 %s\n", 1049 ImpDir.TimeDateStamp, timestampToString(ImpDir.TimeDateStamp, szTmp, sizeof(szTmp))); 1050 myPrintf(" First thunk: %s\n", rvaToStringWithAddr(ImpDir.FirstThunk, szTmp, sizeof(szTmp))); 1051 myPrintf(" Original thunk: %s\n", rvaToStringWithAddr(ImpDir.u.OriginalFirstThunk, szTmp, sizeof(szTmp))); 1052 if (ImpDir.ForwarderChain) 1053 myPrintf(" Forwarder chain: %s\n", rvaToStringWithAddr(ImpDir.ForwarderChain, szTmp, sizeof(szTmp))); 1054 1055 /* 1056 * Try process the arrays. 1057 */ 1058 static char const s_szDashes[] = "-----------------------------------------------"; 1059 static char const s_szHdr1[] = "Thunk RVA/Addr"; 1060 uint32_t uRvaNames = ImpDir.u.OriginalFirstThunk; 1061 uint32_t uRvaThunk = ImpDir.FirstThunk; 1062 if (uRvaThunk == 0) 1063 uRvaThunk = uRvaNames; 1064 if (uRvaNames != 0 && uRvaNames != uRvaThunk) 1065 { 1066 static char const s_szHdr2[] = "Thunk"; 1067 static char const s_szHdr4[] = "Hint+Name RVA/Addr"; 1068 size_t const cchCol1 = RT_MAX(sizeof(s_szHdr1) - 1, cchRvaWithAddr); 1069 size_t const cchCol2 = RT_MAX(sizeof(s_szHdr2) - 1, 2 + sizeof(ThunkType) * 2); 1070 size_t const cchCol4 = RT_MAX(sizeof(s_szHdr4) - 1, cchRvaWithAddr); 1071 1072 myPrintf(" No. %-*s %-*s Ord/Hint %-*s Name\n" 1073 "---- %.*s %.*s -------- %.*s ----------------\n", 1074 cchCol1, s_szHdr1, cchCol2, s_szHdr2, cchCol4, s_szHdr4, 1075 cchCol1, s_szDashes, cchCol2, s_szDashes, cchCol4, s_szDashes); 1076 for (uint32_t iEntry = 0;; iEntry += 1, uRvaThunk += sizeof(ThunkType), uRvaNames += sizeof(ThunkType)) 1077 { 1078 ThunkType const uName = ThunkOrgRdr.bufferedInt<ThunkType>(uRvaNames, 0); 1079 ThunkType const uThunk = Thunk1stRdr.bufferedInt<ThunkType>(uRvaThunk, 0); 1080 if (!uName || !uThunk) 1081 break; 1082 1083 if (!(uName & a_fOrdinalConst)) 1084 { 1085 uint16_t const uHint = NameRdr.bufferedInt<uint16_t>(uName); 1086 const char * const pszName = NameRdr.bufferedString(uName + 2); 1087 if (a_f32Bit) 1088 myPrintf("%4u: %s %#010RX32 %8RU16 %s %s\n", 1089 iEntry, rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uHint, 1090 rvaToStringWithAddr(uName, szTmp2, sizeof(szTmp2)), pszName); 1091 else 1092 myPrintf("%4u: %s %#018RX64 %8RU16 %s %s\n", 1093 iEntry, rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uHint, 1094 rvaToStringWithAddr(uName, szTmp2, sizeof(szTmp2)), pszName); 1095 } 1096 else 1097 { 1098 if (a_f32Bit) 1099 myPrintf("%4u: %s %#010RX32 %8RU32\n", iEntry, 1100 rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uName & ~a_fOrdinalConst); 1101 else 1102 myPrintf("%4u: %s %#018RX64 %8RU64\n", iEntry, 1103 rvaToStringWithAddr(uRvaThunk, szTmp, sizeof(szTmp)), uThunk, uName & ~a_fOrdinalConst); 1104 } 1105 } 1106 } 1107 /** @todo */ 1108 //else if (uRvaThunk) 1109 // for (;;) 1110 // { 1111 // ThunkType const *pThunk = (ThunkType const *)Thunk1stRdr.bufferedBytes(uRvaThunk, sizeof(*pThunk)); 1112 // if (!pThunk->u1.AddressOfData == 0) 1113 // break; 1114 // } 1115 } 1116 return rcRet; 1117 } 1118 1119 int dumpDebugDir(DumpImageBufferedReader *pBufRdr, uint32_t uRvaData, uint32_t cbData) 1120 { 1121 myPrintHeader(uRvaData, "Debug Directory"); 1122 int rcRet = VINF_SUCCESS; 1123 uint32_t const cEntries = cbData / sizeof(IMAGE_DEBUG_DIRECTORY); 1124 for (uint32_t i = 0; i < cEntries; i += 1, uRvaData += sizeof(IMAGE_DEBUG_DIRECTORY)) 1125 { 1126 /* 1127 * Read the entry into memory. 1128 */ 1129 IMAGE_DEBUG_DIRECTORY DbgDir; 1130 int rc = pBufRdr->readBytes(uRvaData, &DbgDir, sizeof(DbgDir)); 1131 if (RT_FAILURE(rc)) 1132 return rc; 1133 1134 /* 1135 * Dump it. 1136 * (longest type is 13 chars:'OMAP_FROM_SRC') 1137 */ 1138 char szTmp[64]; 1139 char szTmp2[64]; 1140 myPrintf("%u: %s LB %06RX32 %#09RX32 %13s", 1141 i, rvaToStringWithAddr(DbgDir.AddressOfRawData, szTmp, sizeof(szTmp)), DbgDir.SizeOfData, 1142 DbgDir.PointerToRawData, 1143 dbgPeDebugTypeName(DbgDir.Type, szTmp2, sizeof(szTmp2))); 1144 if (DbgDir.MajorVersion || DbgDir.MinorVersion) 1145 myPrintf(" v%u.%u", DbgDir.MajorVersion, DbgDir.MinorVersion); 1146 if (DbgDir.Characteristics) 1147 myPrintf(" flags=%#RX32", DbgDir.Characteristics); 1148 myPrintf(" %s (%#010RX32)\n", timestampToString(DbgDir.TimeDateStamp, szTmp, sizeof(szTmp)), DbgDir.TimeDateStamp); 1149 1150 union 1151 { 1152 uint8_t abPage[0x1000]; 1153 CVPDB20INFO Pdb20; 1154 CVPDB70INFO Pdb70; 1155 IMAGE_DEBUG_MISC Misc; 1156 } uBuf; 1157 RT_ZERO(uBuf); 1158 1159 if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW) 1160 { 1161 if ( DbgDir.SizeOfData < sizeof(uBuf) 1162 && DbgDir.SizeOfData > 16 1163 && DbgDir.AddressOfRawData > 0 1164 && RT_SUCCESS(rc)) 1165 { 1166 rc = pBufRdr->readBytes(DbgDir.AddressOfRawData, &uBuf, DbgDir.SizeOfData); 1167 if (RT_SUCCESS(rc)) 1168 { 1169 if ( uBuf.Pdb20.u32Magic == CVPDB20INFO_MAGIC 1170 && uBuf.Pdb20.offDbgInfo == 0 1171 && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) ) 1172 myPrintf(" PDB2.0: ts=%08RX32 age=%RX32 %s\n", 1173 uBuf.Pdb20.uTimestamp, uBuf.Pdb20.uAge, uBuf.Pdb20.szPdbFilename); 1174 else if ( uBuf.Pdb20.u32Magic == CVPDB70INFO_MAGIC 1175 && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) ) 1176 myPrintf(" PDB7.0: %RTuuid age=%u %s\n", 1177 &uBuf.Pdb70.PdbUuid, uBuf.Pdb70.uAge, uBuf.Pdb70.szPdbFilename); 1178 else 1179 myPrintf(" Unknown PDB/codeview magic: %.8Rhxs\n", uBuf.abPage); 1180 } 1181 else 1182 rcRet = rc; 1183 } 1184 } 1185 else if (DbgDir.Type == IMAGE_DEBUG_TYPE_MISC) 1186 { 1187 if ( DbgDir.SizeOfData < sizeof(uBuf) 1188 && DbgDir.SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data) 1189 && DbgDir.AddressOfRawData > 0) 1190 { 1191 rc = pBufRdr->readBytes(DbgDir.AddressOfRawData, &uBuf, DbgDir.SizeOfData); 1192 if (RT_SUCCESS(rc)) 1193 { 1194 if ( uBuf.Misc.DataType == IMAGE_DEBUG_MISC_EXENAME 1195 && uBuf.Misc.Length == DbgDir.SizeOfData) 1196 { 1197 if (!uBuf.Misc.Unicode) 1198 myPrintf(" Misc DBG: ts=%RX32 %s\n", DbgDir.TimeDateStamp, (const char *)&uBuf.Misc.Data[0]); 1199 else 1200 myPrintf(" Misc DBG: ts=%RX32 %ls\n", DbgDir.TimeDateStamp, (PCRTUTF16)&uBuf.Misc.Data[0]); 1201 } 1202 } 1203 else 1204 rcRet = rc; 1205 } 1206 } 1207 } 1208 return rcRet; 1209 } 1210 1211 int dumpDataDirs(DumpImageBufferedReader *pBufRdr, unsigned cDataDirs, PCIMAGE_DATA_DIRECTORY paDataDirs) 1212 { 1213 int rcRet = VINF_SUCCESS; 1214 for (unsigned i = 0; i < cDataDirs; i++) 1215 if (paDataDirs[i].Size > 0 && paDataDirs[i].VirtualAddress) 1216 { 1217 int rc; 1218 if ( i == IMAGE_DIRECTORY_ENTRY_EXPORT 1219 && paDataDirs[i].Size >= sizeof(IMAGE_EXPORT_DIRECTORY)) 1220 rc = dumpExportDir(pBufRdr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size); 1221 else if ( i == IMAGE_DIRECTORY_ENTRY_IMPORT 1222 && paDataDirs[i].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)) 1223 { 1224 if (m_pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) 1225 rc = dumpImportDir<uint32_t, true, IMAGE_ORDINAL_FLAG32>(pBufRdr, paDataDirs[i].VirtualAddress, 1226 paDataDirs[i].Size); 1227 else 1228 rc = dumpImportDir<uint64_t, false, IMAGE_ORDINAL_FLAG64>(pBufRdr, paDataDirs[i].VirtualAddress, 1229 paDataDirs[i].Size); 1230 } 1231 else if ( i == IMAGE_DIRECTORY_ENTRY_DEBUG 1232 && paDataDirs[i].Size >= sizeof(IMAGE_DEBUG_DIRECTORY)) 1233 rc = dumpDebugDir(pBufRdr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size); 1234 else 1235 continue; 1236 if (RT_FAILURE(rc)) 1237 rcRet = rc; 1238 } 1239 return rcRet; 1240 } 1241 1242 /** @} */ 1243 }; 1244 1245 1246 static int dbgcDumpImagePe(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, const char *pszImageBaseAddr, 1247 const char *pszName, uint32_t offPeHdr, PCIMAGE_FILE_HEADER pFileHdr) 1248 { 1249 DBGCCmdHlpPrintf(pCmdHlp, "%s: PE image - %#x (%s), %u sections\n", pszName, pFileHdr->Machine, 367 1250 dbgcPeMachineName(pFileHdr->Machine), pFileHdr->NumberOfSections); 368 DBGCCmdHlpPrintf(pCmdHlp, "Characteristics: %#06x", pFileHdr->Characteristics); 369 if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) DBGCCmdHlpPrintf(pCmdHlp, " RELOCS_STRIPPED"); 370 if (pFileHdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) DBGCCmdHlpPrintf(pCmdHlp, " EXECUTABLE_IMAGE"); 371 if (pFileHdr->Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED) DBGCCmdHlpPrintf(pCmdHlp, " LINE_NUMS_STRIPPED"); 372 if (pFileHdr->Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED) DBGCCmdHlpPrintf(pCmdHlp, " LOCAL_SYMS_STRIPPED"); 373 if (pFileHdr->Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM) DBGCCmdHlpPrintf(pCmdHlp, " AGGRESIVE_WS_TRIM"); 374 if (pFileHdr->Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) DBGCCmdHlpPrintf(pCmdHlp, " LARGE_ADDRESS_AWARE"); 375 if (pFileHdr->Characteristics & IMAGE_FILE_16BIT_MACHINE) DBGCCmdHlpPrintf(pCmdHlp, " 16BIT_MACHINE"); 376 if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_LO) DBGCCmdHlpPrintf(pCmdHlp, " BYTES_REVERSED_LO"); 377 if (pFileHdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) DBGCCmdHlpPrintf(pCmdHlp, " 32BIT_MACHINE"); 378 if (pFileHdr->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) DBGCCmdHlpPrintf(pCmdHlp, " DEBUG_STRIPPED"); 379 if (pFileHdr->Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) DBGCCmdHlpPrintf(pCmdHlp, " REMOVABLE_RUN_FROM_SWAP"); 380 if (pFileHdr->Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) DBGCCmdHlpPrintf(pCmdHlp, " NET_RUN_FROM_SWAP"); 381 if (pFileHdr->Characteristics & IMAGE_FILE_SYSTEM) DBGCCmdHlpPrintf(pCmdHlp, " SYSTEM"); 382 if (pFileHdr->Characteristics & IMAGE_FILE_DLL) DBGCCmdHlpPrintf(pCmdHlp, " DLL"); 383 if (pFileHdr->Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) DBGCCmdHlpPrintf(pCmdHlp, " UP_SYSTEM_ONLY"); 384 if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI) DBGCCmdHlpPrintf(pCmdHlp, " BYTES_REVERSED_HI"); 385 DBGCCmdHlpPrintf(pCmdHlp, "\n"); 1251 1252 /* Is it a supported optional header size? */ 1253 uint8_t cBits; 1254 if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)) 1255 cBits = 32; 1256 else if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) 1257 cBits = 64; 1258 else 1259 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: Unsupported optional header size: %#x\n", 1260 pszName, pFileHdr->SizeOfOptionalHeader); 386 1261 387 1262 /* 388 1263 * Allocate memory for all the headers, including section headers, and read them into memory. 389 1264 */ 390 size_t offSHdrs = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + sizeof(uint32_t);391 size_t c bHdrs = offSHdrs + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);1265 size_t const offShdrs = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + sizeof(uint32_t); 1266 size_t const cbHdrs = offShdrs + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER); 392 1267 if (cbHdrs > _2M) 393 return DBGCCmdHlpFail(pCmdHlp, pCmd, "% Dv: headers too big: %zu.\n", pImageBase, cbHdrs);1268 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: headers too big: %zu.\n", pszName, cbHdrs); 394 1269 395 1270 void *pvBuf = RTMemTmpAllocZ(cbHdrs); 396 1271 if (!pvBuf) 397 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: failed to allocate %zu bytes.\n", pImageBase, cbHdrs); 398 int rc = DBGCCmdHlpMemRead(pCmdHlp, pvBuf, cbHdrs, pPeHdrAddr, NULL); 1272 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: failed to allocate %zu bytes for headers.\n", pszName, cbHdrs); 1273 1274 int rc = dumpReadAt(pCmdHlp, pCmd, pImageBase, pszName, offPeHdr, pvBuf, cbHdrs, NULL); 399 1275 if (RT_SUCCESS(rc)) 400 1276 { 401 DUMPIMAGEPE This;402 RT_ZERO(This);403 This.pImageBase = pImageBase;404 This.pFileHdr = pFileHdr;405 This.u.pv = pvBuf;406 This.cShdrs = pFileHdr->NumberOfSections;407 This.paShdrs = (PCIMAGE_SECTION_HEADER)((uintptr_t)pvBuf + offSHdrs);408 This.pCmd = pCmd;409 410 if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))411 { 412 This.paDataDir = This.u.pNt32->OptionalHeader.DataDirectory;413 This.cDataDir = This.u.pNt32->OptionalHeader.NumberOfRvaAndSizes;414 rc = dbgcDumpImagePeOptHdr32(&This, pCmdHlp, This.u.pNt32);415 }416 else if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))417 { 418 This.paDataDir = This.u.pNt64->OptionalHeader.DataDirectory;419 This.cDataDir = This.u.pNt64->OptionalHeader.NumberOfRvaAndSizes;420 rc = dbgcDumpImagePeOptHdr64(&This, pCmdHlp, This.u.pNt64);421 }1277 /* Format the image base value from the header if one isn't specified. */ 1278 char szTmp[32]; 1279 if (!pszImageBaseAddr) 1280 { 1281 if (cBits == 32) 1282 RTStrPrintf(szTmp, sizeof(szTmp), "%#010RX32", ((PIMAGE_NT_HEADERS32)pvBuf)->OptionalHeader.ImageBase); 1283 else 1284 RTStrPrintf(szTmp, sizeof(szTmp), "%#018RX64", ((PIMAGE_NT_HEADERS64)pvBuf)->OptionalHeader.ImageBase); 1285 pszImageBaseAddr = szTmp; 1286 } 1287 1288 /* Finally, instantiate dumper now that we've got the section table 1289 loaded, and let it contiue. */ 1290 DumpImagePe This(pCmdHlp, pCmd, pImageBase, pszImageBaseAddr, pszName, 1291 offPeHdr, pFileHdr, pvBuf, 1292 (uint32_t)offShdrs, pFileHdr->NumberOfSections, (PCIMAGE_SECTION_HEADER)((uintptr_t)pvBuf + offShdrs)); 1293 1294 This.dumpPeHdr(); 1295 if (cBits == 32) 1296 rc = This.dumpOptHdr<IMAGE_OPTIONAL_HEADER32, true>(&This.u.pNt32->OptionalHeader, 1297 This.u.pNt32->OptionalHeader.BaseOfData); 422 1298 else 423 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unsupported optional header size: %#x\n", 424 pImageBase, pFileHdr->SizeOfOptionalHeader); 425 426 int rc2 = dbgcDumpImagePeSectionHdrs(&This, pCmdHlp, This.cShdrs, This.paShdrs); 1299 rc = This.dumpOptHdr<IMAGE_OPTIONAL_HEADER64, false>(&This.u.pNt64->OptionalHeader); 1300 1301 int rc2 = This.dumpSectionHdrs(); 427 1302 if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) 428 1303 rc = rc2; 429 1304 430 rc2 = dbgcDumpImagePeDataDirs(&This, pCmdHlp, This.cDataDir, This.paDataDir); 1305 DumpImageBufferedReader BufRdr(&This); 1306 rc2 = This.dumpDataDirs(&BufRdr, This.cDataDir, This.paDataDir); 431 1307 if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) 432 1308 rc = rc2; 433 1309 } 434 else435 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu at %Dv", pImageBase, cbHdrs, pPeHdrAddr);436 1310 RTMemTmpFree(pvBuf); 437 1311 return rc; … … 443 1317 *********************************************************************************************************************************/ 444 1318 445 static int dbgcDumpImageElf(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase )446 { 447 RT_NOREF _PV(pCmd);448 DBGCCmdHlpPrintf(pCmdHlp, "% Dv: ELF image dumping not implemented yet.\n", pImageBase);1319 static int dbgcDumpImageElf(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, const char *pszName) 1320 { 1321 RT_NOREF(pCmd, pImageBase); 1322 DBGCCmdHlpPrintf(pCmdHlp, "%s: ELF image dumping not implemented yet.\n", pszName); 449 1323 return VINF_SUCCESS; 450 1324 } … … 579 1453 580 1454 581 static int dbgcDumpImageMachO(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, mach_header_64_t const *pHdr) 1455 static int dbgcDumpImageMachO(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, const char *pszName, 1456 mach_header_64_t const *pHdr) 582 1457 { 583 1458 #define ENTRY(a_Define) { a_Define, #a_Define } … … 587 1462 * Header: 588 1463 */ 589 DBGCCmdHlpPrintf(pCmdHlp, "% Dv: Mach-O image (%s bit) - %s (%u) - %s (%#x / %#x)\n",590 p ImageBase, pHdr->magic == IMAGE_MACHO64_SIGNATURE ? "64" : "32",1464 DBGCCmdHlpPrintf(pCmdHlp, "%s: Mach-O image (%s bit) - %s (%u) - %s (%#x / %#x)\n", 1465 pszName, pHdr->magic == IMAGE_MACHO64_SIGNATURE ? "64" : "32", 591 1466 dbgcMachoFileType(pHdr->filetype), pHdr->filetype, 592 1467 dbgcMachoCpuType(pHdr->cputype, pHdr->cpusubtype), pHdr->cputype, pHdr->cpusubtype); 593 1468 594 DBGCCmdHlpPrintf(pCmdHlp, "% Dv: Flags: %#x", pImageBase, pHdr->flags);1469 DBGCCmdHlpPrintf(pCmdHlp, "%s: Flags: %#x", pszName, pHdr->flags); 595 1470 static DBGCDUMPFLAGENTRY const s_aHdrFlags[] = 596 1471 { … … 612 1487 DBGCCmdHlpPrintf(pCmdHlp, "\n"); 613 1488 if (pHdr->reserved != 0 && pHdr->magic == IMAGE_MACHO64_SIGNATURE) 614 DBGCCmdHlpPrintf(pCmdHlp, "% Dv: Reserved header field: %#x\n", pImageBase, pHdr->reserved);1489 DBGCCmdHlpPrintf(pCmdHlp, "%s: Reserved header field: %#x\n", pszName, pHdr->reserved); 615 1490 616 1491 /* … … 619 1494 const uint32_t cCmds = pHdr->ncmds; 620 1495 const uint32_t cbCmds = pHdr->sizeofcmds; 621 DBGCCmdHlpPrintf(pCmdHlp, "% Dv: %u load commands covering %#x bytes:\n", pImageBase, cCmds, cbCmds);1496 DBGCCmdHlpPrintf(pCmdHlp, "%s: %u load commands covering %#x bytes:\n", pszName, cCmds, cbCmds); 622 1497 if (cbCmds > _16M) 623 1498 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_OUT_OF_RANGE, 624 "%Dv: Commands too big: %#x bytes, max 16MiB\n", pImageBase, cbCmds); 625 626 /* Calc address of the first command: */ 1499 "%s: Commands too big: %#x bytes, max 16MiB\n", pszName, cbCmds); 1500 1501 1502 /* Read the commands into a temp buffer: */ 627 1503 const uint32_t cbHdr = pHdr->magic == IMAGE_MACHO64_SIGNATURE ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t); 628 DBGCVAR Addr;629 int rc = DBGCCmdHlpEval(pCmdHlp, &Addr, "%DV + %#RX32", pImageBase, cbHdr);630 AssertRCReturn(rc, rc);631 632 /* Read them into a temp buffer: */633 1504 uint8_t *pbCmds = (uint8_t *)RTMemTmpAllocZ(cbCmds); 634 1505 if (!pbCmds) 635 1506 return VERR_NO_TMP_MEMORY; 636 1507 637 rc = DBGCCmdHlpMemRead(pCmdHlp, pbCmds, cbCmds, &Addr, NULL);1508 int rc = dumpReadAt(pCmdHlp, pCmd, pImageBase, pszName, cbHdr, pbCmds, cbCmds, NULL); 638 1509 if (RT_SUCCESS(rc)) 639 1510 { … … 652 1523 { 653 1524 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_OUT_OF_RANGE, 654 "% Dv: Load command #%u (offset %#x + %#x) is out of bounds! cmdsize=%u (%#x) cmd=%u\n",655 p ImageBase, iCmd, offCmd, cbHdr, cbCurCmd, cbCurCmd,1525 "%s: Load command #%u (offset %#x + %#x) is out of bounds! cmdsize=%u (%#x) cmd=%u\n", 1526 pszName, iCmd, offCmd, cbHdr, cbCurCmd, cbCurCmd, 656 1527 offCmd + RT_UOFFSET_AFTER(load_command_t, cmd) <= cbCmds ? pCurCmd->cmd : UINT32_MAX); 657 1528 break; 658 1529 } 659 1530 660 DBGCCmdHlpPrintf(pCmdHlp, "% Dv: Load command #%u (offset %#x + %#x): %s (%u) LB %u\n",661 p ImageBase, iCmd, offCmd, cbHdr, dbgcMachoLoadCommand(pCurCmd->cmd), pCurCmd->cmd, cbCurCmd);1531 DBGCCmdHlpPrintf(pCmdHlp, "%s: Load command #%u (offset %#x + %#x): %s (%u) LB %u\n", 1532 pszName, iCmd, offCmd, cbHdr, dbgcMachoLoadCommand(pCurCmd->cmd), pCurCmd->cmd, cbCurCmd); 662 1533 switch (pCurCmd->cmd) 663 1534 { … … 665 1536 if (cbCurCmd < sizeof(segment_command_64_t)) 666 1537 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_LDRMACHO_BAD_LOAD_COMMAND, 667 "% Dv: LC_SEGMENT64 is too short!\n", pImageBase);1538 "%s: LC_SEGMENT64 is too short!\n", pszName); 668 1539 else 669 1540 { 670 1541 segment_command_64_t const *pSeg = (segment_command_64_t const *)pCurCmd; 671 DBGCCmdHlpPrintf(pCmdHlp, "% Dv: vmaddr: %016RX64 LB %08RX64 prot: %s(%x) maxprot: %s(%x) name: %.16s\n",672 p ImageBase, pSeg->vmaddr, pSeg->vmsize, dbgcMachoProt(pSeg->initprot), pSeg->initprot,1542 DBGCCmdHlpPrintf(pCmdHlp, "%s: vmaddr: %016RX64 LB %08RX64 prot: %s(%x) maxprot: %s(%x) name: %.16s\n", 1543 pszName, pSeg->vmaddr, pSeg->vmsize, dbgcMachoProt(pSeg->initprot), pSeg->initprot, 673 1544 dbgcMachoProt(pSeg->maxprot), pSeg->maxprot, pSeg->segname); 674 DBGCCmdHlpPrintf(pCmdHlp, "% Dv: file: %016RX64 LB %08RX64 sections: %2u flags: %#x",675 p ImageBase, pSeg->fileoff, pSeg->filesize, pSeg->nsects, pSeg->flags);1545 DBGCCmdHlpPrintf(pCmdHlp, "%s: file: %016RX64 LB %08RX64 sections: %2u flags: %#x", 1546 pszName, pSeg->fileoff, pSeg->filesize, pSeg->nsects, pSeg->flags); 676 1547 dbgcDumpImageFlags32(pCmdHlp, pSeg->flags, s_aSegFlags, RT_ELEMENTS(s_aSegFlags)); 677 1548 DBGCCmdHlpPrintf(pCmdHlp, "\n"); … … 679 1550 || pSeg->nsects * sizeof(section_64_t) + sizeof(pSeg) > cbCurCmd) 680 1551 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_LDRMACHO_BAD_LOAD_COMMAND, 681 "% Dv: LC_SEGMENT64 is too short for all the sections!\n", pImageBase);1552 "%s: LC_SEGMENT64 is too short for all the sections!\n", pszName); 682 1553 else 683 1554 { … … 686 1557 { 687 1558 DBGCCmdHlpPrintf(pCmdHlp, 688 "% Dv: Section #%u: %016RX64 LB %08RX64 align: 2**%-2u name: %.16s",689 p ImageBase, iSec, paSec[iSec].addr, paSec[iSec].size, paSec[iSec].align,1559 "%s: Section #%u: %016RX64 LB %08RX64 align: 2**%-2u name: %.16s", 1560 pszName, iSec, paSec[iSec].addr, paSec[iSec].size, paSec[iSec].align, 690 1561 paSec[iSec].sectname); 691 1562 if (strncmp(pSeg->segname, paSec[iSec].segname, sizeof(pSeg->segname))) … … 714 1585 } 715 1586 } 716 else717 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Error reading load commands %Dv LB %#x\n",718 pImageBase, &Addr, cbCmds);719 1587 RTMemTmpFree(pbCmds); 720 1588 return rc; … … 724 1592 725 1593 /** 1594 * Common worker for the dumpimage command and the VBoxDumpImage tool. 1595 */ 1596 static int dumpImageCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, const char *pszImageBaseAddr, 1597 const char *pszName) 1598 { 1599 union 1600 { 1601 uint8_t ab[0x10]; 1602 IMAGE_DOS_HEADER DosHdr; 1603 struct 1604 { 1605 uint32_t u32Magic; 1606 IMAGE_FILE_HEADER FileHdr; 1607 } Nt; 1608 mach_header_64_t MachO64; 1609 } uBuf; 1610 int rc = dumpReadAt(pCmdHlp, pCmd, pImageBase, pszName, 0, &uBuf.DosHdr, sizeof(uBuf.DosHdr), NULL); 1611 if (RT_SUCCESS(rc)) 1612 { 1613 /* 1614 * MZ. 1615 */ 1616 if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE) 1617 { 1618 uint32_t offNewHdr = uBuf.DosHdr.e_lfanew; 1619 if (offNewHdr < _256K && offNewHdr >= 16) 1620 { 1621 /* Look for new header. */ 1622 rc = dumpReadAt(pCmdHlp, pCmd, pImageBase, pszName, offNewHdr, &uBuf.Nt, sizeof(uBuf.Nt), NULL); 1623 if (RT_SUCCESS(rc)) 1624 { 1625 /* PE: */ 1626 if (uBuf.Nt.u32Magic == IMAGE_NT_SIGNATURE) 1627 rc = dbgcDumpImagePe(pCmd, pCmdHlp, pImageBase, pszImageBaseAddr, pszName, offNewHdr, &uBuf.Nt.FileHdr); 1628 else 1629 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: Unknown new header magic: %.8Rhxs\n", pszName, uBuf.ab); 1630 } 1631 } 1632 else 1633 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: MZ header but e_lfanew=%#RX32 is out of bounds (16..256K).\n", 1634 pszName, offNewHdr); 1635 } 1636 /* 1637 * ELF. 1638 */ 1639 else if (uBuf.ab[0] == ELFMAG0 && uBuf.ab[1] == ELFMAG1 && uBuf.ab[2] == ELFMAG2 && uBuf.ab[3] == ELFMAG3) 1640 rc = dbgcDumpImageElf(pCmd, pCmdHlp, pImageBase, pszImageBaseAddr); 1641 /* 1642 * Mach-O. 1643 */ 1644 else if ( uBuf.MachO64.magic == IMAGE_MACHO64_SIGNATURE 1645 || uBuf.MachO64.magic == IMAGE_MACHO32_SIGNATURE ) 1646 rc = dbgcDumpImageMachO(pCmd, pCmdHlp, pImageBase, pszImageBaseAddr, &uBuf.MachO64); 1647 /* 1648 * Dunno. 1649 */ 1650 else 1651 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%s: Unknown magic: %.8Rhxs\n", pszName, uBuf.ab); 1652 } 1653 else 1654 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%s: Failed to read %zu", pszName, sizeof(uBuf.DosHdr)); 1655 return rc; 1656 } 1657 1658 1659 #ifndef DBGC_DUMP_IMAGE_TOOL 1660 1661 /** 726 1662 * @callback_method_impl{FNDBGCCMD, The 'dumpimage' command.} 727 1663 */ … … 731 1667 for (unsigned iArg = 0; iArg < cArgs; iArg++) 732 1668 { 733 union734 {735 uint8_t ab[0x10];736 IMAGE_DOS_HEADER DosHdr;737 struct738 {739 uint32_t u32Magic;740 IMAGE_FILE_HEADER FileHdr;741 } Nt;742 mach_header_64_t MachO64;743 } uBuf;744 1669 DBGCVAR const ImageBase = paArgs[iArg]; 745 int rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf.DosHdr, sizeof(uBuf.DosHdr), &ImageBase, NULL); 746 if (RT_SUCCESS(rc)) 747 { 748 /* 749 * MZ. 750 */ 751 if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE) 752 { 753 uint32_t offNewHdr = uBuf.DosHdr.e_lfanew; 754 if (offNewHdr < _256K && offNewHdr >= 16) 755 { 756 /* Look for new header. */ 757 DBGCVAR NewHdrAddr; 758 rc = DBGCCmdHlpEval(pCmdHlp, &NewHdrAddr, "%DV + %#RX32", &ImageBase, offNewHdr); 759 if (RT_SUCCESS(rc)) 760 { 761 rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf.Nt, sizeof(uBuf.Nt), &NewHdrAddr, NULL); 762 if (RT_SUCCESS(rc)) 763 { 764 /* PE: */ 765 if (uBuf.Nt.u32Magic == IMAGE_NT_SIGNATURE) 766 rc = dbgcDumpImagePe(pCmd, pCmdHlp, &ImageBase, &NewHdrAddr, &uBuf.Nt.FileHdr); 767 else 768 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unknown new header magic: %.8Rhxs\n", 769 &ImageBase, uBuf.ab); 770 } 771 else 772 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu at %Dv", 773 &ImageBase, sizeof(uBuf.Nt), &NewHdrAddr); 774 } 775 else 776 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to calc address of new header", &ImageBase); 777 } 778 else 779 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: MZ header but e_lfanew=%#RX32 is out of bounds (16..256K).\n", 780 &ImageBase, offNewHdr); 781 } 782 /* 783 * ELF. 784 */ 785 else if (uBuf.ab[0] == ELFMAG0 && uBuf.ab[1] == ELFMAG1 && uBuf.ab[2] == ELFMAG2 && uBuf.ab[3] == ELFMAG3) 786 rc = dbgcDumpImageElf(pCmd, pCmdHlp, &ImageBase); 787 /* 788 * Mach-O. 789 */ 790 else if ( uBuf.MachO64.magic == IMAGE_MACHO64_SIGNATURE 791 || uBuf.MachO64.magic == IMAGE_MACHO32_SIGNATURE ) 792 rc = dbgcDumpImageMachO(pCmd, pCmdHlp, &ImageBase, &uBuf.MachO64); 793 /* 794 * Dunno. 795 */ 796 else 797 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unknown magic: %.8Rhxs\n", &ImageBase, uBuf.ab); 798 } 799 else 800 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu", &ImageBase, sizeof(uBuf.DosHdr)); 1670 char szImageBaseAddr[64]; 1671 DBGCCmdHlpStrPrintf(pCmdHlp, szImageBaseAddr, sizeof(szImageBaseAddr), "%Dv", &ImageBase); 1672 int rc = dumpImageCommon(pCmd, pCmdHlp, &ImageBase, szImageBaseAddr, szImageBaseAddr); 801 1673 if (RT_FAILURE(rc) && RT_SUCCESS(rcRet)) 802 1674 rcRet = rc; … … 806 1678 } 807 1679 1680 #else /* DBGC_DUMP_IMAGE_TOOL */ 1681 1682 1683 /** 1684 * @interface_member_impl{DBGCCMDHLP,pfnPrintfV} 1685 */ 1686 static DECLCALLBACK(int) toolPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args) 1687 { 1688 int rc = RTPrintfV(pszFormat, args); 1689 if (rc >= 0) 1690 { 1691 if (pcbWritten) 1692 *pcbWritten = (unsigned)rc; 1693 return VINF_SUCCESS; 1694 } 1695 if (pcbWritten) 1696 *pcbWritten = 0; 1697 RT_NOREF(pCmdHlp); 1698 return VERR_IO_GEN_FAILURE; 1699 } 1700 1701 1702 /** 1703 * @interface_member_impl{DBGCCMDHLP,pfnFailV} 1704 */ 1705 static DECLCALLBACK(int) toolFailV(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, const char *pszFormat, va_list va) 1706 { 1707 CMDHLPSTATE * const pCmdHlpState = RT_FROM_MEMBER(pCmdHlp, CMDHLPSTATE, Core); 1708 pCmdHlpState->rcExit = RTEXITCODE_FAILURE; 1709 RTMsgErrorV(pszFormat, va); 1710 RT_NOREF(pCmd); 1711 return VERR_GENERAL_FAILURE; 1712 } 1713 1714 1715 /** 1716 * @interface_member_impl{DBGCCMDHLP,pfnFailRcV} 1717 */ 1718 static DECLCALLBACK(int) toolFailRcV(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, const char *pszFormat, va_list va) 1719 { 1720 CMDHLPSTATE * const pCmdHlpState = RT_FROM_MEMBER(pCmdHlp, CMDHLPSTATE, Core); 1721 pCmdHlpState->rcExit = RTEXITCODE_FAILURE; 1722 1723 va_list vaCopy; 1724 va_copy(vaCopy, va); 1725 RTMsgError("%N: %Rrc", pszFormat, &vaCopy, rc); 1726 va_end(vaCopy); 1727 1728 RT_NOREF(pCmd); 1729 return rc; 1730 } 1731 1732 1733 int main(int argc, char **argv) 1734 { 1735 int rc = RTR3InitExe(argc, &argv, 0); 1736 if (RT_FAILURE(rc)) 1737 return RTMsgInitFailure(rc); 1738 1739 /* 1740 * Setup image helper code. 1741 */ 1742 CMDHLPSTATE ToolState; 1743 RT_ZERO(ToolState); 1744 ToolState.Core.pfnPrintfV = toolPrintfV; 1745 ToolState.Core.pfnFailV = toolFailV; 1746 ToolState.Core.pfnFailRcV = toolFailRcV; 1747 ToolState.hVfsFile = NIL_RTVFSFILE; 1748 ToolState.rcExit = RTEXITCODE_SUCCESS; 1749 1750 char szImageBaseAddr[32] = {0}; 1751 1752 static const RTGETOPTDEF s_aOptions[] = 1753 { 1754 { "--image-base", 'b', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX }, 1755 }; 1756 1757 RTGETOPTSTATE GetState; 1758 rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 1759 AssertRCReturn(rc, RTEXITCODE_FAILURE); 1760 1761 RTGETOPTUNION ValueUnion; 1762 int chOpt; 1763 while ((chOpt = RTGetOpt(&GetState, &ValueUnion)) != 0) 1764 { 1765 switch (chOpt) 1766 { 1767 case 'b': 1768 if (ValueUnion.u64 >= UINT32_MAX - _16M) 1769 RTStrPrintf(szImageBaseAddr, sizeof(szImageBaseAddr), "%#018RX64", ValueUnion.u64); 1770 else 1771 RTStrPrintf(szImageBaseAddr, sizeof(szImageBaseAddr), "%#010RX64", ValueUnion.u64); 1772 break; 1773 1774 case 'V': 1775 RTPrintf("%s\n", RTBldCfgRevision()); 1776 return RTEXITCODE_SUCCESS; 1777 1778 case 'h': 1779 RTPrintf("usage: %s [options] <file> [file2..]\n", RTProcShortName()); 1780 return RTEXITCODE_SUCCESS; 1781 1782 case VINF_GETOPT_NOT_OPTION: 1783 { 1784 RTERRINFOSTATIC ErrInfo; 1785 uint32_t offError = 0; 1786 rc = RTVfsChainOpenFile(ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, 1787 &ToolState.hVfsFile, &offError, RTErrInfoInitStatic(&ErrInfo)); 1788 if (RT_SUCCESS(rc)) 1789 { 1790 rc = dumpImageCommon(NULL, &ToolState.Core, NULL, szImageBaseAddr[0] ? szImageBaseAddr : NULL, ValueUnion.psz); 1791 if (RT_FAILURE(rc) && ToolState.rcExit == RTEXITCODE_SUCCESS) 1792 ToolState.rcExit = RTEXITCODE_FAILURE; 1793 RTVfsFileRelease(ToolState.hVfsFile); 1794 } 1795 else 1796 ToolState.rcExit = RTVfsChainMsgErrorExitFailure("RTVfsChainOpenFile", ValueUnion.psz, 1797 rc, offError, &ErrInfo.Core); 1798 ToolState.hVfsFile = NIL_RTVFSFILE; 1799 break; 1800 } 1801 1802 default: 1803 return RTGetOptPrintError(chOpt, &ValueUnion); 1804 } 1805 } 1806 1807 return ToolState.rcExit; 1808 1809 } 1810 #endif /* !DBGC_DUMP_IMAGE_TOOL */ 1811
Note:
See TracChangeset
for help on using the changeset viewer.