VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGPlugInDarwin.cpp@ 50837

Last change on this file since 50837 was 50616, checked in by vboxsync, 11 years ago

DBGPlugInDarwin.cpp: allow more load commands.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.7 KB
Line 
1/* $Id: DBGPlugInDarwin.cpp 50616 2014-02-26 18:52:55Z vboxsync $ */
2/** @file
3 * DBGPlugInDarwin - Debugger and Guest OS Digger Plugin For Darwin / OS X.
4 */
5
6/*
7 * Copyright (C) 2008-2013 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_DBGF ///@todo add new log group.
23#include "DBGPlugIns.h"
24#include <VBox/vmm/dbgf.h>
25#include <iprt/string.h>
26#include <iprt/mem.h>
27#include <iprt/stream.h>
28#include <iprt/uuid.h>
29#include <iprt/ctype.h>
30#include <iprt/formats/mach-o.h>
31
32
33/*******************************************************************************
34* Structures and Typedefs *
35*******************************************************************************/
36
37/** @name Internal Darwin structures
38 * @{ */
39
40/**
41 * 32-bit darwin kernel module info structure (kmod_info_t).
42 */
43typedef struct OSX32_kmod_info
44{
45 uint32_t next;
46 int32_t info_version;
47 uint32_t id;
48 char name[64];
49 char version[64];
50 int32_t reference_count;
51 uint32_t reference_list; /**< Points to kmod_reference_t. */
52 uint32_t address; /**< Where in memory the kext is loaded. */
53 uint32_t size;
54 uint32_t hdr_size;
55 uint32_t start; /**< Address of kmod_start_func_t. */
56 uint32_t stop; /**< Address of kmod_stop_func_t. */
57} OSX32_kmod_info_t;
58
59/**
60 * 32-bit darwin kernel module info structure (kmod_info_t).
61 */
62#pragma pack(1)
63typedef struct OSX64_kmod_info
64{
65 uint64_t next;
66 int32_t info_version;
67 uint32_t id;
68 char name[64];
69 char version[64];
70 int32_t reference_count;
71 uint64_t reference_list; /**< Points to kmod_reference_t. Misaligned, duh. */
72 uint64_t address; /**< Where in memory the kext is loaded. */
73 uint64_t size;
74 uint64_t hdr_size;
75 uint64_t start; /**< Address of kmod_start_func_t. */
76 uint64_t stop; /**< Address of kmod_stop_func_t. */
77} OSX64_kmod_info_t;
78#pragma pack()
79
80/** The value of the info_version field. */
81#define OSX_KMOD_INFO_VERSION INT32_C(1)
82
83/** @} */
84
85
86/**
87 * Linux guest OS digger instance data.
88 */
89typedef struct DBGDIGGERDARWIN
90{
91 /** Whether the information is valid or not.
92 * (For fending off illegal interface method calls.) */
93 bool fValid;
94
95 /** The address of an kernel version string (there are several).
96 * This is set during probing. */
97 DBGFADDRESS AddrKernelVersion;
98 /** Kernel base address.
99 * This is set during probing. */
100 DBGFADDRESS AddrKernel;
101} DBGDIGGERDARWIN;
102/** Pointer to the linux guest OS digger instance data. */
103typedef DBGDIGGERDARWIN *PDBGDIGGERDARWIN;
104
105
106/*******************************************************************************
107* Defined Constants And Macros *
108*******************************************************************************/
109/** Validates a 32-bit darwin kernel address */
110#define OSX32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x00001000) && (Addr) < UINT32_C(0xfffff000))
111/** Validates a 64-bit darwin kernel address */
112#define OSX64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000))
113/** Validates a 32-bit or 64-bit darwin kernel address. */
114#define OSX_VALID_ADDRESS(a_f64Bits, a_Addr) \
115 ((a_f64Bits) ? OSX64_VALID_ADDRESS(a_Addr) : OSX32_VALID_ADDRESS(a_Addr))
116
117/** AppleOsX on little endian ASCII systems. */
118#define DIG_DARWIN_MOD_TAG UINT64_C(0x58734f656c707041)
119
120
121/*******************************************************************************
122* Internal Functions *
123*******************************************************************************/
124static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, void *pvData);
125
126
127/**
128 * @copydoc DBGFOSREG::pfnQueryInterface
129 */
130static DECLCALLBACK(void *) dbgDiggerDarwinQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
131{
132 return NULL;
133}
134
135
136/**
137 * @copydoc DBGFOSREG::pfnQueryVersion
138 */
139static DECLCALLBACK(int) dbgDiggerDarwinQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
140{
141 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
142 Assert(pThis->fValid);
143
144 /*
145 * It's all in the linux banner.
146 */
147 int rc = DBGFR3MemReadString(pUVM, 0, &pThis->AddrKernelVersion, pszVersion, cchVersion);
148 if (RT_SUCCESS(rc))
149 {
150 char *pszEnd = RTStrEnd(pszVersion, cchVersion);
151 AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
152 while ( pszEnd > pszVersion
153 && RT_C_IS_SPACE(pszEnd[-1]))
154 pszEnd--;
155 *pszEnd = '\0';
156 }
157 else
158 RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemRead -> %Rrc", rc);
159
160 return rc;
161}
162
163
164/**
165 * @copydoc DBGFOSREG::pfnTerm
166 */
167static DECLCALLBACK(void) dbgDiggerDarwinTerm(PUVM pUVM, void *pvData)
168{
169 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
170
171 pThis->fValid = false;
172}
173
174
175/**
176 * @copydoc DBGFOSREG::pfnRefresh
177 */
178static DECLCALLBACK(int) dbgDiggerDarwinRefresh(PUVM pUVM, void *pvData)
179{
180 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
181 NOREF(pThis);
182 Assert(pThis->fValid);
183
184 /*
185 * For now we'll flush and reload everything.
186 */
187 dbgDiggerDarwinTerm(pUVM, pvData);
188 return dbgDiggerDarwinInit(pUVM, pvData);
189}
190
191
192/**
193 * Helper function that validates a segment (or section) name.
194 *
195 * @returns true if valid, false if not.
196 * @param pszName The name string.
197 * @param cbName The size of the string, including terminator.
198 */
199static bool dbgDiggerDarwinIsValidSegOrSectName(const char *pszName, size_t cbName)
200{
201 /* ascii chars */
202 char ch;
203 size_t off = 0;
204 while (off < cbName && (ch = pszName[off]))
205 {
206 if (RT_C_IS_CNTRL(ch) || ch >= 127)
207 return false;
208 off++;
209 }
210
211 /* Not empty nor 100% full. */
212 if (off == 0 || off == cbName)
213 return false;
214
215 /* remainder should be zeros. */
216 while (off < cbName)
217 {
218 if (pszName[off])
219 return false;
220 off++;
221 }
222
223 return true;
224}
225
226
227static int dbgDiggerDarwinAddModule(PDBGDIGGERDARWIN pThis, PUVM pUVM, uint64_t uModAddr, const char *pszName, bool *pf64Bit)
228{
229 union
230 {
231 uint8_t ab[2 * X86_PAGE_4K_SIZE];
232 mach_header_64_t Hdr64;
233 mach_header_32_t Hdr32;
234 } uBuf;
235
236 /* Read the first page of the image. */
237 DBGFADDRESS ModAddr;
238 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr), uBuf.ab, X86_PAGE_4K_SIZE);
239 if (RT_FAILURE(rc))
240 return rc;
241
242 /* Validate the header. */
243 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
244 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
245 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
246 return VERR_INVALID_EXE_SIGNATURE;
247 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
248 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
249 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
250 return VERR_LDR_ARCH_MISMATCH;
251 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
252 if ( uBuf.Hdr32.filetype != MH_EXECUTE
253 && uBuf.Hdr32.filetype != (f64Bit ? MH_KEXT_BUNDLE : MH_OBJECT))
254 return VERR_BAD_EXE_FORMAT;
255 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
256 if (uBuf.Hdr32.ncmds > 256)
257 return VERR_BAD_EXE_FORMAT;
258 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
259 if (uBuf.Hdr32.sizeofcmds > X86_PAGE_4K_SIZE * 2 - sizeof(mach_header_64_t))
260 return VERR_BAD_EXE_FORMAT;
261
262 /* Do we need to read a 2nd page to get all the load commands? If so, do it. */
263 if (uBuf.Hdr32.sizeofcmds + (f64Bit ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t)) > X86_PAGE_4K_SIZE)
264 {
265 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr + X86_PAGE_4K_SIZE),
266 &uBuf.ab[X86_PAGE_4K_SIZE], X86_PAGE_4K_SIZE);
267 if (RT_FAILURE(rc))
268 return rc;
269 }
270
271 /*
272 * Process the load commands.
273 */
274 RTDBGSEGMENT aSegs[24];
275 uint32_t cSegs = 0;
276 RTUUID Uuid = RTUUID_INITIALIZE_NULL;
277 uint32_t cLeft = uBuf.Hdr32.ncmds;
278 uint32_t cbLeft = uBuf.Hdr32.sizeofcmds;
279 union
280 {
281 uint8_t const *pb;
282 load_command_t const *pGenric;
283 segment_command_32_t const *pSeg32;
284 segment_command_64_t const *pSeg64;
285 section_32_t const *pSect32;
286 section_64_t const *pSect64;
287 symtab_command_t const *pSymTab;
288 uuid_command_t const *pUuid;
289 } uLCmd;
290 uLCmd.pb = &uBuf.ab[f64Bit ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t)];
291
292 while (cLeft-- > 0)
293 {
294 uint32_t const cbCmd = uLCmd.pGenric->cmdsize;
295 if (cbCmd > cbLeft || cbCmd < sizeof(load_command_t))
296 return VERR_BAD_EXE_FORMAT;
297
298 switch (uLCmd.pGenric->cmd)
299 {
300 case LC_SEGMENT_32:
301 if (cbCmd != sizeof(segment_command_32_t) + uLCmd.pSeg32->nsects * sizeof(section_32_t))
302 return VERR_BAD_EXE_FORMAT;
303 if (!dbgDiggerDarwinIsValidSegOrSectName(uLCmd.pSeg32->segname, sizeof(uLCmd.pSeg32->segname)))
304 return VERR_INVALID_NAME;
305 if (!strcmp(uLCmd.pSeg32->segname, "__LINKEDIT"))
306 break; /* This usually is discarded or not loaded at all. */
307 if (cSegs >= RT_ELEMENTS(aSegs))
308 return VERR_BUFFER_OVERFLOW;
309 aSegs[cSegs].Address = uLCmd.pSeg32->vmaddr;
310 aSegs[cSegs].uRva = uLCmd.pSeg32->vmaddr - uModAddr;
311 aSegs[cSegs].cb = uLCmd.pSeg32->vmsize;
312 aSegs[cSegs].fFlags = uLCmd.pSeg32->flags; /* Abusing the flags field here... */
313 aSegs[cSegs].iSeg = cSegs;
314 AssertCompile(RTDBG_SEGMENT_NAME_LENGTH > sizeof(uLCmd.pSeg32->segname));
315 strcpy(aSegs[cSegs].szName, uLCmd.pSeg32->segname);
316 cSegs++;
317 break;
318
319 case LC_SEGMENT_64:
320 if (cbCmd != sizeof(segment_command_64_t) + uLCmd.pSeg64->nsects * sizeof(section_64_t))
321 return VERR_BAD_EXE_FORMAT;
322 if (!dbgDiggerDarwinIsValidSegOrSectName(uLCmd.pSeg64->segname, sizeof(uLCmd.pSeg64->segname)))
323 return VERR_INVALID_NAME;
324 if (!strcmp(uLCmd.pSeg64->segname, "__LINKEDIT"))
325 break; /* This usually is discarded or not loaded at all. */
326 if (cSegs >= RT_ELEMENTS(aSegs))
327 return VERR_BUFFER_OVERFLOW;
328 aSegs[cSegs].Address = uLCmd.pSeg64->vmaddr;
329 aSegs[cSegs].uRva = uLCmd.pSeg64->vmaddr - uModAddr;
330 aSegs[cSegs].cb = uLCmd.pSeg64->vmsize;
331 aSegs[cSegs].fFlags = uLCmd.pSeg64->flags; /* Abusing the flags field here... */
332 aSegs[cSegs].iSeg = cSegs;
333 AssertCompile(RTDBG_SEGMENT_NAME_LENGTH > sizeof(uLCmd.pSeg64->segname));
334 strcpy(aSegs[cSegs].szName, uLCmd.pSeg64->segname);
335 cSegs++;
336 break;
337
338 case LC_UUID:
339 if (cbCmd != sizeof(uuid_command_t))
340 return VERR_BAD_EXE_FORMAT;
341 if (RTUuidIsNull((PCRTUUID)&uLCmd.pUuid->uuid[0]))
342 return VERR_BAD_EXE_FORMAT;
343 memcpy(&Uuid, &uLCmd.pUuid->uuid[0], sizeof(uLCmd.pUuid->uuid));
344 break;
345
346 default:
347 /* Current known max plus a lot of slack. */
348 if (uLCmd.pGenric->cmd > LC_DYLIB_CODE_SIGN_DRS + 32)
349 return VERR_BAD_EXE_FORMAT;
350 break;
351 }
352
353 /* next */
354 cbLeft -= cbCmd;
355 uLCmd.pb += cbCmd;
356 }
357
358 if (cbLeft != 0)
359 return VERR_BAD_EXE_FORMAT;
360
361 /*
362 * Some post processing checks.
363 */
364 uint32_t iSeg;
365 for (iSeg = 0; iSeg < cSegs; iSeg++)
366 if (aSegs[iSeg].Address == uModAddr)
367 break;
368 if (iSeg >= cSegs)
369 return VERR_ADDRESS_CONFLICT;
370
371 /*
372 * Create a debug module.
373 */
374 RTDBGMOD hMod;
375 rc = RTDbgModCreateFromMachOImage(&hMod, pszName, NULL, f64Bit ? RTLDRARCH_AMD64 : RTLDRARCH_X86_32, 0 /*cbImage*/,
376 cSegs, aSegs, &Uuid, DBGFR3AsGetConfig(pUVM), RTDBGMOD_F_NOT_DEFERRED);
377
378 if (RT_FAILURE(rc))
379 {
380 /*
381 * Final fallback is a container module.
382 */
383 rc = RTDbgModCreate(&hMod, pszName, 0, 0);
384 if (RT_FAILURE(rc))
385 return rc;
386
387 uint64_t uRvaNext = 0;
388 for (iSeg = 0; iSeg < cSegs && RT_SUCCESS(rc); iSeg++)
389 {
390 if ( aSegs[iSeg].uRva > uRvaNext
391 && aSegs[iSeg].uRva - uRvaNext < _1M)
392 uRvaNext = aSegs[iSeg].uRva;
393 rc = RTDbgModSegmentAdd(hMod, aSegs[iSeg].uRva, aSegs[iSeg].cb, aSegs[iSeg].szName, 0, NULL);
394 if (aSegs[iSeg].cb > 0 && RT_SUCCESS(rc))
395 {
396 char szTmp[RTDBG_SEGMENT_NAME_LENGTH + sizeof("_start")];
397 strcat(strcpy(szTmp, aSegs[iSeg].szName), "_start");
398 rc = RTDbgModSymbolAdd(hMod, szTmp, iSeg, 0 /*uRva*/, 0 /*cb*/, 0 /*fFlags*/, NULL);
399 }
400 uRvaNext += aSegs[iSeg].cb;
401 }
402
403 if (RT_FAILURE(rc))
404 {
405 RTDbgModRelease(hMod);
406 return rc;
407 }
408 }
409
410 /* Tag the module. */
411 rc = RTDbgModSetTag(hMod, DIG_DARWIN_MOD_TAG);
412 AssertRC(rc);
413
414 /*
415 * Link the module.
416 */
417 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
418 if (hAs != NIL_RTDBGAS)
419 {
420 uint64_t uRvaNext = 0;
421 uint32_t cLinked = 0;
422 iSeg = cSegs;
423 while (iSeg-- > 0) /* HACK: Map in reverse order to avoid replacing __TEXT. */
424 if (aSegs[iSeg].cb)
425 {
426 /* Find matching segment in the debug module. */
427 uint32_t iDbgSeg = 0;
428 while (iDbgSeg < cSegs)
429 {
430 RTDBGSEGMENT SegInfo;
431 int rc3 = RTDbgModSegmentByIndex(hMod, iDbgSeg, &SegInfo);
432 if (RT_SUCCESS(rc3) && !strcmp(SegInfo.szName, aSegs[iSeg].szName))
433 break;
434 iDbgSeg++;
435 }
436 AssertMsgStmt(iDbgSeg < cSegs, ("%s\n", aSegs[iSeg].szName), continue);
437
438 /* Map it. */
439 int rc2 = RTDbgAsModuleLinkSeg(hAs, hMod, iDbgSeg, aSegs[iSeg].Address, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
440 if (RT_SUCCESS(rc2))
441 cLinked++;
442 else if (RT_SUCCESS(rc))
443 rc = rc2;
444 }
445 if (RT_FAILURE(rc) && cLinked != 0)
446 rc = -rc;
447 }
448 else
449 rc = VERR_INTERNAL_ERROR;
450
451 RTDbgModRelease(hMod);
452 RTDbgAsRelease(hAs);
453
454 if (pf64Bit)
455 *pf64Bit = f64Bit;
456 return rc;
457}
458
459
460static bool dbgDiggerDarwinIsValidName(const char *pszName)
461{
462 char ch;
463 while ((ch = *pszName++) != '\0')
464 {
465 if (ch < 0x20 || ch >= 127)
466 return false;
467 }
468 return true;
469}
470
471
472static bool dbgDiggerDarwinIsValidVersion(const char *pszVersion)
473{
474 char ch;
475 while ((ch = *pszVersion++) != '\0')
476 {
477 if (ch < 0x20 || ch >= 127)
478 return false;
479 }
480 return true;
481}
482
483
484/**
485 * @copydoc DBGFOSREG::pfnInit
486 */
487static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, void *pvData)
488{
489 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
490 Assert(!pThis->fValid);
491
492 /*
493 * Add the kernel module.
494 */
495 bool f64Bit;
496 int rc = dbgDiggerDarwinAddModule(pThis, pUVM, pThis->AddrKernel.FlatPtr, "mach_kernel", &f64Bit);
497 if (RT_SUCCESS(rc))
498 {
499 /*
500 * The list of modules can be found at the 'kmod' symbol, that means
501 * that we currently require some kind of symbol file for the kernel
502 * to be loaded at this point.
503 *
504 * Note! Could also use the 'gLoadedKextSummaries', but I don't think
505 * it's any easier to find without any kernel map than 'kmod'.
506 */
507 RTDBGSYMBOL SymInfo;
508 rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "mach_kernel!kmod", &SymInfo, NULL);
509 if (RT_FAILURE(rc))
510 rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "mach_kernel!_kmod", &SymInfo, NULL);
511 if (RT_SUCCESS(rc))
512 {
513 DBGFADDRESS AddrModInfo;
514 DBGFR3AddrFromFlat(pUVM, &AddrModInfo, SymInfo.Value);
515
516 /* Read the variable. */
517 RTUINT64U uKmodValue = { 0 };
518 if (f64Bit)
519 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrModInfo, &uKmodValue.u, sizeof(uKmodValue.u));
520 else
521 rc = DBGFR3MemRead (pUVM, 0 /*idCpu*/, &AddrModInfo, &uKmodValue.s.Lo, sizeof(uKmodValue.s.Lo));
522 if (RT_SUCCESS(rc))
523 {
524 DBGFR3AddrFromFlat(pUVM, &AddrModInfo, uKmodValue.u);
525
526 /* Walk the list of modules. */
527 uint32_t cIterations = 0;
528 while (AddrModInfo.FlatPtr != 0)
529 {
530 /* Some extra loop conditions... */
531 if (!OSX_VALID_ADDRESS(f64Bit, AddrModInfo.FlatPtr))
532 {
533 Log(("OSXDig: Invalid kmod_info pointer: %RGv\n", AddrModInfo.FlatPtr));
534 break;
535 }
536 if (AddrModInfo.FlatPtr == uKmodValue.u && cIterations != 0)
537 {
538 Log(("OSXDig: kmod_info list looped back to the start.\n"));
539 break;
540 }
541 if (cIterations++ >= 2048)
542 {
543 Log(("OSXDig: Too many mod_info loops (%u)\n", cIterations));
544 break;
545 }
546
547 /*
548 * Read the kmod_info_t structure.
549 */
550 union
551 {
552 OSX64_kmod_info_t Info64;
553 OSX32_kmod_info_t Info32;
554 } uMod;
555 RT_ZERO(uMod);
556 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrModInfo, &uMod,
557 f64Bit ? sizeof(uMod.Info64) : sizeof(uMod.Info64));
558 if (RT_FAILURE(rc))
559 {
560 Log(("OSXDig: Error reading kmod_info structure at %RGv: %Rrc\n", AddrModInfo.FlatPtr, rc));
561 break;
562 }
563
564 /*
565 * Validate the kmod_info_t structure.
566 */
567 int32_t iInfoVer = f64Bit ? uMod.Info64.info_version : uMod.Info32.info_version;
568 if (iInfoVer != OSX_KMOD_INFO_VERSION)
569 {
570 Log(("OSXDig: kmod_info @%RGv: Bad info_version %d\n", AddrModInfo.FlatPtr, iInfoVer));
571 break;
572 }
573
574 const char *pszName = f64Bit ? uMod.Info64.name : uMod.Info32.name;
575 if ( !*pszName
576 || !RTStrEnd(pszName, sizeof(uMod.Info64.name))
577 || !dbgDiggerDarwinIsValidName(pszName) )
578 {
579 Log(("OSXDig: kmod_info @%RGv: Bad name '%.*s'\n", AddrModInfo.FlatPtr,
580 sizeof(uMod.Info64.name), pszName));
581 break;
582 }
583
584 const char *pszVersion = f64Bit ? uMod.Info64.version : uMod.Info32.version;
585 if ( !RTStrEnd(pszVersion, sizeof(uMod.Info64.version))
586 || !dbgDiggerDarwinIsValidVersion(pszVersion) )
587 {
588 Log(("OSXDig: kmod_info @%RGv: Bad version '%.*s'\n", AddrModInfo.FlatPtr,
589 sizeof(uMod.Info64.version), pszVersion));
590 break;
591 }
592
593 int32_t cRefs = f64Bit ? uMod.Info64.reference_count : uMod.Info32.reference_count;
594 if (cRefs < -1 || cRefs > 16384)
595 {
596 Log(("OSXDig: kmod_info @%RGv: Bad reference_count %d\n", AddrModInfo.FlatPtr, cRefs));
597 break;
598 }
599
600 uint64_t uImageAddr = f64Bit ? uMod.Info64.address : uMod.Info32.address;
601 if (!OSX_VALID_ADDRESS(f64Bit, uImageAddr))
602 {
603 Log(("OSXDig: kmod_info @%RGv: Bad address %#llx\n", AddrModInfo.FlatPtr, uImageAddr));
604 break;
605 }
606
607 uint64_t cbImage = f64Bit ? uMod.Info64.size : uMod.Info32.size;
608 if (cbImage > 64U*_1M)
609 {
610 Log(("OSXDig: kmod_info @%RGv: Bad size %#llx\n", AddrModInfo.FlatPtr, cbImage));
611 break;
612 }
613
614 uint64_t cbHdr = f64Bit ? uMod.Info64.hdr_size : uMod.Info32.hdr_size;
615 if (cbHdr > 16U*_1M)
616 {
617 Log(("OSXDig: kmod_info @%RGv: Bad hdr_size %#llx\n", AddrModInfo.FlatPtr, cbHdr));
618 break;
619 }
620
621 uint64_t uStartAddr = f64Bit ? uMod.Info64.start : uMod.Info32.start;
622 if (!uStartAddr && !OSX_VALID_ADDRESS(f64Bit, uStartAddr))
623 {
624 Log(("OSXDig: kmod_info @%RGv: Bad start function %#llx\n", AddrModInfo.FlatPtr, uStartAddr));
625 break;
626 }
627
628 uint64_t uStopAddr = f64Bit ? uMod.Info64.stop : uMod.Info32.stop;
629 if (!uStopAddr && !OSX_VALID_ADDRESS(f64Bit, uStopAddr))
630 {
631 Log(("OSXDig: kmod_info @%RGv: Bad stop function %#llx\n", AddrModInfo.FlatPtr, uStopAddr));
632 break;
633 }
634
635 /*
636 * Try add the module.
637 */
638 Log(("OSXDig: kmod_info @%RGv: '%s' ver '%s', image @%#llx LB %#llx cbHdr=%#llx\n", AddrModInfo.FlatPtr,
639 pszName, pszVersion, uImageAddr, cbImage, cbHdr));
640 rc = dbgDiggerDarwinAddModule(pThis, pUVM, uImageAddr, pszName, NULL);
641
642
643 /*
644 * Advance to the next kmod_info entry.
645 */
646 DBGFR3AddrFromFlat(pUVM, &AddrModInfo, f64Bit ? uMod.Info64.next : uMod.Info32.next);
647 }
648 }
649 else
650 Log(("OSXDig: Error reading the 'kmod' variable: %Rrc\n", rc));
651 }
652 else
653 Log(("OSXDig: Failed to locate the 'kmod' variable in mach_kernel.\n"));
654
655 pThis->fValid = true;
656 return VINF_SUCCESS;
657 }
658
659 return rc;
660}
661
662
663/**
664 * @copydoc DBGFOSREG::pfnProbe
665 */
666static DECLCALLBACK(bool) dbgDiggerDarwinProbe(PUVM pUVM, void *pvData)
667{
668 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
669
670 /*
671 * Look for a section + segment combo that normally only occures in
672 * mach_kernel. Follow it up with probing of the rest of the executable
673 * header. We must search a largish area because the more recent versions
674 * of darwin have random load address for security raisins.
675 */
676 static struct { uint64_t uStart, uEnd; } const s_aRanges[] =
677 {
678 /* 64-bit: */
679 { UINT64_C(0xffffff8000000000), UINT64_C(0xffffff81ffffffff), },
680
681 /* 32-bit - always search for this because of the hybrid 32-bit kernel
682 with cpu in long mode that darwin used for a number of versions. */
683 { UINT64_C(0x00001000), UINT64_C(0x0ffff000), }
684 };
685 for (unsigned iRange = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/) != CPUMMODE_LONG;
686 iRange < RT_ELEMENTS(s_aRanges);
687 iRange++)
688 {
689 DBGFADDRESS KernelAddr;
690 for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, s_aRanges[iRange].uStart);
691 KernelAddr.FlatPtr < s_aRanges[iRange].uEnd;
692 KernelAddr.FlatPtr += X86_PAGE_4K_SIZE)
693 {
694 static const uint8_t s_abNeedle[16 + 16] =
695 {
696 '_','_','t','e','x','t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::sectname */
697 '_','_','K','L','D', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::segname. */
698 };
699
700 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, s_aRanges[iRange].uEnd - KernelAddr.FlatPtr,
701 1, s_abNeedle, sizeof(s_abNeedle), &KernelAddr);
702 if (RT_FAILURE(rc))
703 break;
704 DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & X86_PAGE_4K_OFFSET_MASK);
705
706 /*
707 * Read the first page of the image and check the headers.
708 */
709 union
710 {
711 uint8_t ab[X86_PAGE_4K_SIZE];
712 mach_header_64_t Hdr64;
713 mach_header_32_t Hdr32;
714 } uBuf;
715 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, uBuf.ab, X86_PAGE_4K_SIZE);
716 if (RT_FAILURE(rc))
717 continue;
718 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
719 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
720 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
721 continue;
722 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
723 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
724 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
725 continue;
726 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
727 if (uBuf.Hdr32.filetype != MH_EXECUTE)
728 continue;
729 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
730 if (uBuf.Hdr32.ncmds > 256)
731 continue;
732 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
733 if (uBuf.Hdr32.sizeofcmds > X86_PAGE_4K_SIZE * 2 - sizeof(mach_header_64_t))
734 continue;
735
736 /* Seems good enough for now.
737
738 If the above causes false positives, check the segments and make
739 sure there is a kernel version string in the right one. */
740 pThis->AddrKernel = KernelAddr;
741
742 /*
743 * Finally, find the kernel version string.
744 */
745 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, 32*_1M, 1, RT_STR_TUPLE("Darwin Kernel Version"),
746 &pThis->AddrKernelVersion);
747 if (RT_FAILURE(rc))
748 DBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelVersion, 0);
749 return true;
750 }
751 }
752 return false;
753}
754
755
756/**
757 * @copydoc DBGFOSREG::pfnDestruct
758 */
759static DECLCALLBACK(void) dbgDiggerDarwinDestruct(PUVM pUVM, void *pvData)
760{
761
762}
763
764
765/**
766 * @copydoc DBGFOSREG::pfnConstruct
767 */
768static DECLCALLBACK(int) dbgDiggerDarwinConstruct(PUVM pUVM, void *pvData)
769{
770 return VINF_SUCCESS;
771}
772
773
774const DBGFOSREG g_DBGDiggerDarwin =
775{
776 /* .u32Magic = */ DBGFOSREG_MAGIC,
777 /* .fFlags = */ 0,
778 /* .cbData = */ sizeof(DBGDIGGERDARWIN),
779 /* .szName = */ "Darwin",
780 /* .pfnConstruct = */ dbgDiggerDarwinConstruct,
781 /* .pfnDestruct = */ dbgDiggerDarwinDestruct,
782 /* .pfnProbe = */ dbgDiggerDarwinProbe,
783 /* .pfnInit = */ dbgDiggerDarwinInit,
784 /* .pfnRefresh = */ dbgDiggerDarwinRefresh,
785 /* .pfnTerm = */ dbgDiggerDarwinTerm,
786 /* .pfnQueryVersion = */ dbgDiggerDarwinQueryVersion,
787 /* .pfnQueryInterface = */ dbgDiggerDarwinQueryInterface,
788 /* .u32EndMagic = */ DBGFOSREG_MAGIC
789};
790
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