VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFR3ModInMem.cpp@ 80191

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

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.0 KB
Line 
1/* $Id: DBGFR3ModInMem.cpp 80191 2019-08-08 00:36:57Z vboxsync $ */
2/** @file
3 * DBGFR3ModInMemPe - In memory PE module 'loader'.
4 */
5
6/*
7 * Copyright (C) 2009-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define VBOX_BUGREF_9217_PART_I
23#define LOG_GROUP LOG_GROUP_DBGF
24#include <VBox/vmm/dbgf.h>
25
26#include <VBox/err.h>
27#include <iprt/ctype.h>
28#include <iprt/ldr.h>
29#include <iprt/mem.h>
30#include <iprt/path.h>
31#include <iprt/string.h>
32#include <iprt/formats/pecoff.h>
33#include <iprt/formats/mz.h>
34#include <iprt/formats/elf.h>
35
36
37/*********************************************************************************************************************************
38* Structures and Typedefs *
39*********************************************************************************************************************************/
40/**
41 * The WinNT digger's loader reader instance data.
42 */
43typedef struct DBGFMODPERDR
44{
45 /** The VM handle (referenced). */
46 PUVM pUVM;
47 /** The image base. */
48 DBGFADDRESS ImageAddr;
49 /** The image size. */
50 uint32_t cbImage;
51 /** The file offset of the SizeOfImage field in the optional header if it
52 * needs patching, otherwise set to UINT32_MAX. */
53 uint32_t offSizeOfImage;
54 /** The correct image size. */
55 uint32_t cbCorrectImageSize;
56 /** Number of entries in the aMappings table. */
57 uint32_t cMappings;
58 /** Mapping hint. */
59 uint32_t iHint;
60 /** Mapping file offset to memory offsets, ordered by file offset. */
61 struct
62 {
63 /** The file offset. */
64 uint32_t offFile;
65 /** The size of this mapping. */
66 uint32_t cbMem;
67 /** The offset to the memory from the start of the image. */
68 uint32_t offMem;
69 } aMappings[1];
70} DBGFMODPERDR;
71/** Pointer a WinNT loader reader instance data. */
72typedef DBGFMODPERDR *PDBGFMODPERDR;
73
74/**
75 * Stack buffer.
76 */
77typedef union DBGFMODINMEMBUF
78{
79 uint8_t ab[0x2000];
80 IMAGE_DOS_HEADER DosHdr;
81 IMAGE_NT_HEADERS32 Nt32;
82 IMAGE_NT_HEADERS64 Nt64;
83} DBGFMODINMEMBUF;
84/** Pointer to stack buffer. */
85typedef DBGFMODINMEMBUF *PDBGFMODINMEMBUF;
86
87
88
89/**
90 * Normalizes a debug module name.
91 *
92 * @returns Normalized debug module name.
93 * @param pszName The name.
94 * @param pszBuf Buffer to use if work is needed.
95 * @param cbBuf Size of buffer.
96 */
97const char *dbgfR3ModNormalizeName(const char *pszName, char *pszBuf, size_t cbBuf)
98{
99 /*
100 * Skip to the filename in case someone gave us a full filename path.
101 */
102 pszName = RTPathFilenameEx(pszName, RTPATH_STR_F_STYLE_DOS);
103
104 /*
105 * Is it okay?
106 */
107 size_t cchName = strlen(pszName);
108 size_t off = 0;
109 for (;; off++)
110 {
111 char ch = pszName[off];
112 if (ch == '\0')
113 return pszName;
114 if (!RT_C_IS_ALNUM(ch) && ch != '_')
115 break;
116 }
117
118 /*
119 * It's no okay, so morph it.
120 */
121 if (cchName >= cbBuf)
122 cchName = cbBuf - 1;
123 for (off = 0; off < cchName; off++)
124 {
125 char ch = pszName[off];
126 if (!RT_C_IS_ALNUM(ch))
127 ch = '_';
128 pszBuf[off] = ch;
129 }
130 pszBuf[off] = '\0';
131
132 return pszBuf;
133}
134
135
136/**
137 * Handles in-memory ELF images.
138 *
139 * @returns VBox status code.
140 * @param pUVM The user mode VM handle.
141 * @param pImageAddr The image address.
142 * @param fFlags Flags, DBGFMODINMEM_F_XXX.
143 * @param pszName The module name, optional.
144 * @param pszFilename The image filename, optional.
145 * @param enmArch The image arch if we force it, pass
146 * RTLDRARCH_WHATEVER if you don't care.
147 * @param cbImage Image size. Pass 0 if not known.
148 * @param puBuf The header buffer.
149 * @param phDbgMod Where to return the resulting debug module on success.
150 * @param pErrInfo Where to return extended error info on failure.
151 */
152static int dbgfR3ModInMemElf(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName, const char *pszFilename,
153 RTLDRARCH enmArch, uint32_t cbImage, PDBGFMODINMEMBUF puBuf,
154 PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo)
155{
156 RT_NOREF(pUVM, fFlags, pszName, pszFilename, enmArch, cbImage, puBuf, phDbgMod);
157 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_INVALID_EXE_SIGNATURE, "Found ELF magic at %RGv", pImageAddr->FlatPtr);
158}
159
160
161/**
162 * @callback_method_impl{PFNRTLDRRDRMEMREAD}
163 */
164static DECLCALLBACK(int) dbgfModInMemPeRdr_Read(void *pvBuf, size_t cb, size_t off, void *pvUser)
165{
166 PDBGFMODPERDR pThis = (PDBGFMODPERDR)pvUser;
167 uint32_t offFile = (uint32_t)off;
168 AssertReturn(offFile == off, VERR_INVALID_PARAMETER);
169
170 uint32_t i = pThis->iHint;
171 if (pThis->aMappings[i].offFile > offFile)
172 {
173 i = pThis->cMappings;
174 while (i-- > 0)
175 if (offFile >= pThis->aMappings[i].offFile)
176 break;
177 pThis->iHint = i;
178 }
179
180 while (cb > 0)
181 {
182 uint32_t offNextMap = i + 1 < pThis->cMappings ? pThis->aMappings[i + 1].offFile : pThis->cbImage;
183 uint32_t offMap = offFile - pThis->aMappings[i].offFile;
184
185 /* Read file bits backed by memory. */
186 if (offMap < pThis->aMappings[i].cbMem)
187 {
188 uint32_t cbToRead = pThis->aMappings[i].cbMem - offMap;
189 if (cbToRead > cb)
190 cbToRead = (uint32_t)cb;
191
192 DBGFADDRESS Addr = pThis->ImageAddr;
193 DBGFR3AddrAdd(&Addr, pThis->aMappings[i].offMem + offMap);
194
195 int rc = DBGFR3MemRead(pThis->pUVM, 0 /*idCpu*/, &Addr, pvBuf, cbToRead);
196 if (RT_FAILURE(rc))
197 return rc;
198
199 /* Apply SizeOfImage patch? */
200 if ( pThis->offSizeOfImage != UINT32_MAX
201 && offFile < pThis->offSizeOfImage + 4
202 && offFile + cbToRead > pThis->offSizeOfImage)
203 {
204 uint32_t SizeOfImage = pThis->cbCorrectImageSize;
205 uint32_t cbPatch = sizeof(SizeOfImage);
206 int32_t offPatch = pThis->offSizeOfImage - offFile;
207 uint8_t *pbPatch = (uint8_t *)pvBuf + offPatch;
208 if (offFile + cbToRead < pThis->offSizeOfImage + cbPatch)
209 cbPatch = offFile + cbToRead - pThis->offSizeOfImage;
210 while (cbPatch-- > 0)
211 {
212 if (offPatch >= 0)
213 *pbPatch = (uint8_t)SizeOfImage;
214 offPatch++;
215 pbPatch++;
216 SizeOfImage >>= 8;
217 }
218 }
219
220 /* Done? */
221 if (cbToRead == cb)
222 break;
223
224 offFile += cbToRead;
225 cb -= cbToRead;
226 pvBuf = (char *)pvBuf + cbToRead;
227 }
228
229 /* Mind the gap. */
230 if (offNextMap > offFile)
231 {
232 uint32_t cbZero = offNextMap - offFile;
233 if (cbZero > cb)
234 {
235 RT_BZERO(pvBuf, cb);
236 break;
237 }
238
239 RT_BZERO(pvBuf, cbZero);
240 offFile += cbZero;
241 cb -= cbZero;
242 pvBuf = (char *)pvBuf + cbZero;
243 }
244
245 pThis->iHint = ++i;
246 }
247
248 return VINF_SUCCESS;
249}
250
251
252/**
253 * @callback_method_impl{PFNRTLDRRDRMEMDTOR}
254 */
255static DECLCALLBACK(void) dbgfModInMemPeRdr_Dtor(void *pvUser, size_t cbImage)
256{
257 PDBGFMODPERDR pThis = (PDBGFMODPERDR)pvUser;
258 RT_NOREF(cbImage);
259
260 VMR3ReleaseUVM(pThis->pUVM);
261 pThis->pUVM = NULL;
262 RTMemFree(pvUser);
263}
264
265
266/**
267 * Checks if the section headers look okay.
268 *
269 * @returns VBox status code.
270 * @param paShdrs Pointer to the section headers.
271 * @param cShdrs Number of headers.
272 * @param cbImage The image size reported by NT.
273 * @param cbImageFromHdr The image size by the linker in the header.
274 * @param uRvaRsrc The RVA of the resource directory. UINT32_MAX if
275 * no resource directory.
276 * @param cbSectAlign The section alignment specified in the header.
277 * @param fNt31 Set if NT 3.1. Needed for chopped off HAL.
278 * @param pcbImageCorrect The corrected image size. This is derived from
279 * cbImage and virtual range of the section tables.
280 *
281 * The problem is that NT may choose to drop the
282 * last pages in images it loads early, starting at
283 * the resource directory. These images will have
284 * a page aligned cbImage.
285 *
286 * @param pErrInfo Where to return more error details.
287 */
288static int dbgfR3ModPeCheckSectHdrsAndImgSize(PCIMAGE_SECTION_HEADER paShdrs, uint32_t cShdrs, uint32_t cbImage,
289 uint32_t cbImageFromHdr, uint32_t uRvaRsrc, uint32_t cbSectAlign,
290 bool fNt31, uint32_t *pcbImageCorrect, PRTERRINFO pErrInfo)
291{
292 *pcbImageCorrect = cbImage;
293
294 for (uint32_t i = 0; i < cShdrs; i++)
295 {
296 if (!paShdrs[i].Name[0])
297 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Section header #%u has no name", i);
298
299 if (paShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
300 continue;
301
302 /* Tweak to determine the virtual size if the linker didn't set it (NT 3.1). */
303 /** @todo this isn't really perfect. cbImage is kind of wrong... */
304 uint32_t cbVirtual = paShdrs[i].Misc.VirtualSize;
305 if (cbVirtual == 0)
306 {
307 for (uint32_t j = i + 1; j < cShdrs; j++)
308 if ( !(paShdrs[j].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
309 && paShdrs[j].VirtualAddress > paShdrs[i].VirtualAddress)
310 {
311 cbVirtual = paShdrs[j].VirtualAddress - paShdrs[i].VirtualAddress;
312 break;
313 }
314 if (!cbVirtual)
315 {
316 if (paShdrs[i].VirtualAddress < cbImageFromHdr)
317 cbVirtual = cbImageFromHdr - paShdrs[i].VirtualAddress;
318 else if (paShdrs[i].SizeOfRawData > 0)
319 cbVirtual = RT_ALIGN(paShdrs[i].SizeOfRawData, _4K);
320 }
321 }
322
323 /* Check that sizes are within the same range and that both sizes and
324 addresses are within reasonable limits. */
325 if ( RT_ALIGN(cbVirtual, _64K) < RT_ALIGN(paShdrs[i].SizeOfRawData, _64K)
326 || cbVirtual >= _1G
327 || paShdrs[i].SizeOfRawData >= _1G)
328 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
329 "Section header #%u (%.8s) has a VirtualSize=%#x (%#x) and SizeOfRawData=%#x, that's too much data!",
330 i, paShdrs[i].Name, cbVirtual, paShdrs[i].Misc.VirtualSize, paShdrs[i].SizeOfRawData);
331 uint32_t uRvaEnd = paShdrs[i].VirtualAddress + cbVirtual;
332 if (uRvaEnd >= _1G || uRvaEnd < paShdrs[i].VirtualAddress)
333 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
334 "Section header #%u (%.8s) has a VirtualSize=%#x (%#x) and VirtualAddr=%#x, %#x in total, that's too much!",
335 i, paShdrs[i].Name, cbVirtual, paShdrs[i].Misc.VirtualSize, paShdrs[i].VirtualAddress, uRvaEnd);
336
337 /* Check for images chopped off around '.rsrc'. */
338 if ( cbImage < uRvaEnd
339 && uRvaEnd >= uRvaRsrc)
340 cbImage = RT_ALIGN(uRvaEnd, cbSectAlign);
341
342 /* Check that the section is within the image. */
343 if (uRvaEnd > cbImage && fNt31)
344 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
345 "Section header #%u has a virtual address range beyond the image: %#x TO %#x cbImage=%#x",
346 i, paShdrs[i].VirtualAddress, uRvaEnd, cbImage);
347 }
348
349 Assert(*pcbImageCorrect == cbImage || !(*pcbImageCorrect & 0xfff));
350 *pcbImageCorrect = cbImage;
351 return VINF_SUCCESS;
352}
353
354
355/**
356 * Create a loader module for the in-guest-memory PE module.
357 */
358static int dbgfR3ModInMemPeCreateLdrMod(PUVM pUVM, uint32_t fFlags, const char *pszName, PCDBGFADDRESS pImageAddr,
359 uint32_t cbImage, uint32_t cbImageFromHdr, bool f32Bit,
360 uint32_t cShdrs, PCIMAGE_SECTION_HEADER paShdrs, uint32_t cbSectAlign,
361 uint32_t cDataDir, PCIMAGE_DATA_DIRECTORY paDataDir, uint32_t offHdrs,
362 PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
363{
364 /*
365 * Allocate and create a reader instance.
366 */
367 PDBGFMODPERDR pRdr = (PDBGFMODPERDR)RTMemAlloc(RT_UOFFSETOF_DYN(DBGFMODPERDR, aMappings[cShdrs + 2]));
368 if (!pRdr)
369 return VERR_NO_MEMORY;
370
371 VMR3RetainUVM(pUVM);
372 pRdr->pUVM = pUVM;
373 pRdr->ImageAddr = *pImageAddr;
374 pRdr->cbImage = cbImage;
375 pRdr->cbCorrectImageSize = cbImage;
376 pRdr->offSizeOfImage = UINT32_MAX;
377 pRdr->iHint = 0;
378
379 /*
380 * Use the section table to construct a more accurate view of the file/image.
381 */
382 uint32_t uRvaRsrc = UINT32_MAX;
383 if ( cDataDir > IMAGE_DIRECTORY_ENTRY_RESOURCE
384 && paDataDir[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > 0)
385 uRvaRsrc = paDataDir[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
386
387 int rc = dbgfR3ModPeCheckSectHdrsAndImgSize(paShdrs, cShdrs, cbImage, cbImageFromHdr, uRvaRsrc, cbSectAlign,
388 RT_BOOL(fFlags & DBGFMODINMEM_F_PE_NT31), &pRdr->cbCorrectImageSize, pErrInfo);
389 if (RT_SUCCESS(rc))
390 {
391 pRdr->cMappings = 0;
392
393 for (uint32_t i = 0; i < cShdrs; i++)
394 if ( paShdrs[i].SizeOfRawData > 0
395 && paShdrs[i].PointerToRawData > 0)
396 {
397 uint32_t j = 1;
398 if (!pRdr->cMappings)
399 pRdr->cMappings++;
400 else
401 {
402 while (j < pRdr->cMappings && pRdr->aMappings[j].offFile < paShdrs[i].PointerToRawData)
403 j++;
404 if (j < pRdr->cMappings)
405 memmove(&pRdr->aMappings[j + 1], &pRdr->aMappings[j], (pRdr->cMappings - j) * sizeof(pRdr->aMappings));
406 }
407 pRdr->aMappings[j].offFile = paShdrs[i].PointerToRawData;
408 pRdr->aMappings[j].offMem = paShdrs[i].VirtualAddress;
409 pRdr->aMappings[j].cbMem = i + 1 < cShdrs
410 ? paShdrs[i + 1].VirtualAddress - paShdrs[i].VirtualAddress
411 : paShdrs[i].Misc.VirtualSize;
412 if (j == pRdr->cMappings)
413 pRdr->cbImage = paShdrs[i].PointerToRawData + paShdrs[i].SizeOfRawData;
414 pRdr->cMappings++;
415 }
416
417 /* Insert the mapping of the headers that isn't covered by the section table. */
418 pRdr->aMappings[0].offFile = 0;
419 pRdr->aMappings[0].offMem = 0;
420 pRdr->aMappings[0].cbMem = pRdr->cMappings ? pRdr->aMappings[1].offFile : pRdr->cbImage;
421
422 int j = pRdr->cMappings - 1;
423 while (j-- > 0)
424 {
425 uint32_t cbFile = pRdr->aMappings[j + 1].offFile - pRdr->aMappings[j].offFile;
426 if (pRdr->aMappings[j].cbMem > cbFile)
427 pRdr->aMappings[j].cbMem = cbFile;
428 }
429 }
430 else if (fFlags & DBGFMODINMEM_F_NO_READER_FALLBACK)
431 return rc;
432 else
433 {
434 /*
435 * Fallback, fake identity mapped file data.
436 */
437 pRdr->cMappings = 1;
438 pRdr->aMappings[0].offFile = 0;
439 pRdr->aMappings[0].offMem = 0;
440 pRdr->aMappings[0].cbMem = pRdr->cbImage;
441 }
442
443 /* Enable the SizeOfImage patching if necessary. */
444 if (pRdr->cbCorrectImageSize != cbImage)
445 {
446 Log(("dbgfR3ModInMemPeCreateLdrMod: The image is really %#x bytes long, not %#x as mapped by NT!\n",
447 pRdr->cbCorrectImageSize, cbImage));
448 pRdr->offSizeOfImage = f32Bit
449 ? offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage)
450 : offHdrs + RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage);
451 }
452
453 /*
454 * Call the loader to open the PE image for debugging.
455 * Note! It always calls pfnDtor.
456 */
457 RTLDRMOD hLdrMod;
458 rc = RTLdrOpenInMemory(pszName, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER, pRdr->cbImage,
459 dbgfModInMemPeRdr_Read, dbgfModInMemPeRdr_Dtor, pRdr,
460 &hLdrMod, pErrInfo);
461 if (RT_SUCCESS(rc))
462 *phLdrMod = hLdrMod;
463 else
464 *phLdrMod = NIL_RTLDRMOD;
465 return rc;
466}
467
468
469/**
470 * Handles in-memory PE images.
471 *
472 * @returns VBox status code.
473 * @param pUVM The user mode VM handle.
474 * @param pImageAddr The image address.
475 * @param fFlags Flags, DBGFMODINMEM_F_XXX.
476 * @param pszName The module name, optional.
477 * @param pszFilename The image filename, optional.
478 * @param enmArch The image arch if we force it, pass
479 * RTLDRARCH_WHATEVER if you don't care.
480 * @param cbImage Image size. Pass 0 if not known.
481 * @param offPeHdrs Offset of the PE header.
482 * @param cbPeHdrsPart1 How read into uBuf at @a offPeHdrs.
483 * @param puBuf The header buffer.
484 * @param phDbgMod Where to return the resulting debug module on success.
485 * @param pErrInfo Where to return extended error info on failure.
486 */
487static int dbgfR3ModInMemPe(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName, const char *pszFilename,
488 RTLDRARCH enmArch, uint32_t cbImage, uint32_t offPeHdrs, uint32_t cbPeHdrsPart1,
489 PDBGFMODINMEMBUF puBuf, PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo)
490{
491 /*
492 * Read the optional header and the section table after validating the
493 * info we need from the file header.
494 */
495 /* Check the opt hdr size and number of sections as these are used to determine how much to read next. */
496 if ( puBuf->Nt32.FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER32)
497 || puBuf->Nt32.FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER64) + 128)
498 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Invalid SizeOfOptionalHeader value: %#RX32",
499 puBuf->Nt32.FileHeader.SizeOfOptionalHeader);
500
501 if ( puBuf->Nt32.FileHeader.NumberOfSections < 1
502 || puBuf->Nt32.FileHeader.NumberOfSections > 190 /* what fits in our 8K buffer */)
503 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "NumberOfSections is out of range: %#RX32 (1..190)",
504 puBuf->Nt32.FileHeader.NumberOfSections);
505
506 /* Read the optional header and section table. */
507 uint32_t const cbHdrs = RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader)
508 + puBuf->Nt32.FileHeader.SizeOfOptionalHeader
509 + puBuf->Nt32.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
510 AssertReturn(cbHdrs <= sizeof(*puBuf), RTERRINFO_LOG_SET_F(pErrInfo, VERR_INTERNAL_ERROR_2, "cbHdrs=%#x", cbHdrs));
511
512 DBGFADDRESS PeHdrPart2Addr = *pImageAddr;
513 DBGFR3AddrAdd(&PeHdrPart2Addr, offPeHdrs + cbPeHdrsPart1);
514 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &PeHdrPart2Addr, &puBuf->ab[cbPeHdrsPart1], cbHdrs - cbPeHdrsPart1);
515 if (RT_FAILURE(rc))
516 return RTERRINFO_LOG_SET_F(pErrInfo, rc,
517 "Failed to read the second part of the PE headers at %RGv (off=%#RX32 + %#RX32): %Rrc",
518 PeHdrPart2Addr.FlatPtr, offPeHdrs, cbPeHdrsPart1, rc);
519
520 /*
521 * Check the image architecture and determine the bitness.
522 */
523 RTLDRARCH enmArchActual;
524 bool f32Bit;
525 switch (puBuf->Nt32.FileHeader.Machine)
526 {
527 case IMAGE_FILE_MACHINE_I386:
528 enmArchActual = RTLDRARCH_X86_32;
529 f32Bit = true;
530 break;
531 case IMAGE_FILE_MACHINE_AMD64:
532 enmArchActual = RTLDRARCH_AMD64;
533 f32Bit = false;
534 break;
535 case IMAGE_FILE_MACHINE_ARM:
536 case IMAGE_FILE_MACHINE_THUMB:
537 case IMAGE_FILE_MACHINE_ARMNT:
538 enmArchActual = RTLDRARCH_ARM32;
539 f32Bit = true;
540 break;
541 case IMAGE_FILE_MACHINE_ARM64:
542 enmArchActual = RTLDRARCH_ARM64;
543 f32Bit = false;
544 break;
545 default:
546 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Unknown machine: %#x", puBuf->Nt32.FileHeader.Machine);
547 }
548 if ( enmArch != RTLDRARCH_WHATEVER
549 && enmArch != enmArchActual)
550 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Found %s expected %s",
551 RTLdrArchName(enmArchActual), RTLdrArchName(enmArch));
552
553 /*
554 * Check optional header magic and size.
555 */
556 uint16_t const uOptMagic = f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
557 if (puBuf->Nt32.OptionalHeader.Magic != uOptMagic)
558 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Unexpected optional header magic: %#x (expected %#x)",
559 puBuf->Nt32.OptionalHeader.Magic, uOptMagic);
560
561 uint32_t const cDataDir = f32Bit ? puBuf->Nt32.OptionalHeader.NumberOfRvaAndSizes : puBuf->Nt64.OptionalHeader.NumberOfRvaAndSizes;
562 if ( cDataDir <= IMAGE_DIRECTORY_ENTRY_BASERELOC /* a bit random */
563 || cDataDir > 32 /* also random */)
564 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Unexpected data directory size: %#x", cDataDir);
565
566 uint32_t cbOptHdr = f32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64);
567 cbOptHdr -= sizeof(IMAGE_DATA_DIRECTORY) * IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
568 cbOptHdr += sizeof(IMAGE_DATA_DIRECTORY) * cDataDir;
569 if (puBuf->Nt32.FileHeader.SizeOfOptionalHeader != cbOptHdr)
570 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "Unexpected optional header size: %#x (expected %#x)",
571 puBuf->Nt32.FileHeader.SizeOfOptionalHeader, cbOptHdr);
572
573 uint32_t const cbSectAlign = f32Bit ? puBuf->Nt32.OptionalHeader.SectionAlignment : puBuf->Nt64.OptionalHeader.SectionAlignment;
574 PCIMAGE_SECTION_HEADER pSHdrs = (PCIMAGE_SECTION_HEADER)((uintptr_t)&puBuf->Nt32.OptionalHeader + cbOptHdr);
575 PCIMAGE_DATA_DIRECTORY paDataDir = (PCIMAGE_DATA_DIRECTORY)((uintptr_t)pSHdrs - cDataDir * sizeof(IMAGE_DATA_DIRECTORY));
576
577 /*
578 * Establish the image size.
579 */
580 uint32_t cbImageFromHdr = f32Bit ? puBuf->Nt32.OptionalHeader.SizeOfImage : puBuf->Nt64.OptionalHeader.SizeOfImage;
581 if ( !cbImage
582 || (fFlags & DBGFMODINMEM_F_PE_NT31))
583 cbImage = RT_ALIGN(cbImageFromHdr, _4K);
584 else if (RT_ALIGN(cbImageFromHdr, _4K) != RT_ALIGN(cbImage, _4K))
585 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_MISMATCH, "Image size mismatch: input=%#x header=%#x", cbImage, cbImageFromHdr);
586
587 /*
588 * Guess the module name if not specified and make sure it conforms to DBGC expectations.
589 */
590 if (!pszName)
591 {
592 if (pszFilename)
593 pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
594 /** @todo */
595 }
596
597 char szNormalized[128];
598 pszName = dbgfR3ModNormalizeName(pszName, szNormalized, sizeof(szNormalized));
599
600 /*
601 * Create the module using the in memory image first, falling back on cached image.
602 */
603 RTLDRMOD hLdrMod;
604 rc = dbgfR3ModInMemPeCreateLdrMod(pUVM, fFlags, pszName, pImageAddr, cbImage, cbImageFromHdr, f32Bit,
605 puBuf->Nt32.FileHeader.NumberOfSections, pSHdrs, cbSectAlign, cDataDir, paDataDir,
606 offPeHdrs, &hLdrMod, pErrInfo);
607 if (RT_FAILURE(rc))
608 hLdrMod = NIL_RTLDRMOD;
609
610 RTDBGMOD hMod;
611 rc = RTDbgModCreateFromPeImage(&hMod, pszFilename, pszName, &hLdrMod, cbImageFromHdr,
612 puBuf->Nt32.FileHeader.TimeDateStamp, DBGFR3AsGetConfig(pUVM));
613 if (RT_SUCCESS(rc))
614 *phDbgMod = hMod;
615 else if (!(fFlags & DBGFMODINMEM_F_NO_CONTAINER_FALLBACK))
616 {
617 /*
618 * Fallback is a container module.
619 */
620 rc = RTDbgModCreate(&hMod, pszName, cbImage, 0);
621 if (RT_SUCCESS(rc))
622 {
623 rc = RTDbgModSymbolAdd(hMod, "Headers", 0 /*iSeg*/, 0, cbImage, 0 /*fFlags*/, NULL);
624 AssertRC(rc);
625 }
626 }
627 return rc;
628}
629
630
631
632/**
633 * Process a PE image found in guest memory.
634 *
635 * @param pUVM The user mode VM handle.
636 * @param pImageAddr The image address.
637 * @param fFlags Flags, DBGFMODINMEM_F_XXX.
638 * @param pszName The module name, optional.
639 * @param pszFilename The image filename, optional.
640 * @param enmArch The image arch if we force it, pass
641 * RTLDRARCH_WHATEVER if you don't care.
642 * @param cbImage Image size. Pass 0 if not known.
643 * @param phDbgMod Where to return the resulting debug module on success.
644 * @param pErrInfo Where to return extended error info on failure.
645 */
646VMMR3DECL(int) DBGFR3ModInMem(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName, const char *pszFilename,
647 RTLDRARCH enmArch, uint32_t cbImage, PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo)
648{
649 /*
650 * Validate and adjust.
651 */
652 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
653 *phDbgMod = NIL_RTDBGMOD;
654 AssertPtrReturn(pImageAddr, VERR_INVALID_POINTER);
655 AssertMsgReturn(cbImage == 0 || cbImage >= sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_DOS_HEADER),
656 ("cbImage=%#x\n", cbImage), VERR_INVALID_PARAMETER);
657 AssertMsgReturn(!(fFlags & ~DBGFMODINMEM_F_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_FLAGS);
658 if (enmArch == RTLDRARCH_HOST)
659 enmArch = RTLdrGetHostArch();
660
661 /*
662 * Look for an image header we can work with.
663 */
664 DBGFMODINMEMBUF uBuf;
665 RT_ZERO(uBuf);
666
667 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, pImageAddr, &uBuf, sizeof(uBuf.DosHdr));
668 if (RT_FAILURE(rc))
669 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "Failed to read DOS header at %RGv: %Rrc", pImageAddr->FlatPtr, rc);
670
671 if (uBuf.ab[0] == ELFMAG0 && uBuf.ab[1] == ELFMAG1 && uBuf.ab[2] == ELFMAG2 && uBuf.ab[3] == ELFMAG3)
672 return dbgfR3ModInMemElf(pUVM, pImageAddr, fFlags, pszName, pszFilename, enmArch, cbImage, &uBuf, phDbgMod, pErrInfo);
673
674 uint32_t offNewHdrs;
675 if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE)
676 {
677 offNewHdrs = uBuf.DosHdr.e_lfanew;
678 if ( offNewHdrs < 16
679 || offNewHdrs > (cbImage ? _2M : cbImage - sizeof(IMAGE_NT_HEADERS32)))
680 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "e_lfanew value is out of range: %RX32 (16..%u)",
681 offNewHdrs, (cbImage ? _2M : cbImage - sizeof(IMAGE_NT_HEADERS32)));
682 }
683 else if (uBuf.Nt32.Signature == IMAGE_NT_SIGNATURE)
684 offNewHdrs = 0;
685 else
686 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_INVALID_EXE_SIGNATURE, "Unknown image magic at %RGv: %.8Rhxs",
687 pImageAddr->FlatPtr, uBuf.ab);
688
689 /*
690 * Read the next bit of header, assuming PE so stop at the end of
691 * the COFF file header.
692 */
693 DBGFADDRESS PeHdrAddr = *pImageAddr;
694 DBGFR3AddrAdd(&PeHdrAddr, offNewHdrs);
695 uint32_t const cbPeHdrsPart1 = RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader);
696 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &PeHdrAddr, &uBuf, cbPeHdrsPart1);
697 if (RT_FAILURE(rc))
698 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "Failed to read PE/LX/NE headers at %RGv (off=%#RX32): %Rrc",
699 PeHdrAddr.FlatPtr, offNewHdrs, rc);
700
701 if (uBuf.Nt32.Signature == IMAGE_NT_SIGNATURE)
702 return dbgfR3ModInMemPe(pUVM, pImageAddr, fFlags, pszName, pszFilename, enmArch, cbImage, offNewHdrs, cbPeHdrsPart1,
703 &uBuf, phDbgMod, pErrInfo);
704
705 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_INVALID_EXE_SIGNATURE, "No PE/LX/NE header at %RGv (off=%#RX32): %.8Rhxs",
706 PeHdrAddr.FlatPtr, offNewHdrs, uBuf.ab);
707}
708
Note: See TracBrowser for help on using the repository browser.

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