VirtualBox

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

Last change on this file since 86208 was 83085, checked in by vboxsync, 5 years ago

IPRT,VMM,DBGPlugInDarwin: Implemented in-memory guest kernel and kext image loading for OS X / Mach-O. Requires LINKEDIT to not be jettisoned to work.

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