VirtualBox

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

Last change on this file was 103424, checked in by vboxsync, 3 months ago

DBGPlugInDarwin: Reworked the r161579 changes. bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.8 KB
Line 
1/* $Id: DBGPlugInDarwin.cpp 103424 2024-02-19 10:25:36Z 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 & GUEST_PAGE_OFFSET_MASK;
461 uSegAddr &= ~(uint64_t)GUEST_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 <= GUEST_PAGE_SIZE)
476 return true;
477 cbSeg -= GUEST_PAGE_SIZE;
478 uSegAddr += GUEST_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 * GUEST_PAGE_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, GUEST_PAGE_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 > GUEST_PAGE_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)) > GUEST_PAGE_SIZE)
558 {
559 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, pVMM->pfnDBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr + GUEST_PAGE_SIZE),
560 &uBuf.ab[GUEST_PAGE_SIZE], GUEST_PAGE_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 static const char s_szSuffix[] = "_start";
718 size_t const cchName = RTStrNLen(aSegs[iSeg].szName, sizeof(aSegs[iSeg].szName));
719 char szTmp[sizeof(aSegs[iSeg].szName) + sizeof(s_szSuffix)];
720 memcpy(mempcpy(szTmp, aSegs[iSeg].szName, cchName), s_szSuffix, sizeof(s_szSuffix));
721 rc = RTDbgModSymbolAdd(hMod, szTmp, iSeg, 0 /*uRva*/, 0 /*cb*/, 0 /*fFlags*/, NULL);
722 }
723 uRvaNext += aSegs[iSeg].cb;
724 }
725
726 if (RT_FAILURE(rc))
727 {
728 RTDbgModRelease(hMod);
729 return rc;
730 }
731 }
732
733 /* Tag the module. */
734 rc = RTDbgModSetTag(hMod, DIG_DARWIN_MOD_TAG);
735 AssertRC(rc);
736
737 /*
738 * Link the module.
739 */
740 RTDBGAS hAs = pVMM->pfnDBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
741 if (hAs != NIL_RTDBGAS)
742 {
743 //uint64_t uRvaNext = 0; - what was this?
744 uint32_t cLinked = 0;
745 iSeg = cSegs;
746 while (iSeg-- > 0) /* HACK: Map in reverse order to avoid replacing __TEXT. */
747 if (aSegs[iSeg].cb)
748 {
749 /* Find matching segment in the debug module. */
750 uint32_t iDbgSeg = 0;
751 while (iDbgSeg < cSegs)
752 {
753 RTDBGSEGMENT SegInfo;
754 int rc3 = RTDbgModSegmentByIndex(hMod, iDbgSeg, &SegInfo);
755 if (RT_SUCCESS(rc3) && !strcmp(SegInfo.szName, aSegs[iSeg].szName))
756 break;
757 iDbgSeg++;
758 }
759 AssertMsgStmt(iDbgSeg < cSegs, ("%s\n", aSegs[iSeg].szName), continue);
760
761 /* Map it. */
762 int rc2 = RTDbgAsModuleLinkSeg(hAs, hMod, iDbgSeg, aSegs[iSeg].Address, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
763 if (RT_SUCCESS(rc2))
764 cLinked++;
765 else if (RT_SUCCESS(rc))
766 rc = rc2;
767 }
768 if (RT_FAILURE(rc) && cLinked != 0)
769 rc = -rc;
770 }
771 else
772 rc = VERR_INTERNAL_ERROR;
773
774 RTDbgModRelease(hMod);
775 RTDbgAsRelease(hAs);
776
777 if (pf64Bit)
778 *pf64Bit = f64Bit;
779 return rc;
780}
781
782
783static bool dbgDiggerDarwinIsValidName(const char *pszName)
784{
785 char ch;
786 while ((ch = *pszName++) != '\0')
787 {
788 if (ch < 0x20 || ch >= 127)
789 return false;
790 }
791 return true;
792}
793
794
795static bool dbgDiggerDarwinIsValidVersion(const char *pszVersion)
796{
797 char ch;
798 while ((ch = *pszVersion++) != '\0')
799 {
800 if (ch < 0x20 || ch >= 127)
801 return false;
802 }
803 return true;
804}
805
806
807/**
808 * @copydoc DBGFOSREG::pfnInit
809 */
810static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
811{
812 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
813 Assert(!pThis->fValid);
814
815 /*
816 * Add the kernel module.
817 */
818 bool f64Bit;
819 int rc = dbgDiggerDarwinAddModule(pThis, pUVM, pVMM, pThis->AddrKernel.FlatPtr, "mach_kernel", &f64Bit);
820 if (RT_SUCCESS(rc))
821 {
822 /*
823 * The list of modules can be found at the 'kmod' symbol, that means
824 * that we currently require some kind of symbol file for the kernel
825 * to be loaded at this point.
826 *
827 * Note! Could also use the 'gLoadedKextSummaries', but I don't think
828 * it's any easier to find without any kernel map than 'kmod'.
829 */
830 RTDBGSYMBOL SymInfo;
831 rc = pVMM->pfnDBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "mach_kernel!kmod", &SymInfo, NULL);
832 if (RT_FAILURE(rc))
833 rc = pVMM->pfnDBGFR3AsSymbolByName(pUVM, DBGF_AS_KERNEL, "mach_kernel!_kmod", &SymInfo, NULL);
834 if (RT_SUCCESS(rc))
835 {
836 DBGFADDRESS AddrModInfo;
837 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &AddrModInfo, SymInfo.Value);
838
839 /* Read the variable. */
840 RTUINT64U uKmodValue = { 0 };
841 if (f64Bit)
842 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrModInfo, &uKmodValue.u, sizeof(uKmodValue.u));
843 else
844 rc = pVMM->pfnDBGFR3MemRead (pUVM, 0 /*idCpu*/, &AddrModInfo, &uKmodValue.s.Lo, sizeof(uKmodValue.s.Lo));
845 if (RT_SUCCESS(rc))
846 {
847 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &AddrModInfo, uKmodValue.u);
848
849 /* Walk the list of modules. */
850 uint32_t cIterations = 0;
851 while (AddrModInfo.FlatPtr != 0)
852 {
853 /* Some extra loop conditions... */
854 if (!OSX_VALID_ADDRESS(f64Bit, AddrModInfo.FlatPtr))
855 {
856 LogRel(("OSXDig: Invalid kmod_info pointer: %RGv\n", AddrModInfo.FlatPtr));
857 break;
858 }
859 if (AddrModInfo.FlatPtr == uKmodValue.u && cIterations != 0)
860 {
861 LogRel(("OSXDig: kmod_info list looped back to the start.\n"));
862 break;
863 }
864 if (cIterations++ >= 2048)
865 {
866 LogRel(("OSXDig: Too many mod_info loops (%u)\n", cIterations));
867 break;
868 }
869
870 /*
871 * Read the kmod_info_t structure.
872 */
873 union
874 {
875 OSX64_kmod_info_t Info64;
876 OSX32_kmod_info_t Info32;
877 } uMod;
878 RT_ZERO(uMod);
879 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, &AddrModInfo, &uMod,
880 f64Bit ? sizeof(uMod.Info64) : sizeof(uMod.Info32));
881 if (RT_FAILURE(rc))
882 {
883 LogRel(("OSXDig: Error reading kmod_info structure at %RGv: %Rrc\n", AddrModInfo.FlatPtr, rc));
884 break;
885 }
886
887 /*
888 * Validate the kmod_info_t structure.
889 */
890 int32_t iInfoVer = f64Bit ? uMod.Info64.info_version : uMod.Info32.info_version;
891 if (iInfoVer != OSX_KMOD_INFO_VERSION)
892 {
893 LogRel(("OSXDig: kmod_info @%RGv: Bad info_version %d\n", AddrModInfo.FlatPtr, iInfoVer));
894 break;
895 }
896
897 const char *pszName = f64Bit ? uMod.Info64.name : uMod.Info32.name;
898 if ( !*pszName
899 || !RTStrEnd(pszName, sizeof(uMod.Info64.name))
900 || !dbgDiggerDarwinIsValidName(pszName) )
901 {
902 LogRel(("OSXDig: kmod_info @%RGv: Bad name '%.*s'\n", AddrModInfo.FlatPtr,
903 sizeof(uMod.Info64.name), pszName));
904 break;
905 }
906
907 const char *pszVersion = f64Bit ? uMod.Info64.version : uMod.Info32.version;
908 if ( !RTStrEnd(pszVersion, sizeof(uMod.Info64.version))
909 || !dbgDiggerDarwinIsValidVersion(pszVersion) )
910 {
911 LogRel(("OSXDig: kmod_info @%RGv: Bad version '%.*s'\n", AddrModInfo.FlatPtr,
912 sizeof(uMod.Info64.version), pszVersion));
913 break;
914 }
915
916 int32_t cRefs = f64Bit ? uMod.Info64.reference_count : uMod.Info32.reference_count;
917 if (cRefs < -1 || cRefs > 16384)
918 {
919 LogRel(("OSXDig: kmod_info @%RGv: Bad reference_count %d\n", AddrModInfo.FlatPtr, cRefs));
920 break;
921 }
922
923 uint64_t uImageAddr = f64Bit ? uMod.Info64.address : uMod.Info32.address;
924 if (!OSX_VALID_ADDRESS(f64Bit, uImageAddr))
925 {
926 LogRel(("OSXDig: kmod_info @%RGv: Bad address %#llx\n", AddrModInfo.FlatPtr, uImageAddr));
927 break;
928 }
929
930 uint64_t cbImage = f64Bit ? uMod.Info64.size : uMod.Info32.size;
931 if (cbImage > 64U*_1M)
932 {
933 LogRel(("OSXDig: kmod_info @%RGv: Bad size %#llx\n", AddrModInfo.FlatPtr, cbImage));
934 break;
935 }
936
937 uint64_t cbHdr = f64Bit ? uMod.Info64.hdr_size : uMod.Info32.hdr_size;
938 if (cbHdr > 16U*_1M)
939 {
940 LogRel(("OSXDig: kmod_info @%RGv: Bad hdr_size %#llx\n", AddrModInfo.FlatPtr, cbHdr));
941 break;
942 }
943
944 uint64_t uStartAddr = f64Bit ? uMod.Info64.start : uMod.Info32.start;
945 if (!uStartAddr && !OSX_VALID_ADDRESS(f64Bit, uStartAddr))
946 {
947 LogRel(("OSXDig: kmod_info @%RGv: Bad start function %#llx\n", AddrModInfo.FlatPtr, uStartAddr));
948 break;
949 }
950
951 uint64_t uStopAddr = f64Bit ? uMod.Info64.stop : uMod.Info32.stop;
952 if (!uStopAddr && !OSX_VALID_ADDRESS(f64Bit, uStopAddr))
953 {
954 LogRel(("OSXDig: kmod_info @%RGv: Bad stop function %#llx\n", AddrModInfo.FlatPtr, uStopAddr));
955 break;
956 }
957
958 /*
959 * Try add the module.
960 */
961 LogRel(("OSXDig: kmod_info @%RGv: '%s' ver '%s', image @%#llx LB %#llx cbHdr=%#llx\n", AddrModInfo.FlatPtr,
962 pszName, pszVersion, uImageAddr, cbImage, cbHdr));
963 rc = dbgDiggerDarwinAddModule(pThis, pUVM, pVMM, uImageAddr, pszName, NULL);
964
965
966 /*
967 * Advance to the next kmod_info entry.
968 */
969 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &AddrModInfo, f64Bit ? uMod.Info64.next : uMod.Info32.next);
970 }
971 }
972 else
973 LogRel(("OSXDig: Error reading the 'kmod' variable: %Rrc\n", rc));
974 }
975 else
976 LogRel(("OSXDig: Failed to locate the 'kmod' variable in mach_kernel.\n"));
977
978 pThis->fValid = true;
979 return VINF_SUCCESS;
980 }
981
982 return rc;
983}
984
985
986/**
987 * @copydoc DBGFOSREG::pfnProbe
988 */
989static DECLCALLBACK(bool) dbgDiggerDarwinProbe(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
990{
991 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
992
993 /*
994 * Look for a section + segment combo that normally only occures in
995 * mach_kernel. Follow it up with probing of the rest of the executable
996 * header. We must search a largish area because the more recent versions
997 * of darwin have random load address for security raisins.
998 */
999 static struct { uint64_t uStart, uEnd; } const s_aRanges[] =
1000 {
1001 /* 64-bit: */
1002 { UINT64_C(0xffffff8000000000), UINT64_C(0xffffff81ffffffff), },
1003
1004 /* 32-bit - always search for this because of the hybrid 32-bit kernel
1005 with cpu in long mode that darwin used for a number of versions. */
1006 { UINT64_C(0x00001000), UINT64_C(0x0ffff000), }
1007 };
1008 for (unsigned iRange = pVMM->pfnDBGFR3CpuGetMode(pUVM, 0 /*idCpu*/) != CPUMMODE_LONG;
1009 iRange < RT_ELEMENTS(s_aRanges);
1010 iRange++)
1011 {
1012 DBGFADDRESS KernelAddr;
1013 for (pVMM->pfnDBGFR3AddrFromFlat(pUVM, &KernelAddr, s_aRanges[iRange].uStart);
1014 KernelAddr.FlatPtr < s_aRanges[iRange].uEnd;
1015 KernelAddr.FlatPtr += GUEST_PAGE_SIZE)
1016 {
1017 static const uint8_t s_abNeedle[16 + 16] =
1018 {
1019 '_','_','t','e','x','t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::sectname */
1020 '_','_','K','L','D', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::segname. */
1021 };
1022
1023 int rc = pVMM->pfnDBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, s_aRanges[iRange].uEnd - KernelAddr.FlatPtr,
1024 1, s_abNeedle, sizeof(s_abNeedle), &KernelAddr);
1025 if (RT_FAILURE(rc))
1026 break;
1027 pVMM->pfnDBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & GUEST_PAGE_OFFSET_MASK);
1028
1029 /*
1030 * Read the first page of the image and check the headers.
1031 */
1032 union
1033 {
1034 uint8_t ab[GUEST_PAGE_SIZE];
1035 mach_header_64_t Hdr64;
1036 mach_header_32_t Hdr32;
1037 } uBuf;
1038 rc = pVMM->pfnDBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, uBuf.ab, GUEST_PAGE_SIZE);
1039 if (RT_FAILURE(rc))
1040 continue;
1041 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
1042 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
1043 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
1044 continue;
1045 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
1046 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
1047 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
1048 continue;
1049 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
1050 if (uBuf.Hdr32.filetype != MH_EXECUTE)
1051 continue;
1052 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
1053 if (uBuf.Hdr32.ncmds > 256)
1054 continue;
1055 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
1056 if (uBuf.Hdr32.sizeofcmds > GUEST_PAGE_SIZE * 2 - sizeof(mach_header_64_t))
1057 continue;
1058
1059 /* Seems good enough for now.
1060
1061 If the above causes false positives, check the segments and make
1062 sure there is a kernel version string in the right one. */
1063 pThis->AddrKernel = KernelAddr;
1064 pThis->f64Bit = f64Bit;
1065
1066 /*
1067 * Finally, find the kernel version string.
1068 */
1069 rc = pVMM->pfnDBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, 32*_1M, 1, RT_STR_TUPLE("Darwin Kernel Version"),
1070 &pThis->AddrKernelVersion);
1071 if (RT_FAILURE(rc))
1072 pVMM->pfnDBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelVersion, 0);
1073 return true;
1074 }
1075 }
1076 return false;
1077}
1078
1079
1080/**
1081 * @copydoc DBGFOSREG::pfnDestruct
1082 */
1083static DECLCALLBACK(void) dbgDiggerDarwinDestruct(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
1084{
1085 RT_NOREF(pUVM, pVMM, pvData);
1086}
1087
1088
1089/**
1090 * @copydoc DBGFOSREG::pfnConstruct
1091 */
1092static DECLCALLBACK(int) dbgDiggerDarwinConstruct(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)
1093{
1094 RT_NOREF(pUVM, pVMM);
1095 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
1096
1097 pThis->IDmesg.u32Magic = DBGFOSIDMESG_MAGIC;
1098 pThis->IDmesg.pfnQueryKernelLog = dbgDiggerDarwinIDmsg_QueryKernelLog;
1099 pThis->IDmesg.u32EndMagic = DBGFOSIDMESG_MAGIC;
1100
1101 return VINF_SUCCESS;
1102}
1103
1104
1105const DBGFOSREG g_DBGDiggerDarwin =
1106{
1107 /* .u32Magic = */ DBGFOSREG_MAGIC,
1108 /* .fFlags = */ 0,
1109 /* .cbData = */ sizeof(DBGDIGGERDARWIN),
1110 /* .szName = */ "Darwin",
1111 /* .pfnConstruct = */ dbgDiggerDarwinConstruct,
1112 /* .pfnDestruct = */ dbgDiggerDarwinDestruct,
1113 /* .pfnProbe = */ dbgDiggerDarwinProbe,
1114 /* .pfnInit = */ dbgDiggerDarwinInit,
1115 /* .pfnRefresh = */ dbgDiggerDarwinRefresh,
1116 /* .pfnTerm = */ dbgDiggerDarwinTerm,
1117 /* .pfnQueryVersion = */ dbgDiggerDarwinQueryVersion,
1118 /* .pfnQueryInterface = */ dbgDiggerDarwinQueryInterface,
1119 /* .pfnStackUnwindAssist = */ dbgDiggerDarwinStackUnwindAssist,
1120 /* .u32EndMagic = */ DBGFOSREG_MAGIC
1121};
1122
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use