VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCDumpImage.cpp@ 83629

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

DBGC/dumpimage: Started on a Mach-O dumper.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.6 KB
Line 
1/* $Id: DBGCDumpImage.cpp 83081 2020-02-15 02:22:58Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, Native Commands.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 LOG_GROUP LOG_GROUP_DBGC
23#include <VBox/dbg.h>
24#include <VBox/vmm/dbgf.h>
25#include <VBox/param.h>
26#include <iprt/errcore.h>
27#include <VBox/log.h>
28
29#include <iprt/assert.h>
30#include <iprt/ctype.h>
31#include <iprt/dir.h>
32#include <iprt/env.h>
33#include <iprt/ldr.h>
34#include <iprt/mem.h>
35#include <iprt/path.h>
36#include <iprt/string.h>
37#include <iprt/formats/mz.h>
38#include <iprt/formats/pecoff.h>
39#include <iprt/formats/elf32.h>
40#include <iprt/formats/elf64.h>
41#include <iprt/formats/codeview.h>
42#include <iprt/formats/mach-o.h>
43
44#include "DBGCInternal.h"
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50/**
51 * PE dumper instance.
52 */
53typedef struct DUMPIMAGEPE
54{
55 /** Pointer to the image base address variable. */
56 PCDBGCVAR pImageBase;
57 /** Pointer to the file header. */
58 PCIMAGE_FILE_HEADER pFileHdr;
59 /** Pointer to the NT headers. */
60 union
61 {
62 PCIMAGE_NT_HEADERS32 pNt32;
63 PCIMAGE_NT_HEADERS64 pNt64;
64 void *pv;
65 } u;
66 /** Pointer to the section headers. */
67 PCIMAGE_SECTION_HEADER paShdrs;
68 /** Number of section headers. */
69 unsigned cShdrs;
70 /** Number of RVA and sizes (data directory entries). */
71 unsigned cDataDir;
72 /** Pointer to the data directory. */
73 PCIMAGE_DATA_DIRECTORY paDataDir;
74
75 /** The command descriptor (for failing the command). */
76 PCDBGCCMD pCmd;
77} DUMPIMAGEPE;
78/** Pointer to a PE dumper instance. */
79typedef DUMPIMAGEPE *PDUMPIMAGEPE;
80
81
82/** Helper for translating flags. */
83typedef struct
84{
85 uint32_t fFlag;
86 const char *pszNm;
87} DBGCDUMPFLAGENTRY;
88#define FLENT(a_Define) { a_Define, #a_Define }
89
90
91/*********************************************************************************************************************************
92* Internal Functions *
93*********************************************************************************************************************************/
94extern FNDBGCCMD dbgcCmdDumpImage; /* See DBGCCommands.cpp. */
95
96
97/** Stringifies a 32-bit flag value. */
98static void dbgcDumpImageFlags32(PDBGCCMDHLP pCmdHlp, uint32_t fFlags, DBGCDUMPFLAGENTRY const *paEntries, size_t cEntries)
99{
100 for (size_t i = 0; i < cEntries; i++)
101 if (fFlags & paEntries[i].fFlag)
102 DBGCCmdHlpPrintf(pCmdHlp, " %s", paEntries[i].pszNm);
103}
104
105
106/*********************************************************************************************************************************
107* PE *
108*********************************************************************************************************************************/
109
110static const char *dbgcPeMachineName(uint16_t uMachine)
111{
112 switch (uMachine)
113 {
114 case IMAGE_FILE_MACHINE_I386 : return "I386";
115 case IMAGE_FILE_MACHINE_AMD64 : return "AMD64";
116 case IMAGE_FILE_MACHINE_UNKNOWN : return "UNKNOWN";
117 case IMAGE_FILE_MACHINE_BASIC_16 : return "BASIC_16";
118 case IMAGE_FILE_MACHINE_BASIC_16_TV : return "BASIC_16_TV";
119 case IMAGE_FILE_MACHINE_IAPX16 : return "IAPX16";
120 case IMAGE_FILE_MACHINE_IAPX16_TV : return "IAPX16_TV";
121 //case IMAGE_FILE_MACHINE_IAPX20 : return "IAPX20";
122 //case IMAGE_FILE_MACHINE_IAPX20_TV : return "IAPX20_TV";
123 case IMAGE_FILE_MACHINE_I8086 : return "I8086";
124 case IMAGE_FILE_MACHINE_I8086_TV : return "I8086_TV";
125 case IMAGE_FILE_MACHINE_I286_SMALL : return "I286_SMALL";
126 case IMAGE_FILE_MACHINE_MC68 : return "MC68";
127 //case IMAGE_FILE_MACHINE_MC68_WR : return "MC68_WR";
128 case IMAGE_FILE_MACHINE_MC68_TV : return "MC68_TV";
129 case IMAGE_FILE_MACHINE_MC68_PG : return "MC68_PG";
130 //case IMAGE_FILE_MACHINE_I286_LARGE : return "I286_LARGE";
131 case IMAGE_FILE_MACHINE_U370_WR : return "U370_WR";
132 case IMAGE_FILE_MACHINE_AMDAHL_470_WR: return "AMDAHL_470_WR";
133 case IMAGE_FILE_MACHINE_AMDAHL_470_RO: return "AMDAHL_470_RO";
134 case IMAGE_FILE_MACHINE_U370_RO : return "U370_RO";
135 case IMAGE_FILE_MACHINE_R4000 : return "R4000";
136 case IMAGE_FILE_MACHINE_WCEMIPSV2 : return "WCEMIPSV2";
137 case IMAGE_FILE_MACHINE_VAX_WR : return "VAX_WR";
138 case IMAGE_FILE_MACHINE_VAX_RO : return "VAX_RO";
139 case IMAGE_FILE_MACHINE_SH3 : return "SH3";
140 case IMAGE_FILE_MACHINE_SH3DSP : return "SH3DSP";
141 case IMAGE_FILE_MACHINE_SH4 : return "SH4";
142 case IMAGE_FILE_MACHINE_SH5 : return "SH5";
143 case IMAGE_FILE_MACHINE_ARM : return "ARM";
144 case IMAGE_FILE_MACHINE_THUMB : return "THUMB";
145 case IMAGE_FILE_MACHINE_ARMNT : return "ARMNT";
146 case IMAGE_FILE_MACHINE_AM33 : return "AM33";
147 case IMAGE_FILE_MACHINE_POWERPC : return "POWERPC";
148 case IMAGE_FILE_MACHINE_POWERPCFP : return "POWERPCFP";
149 case IMAGE_FILE_MACHINE_IA64 : return "IA64";
150 case IMAGE_FILE_MACHINE_MIPS16 : return "MIPS16";
151 case IMAGE_FILE_MACHINE_MIPSFPU : return "MIPSFPU";
152 case IMAGE_FILE_MACHINE_MIPSFPU16 : return "MIPSFPU16";
153 case IMAGE_FILE_MACHINE_EBC : return "EBC";
154 case IMAGE_FILE_MACHINE_M32R : return "M32R";
155 case IMAGE_FILE_MACHINE_ARM64 : return "ARM64";
156 }
157 return "??";
158}
159
160
161static const char *dbgcPeDataDirName(unsigned iDir)
162{
163 switch (iDir)
164 {
165 case IMAGE_DIRECTORY_ENTRY_EXPORT: return "EXPORT";
166 case IMAGE_DIRECTORY_ENTRY_IMPORT: return "IMPORT";
167 case IMAGE_DIRECTORY_ENTRY_RESOURCE: return "RESOURCE";
168 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: return "EXCEPTION";
169 case IMAGE_DIRECTORY_ENTRY_SECURITY: return "SECURITY";
170 case IMAGE_DIRECTORY_ENTRY_BASERELOC: return "BASERELOC";
171 case IMAGE_DIRECTORY_ENTRY_DEBUG: return "DEBUG";
172 case IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: return "ARCHITECTURE";
173 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: return "GLOBALPTR";
174 case IMAGE_DIRECTORY_ENTRY_TLS: return "TLS";
175 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: return "LOAD_CONFIG";
176 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: return "BOUND_IMPORT";
177 case IMAGE_DIRECTORY_ENTRY_IAT: return "IAT";
178 case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: return "DELAY_IMPORT";
179 case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: return "COM_DESCRIPTOR";
180 }
181 return "??";
182}
183
184
185static const char *dbgPeDebugTypeName(uint32_t uType)
186{
187 switch (uType)
188 {
189 case IMAGE_DEBUG_TYPE_UNKNOWN: return "UNKNOWN";
190 case IMAGE_DEBUG_TYPE_COFF: return "COFF";
191 case IMAGE_DEBUG_TYPE_CODEVIEW: return "CODEVIEW";
192 case IMAGE_DEBUG_TYPE_FPO: return "FPO";
193 case IMAGE_DEBUG_TYPE_MISC: return "MISC";
194 case IMAGE_DEBUG_TYPE_EXCEPTION: return "EXCEPTION";
195 case IMAGE_DEBUG_TYPE_FIXUP: return "FIXUP";
196 case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: return "OMAP_TO_SRC";
197 case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: return "OMAP_FROM_SRC";
198 case IMAGE_DEBUG_TYPE_BORLAND: return "BORLAND";
199 case IMAGE_DEBUG_TYPE_RESERVED10: return "RESERVED10";
200 case IMAGE_DEBUG_TYPE_CLSID: return "CLSID";
201 case IMAGE_DEBUG_TYPE_VC_FEATURE: return "VC_FEATURE";
202 case IMAGE_DEBUG_TYPE_POGO: return "POGO";
203 case IMAGE_DEBUG_TYPE_ILTCG: return "ILTCG";
204 case IMAGE_DEBUG_TYPE_MPX: return "MPX";
205 case IMAGE_DEBUG_TYPE_REPRO: return "REPRO";
206 }
207 return "??";
208}
209
210
211static int dbgcDumpImagePeDebugDir(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pDataAddr, uint32_t cbData)
212{
213 uint32_t cEntries = cbData / sizeof(IMAGE_DEBUG_DIRECTORY);
214 for (uint32_t i = 0; i < cEntries; i++)
215 {
216 /*
217 * Read the entry into memory.
218 */
219 DBGCVAR DbgDirAddr;
220 int rc = DBGCCmdHlpEval(pCmdHlp, &DbgDirAddr, "%DV + %#RX32", pDataAddr, i * sizeof(IMAGE_DEBUG_DIRECTORY));
221 if (RT_FAILURE(rc))
222 return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "DBGCCmdHlpEval failed on debug entry %u", i);
223
224 IMAGE_DEBUG_DIRECTORY DbgDir;
225 rc = DBGCCmdHlpMemRead(pCmdHlp, &DbgDir, sizeof(DbgDir), &DbgDirAddr, NULL);
226 if (RT_FAILURE(rc))
227 return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv", sizeof(DbgDir), &DbgDirAddr);
228
229 /*
230 * Dump it.
231 */
232 DBGCVAR DebugDataAddr = *pThis->pImageBase;
233 rc = DBGCCmdHlpEval(pCmdHlp, &DebugDataAddr, "%DV + %#RX32", pThis->pImageBase, DbgDir.AddressOfRawData);
234 DBGCCmdHlpPrintf(pCmdHlp, " Debug[%u]: %Dv/%08RX32 LB %06RX32 %u (%s) v%u.%u file=%RX32 ts=%08RX32 fl=%RX32\n",
235 i, &DebugDataAddr, DbgDir.AddressOfRawData, DbgDir.SizeOfData, DbgDir.Type,
236 dbgPeDebugTypeName(DbgDir.Type), DbgDir.MajorVersion, DbgDir.MinorVersion, DbgDir.PointerToRawData,
237 DbgDir.TimeDateStamp, DbgDir.Characteristics);
238 union
239 {
240 uint8_t abPage[0x1000];
241 CVPDB20INFO Pdb20;
242 CVPDB70INFO Pdb70;
243 IMAGE_DEBUG_MISC Misc;
244 } uBuf;
245 RT_ZERO(uBuf);
246
247 if (DbgDir.Type == IMAGE_DEBUG_TYPE_CODEVIEW)
248 {
249 if ( DbgDir.SizeOfData < sizeof(uBuf)
250 && DbgDir.SizeOfData > 16
251 && DbgDir.AddressOfRawData > 0
252 && RT_SUCCESS(rc))
253 {
254 rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf, DbgDir.SizeOfData, &DebugDataAddr, NULL);
255 if (RT_FAILURE(rc))
256 return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv",
257 DbgDir.SizeOfData, &DebugDataAddr);
258
259 if ( uBuf.Pdb20.u32Magic == CVPDB20INFO_MAGIC
260 && uBuf.Pdb20.offDbgInfo == 0
261 && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
262 DBGCCmdHlpPrintf(pCmdHlp, " PDB2.0: ts=%08RX32 age=%RX32 %s\n",
263 uBuf.Pdb20.uTimestamp, uBuf.Pdb20.uAge, uBuf.Pdb20.szPdbFilename);
264 else if ( uBuf.Pdb20.u32Magic == CVPDB70INFO_MAGIC
265 && DbgDir.SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
266 DBGCCmdHlpPrintf(pCmdHlp, " PDB7.0: %RTuuid age=%u %s\n",
267 &uBuf.Pdb70.PdbUuid, uBuf.Pdb70.uAge, uBuf.Pdb70.szPdbFilename);
268 else
269 DBGCCmdHlpPrintf(pCmdHlp, " Unknown PDB/codeview magic: %.8Rhxs\n", uBuf.abPage);
270 }
271 }
272 else if (DbgDir.Type == IMAGE_DEBUG_TYPE_MISC)
273 {
274 if ( DbgDir.SizeOfData < sizeof(uBuf)
275 && DbgDir.SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data)
276 && DbgDir.AddressOfRawData > 0
277 && RT_SUCCESS(rc) )
278 {
279 rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf, DbgDir.SizeOfData, &DebugDataAddr, NULL);
280 if (RT_FAILURE(rc))
281 return DBGCCmdHlpFailRc(pCmdHlp, pThis->pCmd, rc, "Failed to read %zu at %Dv",
282 DbgDir.SizeOfData, &DebugDataAddr);
283
284 if ( uBuf.Misc.DataType == IMAGE_DEBUG_MISC_EXENAME
285 && uBuf.Misc.Length == DbgDir.SizeOfData)
286 {
287 if (!uBuf.Misc.Unicode)
288 DBGCCmdHlpPrintf(pCmdHlp, " Misc DBG: ts=%RX32 %s\n",
289 DbgDir.TimeDateStamp, (const char *)&uBuf.Misc.Data[0]);
290 else
291 DBGCCmdHlpPrintf(pCmdHlp, " Misc DBG: ts=%RX32 %ls\n",
292 DbgDir.TimeDateStamp, (PCRTUTF16)&uBuf.Misc.Data[0]);
293 }
294 }
295 }
296 }
297 return VINF_SUCCESS;
298}
299
300
301static int dbgcDumpImagePeDataDirs(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, unsigned cDataDirs, PCIMAGE_DATA_DIRECTORY paDataDirs)
302{
303 int rcRet = VINF_SUCCESS;
304 for (unsigned i = 0; i < cDataDirs; i++)
305 {
306 if (paDataDirs[i].Size || paDataDirs[i].VirtualAddress)
307 {
308 DBGCVAR DataAddr = *pThis->pImageBase;
309 DBGCCmdHlpEval(pCmdHlp, &DataAddr, "%DV + %#RX32", pThis->pImageBase, paDataDirs[i].VirtualAddress);
310 DBGCCmdHlpPrintf(pCmdHlp, "DataDir[%02u]: %Dv/%08RX32 LB %08RX32 %s\n",
311 i, &DataAddr, paDataDirs[i].VirtualAddress, paDataDirs[i].Size, dbgcPeDataDirName(i));
312 int rc = VINF_SUCCESS;
313 if ( i == IMAGE_DIRECTORY_ENTRY_DEBUG
314 && paDataDirs[i].Size >= sizeof(IMAGE_DEBUG_DIRECTORY))
315 rc = dbgcDumpImagePeDebugDir(pThis, pCmdHlp, &DataAddr, paDataDirs[i].Size);
316 if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
317 rcRet = rc;
318 }
319 }
320 return rcRet;
321}
322
323
324static int dbgcDumpImagePeSectionHdrs(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, unsigned cShdrs, PCIMAGE_SECTION_HEADER paShdrs)
325{
326 for (unsigned i = 0; i < cShdrs; i++)
327 {
328 DBGCVAR SectAddr = *pThis->pImageBase;
329 DBGCCmdHlpEval(pCmdHlp, &SectAddr, "%DV + %#RX32", pThis->pImageBase, paShdrs[i].VirtualAddress);
330 DBGCCmdHlpPrintf(pCmdHlp, "Section[%02u]: %Dv/%08RX32 LB %08RX32 %.8s\n",
331 i, &SectAddr, paShdrs[i].VirtualAddress, paShdrs[i].Misc.VirtualSize, paShdrs[i].Name);
332 }
333 return VINF_SUCCESS;
334}
335
336
337static int dbgcDumpImagePeOptHdr32(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCIMAGE_NT_HEADERS32 pNtHdrs)
338{
339 RT_NOREF(pThis, pCmdHlp, pNtHdrs);
340 return VINF_SUCCESS;
341}
342
343static int dbgcDumpImagePeOptHdr64(PDUMPIMAGEPE pThis, PDBGCCMDHLP pCmdHlp, PCIMAGE_NT_HEADERS64 pNtHdrs)
344{
345 RT_NOREF(pThis, pCmdHlp, pNtHdrs);
346 return VINF_SUCCESS;
347}
348
349
350static int dbgcDumpImagePe(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase,
351 PCDBGCVAR pPeHdrAddr, PCIMAGE_FILE_HEADER pFileHdr)
352{
353 /*
354 * Dump file header fields.
355 */
356 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: PE image - %#x (%s), %u sections\n", pImageBase, pFileHdr->Machine,
357 dbgcPeMachineName(pFileHdr->Machine), pFileHdr->NumberOfSections);
358 DBGCCmdHlpPrintf(pCmdHlp, "Characteristics: %#06x", pFileHdr->Characteristics);
359 if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) DBGCCmdHlpPrintf(pCmdHlp, " RELOCS_STRIPPED");
360 if (pFileHdr->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) DBGCCmdHlpPrintf(pCmdHlp, " EXECUTABLE_IMAGE");
361 if (pFileHdr->Characteristics & IMAGE_FILE_LINE_NUMS_STRIPPED) DBGCCmdHlpPrintf(pCmdHlp, " LINE_NUMS_STRIPPED");
362 if (pFileHdr->Characteristics & IMAGE_FILE_LOCAL_SYMS_STRIPPED) DBGCCmdHlpPrintf(pCmdHlp, " LOCAL_SYMS_STRIPPED");
363 if (pFileHdr->Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM) DBGCCmdHlpPrintf(pCmdHlp, " AGGRESIVE_WS_TRIM");
364 if (pFileHdr->Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) DBGCCmdHlpPrintf(pCmdHlp, " LARGE_ADDRESS_AWARE");
365 if (pFileHdr->Characteristics & IMAGE_FILE_16BIT_MACHINE) DBGCCmdHlpPrintf(pCmdHlp, " 16BIT_MACHINE");
366 if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_LO) DBGCCmdHlpPrintf(pCmdHlp, " BYTES_REVERSED_LO");
367 if (pFileHdr->Characteristics & IMAGE_FILE_32BIT_MACHINE) DBGCCmdHlpPrintf(pCmdHlp, " 32BIT_MACHINE");
368 if (pFileHdr->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) DBGCCmdHlpPrintf(pCmdHlp, " DEBUG_STRIPPED");
369 if (pFileHdr->Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) DBGCCmdHlpPrintf(pCmdHlp, " REMOVABLE_RUN_FROM_SWAP");
370 if (pFileHdr->Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) DBGCCmdHlpPrintf(pCmdHlp, " NET_RUN_FROM_SWAP");
371 if (pFileHdr->Characteristics & IMAGE_FILE_SYSTEM) DBGCCmdHlpPrintf(pCmdHlp, " SYSTEM");
372 if (pFileHdr->Characteristics & IMAGE_FILE_DLL) DBGCCmdHlpPrintf(pCmdHlp, " DLL");
373 if (pFileHdr->Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) DBGCCmdHlpPrintf(pCmdHlp, " UP_SYSTEM_ONLY");
374 if (pFileHdr->Characteristics & IMAGE_FILE_BYTES_REVERSED_HI) DBGCCmdHlpPrintf(pCmdHlp, " BYTES_REVERSED_HI");
375 DBGCCmdHlpPrintf(pCmdHlp, "\n");
376
377 /*
378 * Allocate memory for all the headers, including section headers, and read them into memory.
379 */
380 size_t offSHdrs = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + sizeof(uint32_t);
381 size_t cbHdrs = offSHdrs + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
382 if (cbHdrs > _2M)
383 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: headers too big: %zu.\n", pImageBase, cbHdrs);
384
385 void *pvBuf = RTMemTmpAllocZ(cbHdrs);
386 if (!pvBuf)
387 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: failed to allocate %zu bytes.\n", pImageBase, cbHdrs);
388 int rc = DBGCCmdHlpMemRead(pCmdHlp, pvBuf, cbHdrs, pPeHdrAddr, NULL);
389 if (RT_SUCCESS(rc))
390 {
391 DUMPIMAGEPE This;
392 RT_ZERO(This);
393 This.pImageBase = pImageBase;
394 This.pFileHdr = pFileHdr;
395 This.u.pv = pvBuf;
396 This.cShdrs = pFileHdr->NumberOfSections;
397 This.paShdrs = (PCIMAGE_SECTION_HEADER)((uintptr_t)pvBuf + offSHdrs);
398 This.pCmd = pCmd;
399
400 if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
401 {
402 This.paDataDir = This.u.pNt32->OptionalHeader.DataDirectory;
403 This.cDataDir = This.u.pNt32->OptionalHeader.NumberOfRvaAndSizes;
404 rc = dbgcDumpImagePeOptHdr32(&This, pCmdHlp, This.u.pNt32);
405 }
406 else if (pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
407 {
408 This.paDataDir = This.u.pNt64->OptionalHeader.DataDirectory;
409 This.cDataDir = This.u.pNt64->OptionalHeader.NumberOfRvaAndSizes;
410 rc = dbgcDumpImagePeOptHdr64(&This, pCmdHlp, This.u.pNt64);
411 }
412 else
413 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unsupported optional header size: %#x\n",
414 pImageBase, pFileHdr->SizeOfOptionalHeader);
415
416 int rc2 = dbgcDumpImagePeSectionHdrs(&This, pCmdHlp, This.cShdrs, This.paShdrs);
417 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
418 rc = rc2;
419
420 rc2 = dbgcDumpImagePeDataDirs(&This, pCmdHlp, This.cDataDir, This.paDataDir);
421 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
422 rc = rc2;
423 }
424 else
425 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu at %Dv", pImageBase, cbHdrs, pPeHdrAddr);
426 RTMemTmpFree(pvBuf);
427 return rc;
428}
429
430
431/*********************************************************************************************************************************
432* ELF *
433*********************************************************************************************************************************/
434
435static int dbgcDumpImageElf(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase)
436{
437 RT_NOREF_PV(pCmd);
438 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: ELF image dumping not implemented yet.\n", pImageBase);
439 return VINF_SUCCESS;
440}
441
442
443/*********************************************************************************************************************************
444* Mach-O *
445*********************************************************************************************************************************/
446
447static const char *dbgcMachoFileType(uint32_t uType)
448{
449 switch (uType)
450 {
451 case MH_OBJECT: return "MH_OBJECT";
452 case MH_EXECUTE: return "MH_EXECUTE";
453 case MH_FVMLIB: return "MH_FVMLIB";
454 case MH_CORE: return "MH_CORE";
455 case MH_PRELOAD: return "MH_PRELOAD";
456 case MH_DYLIB: return "MH_DYLIB";
457 case MH_DYLINKER: return "MH_DYLINKER";
458 case MH_BUNDLE: return "MH_BUNDLE";
459 case MH_DYLIB_STUB: return "MH_DYLIB_STUB";
460 case MH_DSYM: return "MH_DSYM";
461 case MH_KEXT_BUNDLE: return "MH_KEXT_BUNDLE";
462 }
463 return "??";
464}
465
466
467static const char *dbgcMachoCpuType(uint32_t uType, uint32_t uSubType)
468{
469 switch (uType)
470 {
471 case CPU_TYPE_ANY: return "CPU_TYPE_ANY";
472 case CPU_TYPE_VAX: return "VAX";
473 case CPU_TYPE_MC680x0: return "MC680x0";
474 case CPU_TYPE_X86: return "X86";
475 case CPU_TYPE_X86_64:
476 switch (uSubType)
477 {
478 case CPU_SUBTYPE_X86_64_ALL: return "X86_64/ALL64";
479 }
480 return "X86_64";
481 case CPU_TYPE_MC98000: return "MC98000";
482 case CPU_TYPE_HPPA: return "HPPA";
483 case CPU_TYPE_MC88000: return "MC88000";
484 case CPU_TYPE_SPARC: return "SPARC";
485 case CPU_TYPE_I860: return "I860";
486 case CPU_TYPE_POWERPC: return "POWERPC";
487 case CPU_TYPE_POWERPC64: return "POWERPC64";
488
489 }
490 return "??";
491}
492
493
494static const char *dbgcMachoLoadCommand(uint32_t uCmd)
495{
496 switch (uCmd)
497 {
498 RT_CASE_RET_STR(LC_SEGMENT_32);
499 RT_CASE_RET_STR(LC_SYMTAB);
500 RT_CASE_RET_STR(LC_SYMSEG);
501 RT_CASE_RET_STR(LC_THREAD);
502 RT_CASE_RET_STR(LC_UNIXTHREAD);
503 RT_CASE_RET_STR(LC_LOADFVMLIB);
504 RT_CASE_RET_STR(LC_IDFVMLIB);
505 RT_CASE_RET_STR(LC_IDENT);
506 RT_CASE_RET_STR(LC_FVMFILE);
507 RT_CASE_RET_STR(LC_PREPAGE);
508 RT_CASE_RET_STR(LC_DYSYMTAB);
509 RT_CASE_RET_STR(LC_LOAD_DYLIB);
510 RT_CASE_RET_STR(LC_ID_DYLIB);
511 RT_CASE_RET_STR(LC_LOAD_DYLINKER);
512 RT_CASE_RET_STR(LC_ID_DYLINKER);
513 RT_CASE_RET_STR(LC_PREBOUND_DYLIB);
514 RT_CASE_RET_STR(LC_ROUTINES);
515 RT_CASE_RET_STR(LC_SUB_FRAMEWORK);
516 RT_CASE_RET_STR(LC_SUB_UMBRELLA);
517 RT_CASE_RET_STR(LC_SUB_CLIENT);
518 RT_CASE_RET_STR(LC_SUB_LIBRARY);
519 RT_CASE_RET_STR(LC_TWOLEVEL_HINTS);
520 RT_CASE_RET_STR(LC_PREBIND_CKSUM);
521 RT_CASE_RET_STR(LC_LOAD_WEAK_DYLIB);
522 RT_CASE_RET_STR(LC_SEGMENT_64);
523 RT_CASE_RET_STR(LC_ROUTINES_64);
524 RT_CASE_RET_STR(LC_UUID);
525 RT_CASE_RET_STR(LC_RPATH);
526 RT_CASE_RET_STR(LC_CODE_SIGNATURE);
527 RT_CASE_RET_STR(LC_SEGMENT_SPLIT_INFO);
528 RT_CASE_RET_STR(LC_REEXPORT_DYLIB);
529 RT_CASE_RET_STR(LC_LAZY_LOAD_DYLIB);
530 RT_CASE_RET_STR(LC_ENCRYPTION_INFO);
531 RT_CASE_RET_STR(LC_DYLD_INFO);
532 RT_CASE_RET_STR(LC_DYLD_INFO_ONLY);
533 RT_CASE_RET_STR(LC_LOAD_UPWARD_DYLIB);
534 RT_CASE_RET_STR(LC_VERSION_MIN_MACOSX);
535 RT_CASE_RET_STR(LC_VERSION_MIN_IPHONEOS);
536 RT_CASE_RET_STR(LC_FUNCTION_STARTS);
537 RT_CASE_RET_STR(LC_DYLD_ENVIRONMENT);
538 RT_CASE_RET_STR(LC_MAIN);
539 RT_CASE_RET_STR(LC_DATA_IN_CODE);
540 RT_CASE_RET_STR(LC_SOURCE_VERSION);
541 RT_CASE_RET_STR(LC_DYLIB_CODE_SIGN_DRS);
542 RT_CASE_RET_STR(LC_ENCRYPTION_INFO_64);
543 RT_CASE_RET_STR(LC_LINKER_OPTION);
544 RT_CASE_RET_STR(LC_LINKER_OPTIMIZATION_HINT);
545 RT_CASE_RET_STR(LC_VERSION_MIN_TVOS);
546 RT_CASE_RET_STR(LC_VERSION_MIN_WATCHOS);
547 RT_CASE_RET_STR(LC_NOTE);
548 RT_CASE_RET_STR(LC_BUILD_VERSION);
549 }
550 return "??";
551}
552
553
554static const char *dbgcMachoProt(uint32_t fProt)
555{
556 switch (fProt)
557 {
558 case VM_PROT_NONE: return "---";
559 case VM_PROT_READ: return "r--";
560 case VM_PROT_READ | VM_PROT_WRITE: return "rw-";
561 case VM_PROT_READ | VM_PROT_EXECUTE: return "r-x";
562 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: return "rwx";
563 case VM_PROT_WRITE: return "-w-";
564 case VM_PROT_WRITE | VM_PROT_EXECUTE: return "-wx";
565 case VM_PROT_EXECUTE: return "-w-";
566 }
567 return "???";
568}
569
570
571static int dbgcDumpImageMachO(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pImageBase, mach_header_64_t const *pHdr)
572{
573#define ENTRY(a_Define) { a_Define, #a_Define }
574 RT_NOREF_PV(pCmd);
575
576 /*
577 * Header:
578 */
579 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: Mach-O image (%s bit) - %s (%u) - %s (%#x / %#x)\n",
580 pImageBase, pHdr->magic == IMAGE_MACHO64_SIGNATURE ? "64" : "32",
581 dbgcMachoFileType(pHdr->filetype), pHdr->filetype,
582 dbgcMachoCpuType(pHdr->cputype, pHdr->cpusubtype), pHdr->cputype, pHdr->cpusubtype);
583
584 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: Flags: %#x", pImageBase, pHdr->flags);
585 static DBGCDUMPFLAGENTRY const s_aHdrFlags[] =
586 {
587 FLENT(MH_NOUNDEFS), FLENT(MH_INCRLINK),
588 FLENT(MH_DYLDLINK), FLENT(MH_BINDATLOAD),
589 FLENT(MH_PREBOUND), FLENT(MH_SPLIT_SEGS),
590 FLENT(MH_LAZY_INIT), FLENT(MH_TWOLEVEL),
591 FLENT(MH_FORCE_FLAT), FLENT(MH_NOMULTIDEFS),
592 FLENT(MH_NOFIXPREBINDING), FLENT(MH_PREBINDABLE),
593 FLENT(MH_ALLMODSBOUND), FLENT(MH_SUBSECTIONS_VIA_SYMBOLS),
594 FLENT(MH_CANONICAL), FLENT(MH_WEAK_DEFINES),
595 FLENT(MH_BINDS_TO_WEAK), FLENT(MH_ALLOW_STACK_EXECUTION),
596 FLENT(MH_ROOT_SAFE), FLENT(MH_SETUID_SAFE),
597 FLENT(MH_NO_REEXPORTED_DYLIBS), FLENT(MH_PIE),
598 FLENT(MH_DEAD_STRIPPABLE_DYLIB), FLENT(MH_HAS_TLV_DESCRIPTORS),
599 FLENT(MH_NO_HEAP_EXECUTION),
600 };
601 dbgcDumpImageFlags32(pCmdHlp, pHdr->flags, s_aHdrFlags, RT_ELEMENTS(s_aHdrFlags));
602 DBGCCmdHlpPrintf(pCmdHlp, "\n");
603 if (pHdr->reserved != 0 && pHdr->magic == IMAGE_MACHO64_SIGNATURE)
604 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: Reserved header field: %#x\n", pImageBase, pHdr->reserved);
605
606 /*
607 * And now the load commands.
608 */
609 const uint32_t cCmds = pHdr->ncmds;
610 const uint32_t cbCmds = pHdr->sizeofcmds;
611 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: %u load commands covering %#x bytes:\n", pImageBase, cCmds, cbCmds);
612 if (cbCmds > _16M)
613 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_OUT_OF_RANGE,
614 "%Dv: Commands too big: %#x bytes, max 16MiB\n", pImageBase, cbCmds);
615
616 /* Calc address of the first command: */
617 const uint32_t cbHdr = pHdr->magic == IMAGE_MACHO64_SIGNATURE ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t);
618 DBGCVAR Addr;
619 int rc = DBGCCmdHlpEval(pCmdHlp, &Addr, "%DV + %#RX32", pImageBase, cbHdr);
620 AssertRCReturn(rc, rc);
621
622 /* Read them into a temp buffer: */
623 uint8_t *pbCmds = (uint8_t *)RTMemTmpAllocZ(cbCmds);
624 if (!pbCmds)
625 return VERR_NO_TMP_MEMORY;
626
627 rc = DBGCCmdHlpMemRead(pCmdHlp, pbCmds, cbCmds, &Addr, NULL);
628 if (RT_SUCCESS(rc))
629 {
630 static const DBGCDUMPFLAGENTRY s_aSegFlags[] =
631 { FLENT(SG_HIGHVM), FLENT(SG_FVMLIB), FLENT(SG_NORELOC), FLENT(SG_PROTECTED_VERSION_1), };
632
633 /*
634 * Iterate the commands.
635 */
636 uint32_t offCmd = 0;
637 for (uint32_t iCmd = 0; iCmd < cCmds; iCmd++)
638 {
639 load_command_t const *pCurCmd = (load_command_t const *)&pbCmds[offCmd];
640 const uint32_t cbCurCmd = offCmd + sizeof(*pCurCmd) <= cbCmds ? pCurCmd->cmdsize : sizeof(*pCurCmd);
641 if (offCmd + cbCurCmd > cbCmds)
642 {
643 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_OUT_OF_RANGE,
644 "%Dv: Load command #%u (offset %#x + %#x) is out of bounds! cmdsize=%u (%#x) cmd=%u\n",
645 pImageBase, iCmd, offCmd, cbHdr, cbCurCmd, cbCurCmd,
646 offCmd + RT_UOFFSET_AFTER(load_command_t, cmd) <= cbCmds ? pCurCmd->cmd : UINT32_MAX);
647 break;
648 }
649
650 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: Load command #%u (offset %#x + %#x): %s (%u) LB %u\n",
651 pImageBase, iCmd, offCmd, cbHdr, dbgcMachoLoadCommand(pCurCmd->cmd), pCurCmd->cmd, cbCurCmd);
652 switch (pCurCmd->cmd)
653 {
654 case LC_SEGMENT_64:
655 if (cbCurCmd < sizeof(segment_command_64_t))
656 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_LDRMACHO_BAD_LOAD_COMMAND,
657 "%Dv: LC_SEGMENT64 is too short!\n", pImageBase);
658 else
659 {
660 segment_command_64_t const *pSeg = (segment_command_64_t const *)pCurCmd;
661 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: vmaddr: %016RX64 LB %08RX64 prot: %s(%x) maxprot: %s(%x) name: %.16s\n",
662 pImageBase, pSeg->vmaddr, pSeg->vmsize, dbgcMachoProt(pSeg->initprot), pSeg->initprot,
663 dbgcMachoProt(pSeg->maxprot), pSeg->maxprot, pSeg->segname);
664 DBGCCmdHlpPrintf(pCmdHlp, "%Dv: file: %016RX64 LB %08RX64 sections: %2u flags: %#x",
665 pImageBase, pSeg->fileoff, pSeg->filesize, pSeg->nsects, pSeg->flags);
666 dbgcDumpImageFlags32(pCmdHlp, pSeg->flags, s_aSegFlags, RT_ELEMENTS(s_aSegFlags));
667 DBGCCmdHlpPrintf(pCmdHlp, "\n");
668 if ( pSeg->nsects > _64K
669 || pSeg->nsects * sizeof(section_64_t) + sizeof(pSeg) > cbCurCmd)
670 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_LDRMACHO_BAD_LOAD_COMMAND,
671 "%Dv: LC_SEGMENT64 is too short for all the sections!\n", pImageBase);
672 else
673 {
674 section_64_t const *paSec = (section_64_t const *)(pSeg + 1);
675 for (uint32_t iSec = 0; iSec < pSeg->nsects; iSec++)
676 {
677 DBGCCmdHlpPrintf(pCmdHlp,
678 "%Dv: Section #%u: %016RX64 LB %08RX64 align: 2**%-2u name: %.16s",
679 pImageBase, iSec, paSec[iSec].addr, paSec[iSec].size, paSec[iSec].align,
680 paSec[iSec].sectname);
681 if (strncmp(pSeg->segname, paSec[iSec].segname, sizeof(pSeg->segname)))
682 DBGCCmdHlpPrintf(pCmdHlp, "(in %.16s)", paSec[iSec].segname);
683 DBGCCmdHlpPrintf(pCmdHlp, "\n");
684
685 /// @todo Good night!
686 /// uint32_t offset;
687 /// uint32_t reloff;
688 /// uint32_t nreloc;
689 /// uint32_t flags;
690 /// /** For S_LAZY_SYMBOL_POINTERS, S_NON_LAZY_SYMBOL_POINTERS and S_SYMBOL_STUBS
691 /// * this is the index into the indirect symbol table. */
692 /// uint32_t reserved1;
693 /// uint32_t reserved2;
694 /// uint32_t reserved3;
695 ///
696 }
697 }
698 }
699 break;
700 }
701
702 /* Advance: */
703 offCmd += cbCurCmd;
704 }
705 }
706 else
707 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Error reading load commands %Dv LB %#x\n",
708 pImageBase, &Addr, cbCmds);
709 RTMemTmpFree(pbCmds);
710 return rc;
711#undef ENTRY
712}
713
714
715/**
716 * @callback_method_impl{FNDBGCCMD, The 'dumpimage' command.}
717 */
718DECLCALLBACK(int) dbgcCmdDumpImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
719{
720 int rcRet = VINF_SUCCESS;
721 for (unsigned iArg = 0; iArg < cArgs; iArg++)
722 {
723 union
724 {
725 uint8_t ab[0x10];
726 IMAGE_DOS_HEADER DosHdr;
727 struct
728 {
729 uint32_t u32Magic;
730 IMAGE_FILE_HEADER FileHdr;
731 } Nt;
732 mach_header_64_t MachO64;
733 } uBuf;
734 DBGCVAR const ImageBase = paArgs[iArg];
735 int rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf.DosHdr, sizeof(uBuf.DosHdr), &ImageBase, NULL);
736 if (RT_SUCCESS(rc))
737 {
738 /*
739 * MZ.
740 */
741 if (uBuf.DosHdr.e_magic == IMAGE_DOS_SIGNATURE)
742 {
743 uint32_t offNewHdr = uBuf.DosHdr.e_lfanew;
744 if (offNewHdr < _256K && offNewHdr >= 16)
745 {
746 /* Look for new header. */
747 DBGCVAR NewHdrAddr;
748 rc = DBGCCmdHlpEval(pCmdHlp, &NewHdrAddr, "%DV + %#RX32", &ImageBase, offNewHdr);
749 if (RT_SUCCESS(rc))
750 {
751 rc = DBGCCmdHlpMemRead(pCmdHlp, &uBuf.Nt, sizeof(uBuf.Nt), &NewHdrAddr, NULL);
752 if (RT_SUCCESS(rc))
753 {
754 /* PE: */
755 if (uBuf.Nt.u32Magic == IMAGE_NT_SIGNATURE)
756 rc = dbgcDumpImagePe(pCmd, pCmdHlp, &ImageBase, &NewHdrAddr, &uBuf.Nt.FileHdr);
757 else
758 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unknown new header magic: %.8Rhxs\n",
759 &ImageBase, uBuf.ab);
760 }
761 else
762 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu at %Dv",
763 &ImageBase, sizeof(uBuf.Nt), &NewHdrAddr);
764 }
765 else
766 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to calc address of new header", &ImageBase);
767 }
768 else
769 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: MZ header but e_lfanew=%#RX32 is out of bounds (16..256K).\n",
770 &ImageBase, offNewHdr);
771 }
772 /*
773 * ELF.
774 */
775 else if (uBuf.ab[0] == ELFMAG0 && uBuf.ab[1] == ELFMAG1 && uBuf.ab[2] == ELFMAG2 && uBuf.ab[3] == ELFMAG3)
776 rc = dbgcDumpImageElf(pCmd, pCmdHlp, &ImageBase);
777 /*
778 * Mach-O.
779 */
780 else if ( uBuf.MachO64.magic == IMAGE_MACHO64_SIGNATURE
781 || uBuf.MachO64.magic == IMAGE_MACHO32_SIGNATURE )
782 rc = dbgcDumpImageMachO(pCmd, pCmdHlp, &ImageBase, &uBuf.MachO64);
783 /*
784 * Dunno.
785 */
786 else
787 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "%Dv: Unknown magic: %.8Rhxs\n", &ImageBase, uBuf.ab);
788 }
789 else
790 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "%Dv: Failed to read %zu", &ImageBase, sizeof(uBuf.DosHdr));
791 if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
792 rcRet = rc;
793 }
794 RT_NOREF(pUVM);
795 return rcRet;
796}
797
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