VirtualBox

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

Last change on this file since 96014 was 93470, checked in by vboxsync, 3 years ago

DbgPlugInDiggers,VMM,Main: Refactored the diggers and related interfaces to work via the VMM function table. Removed non-working tstVBoxDbg (needs proper COM now). bugref:10072

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