VirtualBox

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

Last change on this file since 98123 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.6 KB
Line 
1/* $Id: DBGPlugInDarwin.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * DBGPlugInDarwin - Debugger and Guest OS Digger Plugin For Darwin / OS X.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DBGF /// @todo add new log group.
33#include "DBGPlugIns.h"
34#include <VBox/vmm/vmmr3vtable.h>
35#include <iprt/err.h>
36#include <iprt/mem.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include <iprt/uuid.h>
40#include <iprt/ctype.h>
41#include <iprt/formats/mach-o.h>
42
43#undef LogRel2
44#define LogRel2 LogRel
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50
51/** @name Internal Darwin structures
52 * @{ */
53
54/**
55 * 32-bit darwin kernel module info structure (kmod_info_t).
56 */
57typedef struct OSX32_kmod_info
58{
59 uint32_t next;
60 int32_t info_version;
61 uint32_t id;
62 char name[64];
63 char version[64];
64 int32_t reference_count;
65 uint32_t reference_list; /**< Points to kmod_reference_t. */
66 uint32_t address; /**< Where in memory the kext is loaded. */
67 uint32_t size;
68 uint32_t hdr_size;
69 uint32_t start; /**< Address of kmod_start_func_t. */
70 uint32_t stop; /**< Address of kmod_stop_func_t. */
71} OSX32_kmod_info_t;
72
73/**
74 * 32-bit darwin kernel module info structure (kmod_info_t).
75 */
76#pragma pack(1)
77typedef struct OSX64_kmod_info
78{
79 uint64_t next;
80 int32_t info_version;
81 uint32_t id;
82 char name[64];
83 char version[64];
84 int32_t reference_count;
85 uint64_t reference_list; /**< Points to kmod_reference_t. Misaligned, duh. */
86 uint64_t address; /**< Where in memory the kext is loaded. */
87 uint64_t size;
88 uint64_t hdr_size;
89 uint64_t start; /**< Address of kmod_start_func_t. */
90 uint64_t stop; /**< Address of kmod_stop_func_t. */
91} OSX64_kmod_info_t;
92#pragma pack()
93
94/** The value of the info_version field. */
95#define OSX_KMOD_INFO_VERSION INT32_C(1)
96
97/** @} */
98
99
100/**
101 * Linux guest OS digger instance data.
102 */
103typedef struct DBGDIGGERDARWIN
104{
105 /** Whether the information is valid or not.
106 * (For fending off illegal interface method calls.) */
107 bool fValid;
108
109 /** Set if 64-bit kernel, clear if 32-bit.
110 * Set during probing. */
111 bool f64Bit;
112 /** The address of an kernel version string (there are several).
113 * This is set during probing. */
114 DBGFADDRESS AddrKernelVersion;
115 /** Kernel base address.
116 * This is set during probing. */
117 DBGFADDRESS AddrKernel;
118
119 /** The kernel message log interface. */
120 DBGFOSIDMESG IDmesg;
121} DBGDIGGERDARWIN;
122/** Pointer to the linux guest OS digger instance data. */
123typedef DBGDIGGERDARWIN *PDBGDIGGERDARWIN;
124
125
126/*********************************************************************************************************************************
127* Defined Constants And Macros *
128*********************************************************************************************************************************/
129/** Validates a 32-bit darwin kernel address */
130#define OSX32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x00001000) && (Addr) < UINT32_C(0xfffff000))
131/** Validates a 64-bit darwin kernel address */
132#define OSX64_VALID_ADDRESS(Addr) ((Addr) > UINT64_C(0xffff800000000000) && (Addr) < UINT64_C(0xfffffffffffff000))
133/** Validates a 32-bit or 64-bit darwin kernel address. */
134#define OSX_VALID_ADDRESS(a_f64Bits, a_Addr) \
135 ((a_f64Bits) ? OSX64_VALID_ADDRESS(a_Addr) : OSX32_VALID_ADDRESS(a_Addr))
136
137/** AppleOsX on little endian ASCII systems. */
138#define DIG_DARWIN_MOD_TAG UINT64_C(0x58734f656c707041)
139
140
141/*********************************************************************************************************************************
142* Internal Functions *
143*********************************************************************************************************************************/
144static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData);
145
146
147
148/**
149 * @interface_method_impl{DBGFOSIDMESG,pfnQueryKernelLog}
150 */
151static DECLCALLBACK(int) dbgDiggerDarwinIDmsg_QueryKernelLog(PDBGFOSIDMESG pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, uint32_t fFlags,
152 uint32_t cMessages, char *pszBuf, size_t cbBuf, size_t *pcbActual)
153{
154 RT_NOREF1(fFlags);
155 PDBGDIGGERDARWIN pData = RT_FROM_MEMBER(pThis, DBGDIGGERDARWIN, IDmesg);
156
157 if (cMessages < 1)
158 return VERR_INVALID_PARAMETER;
159
160 /*
161 * The 'msgbufp' variable points to a struct msgbuf (bsd/kern/subr_log.c).
162 */
163 RTDBGAS hAs = pVMM->pfnDBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
164 RTDBGMOD hMod;
165 int rc = RTDbgAsModuleByName(hAs, "mach_kernel", 0, &hMod);
166 if (RT_FAILURE(rc))
167 return VERR_NOT_FOUND;
168 RTDbgAsRelease(hAs);
169
170 DBGFADDRESS Addr;
171 RTGCPTR GCPtrMsgBufP = 0;
172 RTDBGSYMBOL SymInfo;
173 rc = RTDbgModSymbolByName(hMod, "_msgbufp", &SymInfo);
174 if (RT_SUCCESS(rc))
175 {
176 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/,
177 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &Addr, SymInfo.Value + pData->AddrKernel.FlatPtr),
178 &GCPtrMsgBufP, pData->f64Bit ? sizeof(uint64_t) : sizeof(uint32_t));
179 if (RT_FAILURE(rc))
180 {
181 LogRel(("dbgDiggerDarwinIDmsg_QueryKernelLog: failed to read _msgbufp at %RGv: %Rrc\n", Addr.FlatPtr, rc));
182 return VERR_NOT_FOUND;
183 }
184 if (!OSX_VALID_ADDRESS(pData->f64Bit, GCPtrMsgBufP))
185 {
186 LogRel(("dbgDiggerDarwinIDmsg_QueryKernelLog: Invalid address for _msgbufp: %RGv\n", GCPtrMsgBufP));
187 return VERR_NOT_FOUND;
188 }
189 }
190 else
191 {
192 rc = RTDbgModSymbolByName(hMod, "_msgbuf", &SymInfo);
193 if (RT_FAILURE(rc))
194 {
195 LogRel(("dbgDiggerDarwinIDmsg_QueryKernelLog: failed to find _msgbufp and _msgbuf: %Rrc\n", rc));
196 return VERR_NOT_FOUND;
197 }
198 GCPtrMsgBufP = SymInfo.Value + pData->AddrKernel.FlatPtr;
199 if (!OSX_VALID_ADDRESS(pData->f64Bit, GCPtrMsgBufP))
200 {
201 LogRel(("dbgDiggerDarwinIDmsg_QueryKernelLog: Invalid address for _msgbuf: %RGv\n", GCPtrMsgBufP));
202 return VERR_NOT_FOUND;
203 }
204 }
205
206 /*
207 * Read the msgbuf structure.
208 */
209 struct
210 {
211 uint32_t msg_magic;
212 uint32_t msg_size;
213 uint32_t msg_bufx;
214 uint32_t msg_bufr;
215 uint64_t msg_bufc; /**< Size depends on windows size. */
216 } MsgBuf;
217 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, pVMM->pfnDBGFR3AddrFromFlat(pUVM, &Addr, GCPtrMsgBufP),
218 &MsgBuf, sizeof(MsgBuf) - (pData->f64Bit ? 0 : sizeof(uint32_t)) );
219 if (RT_FAILURE(rc))
220 {
221 LogRel(("dbgDiggerDarwinIDmsg_QueryKernelLog: failed to read msgbuf struct at %RGv: %Rrc\n", Addr.FlatPtr, rc));
222 return VERR_NOT_FOUND;
223 }
224 if (!pData->f64Bit)
225 MsgBuf.msg_bufc &= UINT32_MAX;
226
227 /*
228 * Validate the structure.
229 */
230 if ( MsgBuf.msg_magic != UINT32_C(0x63061)
231 || MsgBuf.msg_size < UINT32_C(4096)
232 || MsgBuf.msg_size > 16*_1M
233 || MsgBuf.msg_bufx > MsgBuf.msg_size
234 || MsgBuf.msg_bufr > MsgBuf.msg_size
235 || !OSX_VALID_ADDRESS(pData->f64Bit, MsgBuf.msg_bufc) )
236 {
237 LogRel(("dbgDiggerDarwinIDmsg_QueryKernelLog: Invalid MsgBuf data: magic=%#x size=%#x bufx=%#x bufr=%#x bufc=%RGv\n",
238 MsgBuf.msg_magic, MsgBuf.msg_size, MsgBuf.msg_bufx, MsgBuf.msg_bufr, MsgBuf.msg_bufc));
239 return VERR_INVALID_STATE;
240 }
241
242 /*
243 * Read the buffer.
244 */
245 char *pchMsgBuf = (char *)RTMemAlloc(MsgBuf.msg_size);
246 if (!pchMsgBuf)
247 {
248 LogRel(("dbgDiggerDarwinIDmsg_QueryKernelLog: Failed to allocate %#x bytes of memory for the log buffer\n",
249 MsgBuf.msg_size));
250 return VERR_INVALID_STATE;
251 }
252 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/,
253 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &Addr, MsgBuf.msg_bufc), pchMsgBuf, MsgBuf.msg_size);
254 if (RT_SUCCESS(rc))
255 {
256 /*
257 * Copy it out raw.
258 */
259 uint32_t offDst = 0;
260 if (MsgBuf.msg_bufr < MsgBuf.msg_bufx)
261 {
262 /* Single chunk between the read and write offsets. */
263 uint32_t cbToCopy = MsgBuf.msg_bufx - MsgBuf.msg_bufr;
264 if (cbToCopy < cbBuf)
265 {
266 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbToCopy);
267 pszBuf[cbToCopy] = '\0';
268 rc = VINF_SUCCESS;
269 }
270 else
271 {
272 if (cbBuf)
273 {
274 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbBuf - 1);
275 pszBuf[cbBuf - 1] = '\0';
276 }
277 rc = VERR_BUFFER_OVERFLOW;
278 }
279 offDst = cbToCopy + 1;
280 }
281 else
282 {
283 /* Two chunks, read offset to end, start to write offset. */
284 uint32_t cbFirst = MsgBuf.msg_size - MsgBuf.msg_bufr;
285 uint32_t cbSecond = MsgBuf.msg_bufx;
286 if (cbFirst + cbSecond < cbBuf)
287 {
288 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbFirst);
289 memcpy(&pszBuf[cbFirst], pchMsgBuf, cbSecond);
290 offDst = cbFirst + cbSecond;
291 pszBuf[offDst++] = '\0';
292 rc = VINF_SUCCESS;
293 }
294 else
295 {
296 offDst = cbFirst + cbSecond + 1;
297 if (cbFirst < cbBuf)
298 {
299 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbFirst);
300 memcpy(&pszBuf[cbFirst], pchMsgBuf, cbBuf - cbFirst);
301 pszBuf[cbBuf - 1] = '\0';
302 }
303 else if (cbBuf)
304 {
305 memcpy(pszBuf, &pchMsgBuf[MsgBuf.msg_bufr], cbBuf - 1);
306 pszBuf[cbBuf - 1] = '\0';
307 }
308 rc = VERR_BUFFER_OVERFLOW;
309 }
310 }
311
312 if (pcbActual)
313 *pcbActual = offDst;
314 }
315 else
316 LogRel(("dbgDiggerDarwinIDmsg_QueryKernelLog: Error reading %#x bytes at %RGv: %Rrc\n",
317 MsgBuf.msg_size, MsgBuf.msg_bufc, rc));
318 RTMemFree(pchMsgBuf);
319 return rc;
320}
321
322
323/**
324 * @copydoc DBGFOSREG::pfnStackUnwindAssist
325 */
326static DECLCALLBACK(int) dbgDiggerDarwinStackUnwindAssist(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, VMCPUID idCpu,
327 PDBGFSTACKFRAME pFrame, PRTDBGUNWINDSTATE pState, PCCPUMCTX pInitialCtx,
328 RTDBGAS hAs, uint64_t *puScratch)
329{
330 RT_NOREF(pUVM, pVMM, pvData, idCpu, pFrame, pState, pInitialCtx, hAs, puScratch);
331 return VINF_SUCCESS;
332}
333
334
335/**
336 * @copydoc DBGFOSREG::pfnQueryInterface
337 */
338static DECLCALLBACK(void *) dbgDiggerDarwinQueryInterface(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, DBGFOSINTERFACE enmIf)
339{
340 RT_NOREF(pUVM, pVMM);
341 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
342 switch (enmIf)
343 {
344 case DBGFOSINTERFACE_DMESG:
345 return &pThis->IDmesg;
346
347 default:
348 return NULL;
349 }
350}
351
352
353/**
354 * @copydoc DBGFOSREG::pfnQueryVersion
355 */
356static DECLCALLBACK(int) dbgDiggerDarwinQueryVersion(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData,
357 char *pszVersion, size_t cchVersion)
358{
359 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
360 Assert(pThis->fValid);
361
362 /*
363 * It's all in the linux banner.
364 */
365 int rc = pVMM->pfnDBGFR3MemReadString(pUVM, 0, &pThis->AddrKernelVersion, pszVersion, cchVersion);
366 if (RT_SUCCESS(rc))
367 {
368 char *pszEnd = RTStrEnd(pszVersion, cchVersion);
369 AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
370 while ( pszEnd > pszVersion
371 && RT_C_IS_SPACE(pszEnd[-1]))
372 pszEnd--;
373 *pszEnd = '\0';
374 }
375 else
376 RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemRead -> %Rrc", rc);
377
378 return rc;
379}
380
381
382/**
383 * @copydoc DBGFOSREG::pfnTerm
384 */
385static DECLCALLBACK(void) dbgDiggerDarwinTerm(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
386{
387 RT_NOREF(pUVM, pVMM);
388 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
389
390 pThis->fValid = false;
391}
392
393
394/**
395 * @copydoc DBGFOSREG::pfnRefresh
396 */
397static DECLCALLBACK(int) dbgDiggerDarwinRefresh(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
398{
399 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
400 NOREF(pThis);
401 Assert(pThis->fValid);
402
403 /*
404 * For now we'll flush and reload everything.
405 */
406 dbgDiggerDarwinTerm(pUVM, pVMM, pvData);
407 return dbgDiggerDarwinInit(pUVM, pVMM, pvData);
408}
409
410
411/**
412 * Helper function that tries to accertain whether a segment (__LINKEDIT) is
413 * present or not.
414 *
415 * @returns true if present, false if not.
416 * @param pUVM The user mode VM structure.
417 * @param pVMM The VMM function table.
418 * @param uSegAddr The segment addresss.
419 * @param cbSeg The segment size.
420 * @param uMinAddr Lowest allowed address.
421 * @param uMaxAddr Highest allowed address.
422 */
423static bool dbgDiggerDarwinIsSegmentPresent(PUVM pUVM, PCVMMR3VTABLE pVMM, uint64_t uSegAddr, uint64_t cbSeg,
424 uint64_t uMinAddr, uint64_t uMaxAddr)
425{
426 /*
427 * Validate the size and address.
428 */
429 if (cbSeg < 32)
430 {
431 LogRel(("OSXDig: __LINKEDIT too small %#RX64\n", cbSeg));
432 return false;
433 }
434 if (cbSeg > uMaxAddr - uMinAddr)
435 {
436 LogRel(("OSXDig: __LINKEDIT too big %#RX64, max %#RX64\n", cbSeg, uMaxAddr - uMinAddr));
437 return false;
438 }
439
440 if (uSegAddr < uMinAddr)
441 {
442 LogRel(("OSXDig: __LINKEDIT too low %#RX64, min %#RX64\n", uSegAddr, uMinAddr));
443 return false;
444 }
445 if (uSegAddr > uMaxAddr)
446 {
447 LogRel(("OSXDig: __LINKEDIT too high %#RX64, max %#RX64\n", uSegAddr, uMaxAddr));
448 return false;
449 }
450 if (uSegAddr + cbSeg > uMaxAddr)
451 {
452 LogRel(("OSXDig: __LINKEDIT ends too high %#RX64 (%#RX64+%#RX64), max %#RX64\n",
453 uSegAddr + cbSeg, uSegAddr, cbSeg, uMaxAddr));
454 return false;
455 }
456
457 /*
458 * Check that all the pages are present.
459 */
460 cbSeg += uSegAddr & X86_PAGE_OFFSET_MASK;
461 uSegAddr &= ~(uint64_t)X86_PAGE_OFFSET_MASK;
462 for (;;)
463 {
464 uint8_t abBuf[8];
465 DBGFADDRESS Addr;
466 int rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, pVMM->pfnDBGFR3AddrFromFlat(pUVM, &Addr, uSegAddr),
467 abBuf, sizeof(abBuf));
468 if (RT_FAILURE(rc))
469 {
470 LogRel(("OSXDig: __LINKEDIT read error at %#RX64: %Rrc\n", uSegAddr, rc));
471 return false;
472 }
473
474 /* Advance */
475 if (cbSeg <= X86_PAGE_SIZE)
476 return true;
477 cbSeg -= X86_PAGE_SIZE;
478 uSegAddr += X86_PAGE_SIZE;
479 }
480}
481
482
483/**
484 * Helper function that validates a segment (or section) name.
485 *
486 * @returns true if valid, false if not.
487 * @param pszName The name string.
488 * @param cbName The size of the string, including terminator.
489 */
490static bool dbgDiggerDarwinIsValidSegOrSectName(const char *pszName, size_t cbName)
491{
492 /* ascii chars */
493 char ch;
494 size_t off = 0;
495 while (off < cbName && (ch = pszName[off]))
496 {
497 if (RT_C_IS_CNTRL(ch) || ch >= 127)
498 return false;
499 off++;
500 }
501
502 /* Not empty nor 100% full. */
503 if (off == 0 || off == cbName)
504 return false;
505
506 /* remainder should be zeros. */
507 while (off < cbName)
508 {
509 if (pszName[off])
510 return false;
511 off++;
512 }
513
514 return true;
515}
516
517
518static int dbgDiggerDarwinAddModule(PDBGDIGGERDARWIN pThis, PUVM pUVM, PCVMMR3VTABLE pVMM,
519 uint64_t uModAddr, const char *pszName, bool *pf64Bit)
520{
521 RT_NOREF1(pThis);
522 union
523 {
524 uint8_t ab[2 * X86_PAGE_4K_SIZE];
525 mach_header_64_t Hdr64;
526 mach_header_32_t Hdr32;
527 } uBuf;
528
529 /* Read the first page of the image. */
530 DBGFADDRESS ModAddr;
531 int rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/,
532 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr), uBuf.ab, X86_PAGE_4K_SIZE);
533 if (RT_FAILURE(rc))
534 return rc;
535
536 /* Validate the header. */
537 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
538 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
539 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
540 return VERR_INVALID_EXE_SIGNATURE;
541 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
542 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
543 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
544 return VERR_LDR_ARCH_MISMATCH;
545 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
546 if ( uBuf.Hdr32.filetype != MH_EXECUTE
547 && uBuf.Hdr32.filetype != (f64Bit ? MH_KEXT_BUNDLE : MH_OBJECT))
548 return VERR_BAD_EXE_FORMAT;
549 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
550 if (uBuf.Hdr32.ncmds > 256)
551 return VERR_BAD_EXE_FORMAT;
552 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
553 if (uBuf.Hdr32.sizeofcmds > X86_PAGE_4K_SIZE * 2 - sizeof(mach_header_64_t))
554 return VERR_BAD_EXE_FORMAT;
555
556 /* Do we need to read a 2nd page to get all the load commands? If so, do it. */
557 if (uBuf.Hdr32.sizeofcmds + (f64Bit ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t)) > X86_PAGE_4K_SIZE)
558 {
559 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, pVMM->pfnDBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr + X86_PAGE_4K_SIZE),
560 &uBuf.ab[X86_PAGE_4K_SIZE], X86_PAGE_4K_SIZE);
561 if (RT_FAILURE(rc))
562 return rc;
563 }
564
565 /*
566 * Process the load commands.
567 */
568 RTUUID Uuid = RTUUID_INITIALIZE_NULL;
569 RTDBGSEGMENT aSegs[24];
570 uint32_t cSegs = 0;
571 bool fHasLinkEdit = false;
572 uint32_t cLeft = uBuf.Hdr32.ncmds;
573 uint32_t cbLeft = uBuf.Hdr32.sizeofcmds;
574 union
575 {
576 uint8_t const *pb;
577 load_command_t const *pGenric;
578 segment_command_32_t const *pSeg32;
579 segment_command_64_t const *pSeg64;
580 uuid_command_t const *pUuid;
581 } uLCmd;
582 uLCmd.pb = &uBuf.ab[f64Bit ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t)];
583
584 while (cLeft-- > 0)
585 {
586 uint32_t const cbCmd = uLCmd.pGenric->cmdsize;
587 if (cbCmd > cbLeft || cbCmd < sizeof(load_command_t))
588 return VERR_BAD_EXE_FORMAT;
589
590 switch (uLCmd.pGenric->cmd)
591 {
592 case LC_SEGMENT_32:
593 if (cbCmd != sizeof(segment_command_32_t) + uLCmd.pSeg32->nsects * sizeof(section_32_t))
594 return VERR_BAD_EXE_FORMAT;
595 if (!dbgDiggerDarwinIsValidSegOrSectName(uLCmd.pSeg32->segname, sizeof(uLCmd.pSeg32->segname)))
596 return VERR_INVALID_NAME;
597 if ( !strcmp(uLCmd.pSeg32->segname, "__LINKEDIT")
598 && !(fHasLinkEdit = dbgDiggerDarwinIsSegmentPresent(pUVM, pVMM, uLCmd.pSeg32->vmaddr, uLCmd.pSeg32->vmsize,
599 uModAddr, uModAddr + _64M)))
600 break; /* This usually is discarded or not loaded at all. */
601 if (cSegs >= RT_ELEMENTS(aSegs))
602 return VERR_BUFFER_OVERFLOW;
603 aSegs[cSegs].Address = uLCmd.pSeg32->vmaddr;
604 aSegs[cSegs].uRva = uLCmd.pSeg32->vmaddr - uModAddr;
605 aSegs[cSegs].cb = uLCmd.pSeg32->vmsize;
606 aSegs[cSegs].fFlags = uLCmd.pSeg32->flags; /* Abusing the flags field here... */
607 aSegs[cSegs].iSeg = cSegs;
608 AssertCompile(RTDBG_SEGMENT_NAME_LENGTH > sizeof(uLCmd.pSeg32->segname));
609 strcpy(aSegs[cSegs].szName, uLCmd.pSeg32->segname);
610 cSegs++;
611 break;
612
613 case LC_SEGMENT_64:
614 if (cbCmd != sizeof(segment_command_64_t) + uLCmd.pSeg64->nsects * sizeof(section_64_t))
615 return VERR_BAD_EXE_FORMAT;
616 if (!dbgDiggerDarwinIsValidSegOrSectName(uLCmd.pSeg64->segname, sizeof(uLCmd.pSeg64->segname)))
617 return VERR_INVALID_NAME;
618 if ( !strcmp(uLCmd.pSeg64->segname, "__LINKEDIT")
619 && !(fHasLinkEdit = dbgDiggerDarwinIsSegmentPresent(pUVM, pVMM, uLCmd.pSeg64->vmaddr, uLCmd.pSeg64->vmsize,
620 uModAddr, uModAddr + _128M)))
621 break; /* This usually is discarded or not loaded at all. */
622 if (cSegs >= RT_ELEMENTS(aSegs))
623 return VERR_BUFFER_OVERFLOW;
624 aSegs[cSegs].Address = uLCmd.pSeg64->vmaddr;
625 aSegs[cSegs].uRva = uLCmd.pSeg64->vmaddr - uModAddr;
626 aSegs[cSegs].cb = uLCmd.pSeg64->vmsize;
627 aSegs[cSegs].fFlags = uLCmd.pSeg64->flags; /* Abusing the flags field here... */
628 aSegs[cSegs].iSeg = cSegs;
629 AssertCompile(RTDBG_SEGMENT_NAME_LENGTH > sizeof(uLCmd.pSeg64->segname));
630 strcpy(aSegs[cSegs].szName, uLCmd.pSeg64->segname);
631 cSegs++;
632 break;
633
634 case LC_UUID:
635 if (cbCmd != sizeof(uuid_command_t))
636 return VERR_BAD_EXE_FORMAT;
637 if (RTUuidIsNull((PCRTUUID)&uLCmd.pUuid->uuid[0]))
638 return VERR_BAD_EXE_FORMAT;
639 memcpy(&Uuid, &uLCmd.pUuid->uuid[0], sizeof(uLCmd.pUuid->uuid));
640 break;
641
642 default:
643 /* Current known max plus a lot of slack. */
644 if (uLCmd.pGenric->cmd > LC_DYLIB_CODE_SIGN_DRS + 32)
645 return VERR_BAD_EXE_FORMAT;
646 break;
647 }
648
649 /* next */
650 cbLeft -= cbCmd;
651 uLCmd.pb += cbCmd;
652 }
653
654 if (cbLeft != 0)
655 {
656 LogRel(("OSXDig: uModAddr=%#RX64 - %u bytes of command left over!\n", uModAddr, cbLeft));
657 return VERR_BAD_EXE_FORMAT;
658 }
659
660 /*
661 * Some post processing checks.
662 */
663 uint32_t iSeg;
664 for (iSeg = 0; iSeg < cSegs; iSeg++)
665 if (aSegs[iSeg].Address == uModAddr)
666 break;
667 if (iSeg >= cSegs)
668 {
669 LogRel2(("OSXDig: uModAddr=%#RX64 was not found among the segments segments\n", uModAddr));
670 return VERR_ADDRESS_CONFLICT;
671 }
672
673 /*
674 * Create a debug module.
675 */
676 RTDBGMOD hMod;
677 rc = RTDbgModCreateFromMachOImage(&hMod, pszName, NULL, f64Bit ? RTLDRARCH_AMD64 : RTLDRARCH_X86_32, NULL /*phLdrModIn*/,
678 0 /*cbImage*/, cSegs, aSegs, &Uuid, pVMM->pfnDBGFR3AsGetConfig(pUVM),
679 RTDBGMOD_F_NOT_DEFERRED | (fHasLinkEdit ? RTDBGMOD_F_MACHO_LOAD_LINKEDIT : 0));
680
681
682 /*
683 * If module creation failed and we've got a linkedit segment, try open the
684 * image in-memory, because that will at a minimum give us symbol table symbols.
685 */
686 if (RT_FAILURE(rc) && fHasLinkEdit)
687 {
688 DBGFADDRESS DbgfAddr;
689 RTERRINFOSTATIC ErrInfo;
690 rc = pVMM->pfnDBGFR3ModInMem(pUVM, pVMM->pfnDBGFR3AddrFromFlat(pUVM, &DbgfAddr, uModAddr),
691 DBGFMODINMEM_F_NO_CONTAINER_FALLBACK,
692 pszName, NULL /*pszFilename*/, f64Bit ? RTLDRARCH_AMD64 : RTLDRARCH_X86_32, 0 /*cbImage */,
693 &hMod, RTErrInfoInitStatic(&ErrInfo));
694 if (RT_FAILURE(rc))
695 LogRel(("OSXDig: Failed to do an in-memory-opening of '%s' at %#RX64: %Rrc%s%s\n", pszName, uModAddr, rc,
696 RTErrInfoIsSet(&ErrInfo.Core) ? " - " : "", RTErrInfoIsSet(&ErrInfo.Core) ? ErrInfo.Core.pszMsg : ""));
697 }
698
699 /*
700 * Final fallback is a container module.
701 */
702 if (RT_FAILURE(rc))
703 {
704 rc = RTDbgModCreate(&hMod, pszName, 0, 0);
705 if (RT_FAILURE(rc))
706 return rc;
707
708 uint64_t uRvaNext = 0;
709 for (iSeg = 0; iSeg < cSegs && RT_SUCCESS(rc); iSeg++)
710 {
711 if ( aSegs[iSeg].uRva > uRvaNext
712 && aSegs[iSeg].uRva - uRvaNext < _1M)
713 uRvaNext = aSegs[iSeg].uRva;
714 rc = RTDbgModSegmentAdd(hMod, aSegs[iSeg].uRva, aSegs[iSeg].cb, aSegs[iSeg].szName, 0, NULL);
715 if (aSegs[iSeg].cb > 0 && RT_SUCCESS(rc))
716 {
717 char szTmp[RTDBG_SEGMENT_NAME_LENGTH + sizeof("_start")];
718 strcat(strcpy(szTmp, aSegs[iSeg].szName), "_start");
719 rc = RTDbgModSymbolAdd(hMod, szTmp, iSeg, 0 /*uRva*/, 0 /*cb*/, 0 /*fFlags*/, NULL);
720 }
721 uRvaNext += aSegs[iSeg].cb;
722 }
723
724 if (RT_FAILURE(rc))
725 {
726 RTDbgModRelease(hMod);
727 return rc;
728 }
729 }
730
731 /* Tag the module. */
732 rc = RTDbgModSetTag(hMod, DIG_DARWIN_MOD_TAG);
733 AssertRC(rc);
734
735 /*
736 * Link the module.
737 */
738 RTDBGAS hAs = pVMM->pfnDBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
739 if (hAs != NIL_RTDBGAS)
740 {
741 //uint64_t uRvaNext = 0; - what was this?
742 uint32_t cLinked = 0;
743 iSeg = cSegs;
744 while (iSeg-- > 0) /* HACK: Map in reverse order to avoid replacing __TEXT. */
745 if (aSegs[iSeg].cb)
746 {
747 /* Find matching segment in the debug module. */
748 uint32_t iDbgSeg = 0;
749 while (iDbgSeg < cSegs)
750 {
751 RTDBGSEGMENT SegInfo;
752 int rc3 = RTDbgModSegmentByIndex(hMod, iDbgSeg, &SegInfo);
753 if (RT_SUCCESS(rc3) && !strcmp(SegInfo.szName, aSegs[iSeg].szName))
754 break;
755 iDbgSeg++;
756 }
757 AssertMsgStmt(iDbgSeg < cSegs, ("%s\n", aSegs[iSeg].szName), continue);
758
759 /* Map it. */
760 int rc2 = RTDbgAsModuleLinkSeg(hAs, hMod, iDbgSeg, aSegs[iSeg].Address, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
761 if (RT_SUCCESS(rc2))
762 cLinked++;
763 else if (RT_SUCCESS(rc))
764 rc = rc2;
765 }
766 if (RT_FAILURE(rc) && cLinked != 0)
767 rc = -rc;
768 }
769 else
770 rc = VERR_INTERNAL_ERROR;
771
772 RTDbgModRelease(hMod);
773 RTDbgAsRelease(hAs);
774
775 if (pf64Bit)
776 *pf64Bit = f64Bit;
777 return rc;
778}
779
780
781static bool dbgDiggerDarwinIsValidName(const char *pszName)
782{
783 char ch;
784 while ((ch = *pszName++) != '\0')
785 {
786 if (ch < 0x20 || ch >= 127)
787 return false;
788 }
789 return true;
790}
791
792
793static bool dbgDiggerDarwinIsValidVersion(const char *pszVersion)
794{
795 char ch;
796 while ((ch = *pszVersion++) != '\0')
797 {
798 if (ch < 0x20 || ch >= 127)
799 return false;
800 }
801 return true;
802}
803
804
805/**
806 * @copydoc DBGFOSREG::pfnInit
807 */
808static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
809{
810 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
811 Assert(!pThis->fValid);
812
813 /*
814 * Add the kernel module.
815 */
816 bool f64Bit;
817 int rc = dbgDiggerDarwinAddModule(pThis, pUVM, pVMM, pThis->AddrKernel.FlatPtr, "mach_kernel", &f64Bit);
818 if (RT_SUCCESS(rc))
819 {
820 /*
821 * The list of modules can be found at the 'kmod' symbol, that means
822 * that we currently require some kind of symbol file for the kernel
823 * to be loaded at this point.
824 *
825 * Note! Could also use the 'gLoadedKextSummaries', but I don't think
826 * it's any easier to find without any kernel map than 'kmod'.
827 */
828 RTDBGSYMBOL SymInfo;
829 rc = pVMM->pfnDBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "mach_kernel!kmod", &SymInfo, NULL);
830 if (RT_FAILURE(rc))
831 rc = pVMM->pfnDBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "mach_kernel!_kmod", &SymInfo, NULL);
832 if (RT_SUCCESS(rc))
833 {
834 DBGFADDRESS AddrModInfo;
835 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &AddrModInfo, SymInfo.Value);
836
837 /* Read the variable. */
838 RTUINT64U uKmodValue = { 0 };
839 if (f64Bit)
840 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrModInfo, &uKmodValue.u, sizeof(uKmodValue.u));
841 else
842 rc = pVMM->pfnDBGFR3MemRead (pUVM, 0 /*idCpu*/, &AddrModInfo, &uKmodValue.s.Lo, sizeof(uKmodValue.s.Lo));
843 if (RT_SUCCESS(rc))
844 {
845 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &AddrModInfo, uKmodValue.u);
846
847 /* Walk the list of modules. */
848 uint32_t cIterations = 0;
849 while (AddrModInfo.FlatPtr != 0)
850 {
851 /* Some extra loop conditions... */
852 if (!OSX_VALID_ADDRESS(f64Bit, AddrModInfo.FlatPtr))
853 {
854 LogRel(("OSXDig: Invalid kmod_info pointer: %RGv\n", AddrModInfo.FlatPtr));
855 break;
856 }
857 if (AddrModInfo.FlatPtr == uKmodValue.u && cIterations != 0)
858 {
859 LogRel(("OSXDig: kmod_info list looped back to the start.\n"));
860 break;
861 }
862 if (cIterations++ >= 2048)
863 {
864 LogRel(("OSXDig: Too many mod_info loops (%u)\n", cIterations));
865 break;
866 }
867
868 /*
869 * Read the kmod_info_t structure.
870 */
871 union
872 {
873 OSX64_kmod_info_t Info64;
874 OSX32_kmod_info_t Info32;
875 } uMod;
876 RT_ZERO(uMod);
877 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrModInfo, &uMod,
878 f64Bit ? sizeof(uMod.Info64) : sizeof(uMod.Info32));
879 if (RT_FAILURE(rc))
880 {
881 LogRel(("OSXDig: Error reading kmod_info structure at %RGv: %Rrc\n", AddrModInfo.FlatPtr, rc));
882 break;
883 }
884
885 /*
886 * Validate the kmod_info_t structure.
887 */
888 int32_t iInfoVer = f64Bit ? uMod.Info64.info_version : uMod.Info32.info_version;
889 if (iInfoVer != OSX_KMOD_INFO_VERSION)
890 {
891 LogRel(("OSXDig: kmod_info @%RGv: Bad info_version %d\n", AddrModInfo.FlatPtr, iInfoVer));
892 break;
893 }
894
895 const char *pszName = f64Bit ? uMod.Info64.name : uMod.Info32.name;
896 if ( !*pszName
897 || !RTStrEnd(pszName, sizeof(uMod.Info64.name))
898 || !dbgDiggerDarwinIsValidName(pszName) )
899 {
900 LogRel(("OSXDig: kmod_info @%RGv: Bad name '%.*s'\n", AddrModInfo.FlatPtr,
901 sizeof(uMod.Info64.name), pszName));
902 break;
903 }
904
905 const char *pszVersion = f64Bit ? uMod.Info64.version : uMod.Info32.version;
906 if ( !RTStrEnd(pszVersion, sizeof(uMod.Info64.version))
907 || !dbgDiggerDarwinIsValidVersion(pszVersion) )
908 {
909 LogRel(("OSXDig: kmod_info @%RGv: Bad version '%.*s'\n", AddrModInfo.FlatPtr,
910 sizeof(uMod.Info64.version), pszVersion));
911 break;
912 }
913
914 int32_t cRefs = f64Bit ? uMod.Info64.reference_count : uMod.Info32.reference_count;
915 if (cRefs < -1 || cRefs > 16384)
916 {
917 LogRel(("OSXDig: kmod_info @%RGv: Bad reference_count %d\n", AddrModInfo.FlatPtr, cRefs));
918 break;
919 }
920
921 uint64_t uImageAddr = f64Bit ? uMod.Info64.address : uMod.Info32.address;
922 if (!OSX_VALID_ADDRESS(f64Bit, uImageAddr))
923 {
924 LogRel(("OSXDig: kmod_info @%RGv: Bad address %#llx\n", AddrModInfo.FlatPtr, uImageAddr));
925 break;
926 }
927
928 uint64_t cbImage = f64Bit ? uMod.Info64.size : uMod.Info32.size;
929 if (cbImage > 64U*_1M)
930 {
931 LogRel(("OSXDig: kmod_info @%RGv: Bad size %#llx\n", AddrModInfo.FlatPtr, cbImage));
932 break;
933 }
934
935 uint64_t cbHdr = f64Bit ? uMod.Info64.hdr_size : uMod.Info32.hdr_size;
936 if (cbHdr > 16U*_1M)
937 {
938 LogRel(("OSXDig: kmod_info @%RGv: Bad hdr_size %#llx\n", AddrModInfo.FlatPtr, cbHdr));
939 break;
940 }
941
942 uint64_t uStartAddr = f64Bit ? uMod.Info64.start : uMod.Info32.start;
943 if (!uStartAddr && !OSX_VALID_ADDRESS(f64Bit, uStartAddr))
944 {
945 LogRel(("OSXDig: kmod_info @%RGv: Bad start function %#llx\n", AddrModInfo.FlatPtr, uStartAddr));
946 break;
947 }
948
949 uint64_t uStopAddr = f64Bit ? uMod.Info64.stop : uMod.Info32.stop;
950 if (!uStopAddr && !OSX_VALID_ADDRESS(f64Bit, uStopAddr))
951 {
952 LogRel(("OSXDig: kmod_info @%RGv: Bad stop function %#llx\n", AddrModInfo.FlatPtr, uStopAddr));
953 break;
954 }
955
956 /*
957 * Try add the module.
958 */
959 LogRel(("OSXDig: kmod_info @%RGv: '%s' ver '%s', image @%#llx LB %#llx cbHdr=%#llx\n", AddrModInfo.FlatPtr,
960 pszName, pszVersion, uImageAddr, cbImage, cbHdr));
961 rc = dbgDiggerDarwinAddModule(pThis, pUVM, pVMM, uImageAddr, pszName, NULL);
962
963
964 /*
965 * Advance to the next kmod_info entry.
966 */
967 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &AddrModInfo, f64Bit ? uMod.Info64.next : uMod.Info32.next);
968 }
969 }
970 else
971 LogRel(("OSXDig: Error reading the 'kmod' variable: %Rrc\n", rc));
972 }
973 else
974 LogRel(("OSXDig: Failed to locate the 'kmod' variable in mach_kernel.\n"));
975
976 pThis->fValid = true;
977 return VINF_SUCCESS;
978 }
979
980 return rc;
981}
982
983
984/**
985 * @copydoc DBGFOSREG::pfnProbe
986 */
987static DECLCALLBACK(bool) dbgDiggerDarwinProbe(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
988{
989 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
990
991 /*
992 * Look for a section + segment combo that normally only occures in
993 * mach_kernel. Follow it up with probing of the rest of the executable
994 * header. We must search a largish area because the more recent versions
995 * of darwin have random load address for security raisins.
996 */
997 static struct { uint64_t uStart, uEnd; } const s_aRanges[] =
998 {
999 /* 64-bit: */
1000 { UINT64_C(0xffffff8000000000), UINT64_C(0xffffff81ffffffff), },
1001
1002 /* 32-bit - always search for this because of the hybrid 32-bit kernel
1003 with cpu in long mode that darwin used for a number of versions. */
1004 { UINT64_C(0x00001000), UINT64_C(0x0ffff000), }
1005 };
1006 for (unsigned iRange = pVMM->pfnDBGFR3CpuGetMode(pUVM, 0 /*idCpu*/) != CPUMMODE_LONG;
1007 iRange < RT_ELEMENTS(s_aRanges);
1008 iRange++)
1009 {
1010 DBGFADDRESS KernelAddr;
1011 for (pVMM->pfnDBGFR3AddrFromFlat(pUVM, &KernelAddr, s_aRanges[iRange].uStart);
1012 KernelAddr.FlatPtr < s_aRanges[iRange].uEnd;
1013 KernelAddr.FlatPtr += X86_PAGE_4K_SIZE)
1014 {
1015 static const uint8_t s_abNeedle[16 + 16] =
1016 {
1017 '_','_','t','e','x','t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::sectname */
1018 '_','_','K','L','D', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::segname. */
1019 };
1020
1021 int rc = pVMM->pfnDBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, s_aRanges[iRange].uEnd - KernelAddr.FlatPtr,
1022 1, s_abNeedle, sizeof(s_abNeedle), &KernelAddr);
1023 if (RT_FAILURE(rc))
1024 break;
1025 pVMM->pfnDBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & X86_PAGE_4K_OFFSET_MASK);
1026
1027 /*
1028 * Read the first page of the image and check the headers.
1029 */
1030 union
1031 {
1032 uint8_t ab[X86_PAGE_4K_SIZE];
1033 mach_header_64_t Hdr64;
1034 mach_header_32_t Hdr32;
1035 } uBuf;
1036 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, uBuf.ab, X86_PAGE_4K_SIZE);
1037 if (RT_FAILURE(rc))
1038 continue;
1039 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
1040 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
1041 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
1042 continue;
1043 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
1044 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
1045 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
1046 continue;
1047 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
1048 if (uBuf.Hdr32.filetype != MH_EXECUTE)
1049 continue;
1050 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
1051 if (uBuf.Hdr32.ncmds > 256)
1052 continue;
1053 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
1054 if (uBuf.Hdr32.sizeofcmds > X86_PAGE_4K_SIZE * 2 - sizeof(mach_header_64_t))
1055 continue;
1056
1057 /* Seems good enough for now.
1058
1059 If the above causes false positives, check the segments and make
1060 sure there is a kernel version string in the right one. */
1061 pThis->AddrKernel = KernelAddr;
1062 pThis->f64Bit = f64Bit;
1063
1064 /*
1065 * Finally, find the kernel version string.
1066 */
1067 rc = pVMM->pfnDBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, 32*_1M, 1, RT_STR_TUPLE("Darwin Kernel Version"),
1068 &pThis->AddrKernelVersion);
1069 if (RT_FAILURE(rc))
1070 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelVersion, 0);
1071 return true;
1072 }
1073 }
1074 return false;
1075}
1076
1077
1078/**
1079 * @copydoc DBGFOSREG::pfnDestruct
1080 */
1081static DECLCALLBACK(void) dbgDiggerDarwinDestruct(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
1082{
1083 RT_NOREF(pUVM, pVMM, pvData);
1084}
1085
1086
1087/**
1088 * @copydoc DBGFOSREG::pfnConstruct
1089 */
1090static DECLCALLBACK(int) dbgDiggerDarwinConstruct(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
1091{
1092 RT_NOREF(pUVM, pVMM);
1093 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
1094
1095 pThis->IDmesg.u32Magic = DBGFOSIDMESG_MAGIC;
1096 pThis->IDmesg.pfnQueryKernelLog = dbgDiggerDarwinIDmsg_QueryKernelLog;
1097 pThis->IDmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
1098
1099 return VINF_SUCCESS;
1100}
1101
1102
1103const DBGFOSREG g_DBGDiggerDarwin =
1104{
1105 /* .u32Magic = */ DBGFOSREG_MAGIC,
1106 /* .fFlags = */ 0,
1107 /* .cbData = */ sizeof(DBGDIGGERDARWIN),
1108 /* .szName = */ "Darwin",
1109 /* .pfnConstruct = */ dbgDiggerDarwinConstruct,
1110 /* .pfnDestruct = */ dbgDiggerDarwinDestruct,
1111 /* .pfnProbe = */ dbgDiggerDarwinProbe,
1112 /* .pfnInit = */ dbgDiggerDarwinInit,
1113 /* .pfnRefresh = */ dbgDiggerDarwinRefresh,
1114 /* .pfnTerm = */ dbgDiggerDarwinTerm,
1115 /* .pfnQueryVersion = */ dbgDiggerDarwinQueryVersion,
1116 /* .pfnQueryInterface = */ dbgDiggerDarwinQueryInterface,
1117 /* .pfnStackUnwindAssist = */ dbgDiggerDarwinStackUnwindAssist,
1118 /* .u32EndMagic = */ DBGFOSREG_MAGIC
1119};
1120
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