VirtualBox

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

Last change on this file since 74442 was 73460, checked in by vboxsync, 6 years ago

IPRT,DBGF,Diggers: Moved DBGFRETURNTYPE and the unwind state structure to IPRT (dbg.h) in prep for debug module interface and more. Added stack unwind assist callback for the OS diggers so they can identify special stack frames and supply more info via the sure-register-value array and frame flags. Identify and decode NT/AMD64 trap frames.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.6 KB
Line 
1/* $Id: DBGPlugInDarwin.cpp 73460 2018-08-02 21:06:59Z vboxsync $ */
2/** @file
3 * DBGPlugInDarwin - Debugger and Guest OS Digger Plugin For Darwin / OS X.
4 */
5
6/*
7 * Copyright (C) 2008-2017 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 /** Set if 64-bit kernel, clear if 32-bit.
96 * Set during probing. */
97 bool f64Bit;
98 /** The address of an kernel version string (there are several).
99 * This is set during probing. */
100 DBGFADDRESS AddrKernelVersion;
101 /** Kernel base address.
102 * This is set during probing. */
103 DBGFADDRESS AddrKernel;
104
105 /** The kernel message log interface. */
106 DBGFOSIDMESG IDmesg;
107} DBGDIGGERDARWIN;
108/** Pointer to the linux guest OS digger instance data. */
109typedef DBGDIGGERDARWIN *PDBGDIGGERDARWIN;
110
111
112/*********************************************************************************************************************************
113* Defined Constants And Macros *
114*********************************************************************************************************************************/
115/** Validates a 32-bit darwin kernel address */
116#define OSX32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x00001000) && (Addr) < UINT32_C(0xfffff000))
117/** Validates a 64-bit darwin kernel address */
118#define OSX64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000))
119/** Validates a 32-bit or 64-bit darwin kernel address. */
120#define OSX_VALID_ADDRESS(a_f64Bits, a_Addr) \
121 ((a_f64Bits) ? OSX64_VALID_ADDRESS(a_Addr) : OSX32_VALID_ADDRESS(a_Addr))
122
123/** AppleOsX on little endian ASCII systems. */
124#define DIG_DARWIN_MOD_TAG UINT64_C(0x58734f656c707041)
125
126
127/*********************************************************************************************************************************
128* Internal Functions *
129*********************************************************************************************************************************/
130static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, void *pvData);
131
132
133
134/**
135 * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
136 */
137static DECLCALLBACK(int) dbgDiggerDarwinIDmsg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, uint32_t fFlags, uint32_t cMessages,
138 char *pszBuf, size_t cbBuf, size_t *pcbActual)
139{
140 RT_NOREF1(fFlags);
141 PDBGDIGGERDARWIN pData = RT_FROM_MEMBER(pThis, DBGDIGGERDARWIN, IDmesg);
142
143 if (cMessages < 1)
144 return VERR_INVALID_PARAMETER;
145
146 /*
147 * The 'msgbufp' variable points to a struct msgbuf (bsd/kern/subr_log.c).
148 */
149 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
150 RTDBGMOD hMod;
151 int rc = RTDbgAsModuleByName(hAs, "mach_kernel", 0, &hMod);
152 if (RT_FAILURE(rc))
153 return VERR_NOT_FOUND;
154 RTDbgAsRelease(hAs);
155
156 DBGFADDRESS Addr;
157 RTGCPTR GCPtrMsgBufP = 0;
158 RTDBGSYMBOL SymInfo;
159 rc = RTDbgModSymbolByName(hMod, "_msgbufp", &SymInfo);
160 if (RT_SUCCESS(rc))
161 {
162 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, SymInfo.Value + pData->AddrKernel.FlatPtr),
163 &GCPtrMsgBufP, pData->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t));
164 if (RT_FAILURE(rc))
165 {
166 Log(("dbgDiggerDarwinIDmsg_QueryKernelLog: failed to read _msgbufp at %RGv: %Rrc\n", Addr.FlatPtr, rc));
167 return VERR_NOT_FOUND;
168 }
169 if (!OSX_VALID_ADDRESS(pData->f64Bit, GCPtrMsgBufP))
170 {
171 Log(("dbgDiggerDarwinIDmsg_QueryKernelLog: Invalid address for _msgbufp: %RGv\n", GCPtrMsgBufP));
172 return VERR_NOT_FOUND;
173 }
174 }
175 else
176 {
177 rc = RTDbgModSymbolByName(hMod, "_msgbuf", &SymInfo);
178 if (RT_FAILURE(rc))
179 {
180 Log(("dbgDiggerDarwinIDmsg_QueryKernelLog: failed to find _msgbufp and _msgbuf: %Rrc\n", rc));
181 return VERR_NOT_FOUND;
182 }
183 GCPtrMsgBufP = SymInfo.Value + pData->AddrKernel.FlatPtr;
184 if (!OSX_VALID_ADDRESS(pData->f64Bit, GCPtrMsgBufP))
185 {
186 Log(("dbgDiggerDarwinIDmsg_QueryKernelLog: Invalid address for _msgbuf: %RGv\n", GCPtrMsgBufP));
187 return VERR_NOT_FOUND;
188 }
189 }
190
191 /*
192 * Read the msgbuf structure.
193 */
194 struct
195 {
196 uint32_t msg_magic;
197 uint32_t msg_size;
198 uint32_t msg_bufx;
199 uint32_t msg_bufr;
200 uint64_t msg_bufc; /**< Size depends on windows size. */
201 } MsgBuf;
202 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, GCPtrMsgBufP),
203 &MsgBuf, sizeof(MsgBuf) - (pData->f64Bit ? 0 : sizeof(uint32_t)) );
204 if (RT_FAILURE(rc))
205 {
206 Log(("dbgDiggerDarwinIDmsg_QueryKernelLog: failed to read msgbuf struct at %RGv: %Rrc\n", Addr.FlatPtr, rc));
207 return VERR_NOT_FOUND;
208 }
209 if (!pData->f64Bit)
210 MsgBuf.msg_bufc &= UINT32_MAX;
211
212 /*
213 * Validate the structure.
214 */
215 if ( MsgBuf.msg_magic != UINT32_C(0x63061)
216 || MsgBuf.msg_size < UINT32_C(4096)
217 || MsgBuf.msg_size > 16*_1M
218 || MsgBuf.msg_bufx > MsgBuf.msg_size
219 || MsgBuf.msg_bufr > MsgBuf.msg_size
220 || !OSX_VALID_ADDRESS(pData->f64Bit, MsgBuf.msg_bufc) )
221 {
222 Log(("dbgDiggerDarwinIDmsg_QueryKernelLog: Invalid MsgBuf data: magic=%#x size=%#x bufx=%#x bufr=%#x bufc=%RGv\n",
223 MsgBuf.msg_magic, MsgBuf.msg_size, MsgBuf.msg_bufx, MsgBuf.msg_bufr, MsgBuf.msg_bufc));
224 return VERR_INVALID_STATE;
225 }
226
227 /*
228 * Read the buffer.
229 */
230 char *pchMsgBuf = (char *)RTMemAlloc(MsgBuf.msg_size);
231 if (!pchMsgBuf)
232 {
233 Log(("dbgDiggerDarwinIDmsg_QueryKernelLog: Failed to allocate %#x bytes of memory for the log buffer\n",
234 MsgBuf.msg_size));
235 return VERR_INVALID_STATE;
236 }
237 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &Addr, MsgBuf.msg_bufc), pchMsgBuf, MsgBuf.msg_size);
238 if (RT_SUCCESS(rc))
239 {
240 /*
241 * Copy it out raw.
242 */
243 uint32_t offDst = 0;
244 if (MsgBuf.msg_bufr < MsgBuf.msg_bufx)
245 {
246 /* Single chunk between the read and write offsets. */
247 uint32_t cbToCopy = MsgBuf.msg_bufx - MsgBuf.msg_bufr;
248 if (cbToCopy < cbBuf)
249 {
250 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbToCopy);
251 pszBuf[cbToCopy] = '\0';
252 rc = VINF_SUCCESS;
253 }
254 else
255 {
256 if (cbBuf)
257 {
258 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbBuf - 1);
259 pszBuf[cbBuf - 1] = '\0';
260 }
261 rc = VERR_BUFFER_OVERFLOW;
262 }
263 offDst = cbToCopy + 1;
264 }
265 else
266 {
267 /* Two chunks, read offset to end, start to write offset. */
268 uint32_t cbFirst = MsgBuf.msg_size - MsgBuf.msg_bufr;
269 uint32_t cbSecond = MsgBuf.msg_bufx;
270 if (cbFirst + cbSecond < cbBuf)
271 {
272 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbFirst);
273 memcpy(&pszBuf[cbFirst], pchMsgBuf, cbSecond);
274 offDst = cbFirst + cbSecond;
275 pszBuf[offDst++] = '\0';
276 rc = VINF_SUCCESS;
277 }
278 else
279 {
280 offDst = cbFirst + cbSecond + 1;
281 if (cbFirst < cbBuf)
282 {
283 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbFirst);
284 memcpy(&pszBuf[cbFirst], pchMsgBuf, cbBuf - cbFirst);
285 pszBuf[cbBuf - 1] = '\0';
286 }
287 else if (cbBuf)
288 {
289 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbBuf - 1);
290 pszBuf[cbBuf - 1] = '\0';
291 }
292 rc = VERR_BUFFER_OVERFLOW;
293 }
294 }
295
296 if (pcbActual)
297 *pcbActual = offDst;
298 }
299 else
300 Log(("dbgDiggerDarwinIDmsg_QueryKernelLog: Error reading %#x bytes at %RGv: %Rrc\n", MsgBuf.msg_size, MsgBuf.msg_bufc, rc));
301 RTMemFree(pchMsgBuf);
302 return rc;
303}
304
305
306/**
307 * @copydoc DBGFOSREG::pfnStackUnwindAssist
308 */
309static DECLCALLBACK(int) dbgDiggerDarwinStackUnwindAssist(PUVM pUVM, void *pvData, VMCPUID idCpu, PDBGFSTACKFRAME pFrame,
310 PRTDBGUNWINDSTATE pState, PCCPUMCTX pInitialCtx, RTDBGAS hAs,
311 uint64_t *puScratch)
312{
313 RT_NOREF(pUVM, pvData, idCpu, pFrame, pState, pInitialCtx, hAs, puScratch);
314 return VINF_SUCCESS;
315}
316
317
318/**
319 * @copydoc DBGFOSREG::pfnQueryInterface
320 */
321static DECLCALLBACK(void *) dbgDiggerDarwinQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
322{
323 RT_NOREF1(pUVM);
324 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
325 switch (enmIf)
326 {
327 case DBGFOSINTERFACE_DMESG:
328 return &pThis->IDmesg;
329
330 default:
331 return NULL;
332 }
333}
334
335
336/**
337 * @copydoc DBGFOSREG::pfnQueryVersion
338 */
339static DECLCALLBACK(int) dbgDiggerDarwinQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
340{
341 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
342 Assert(pThis->fValid);
343
344 /*
345 * It's all in the linux banner.
346 */
347 int rc = DBGFR3MemReadString(pUVM, 0, &pThis->AddrKernelVersion, pszVersion, cchVersion);
348 if (RT_SUCCESS(rc))
349 {
350 char *pszEnd = RTStrEnd(pszVersion, cchVersion);
351 AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
352 while ( pszEnd > pszVersion
353 && RT_C_IS_SPACE(pszEnd[-1]))
354 pszEnd--;
355 *pszEnd = '\0';
356 }
357 else
358 RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemRead -> %Rrc", rc);
359
360 return rc;
361}
362
363
364/**
365 * @copydoc DBGFOSREG::pfnTerm
366 */
367static DECLCALLBACK(void) dbgDiggerDarwinTerm(PUVM pUVM, void *pvData)
368{
369 RT_NOREF1(pUVM);
370 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
371
372 pThis->fValid = false;
373}
374
375
376/**
377 * @copydoc DBGFOSREG::pfnRefresh
378 */
379static DECLCALLBACK(int) dbgDiggerDarwinRefresh(PUVM pUVM, void *pvData)
380{
381 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
382 NOREF(pThis);
383 Assert(pThis->fValid);
384
385 /*
386 * For now we'll flush and reload everything.
387 */
388 dbgDiggerDarwinTerm(pUVM, pvData);
389 return dbgDiggerDarwinInit(pUVM, pvData);
390}
391
392
393/**
394 * Helper function that validates a segment (or section) name.
395 *
396 * @returns true if valid, false if not.
397 * @param pszName The name string.
398 * @param cbName The size of the string, including terminator.
399 */
400static bool dbgDiggerDarwinIsValidSegOrSectName(const char *pszName, size_t cbName)
401{
402 /* ascii chars */
403 char ch;
404 size_t off = 0;
405 while (off < cbName && (ch = pszName[off]))
406 {
407 if (RT_C_IS_CNTRL(ch) || ch >= 127)
408 return false;
409 off++;
410 }
411
412 /* Not empty nor 100% full. */
413 if (off == 0 || off == cbName)
414 return false;
415
416 /* remainder should be zeros. */
417 while (off < cbName)
418 {
419 if (pszName[off])
420 return false;
421 off++;
422 }
423
424 return true;
425}
426
427
428static int dbgDiggerDarwinAddModule(PDBGDIGGERDARWIN pThis, PUVM pUVM, uint64_t uModAddr, const char *pszName, bool *pf64Bit)
429{
430 RT_NOREF1(pThis);
431 union
432 {
433 uint8_t ab[2 * X86_PAGE_4K_SIZE];
434 mach_header_64_t Hdr64;
435 mach_header_32_t Hdr32;
436 } uBuf;
437
438 /* Read the first page of the image. */
439 DBGFADDRESS ModAddr;
440 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr), uBuf.ab, X86_PAGE_4K_SIZE);
441 if (RT_FAILURE(rc))
442 return rc;
443
444 /* Validate the header. */
445 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
446 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
447 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
448 return VERR_INVALID_EXE_SIGNATURE;
449 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
450 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
451 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
452 return VERR_LDR_ARCH_MISMATCH;
453 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
454 if ( uBuf.Hdr32.filetype != MH_EXECUTE
455 && uBuf.Hdr32.filetype != (f64Bit ? MH_KEXT_BUNDLE : MH_OBJECT))
456 return VERR_BAD_EXE_FORMAT;
457 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
458 if (uBuf.Hdr32.ncmds > 256)
459 return VERR_BAD_EXE_FORMAT;
460 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
461 if (uBuf.Hdr32.sizeofcmds > X86_PAGE_4K_SIZE * 2 - sizeof(mach_header_64_t))
462 return VERR_BAD_EXE_FORMAT;
463
464 /* Do we need to read a 2nd page to get all the load commands? If so, do it. */
465 if (uBuf.Hdr32.sizeofcmds + (f64Bit ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t)) > X86_PAGE_4K_SIZE)
466 {
467 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr + X86_PAGE_4K_SIZE),
468 &uBuf.ab[X86_PAGE_4K_SIZE], X86_PAGE_4K_SIZE);
469 if (RT_FAILURE(rc))
470 return rc;
471 }
472
473 /*
474 * Process the load commands.
475 */
476 RTDBGSEGMENT aSegs[24];
477 uint32_t cSegs = 0;
478 RTUUID Uuid = RTUUID_INITIALIZE_NULL;
479 uint32_t cLeft = uBuf.Hdr32.ncmds;
480 uint32_t cbLeft = uBuf.Hdr32.sizeofcmds;
481 union
482 {
483 uint8_t const *pb;
484 load_command_t const *pGenric;
485 segment_command_32_t const *pSeg32;
486 segment_command_64_t const *pSeg64;
487 section_32_t const *pSect32;
488 section_64_t const *pSect64;
489 symtab_command_t const *pSymTab;
490 uuid_command_t const *pUuid;
491 } uLCmd;
492 uLCmd.pb = &uBuf.ab[f64Bit ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t)];
493
494 while (cLeft-- > 0)
495 {
496 uint32_t const cbCmd = uLCmd.pGenric->cmdsize;
497 if (cbCmd > cbLeft || cbCmd < sizeof(load_command_t))
498 return VERR_BAD_EXE_FORMAT;
499
500 switch (uLCmd.pGenric->cmd)
501 {
502 case LC_SEGMENT_32:
503 if (cbCmd != sizeof(segment_command_32_t) + uLCmd.pSeg32->nsects * sizeof(section_32_t))
504 return VERR_BAD_EXE_FORMAT;
505 if (!dbgDiggerDarwinIsValidSegOrSectName(uLCmd.pSeg32->segname, sizeof(uLCmd.pSeg32->segname)))
506 return VERR_INVALID_NAME;
507 if (!strcmp(uLCmd.pSeg32->segname, "__LINKEDIT"))
508 break; /* This usually is discarded or not loaded at all. */
509 if (cSegs >= RT_ELEMENTS(aSegs))
510 return VERR_BUFFER_OVERFLOW;
511 aSegs[cSegs].Address = uLCmd.pSeg32->vmaddr;
512 aSegs[cSegs].uRva = uLCmd.pSeg32->vmaddr - uModAddr;
513 aSegs[cSegs].cb = uLCmd.pSeg32->vmsize;
514 aSegs[cSegs].fFlags = uLCmd.pSeg32->flags; /* Abusing the flags field here... */
515 aSegs[cSegs].iSeg = cSegs;
516 AssertCompile(RTDBG_SEGMENT_NAME_LENGTH > sizeof(uLCmd.pSeg32->segname));
517 strcpy(aSegs[cSegs].szName, uLCmd.pSeg32->segname);
518 cSegs++;
519 break;
520
521 case LC_SEGMENT_64:
522 if (cbCmd != sizeof(segment_command_64_t) + uLCmd.pSeg64->nsects * sizeof(section_64_t))
523 return VERR_BAD_EXE_FORMAT;
524 if (!dbgDiggerDarwinIsValidSegOrSectName(uLCmd.pSeg64->segname, sizeof(uLCmd.pSeg64->segname)))
525 return VERR_INVALID_NAME;
526 if (!strcmp(uLCmd.pSeg64->segname, "__LINKEDIT"))
527 break; /* This usually is discarded or not loaded at all. */
528 if (cSegs >= RT_ELEMENTS(aSegs))
529 return VERR_BUFFER_OVERFLOW;
530 aSegs[cSegs].Address = uLCmd.pSeg64->vmaddr;
531 aSegs[cSegs].uRva = uLCmd.pSeg64->vmaddr - uModAddr;
532 aSegs[cSegs].cb = uLCmd.pSeg64->vmsize;
533 aSegs[cSegs].fFlags = uLCmd.pSeg64->flags; /* Abusing the flags field here... */
534 aSegs[cSegs].iSeg = cSegs;
535 AssertCompile(RTDBG_SEGMENT_NAME_LENGTH > sizeof(uLCmd.pSeg64->segname));
536 strcpy(aSegs[cSegs].szName, uLCmd.pSeg64->segname);
537 cSegs++;
538 break;
539
540 case LC_UUID:
541 if (cbCmd != sizeof(uuid_command_t))
542 return VERR_BAD_EXE_FORMAT;
543 if (RTUuidIsNull((PCRTUUID)&uLCmd.pUuid->uuid[0]))
544 return VERR_BAD_EXE_FORMAT;
545 memcpy(&Uuid, &uLCmd.pUuid->uuid[0], sizeof(uLCmd.pUuid->uuid));
546 break;
547
548 default:
549 /* Current known max plus a lot of slack. */
550 if (uLCmd.pGenric->cmd > LC_DYLIB_CODE_SIGN_DRS + 32)
551 return VERR_BAD_EXE_FORMAT;
552 break;
553 }
554
555 /* next */
556 cbLeft -= cbCmd;
557 uLCmd.pb += cbCmd;
558 }
559
560 if (cbLeft != 0)
561 return VERR_BAD_EXE_FORMAT;
562
563 /*
564 * Some post processing checks.
565 */
566 uint32_t iSeg;
567 for (iSeg = 0; iSeg < cSegs; iSeg++)
568 if (aSegs[iSeg].Address == uModAddr)
569 break;
570 if (iSeg >= cSegs)
571 return VERR_ADDRESS_CONFLICT;
572
573 /*
574 * Create a debug module.
575 */
576 RTDBGMOD hMod;
577 rc = RTDbgModCreateFromMachOImage(&hMod, pszName, NULL, f64Bit ? RTLDRARCH_AMD64 : RTLDRARCH_X86_32, 0 /*cbImage*/,
578 cSegs, aSegs, &Uuid, DBGFR3AsGetConfig(pUVM), RTDBGMOD_F_NOT_DEFERRED);
579
580 if (RT_FAILURE(rc))
581 {
582 /*
583 * Final fallback is a container module.
584 */
585 rc = RTDbgModCreate(&hMod, pszName, 0, 0);
586 if (RT_FAILURE(rc))
587 return rc;
588
589 uint64_t uRvaNext = 0;
590 for (iSeg = 0; iSeg < cSegs && RT_SUCCESS(rc); iSeg++)
591 {
592 if ( aSegs[iSeg].uRva > uRvaNext
593 && aSegs[iSeg].uRva - uRvaNext < _1M)
594 uRvaNext = aSegs[iSeg].uRva;
595 rc = RTDbgModSegmentAdd(hMod, aSegs[iSeg].uRva, aSegs[iSeg].cb, aSegs[iSeg].szName, 0, NULL);
596 if (aSegs[iSeg].cb > 0 && RT_SUCCESS(rc))
597 {
598 char szTmp[RTDBG_SEGMENT_NAME_LENGTH + sizeof("_start")];
599 strcat(strcpy(szTmp, aSegs[iSeg].szName), "_start");
600 rc = RTDbgModSymbolAdd(hMod, szTmp, iSeg, 0 /*uRva*/, 0 /*cb*/, 0 /*fFlags*/, NULL);
601 }
602 uRvaNext += aSegs[iSeg].cb;
603 }
604
605 if (RT_FAILURE(rc))
606 {
607 RTDbgModRelease(hMod);
608 return rc;
609 }
610 }
611
612 /* Tag the module. */
613 rc = RTDbgModSetTag(hMod, DIG_DARWIN_MOD_TAG);
614 AssertRC(rc);
615
616 /*
617 * Link the module.
618 */
619 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
620 if (hAs != NIL_RTDBGAS)
621 {
622 //uint64_t uRvaNext = 0; - what was this?
623 uint32_t cLinked = 0;
624 iSeg = cSegs;
625 while (iSeg-- > 0) /* HACK: Map in reverse order to avoid replacing __TEXT. */
626 if (aSegs[iSeg].cb)
627 {
628 /* Find matching segment in the debug module. */
629 uint32_t iDbgSeg = 0;
630 while (iDbgSeg < cSegs)
631 {
632 RTDBGSEGMENT SegInfo;
633 int rc3 = RTDbgModSegmentByIndex(hMod, iDbgSeg, &SegInfo);
634 if (RT_SUCCESS(rc3) && !strcmp(SegInfo.szName, aSegs[iSeg].szName))
635 break;
636 iDbgSeg++;
637 }
638 AssertMsgStmt(iDbgSeg < cSegs, ("%s\n", aSegs[iSeg].szName), continue);
639
640 /* Map it. */
641 int rc2 = RTDbgAsModuleLinkSeg(hAs, hMod, iDbgSeg, aSegs[iSeg].Address, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
642 if (RT_SUCCESS(rc2))
643 cLinked++;
644 else if (RT_SUCCESS(rc))
645 rc = rc2;
646 }
647 if (RT_FAILURE(rc) && cLinked != 0)
648 rc = -rc;
649 }
650 else
651 rc = VERR_INTERNAL_ERROR;
652
653 RTDbgModRelease(hMod);
654 RTDbgAsRelease(hAs);
655
656 if (pf64Bit)
657 *pf64Bit = f64Bit;
658 return rc;
659}
660
661
662static bool dbgDiggerDarwinIsValidName(const char *pszName)
663{
664 char ch;
665 while ((ch = *pszName++) != '\0')
666 {
667 if (ch < 0x20 || ch >= 127)
668 return false;
669 }
670 return true;
671}
672
673
674static bool dbgDiggerDarwinIsValidVersion(const char *pszVersion)
675{
676 char ch;
677 while ((ch = *pszVersion++) != '\0')
678 {
679 if (ch < 0x20 || ch >= 127)
680 return false;
681 }
682 return true;
683}
684
685
686/**
687 * @copydoc DBGFOSREG::pfnInit
688 */
689static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, void *pvData)
690{
691 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
692 Assert(!pThis->fValid);
693
694 /*
695 * Add the kernel module.
696 */
697 bool f64Bit;
698 int rc = dbgDiggerDarwinAddModule(pThis, pUVM, pThis->AddrKernel.FlatPtr, "mach_kernel", &f64Bit);
699 if (RT_SUCCESS(rc))
700 {
701 /*
702 * The list of modules can be found at the 'kmod' symbol, that means
703 * that we currently require some kind of symbol file for the kernel
704 * to be loaded at this point.
705 *
706 * Note! Could also use the 'gLoadedKextSummaries', but I don't think
707 * it's any easier to find without any kernel map than 'kmod'.
708 */
709 RTDBGSYMBOL SymInfo;
710 rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "mach_kernel!kmod", &SymInfo, NULL);
711 if (RT_FAILURE(rc))
712 rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "mach_kernel!_kmod", &SymInfo, NULL);
713 if (RT_SUCCESS(rc))
714 {
715 DBGFADDRESS AddrModInfo;
716 DBGFR3AddrFromFlat(pUVM, &AddrModInfo, SymInfo.Value);
717
718 /* Read the variable. */
719 RTUINT64U uKmodValue = { 0 };
720 if (f64Bit)
721 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrModInfo, &uKmodValue.u, sizeof(uKmodValue.u));
722 else
723 rc = DBGFR3MemRead (pUVM, 0 /*idCpu*/, &AddrModInfo, &uKmodValue.s.Lo, sizeof(uKmodValue.s.Lo));
724 if (RT_SUCCESS(rc))
725 {
726 DBGFR3AddrFromFlat(pUVM, &AddrModInfo, uKmodValue.u);
727
728 /* Walk the list of modules. */
729 uint32_t cIterations = 0;
730 while (AddrModInfo.FlatPtr != 0)
731 {
732 /* Some extra loop conditions... */
733 if (!OSX_VALID_ADDRESS(f64Bit, AddrModInfo.FlatPtr))
734 {
735 Log(("OSXDig: Invalid kmod_info pointer: %RGv\n", AddrModInfo.FlatPtr));
736 break;
737 }
738 if (AddrModInfo.FlatPtr == uKmodValue.u && cIterations != 0)
739 {
740 Log(("OSXDig: kmod_info list looped back to the start.\n"));
741 break;
742 }
743 if (cIterations++ >= 2048)
744 {
745 Log(("OSXDig: Too many mod_info loops (%u)\n", cIterations));
746 break;
747 }
748
749 /*
750 * Read the kmod_info_t structure.
751 */
752 union
753 {
754 OSX64_kmod_info_t Info64;
755 OSX32_kmod_info_t Info32;
756 } uMod;
757 RT_ZERO(uMod);
758 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrModInfo, &uMod,
759 f64Bit ? sizeof(uMod.Info64) : sizeof(uMod.Info32));
760 if (RT_FAILURE(rc))
761 {
762 Log(("OSXDig: Error reading kmod_info structure at %RGv: %Rrc\n", AddrModInfo.FlatPtr, rc));
763 break;
764 }
765
766 /*
767 * Validate the kmod_info_t structure.
768 */
769 int32_t iInfoVer = f64Bit ? uMod.Info64.info_version : uMod.Info32.info_version;
770 if (iInfoVer != OSX_KMOD_INFO_VERSION)
771 {
772 Log(("OSXDig: kmod_info @%RGv: Bad info_version %d\n", AddrModInfo.FlatPtr, iInfoVer));
773 break;
774 }
775
776 const char *pszName = f64Bit ? uMod.Info64.name : uMod.Info32.name;
777 if ( !*pszName
778 || !RTStrEnd(pszName, sizeof(uMod.Info64.name))
779 || !dbgDiggerDarwinIsValidName(pszName) )
780 {
781 Log(("OSXDig: kmod_info @%RGv: Bad name '%.*s'\n", AddrModInfo.FlatPtr,
782 sizeof(uMod.Info64.name), pszName));
783 break;
784 }
785
786 const char *pszVersion = f64Bit ? uMod.Info64.version : uMod.Info32.version;
787 if ( !RTStrEnd(pszVersion, sizeof(uMod.Info64.version))
788 || !dbgDiggerDarwinIsValidVersion(pszVersion) )
789 {
790 Log(("OSXDig: kmod_info @%RGv: Bad version '%.*s'\n", AddrModInfo.FlatPtr,
791 sizeof(uMod.Info64.version), pszVersion));
792 break;
793 }
794
795 int32_t cRefs = f64Bit ? uMod.Info64.reference_count : uMod.Info32.reference_count;
796 if (cRefs < -1 || cRefs > 16384)
797 {
798 Log(("OSXDig: kmod_info @%RGv: Bad reference_count %d\n", AddrModInfo.FlatPtr, cRefs));
799 break;
800 }
801
802 uint64_t uImageAddr = f64Bit ? uMod.Info64.address : uMod.Info32.address;
803 if (!OSX_VALID_ADDRESS(f64Bit, uImageAddr))
804 {
805 Log(("OSXDig: kmod_info @%RGv: Bad address %#llx\n", AddrModInfo.FlatPtr, uImageAddr));
806 break;
807 }
808
809 uint64_t cbImage = f64Bit ? uMod.Info64.size : uMod.Info32.size;
810 if (cbImage > 64U*_1M)
811 {
812 Log(("OSXDig: kmod_info @%RGv: Bad size %#llx\n", AddrModInfo.FlatPtr, cbImage));
813 break;
814 }
815
816 uint64_t cbHdr = f64Bit ? uMod.Info64.hdr_size : uMod.Info32.hdr_size;
817 if (cbHdr > 16U*_1M)
818 {
819 Log(("OSXDig: kmod_info @%RGv: Bad hdr_size %#llx\n", AddrModInfo.FlatPtr, cbHdr));
820 break;
821 }
822
823 uint64_t uStartAddr = f64Bit ? uMod.Info64.start : uMod.Info32.start;
824 if (!uStartAddr && !OSX_VALID_ADDRESS(f64Bit, uStartAddr))
825 {
826 Log(("OSXDig: kmod_info @%RGv: Bad start function %#llx\n", AddrModInfo.FlatPtr, uStartAddr));
827 break;
828 }
829
830 uint64_t uStopAddr = f64Bit ? uMod.Info64.stop : uMod.Info32.stop;
831 if (!uStopAddr && !OSX_VALID_ADDRESS(f64Bit, uStopAddr))
832 {
833 Log(("OSXDig: kmod_info @%RGv: Bad stop function %#llx\n", AddrModInfo.FlatPtr, uStopAddr));
834 break;
835 }
836
837 /*
838 * Try add the module.
839 */
840 Log(("OSXDig: kmod_info @%RGv: '%s' ver '%s', image @%#llx LB %#llx cbHdr=%#llx\n", AddrModInfo.FlatPtr,
841 pszName, pszVersion, uImageAddr, cbImage, cbHdr));
842 rc = dbgDiggerDarwinAddModule(pThis, pUVM, uImageAddr, pszName, NULL);
843
844
845 /*
846 * Advance to the next kmod_info entry.
847 */
848 DBGFR3AddrFromFlat(pUVM, &AddrModInfo, f64Bit ? uMod.Info64.next : uMod.Info32.next);
849 }
850 }
851 else
852 Log(("OSXDig: Error reading the 'kmod' variable: %Rrc\n", rc));
853 }
854 else
855 Log(("OSXDig: Failed to locate the 'kmod' variable in mach_kernel.\n"));
856
857 pThis->fValid = true;
858 return VINF_SUCCESS;
859 }
860
861 return rc;
862}
863
864
865/**
866 * @copydoc DBGFOSREG::pfnProbe
867 */
868static DECLCALLBACK(bool) dbgDiggerDarwinProbe(PUVM pUVM, void *pvData)
869{
870 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
871
872 /*
873 * Look for a section + segment combo that normally only occures in
874 * mach_kernel. Follow it up with probing of the rest of the executable
875 * header. We must search a largish area because the more recent versions
876 * of darwin have random load address for security raisins.
877 */
878 static struct { uint64_t uStart, uEnd; } const s_aRanges[] =
879 {
880 /* 64-bit: */
881 { UINT64_C(0xffffff8000000000), UINT64_C(0xffffff81ffffffff), },
882
883 /* 32-bit - always search for this because of the hybrid 32-bit kernel
884 with cpu in long mode that darwin used for a number of versions. */
885 { UINT64_C(0x00001000), UINT64_C(0x0ffff000), }
886 };
887 for (unsigned iRange = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/) != CPUMMODE_LONG;
888 iRange < RT_ELEMENTS(s_aRanges);
889 iRange++)
890 {
891 DBGFADDRESS KernelAddr;
892 for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, s_aRanges[iRange].uStart);
893 KernelAddr.FlatPtr < s_aRanges[iRange].uEnd;
894 KernelAddr.FlatPtr += X86_PAGE_4K_SIZE)
895 {
896 static const uint8_t s_abNeedle[16 + 16] =
897 {
898 '_','_','t','e','x','t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::sectname */
899 '_','_','K','L','D', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::segname. */
900 };
901
902 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, s_aRanges[iRange].uEnd - KernelAddr.FlatPtr,
903 1, s_abNeedle, sizeof(s_abNeedle), &KernelAddr);
904 if (RT_FAILURE(rc))
905 break;
906 DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & X86_PAGE_4K_OFFSET_MASK);
907
908 /*
909 * Read the first page of the image and check the headers.
910 */
911 union
912 {
913 uint8_t ab[X86_PAGE_4K_SIZE];
914 mach_header_64_t Hdr64;
915 mach_header_32_t Hdr32;
916 } uBuf;
917 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, uBuf.ab, X86_PAGE_4K_SIZE);
918 if (RT_FAILURE(rc))
919 continue;
920 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
921 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
922 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
923 continue;
924 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
925 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
926 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
927 continue;
928 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
929 if (uBuf.Hdr32.filetype != MH_EXECUTE)
930 continue;
931 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
932 if (uBuf.Hdr32.ncmds > 256)
933 continue;
934 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
935 if (uBuf.Hdr32.sizeofcmds > X86_PAGE_4K_SIZE * 2 - sizeof(mach_header_64_t))
936 continue;
937
938 /* Seems good enough for now.
939
940 If the above causes false positives, check the segments and make
941 sure there is a kernel version string in the right one. */
942 pThis->AddrKernel = KernelAddr;
943 pThis->f64Bit = f64Bit;
944
945 /*
946 * Finally, find the kernel version string.
947 */
948 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, 32*_1M, 1, RT_STR_TUPLE("Darwin Kernel Version"),
949 &pThis->AddrKernelVersion);
950 if (RT_FAILURE(rc))
951 DBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelVersion, 0);
952 return true;
953 }
954 }
955 return false;
956}
957
958
959/**
960 * @copydoc DBGFOSREG::pfnDestruct
961 */
962static DECLCALLBACK(void) dbgDiggerDarwinDestruct(PUVM pUVM, void *pvData)
963{
964 RT_NOREF2(pUVM, pvData);
965
966}
967
968
969/**
970 * @copydoc DBGFOSREG::pfnConstruct
971 */
972static DECLCALLBACK(int) dbgDiggerDarwinConstruct(PUVM pUVM, void *pvData)
973{
974 RT_NOREF1(pUVM);
975 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
976
977 pThis->IDmesg.u32Magic = DBGFOSIDMESG_MAGIC;
978 pThis->IDmesg.pfnQueryKernelLog = dbgDiggerDarwinIDmsg_QueryKernelLog;
979 pThis->IDmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
980
981 return VINF_SUCCESS;
982}
983
984
985const DBGFOSREG g_DBGDiggerDarwin =
986{
987 /* .u32Magic = */ DBGFOSREG_MAGIC,
988 /* .fFlags = */ 0,
989 /* .cbData = */ sizeof(DBGDIGGERDARWIN),
990 /* .szName = */ "Darwin",
991 /* .pfnConstruct = */ dbgDiggerDarwinConstruct,
992 /* .pfnDestruct = */ dbgDiggerDarwinDestruct,
993 /* .pfnProbe = */ dbgDiggerDarwinProbe,
994 /* .pfnInit = */ dbgDiggerDarwinInit,
995 /* .pfnRefresh = */ dbgDiggerDarwinRefresh,
996 /* .pfnTerm = */ dbgDiggerDarwinTerm,
997 /* .pfnQueryVersion = */ dbgDiggerDarwinQueryVersion,
998 /* .pfnQueryInterface = */ dbgDiggerDarwinQueryInterface,
999 /* .pfnStackUnwindAssist = */ dbgDiggerDarwinStackUnwindAssist,
1000 /* .u32EndMagic = */ DBGFOSREG_MAGIC
1001};
1002
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