Changeset 83085 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Feb 15, 2020 9:19:54 PM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 136140
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/DBGFR3ModInMem.cpp
r82968 r83085 29 29 #include <iprt/path.h> 30 30 #include <iprt/string.h> 31 #include <iprt/sort.h> 31 32 #include <iprt/formats/pecoff.h> 32 33 #include <iprt/formats/mz.h> 33 34 #include <iprt/formats/elf.h> 35 #include <iprt/formats/mach-o.h> 34 36 35 37 … … 37 39 * Structures and Typedefs * 38 40 *********************************************************************************************************************************/ 41 /** Entry for mapping file offset to memory location. */ 42 typedef struct DBGFMODINMEMMAPPING 43 { 44 /** The file offset. */ 45 uint32_t offFile; 46 /** The file size of this mapping. */ 47 uint32_t cbFile; 48 /** The size of this mapping. */ 49 uint32_t cbMem; 50 /** The offset to the memory from the start of the image. 51 * @note This can be negative (for mach_kernel). */ 52 int32_t offMem; 53 } DBGFMODINMEMMAPPING; 54 typedef DBGFMODINMEMMAPPING *PDBGFMODINMEMMAPPING; 55 typedef DBGFMODINMEMMAPPING const *PCDBGFMODINMEMMAPPING; 56 57 /** 58 * Common in-memory reader instance data. 59 */ 60 typedef struct DBGFMODINMEMRDR 61 { 62 /** The VM handle (referenced). */ 63 PUVM pUVM; 64 /** The image base. */ 65 DBGFADDRESS ImageAddr; 66 /** The file size, based on the offFile and cbFile of the last mapping. */ 67 uint32_t cbFile; 68 /** Number of entries in the aMappings table. */ 69 uint32_t cMappings; 70 /** Mapping hint. */ 71 uint32_t iHint; 72 /** Mapping file offset to memory offsets, ordered by file offset. */ 73 DBGFMODINMEMMAPPING aMappings[RT_FLEXIBLE_ARRAY_NESTED]; 74 } DBGFMODINMEMRDR; 75 /** Pointer to the common instance data for an in-memory file reader. */ 76 typedef DBGFMODINMEMRDR *PDBGFMODINMEMRDR; 77 39 78 /** 40 79 * The WinNT digger's loader reader instance data. … … 80 119 IMAGE_NT_HEADERS32 Nt32; 81 120 IMAGE_NT_HEADERS64 Nt64; 121 mach_header_64 MachoHdr; 122 DBGFMODINMEMMAPPING aMappings[0x2000 / sizeof(DBGFMODINMEMMAPPING)]; 82 123 } DBGFMODINMEMBUF; 83 124 /** Pointer to stack buffer. */ … … 130 171 131 172 return pszBuf; 173 } 174 175 176 /** 177 * @callback_method_impl{PFNRTLDRRDRMEMREAD} 178 */ 179 static DECLCALLBACK(int) dbgfModInMemCommon_Read(void *pvBuf, size_t cb, size_t off, void *pvUser) 180 { 181 PDBGFMODINMEMRDR pThis = (PDBGFMODINMEMRDR)pvUser; 182 uint32_t offFile = (uint32_t)off; 183 AssertReturn(offFile == off, VERR_INVALID_PARAMETER); 184 185 /* 186 * Set i to a mapping that starts at or before the specified offset. 187 * ASSUMING aMappings are sorted by offFile. 188 */ 189 uint32_t i = pThis->iHint; 190 if (pThis->aMappings[i].offFile > offFile) 191 { 192 i = pThis->cMappings; /** @todo doesn't need to start from the end here... */ 193 while (i-- > 0) 194 if (offFile >= pThis->aMappings[i].offFile) 195 break; 196 pThis->iHint = i; 197 } 198 199 while (cb > 0) 200 { 201 uint32_t offNextMap = i + 1 < pThis->cMappings ? pThis->aMappings[i + 1].offFile 202 : pThis->aMappings[i].offFile + RT_MAX(pThis->aMappings[i].cbFile, pThis->aMappings[i].cbMem); 203 uint32_t offMap = offFile - pThis->aMappings[i].offFile; 204 205 /* Read file bits backed by memory. */ 206 if (offMap < pThis->aMappings[i].cbMem) 207 { 208 uint32_t cbToRead = pThis->aMappings[i].cbMem - offMap; 209 if (cbToRead > cb) 210 cbToRead = (uint32_t)cb; 211 212 DBGFADDRESS Addr = pThis->ImageAddr; 213 DBGFR3AddrAdd(&Addr, pThis->aMappings[i].offMem + offMap); 214 215 int rc = DBGFR3MemRead(pThis->pUVM, 0 /*idCpu*/, &Addr, pvBuf, cbToRead); 216 if (RT_FAILURE(rc)) 217 return rc; 218 219 /* Done? */ 220 if (cbToRead == cb) 221 break; 222 223 offFile += cbToRead; 224 cb -= cbToRead; 225 pvBuf = (char *)pvBuf + cbToRead; 226 } 227 228 /* Mind the gap. */ 229 if (offNextMap > offFile) 230 { 231 uint32_t cbZero = offNextMap - offFile; 232 if (cbZero > cb) 233 { 234 RT_BZERO(pvBuf, cb); 235 break; 236 } 237 238 RT_BZERO(pvBuf, cbZero); 239 offFile += cbZero; 240 cb -= cbZero; 241 pvBuf = (char *)pvBuf + cbZero; 242 } 243 244 pThis->iHint = ++i; 245 } 246 247 return VINF_SUCCESS; 248 } 249 250 251 /** 252 * @callback_method_impl{PFNRTLDRRDRMEMDTOR} 253 */ 254 static DECLCALLBACK(void) dbgfModInMemCommon_Dtor(void *pvUser, size_t cbImage) 255 { 256 PDBGFMODINMEMRDR pThis = (PDBGFMODINMEMRDR)pvUser; 257 RT_NOREF(cbImage); 258 259 VMR3ReleaseUVM(pThis->pUVM); 260 pThis->pUVM = NULL; 261 262 RTMemFree(pThis); 263 } 264 265 266 /** 267 * @callback_method_impl{FNRTSORTCMP} 268 */ 269 static DECLCALLBACK(int) dbgfModInMemCompMappings(void const *pvElement1, void const *pvElement2, void *pvUser) 270 { 271 RT_NOREF(pvUser); 272 PCDBGFMODINMEMMAPPING pElement1 = (PCDBGFMODINMEMMAPPING)pvElement1; 273 PCDBGFMODINMEMMAPPING pElement2 = (PCDBGFMODINMEMMAPPING)pvElement2; 274 if (pElement1->offFile < pElement2->offFile) 275 return -1; 276 if (pElement1->offFile > pElement2->offFile) 277 return 1; 278 if (pElement1->cbFile < pElement2->cbFile) 279 return -1; 280 if (pElement1->cbFile > pElement2->cbFile) 281 return 1; 282 if (pElement1->offMem < pElement2->offMem) 283 return -1; 284 if (pElement1->offMem > pElement2->offMem) 285 return 1; 286 if (pElement1->cbMem < pElement2->cbMem) 287 return -1; 288 if (pElement1->cbMem > pElement2->cbMem) 289 return 1; 290 return 0; 291 } 292 293 294 static int dbgfModInMemCommon_Init(PDBGFMODINMEMRDR pThis, PUVM pUVM, PCDBGFADDRESS pImageAddr,PCDBGFMODINMEMMAPPING paMappings, 295 uint32_t cMappings, const char *pszName, RTLDRARCH enmArch, 296 PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo) 297 { 298 /* 299 * Initialize the reader instance. 300 */ 301 VMR3RetainUVM(pUVM); 302 pThis->pUVM = pUVM; 303 pThis->ImageAddr = *pImageAddr; 304 pThis->cMappings = cMappings; 305 pThis->iHint = 0; 306 memcpy(pThis->aMappings, paMappings, cMappings * sizeof(pThis->aMappings[0])); 307 RTSortShell(pThis->aMappings, cMappings, sizeof(pThis->aMappings[0]), dbgfModInMemCompMappings, NULL); 308 pThis->cbFile = pThis->aMappings[cMappings - 1].offFile + pThis->aMappings[cMappings - 1].cbFile; 309 310 /* 311 * Call the loader to open it. 312 * Note! destructore is always called. 313 */ 314 315 RTLDRMOD hLdrMod; 316 int rc = RTLdrOpenInMemory(pszName, RTLDR_O_FOR_DEBUG, enmArch, pThis->cbFile, 317 dbgfModInMemCommon_Read, dbgfModInMemCommon_Dtor, pThis, 318 &hLdrMod, pErrInfo); 319 if (RT_SUCCESS(rc)) 320 *phLdrMod = hLdrMod; 321 else 322 *phLdrMod = NIL_RTLDRMOD; 323 return rc; 132 324 } 133 325 … … 155 347 RT_NOREF(pUVM, fFlags, pszName, pszFilename, enmArch, cbImage, puBuf, phDbgMod); 156 348 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_INVALID_EXE_SIGNATURE, "Found ELF magic at %RGv", pImageAddr->FlatPtr); 349 } 350 351 352 /** 353 * Handles in-memory Mach-O images. 354 * 355 * @returns VBox status code. 356 * @param pUVM The user mode VM handle. 357 * @param pImageAddr The image address. 358 * @param fFlags Flags, DBGFMODINMEM_F_XXX. 359 * @param pszName The module name, optional. 360 * @param pszFilename The image filename, optional. 361 * @param enmArch The image arch if we force it, pass 362 * RTLDRARCH_WHATEVER if you don't care. 363 * @param cbImage Image size. Pass 0 if not known. 364 * @param puBuf The header buffer. 365 * @param phDbgMod Where to return the resulting debug module on success. 366 * @param pErrInfo Where to return extended error info on failure. 367 */ 368 static int dbgfR3ModInMemMachO(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName, const char *pszFilename, 369 RTLDRARCH enmArch, uint32_t cbImage, PDBGFMODINMEMBUF puBuf, 370 PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo) 371 { 372 RT_NOREF(cbImage, fFlags); 373 374 /* 375 * Match up enmArch. 376 */ 377 if (enmArch == RTLDRARCH_AMD64) 378 { 379 if (puBuf->MachoHdr.magic != IMAGE_MACHO64_SIGNATURE) 380 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Wanted AMD64 but header is not 64-bit"); 381 if (puBuf->MachoHdr.cputype != CPU_TYPE_X86_64) 382 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Wanted AMD64 but cpu type is %#x instead of %#x", 383 puBuf->MachoHdr.cputype, CPU_TYPE_X86_64); 384 } 385 else if (enmArch == RTLDRARCH_X86_32) 386 { 387 if (puBuf->MachoHdr.magic != IMAGE_MACHO32_SIGNATURE) 388 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Wanted X86_32 but header is not 32-bit"); 389 if (puBuf->MachoHdr.cputype != CPU_TYPE_X86) 390 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Wanted X86_32 but cpu type is %#x instead of %#x", 391 puBuf->MachoHdr.cputype, CPU_TYPE_X86); 392 } 393 else if (enmArch != RTLDRARCH_WHATEVER) 394 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Unsupported enmArch value %s (%d)", 395 RTLdrArchName(enmArch), enmArch); 396 397 /* 398 * Guess the module name if not specified and make sure it conforms to DBGC expectations. 399 */ 400 char szNormalized[128]; 401 if (!pszName) 402 { 403 if (pszFilename) 404 pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS /*whatever*/); 405 if (!pszName) 406 { 407 RTStrPrintf(szNormalized, sizeof(szNormalized), "image_%#llx", (uint64_t)pImageAddr->FlatPtr); 408 pszName = szNormalized; 409 } 410 } 411 if (pszName != szNormalized) 412 pszName = dbgfR3ModNormalizeName(pszName, szNormalized, sizeof(szNormalized)); 413 414 /* 415 * Read the load commands into memory, they follow the header. Refuse 416 * if there appear to be too many or too much of these. 417 */ 418 uint32_t const cLoadCmds = puBuf->MachoHdr.ncmds; 419 uint32_t const cbLoadCmds = puBuf->MachoHdr.sizeofcmds; 420 if (cLoadCmds > _8K || cLoadCmds < 2) 421 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRMACHO_BAD_HEADER, 422 "ncmds=%u is out of sensible range (2..8192)", cLoadCmds); 423 if (cbLoadCmds > _2M || cbLoadCmds < sizeof(load_command_t) * 2) 424 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRMACHO_BAD_HEADER, 425 "cbLoadCmds=%#x is out of sensible range (8..2MiB)", cbLoadCmds); 426 427 uint8_t *pbLoadCmds = (uint8_t *)RTMemTmpAllocZ(cbLoadCmds); 428 AssertReturn(pbLoadCmds, VERR_NO_TMP_MEMORY); 429 430 uint32_t const cbHdr = puBuf->MachoHdr.magic == IMAGE_MACHO64_SIGNATURE ? sizeof(mach_header_64) : sizeof(mach_header_32); 431 DBGFADDRESS Addr = *pImageAddr; 432 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrAdd(&Addr, cbHdr), pbLoadCmds, cbLoadCmds); 433 if (RT_SUCCESS(rc)) 434 { 435 /* 436 * Scan it for segments so we can tranlate file offsets to virtual 437 * memory locations. 438 */ 439 RTUUID Uuid = RTUUID_INITIALIZE_NULL; 440 uint32_t cMappings = 0; 441 uint32_t offCmd = 0; 442 for (uint32_t iCmd = 0; iCmd < cLoadCmds; iCmd++) 443 { 444 load_command_t const *pCurCmd = (load_command_t const *)&pbLoadCmds[offCmd]; 445 uint32_t const cbCurCmd = offCmd + sizeof(*pCurCmd) <= cbLoadCmds ? pCurCmd->cmdsize : sizeof(*pCurCmd); 446 if (offCmd + cbCurCmd > cbLoadCmds) 447 rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 448 "Load command #%u @ %#x is out of bounds: size %#x, left %#x", iCmd, offCmd, cbCurCmd, 449 cbLoadCmds - offCmd); 450 else if (pCurCmd->cmd == LC_SEGMENT_64) 451 { 452 segment_command_64 const *pSeg = (segment_command_64 const *)pCurCmd; 453 if (cbCurCmd >= sizeof(*pSeg)) 454 { 455 if (cMappings >= RT_ELEMENTS(puBuf->aMappings)) 456 rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_OUT_OF_RANGE, "Too many segments!"); 457 else 458 { 459 puBuf->aMappings[cMappings].offFile = pSeg->fileoff; 460 puBuf->aMappings[cMappings].cbFile = pSeg->filesize; 461 puBuf->aMappings[cMappings].offMem = pSeg->vmaddr - pImageAddr->FlatPtr; 462 puBuf->aMappings[cMappings].cbMem = pSeg->vmsize; 463 cMappings++; 464 } 465 } 466 else 467 rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 468 "Load command #%u @ %#x is too small for a 64-bit segment: %#x", iCmd, offCmd, cbCurCmd); 469 } 470 else if (pCurCmd->cmd == LC_SEGMENT_32) 471 { 472 segment_command_32 const *pSeg = (segment_command_32 const *)pCurCmd; 473 if (cbCurCmd >= sizeof(*pSeg)) 474 { 475 if (cMappings >= RT_ELEMENTS(puBuf->aMappings)) 476 rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_OUT_OF_RANGE, "Too many segments!"); 477 else 478 { 479 puBuf->aMappings[cMappings].offFile = pSeg->fileoff; 480 puBuf->aMappings[cMappings].cbFile = pSeg->filesize; 481 puBuf->aMappings[cMappings].offMem = pSeg->vmaddr - pImageAddr->FlatPtr; 482 puBuf->aMappings[cMappings].cbMem = pSeg->vmsize; 483 cMappings++; 484 } 485 } 486 else 487 rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRMACHO_BAD_LOAD_COMMAND, 488 "Load command #%u @ %#x is too small for a 32-bit segment: %#x", iCmd, offCmd, cbCurCmd); 489 } 490 else if (pCurCmd->cmd == LC_UUID && cbCurCmd == sizeof(uuid_command_t)) 491 memcpy(&Uuid, ((uuid_command_t const *)pCurCmd)->uuid, sizeof(Uuid)); 492 493 if (RT_SUCCESS(rc)) 494 offCmd += cbCurCmd; 495 else 496 break; 497 } /* for each command */ 498 499 if (RT_SUCCESS(rc)) 500 { 501 /* 502 * Create generic loader module instance (pThis is tied to it 503 * come rain come shine). 504 */ 505 PDBGFMODINMEMRDR pThis = (PDBGFMODINMEMRDR)RTMemAllocZVar(RT_UOFFSETOF_DYN(DBGFMODINMEMRDR, aMappings[cMappings])); 506 if (pThis) 507 { 508 RTLDRMOD hLdrMod; 509 rc = dbgfModInMemCommon_Init(pThis, pUVM, pImageAddr, puBuf->aMappings, cMappings, 510 pszName, enmArch, &hLdrMod, pErrInfo); 511 if (RT_FAILURE(rc)) 512 hLdrMod = NIL_RTLDRMOD; 513 514 RTDBGMOD hMod; 515 rc = RTDbgModCreateFromMachOImage(&hMod, pszFilename ? pszFilename : pszName, pszName, enmArch, 516 &hLdrMod, 0 /*cbImage*/, 0, NULL, &Uuid, DBGFR3AsGetConfig(pUVM), fFlags); 517 if (RT_SUCCESS(rc)) 518 *phDbgMod = hMod; 519 #if 0 /** @todo later */ 520 else if (!(fFlags & DBGFMODINMEM_F_NO_CONTAINER_FALLBACK)) 521 { 522 /* 523 * Fallback is a container module. 524 */ 525 rc = RTDbgModCreate(&hMod, pszName, cbImage, 0); 526 if (RT_SUCCESS(rc)) 527 { 528 rc = RTDbgModSymbolAdd(hMod, "Headers", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL); 529 AssertRC(rc); 530 } 531 } 532 #endif 533 if (hLdrMod != NIL_RTLDRMOD) 534 RTLdrClose(hLdrMod); 535 } 536 else 537 rc = VERR_NO_MEMORY; 538 } 539 } 540 else 541 RTERRINFO_LOG_SET_F(pErrInfo, rc, "Failed to read %#x bytes of load commands", cbLoadCmds); 542 RTMemTmpFree(pbLoadCmds); 543 return rc; 157 544 } 158 545 … … 671 1058 return dbgfR3ModInMemElf(pUVM, pImageAddr, fFlags, pszName, pszFilename, enmArch, cbImage, &uBuf, phDbgMod, pErrInfo); 672 1059 1060 if ( uBuf.MachoHdr.magic == IMAGE_MACHO64_SIGNATURE 1061 || uBuf.MachoHdr.magic == IMAGE_MACHO32_SIGNATURE) 1062 return dbgfR3ModInMemMachO(pUVM, pImageAddr, fFlags, pszName, pszFilename, enmArch, cbImage, &uBuf, phDbgMod, pErrInfo); 1063 673 1064 uint32_t offNewHdrs; 674 1065 if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE)
Note:
See TracChangeset
for help on using the changeset viewer.