VirtualBox

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

Last change on this file since 49064 was 49061, checked in by vboxsync, 12 years ago

More Mach-O symbol hacking.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.0 KB
Line 
1/* $Id: DBGPlugInDarwin.cpp 49061 2013-10-11 20:15:59Z vboxsync $ */
2/** @file
3 * DBGPlugInDarwin - Debugger and Guest OS Digger Plugin For Darwin / OS X.
4 */
5
6/*
7 * Copyright (C) 2008-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGF ///@todo add new log group.
23#include "DBGPlugIns.h"
24#include <VBox/vmm/dbgf.h>
25#include <iprt/string.h>
26#include <iprt/mem.h>
27#include <iprt/stream.h>
28#include <iprt/uuid.h>
29#include <iprt/ctype.h>
30#include <iprt/formats/mach-o.h>
31
32
33/*******************************************************************************
34* Structures and Typedefs *
35*******************************************************************************/
36
37/** @name Internal Darwin structures
38 * @{ */
39
40
41/** @} */
42
43
44/**
45 * Linux guest OS digger instance data.
46 */
47typedef struct DBGDIGGERDARWIN
48{
49 /** Whether the information is valid or not.
50 * (For fending off illegal interface method calls.) */
51 bool fValid;
52
53 /** The address of an kernel version string (there are several).
54 * This is set during probing. */
55 DBGFADDRESS AddrKernelVersion;
56 /** Kernel base address.
57 * This is set during probing. */
58 DBGFADDRESS AddrKernel;
59} DBGDIGGERDARWIN;
60/** Pointer to the linux guest OS digger instance data. */
61typedef DBGDIGGERDARWIN *PDBGDIGGERDARWIN;
62
63
64/*******************************************************************************
65* Defined Constants And Macros *
66*******************************************************************************/
67/** Validates a 32-bit linux kernel address */
68#define DARWIN32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000))
69
70/** The max kernel size. */
71#define DARWIN_MAX_KERNEL_SIZE 0x0f000000
72
73/** AppleOsX on little endian ASCII systems. */
74#define DIG_DARWIN_MOD_TAG UINT64_C(0x58734f656c707041)
75
76
77/*******************************************************************************
78* Internal Functions *
79*******************************************************************************/
80static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, void *pvData);
81
82
83/*******************************************************************************
84* Global Variables *
85*******************************************************************************/
86/** Table of common linux kernel addresses. */
87static uint64_t g_au64LnxKernelAddresses[] =
88{
89 UINT64_C(0xc0100000),
90 UINT64_C(0x90100000),
91 UINT64_C(0xffffffff80200000)
92};
93
94
95/**
96 * @copydoc DBGFOSREG::pfnQueryInterface
97 */
98static DECLCALLBACK(void *) dbgDiggerDarwinQueryInterface(PUVM pUVM, void *pvData, DBGFOSINTERFACE enmIf)
99{
100 return NULL;
101}
102
103
104/**
105 * @copydoc DBGFOSREG::pfnQueryVersion
106 */
107static DECLCALLBACK(int) dbgDiggerDarwinQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
108{
109 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
110 Assert(pThis->fValid);
111
112 /*
113 * It's all in the linux banner.
114 */
115 int rc = DBGFR3MemReadString(pUVM, 0, &pThis->AddrKernelVersion, pszVersion, cchVersion);
116 if (RT_SUCCESS(rc))
117 {
118 char *pszEnd = RTStrEnd(pszVersion, cchVersion);
119 AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
120 while ( pszEnd > pszVersion
121 && RT_C_IS_SPACE(pszEnd[-1]))
122 pszEnd--;
123 *pszEnd = '\0';
124 }
125 else
126 RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemRead -> %Rrc", rc);
127
128 return rc;
129}
130
131
132/**
133 * @copydoc DBGFOSREG::pfnTerm
134 */
135static DECLCALLBACK(void) dbgDiggerDarwinTerm(PUVM pUVM, void *pvData)
136{
137 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
138
139 pThis->fValid = false;
140}
141
142
143/**
144 * @copydoc DBGFOSREG::pfnRefresh
145 */
146static DECLCALLBACK(int) dbgDiggerDarwinRefresh(PUVM pUVM, void *pvData)
147{
148 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
149 NOREF(pThis);
150 Assert(pThis->fValid);
151
152 /*
153 * For now we'll flush and reload everything.
154 */
155 dbgDiggerDarwinTerm(pUVM, pvData);
156 return dbgDiggerDarwinInit(pUVM, pvData);
157}
158
159
160/**
161 * Helper function that validates a segment (or section) name.
162 *
163 * @returns true if valid, false if not.
164 * @param pszName The name string.
165 * @param cbName The size of the string, including terminator.
166 */
167static bool dbgDiggerDarwinIsValidSegOrSectName(const char *pszName, size_t cbName)
168{
169 /* ascii chars */
170 char ch;
171 size_t off = 0;
172 while (off < cbName && (ch = pszName[off]))
173 {
174 if (RT_C_IS_CNTRL(ch) || ch > 127)
175 return false;
176 off++;
177 }
178
179 /* Not empty nor 100% full. */
180 if (off == 0 || off == cbName)
181 return false;
182
183 /* remainder should be zeros. */
184 while (off < cbName)
185 {
186 if (pszName[off])
187 return false;
188 off++;
189 }
190
191 return true;
192}
193
194
195static int dbgDiggerDarwinAddModule(PDBGDIGGERDARWIN pThis, PUVM pUVM, uint64_t uModAddr, const char *pszName)
196{
197 union
198 {
199 uint8_t ab[2 * X86_PAGE_4K_SIZE];
200 mach_header_64_t Hdr64;
201 mach_header_32_t Hdr32;
202 } uBuf;
203
204 /* Read the first page of the image. */
205 DBGFADDRESS ModAddr;
206 int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr), uBuf.ab, X86_PAGE_4K_SIZE);
207 if (RT_FAILURE(rc))
208 return rc;
209
210 /* Validate the header. */
211 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
212 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
213 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
214 return VERR_INVALID_EXE_SIGNATURE;
215 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
216 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
217 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
218 return VERR_LDR_ARCH_MISMATCH;
219 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
220 if ( uBuf.Hdr32.filetype != MH_EXECUTE
221 && uBuf.Hdr32.filetype != (f64Bit ? MH_KEXT_BUNDLE : MH_OBJECT))
222 return VERR_BAD_EXE_FORMAT;
223 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
224 if (uBuf.Hdr32.ncmds > 256)
225 return VERR_BAD_EXE_FORMAT;
226 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
227 if (uBuf.Hdr32.sizeofcmds > X86_PAGE_4K_SIZE * 2 - sizeof(mach_header_64_t))
228 return VERR_BAD_EXE_FORMAT;
229
230 /* Do we need to read a 2nd page to get all the load commands? If so, do it. */
231 if (uBuf.Hdr32.sizeofcmds + (f64Bit ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t)) > X86_PAGE_4K_SIZE)
232 {
233 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrFromFlat(pUVM, &ModAddr, uModAddr + X86_PAGE_4K_SIZE),
234 &uBuf.ab[X86_PAGE_4K_SIZE], X86_PAGE_4K_SIZE);
235 if (RT_FAILURE(rc))
236 return rc;
237 }
238
239 /*
240 * Process the load commands.
241 */
242 RTDBGSEGMENT aSegs[12];
243 uint32_t cSegs = 0;
244 RTUUID Uuid = RTUUID_INITIALIZE_NULL;
245 uint32_t cLeft = uBuf.Hdr32.ncmds;
246 uint32_t cbLeft = uBuf.Hdr32.sizeofcmds;
247 union
248 {
249 uint8_t const *pb;
250 load_command_t const *pGenric;
251 segment_command_32_t const *pSeg32;
252 segment_command_64_t const *pSeg64;
253 section_32_t const *pSect32;
254 section_64_t const *pSect64;
255 symtab_command_t const *pSymTab;
256 uuid_command_t const *pUuid;
257 } uLCmd;
258 uLCmd.pb = &uBuf.ab[f64Bit ? sizeof(mach_header_64_t) : sizeof(mach_header_32_t)];
259
260 while (cLeft-- > 0)
261 {
262 uint32_t const cbCmd = uLCmd.pGenric->cmdsize;
263 if (cbCmd > cbLeft || cbCmd < sizeof(load_command_t))
264 return VERR_BAD_EXE_FORMAT;
265
266 switch (uLCmd.pGenric->cmd)
267 {
268 case LC_SEGMENT_32:
269 if (cbCmd != sizeof(segment_command_32_t) + uLCmd.pSeg32->nsects * sizeof(section_32_t))
270 return VERR_BAD_EXE_FORMAT;
271 if (!dbgDiggerDarwinIsValidSegOrSectName(uLCmd.pSeg32->segname, sizeof(uLCmd.pSeg32->segname)))
272 return VERR_INVALID_NAME;
273 if (!strcmp(uLCmd.pSeg32->segname, "__LINKEDIT"))
274 break; /* This usually is discarded or not loaded at all. */
275 if (cSegs >= RT_ELEMENTS(aSegs))
276 return VERR_BUFFER_OVERFLOW;
277 aSegs[cSegs].Address = uLCmd.pSeg32->vmaddr;
278 aSegs[cSegs].uRva = uLCmd.pSeg32->vmaddr - uModAddr;
279 aSegs[cSegs].cb = uLCmd.pSeg32->vmsize;
280 aSegs[cSegs].fFlags = uLCmd.pSeg32->flags; /* Abusing the flags field here... */
281 aSegs[cSegs].iSeg = cSegs;
282 AssertCompile(RTDBG_SEGMENT_NAME_LENGTH > sizeof(uLCmd.pSeg32->segname));
283 strcpy(aSegs[cSegs].szName, uLCmd.pSeg32->segname);
284 cSegs++;
285 break;
286
287 case LC_SEGMENT_64:
288 if (cbCmd != sizeof(segment_command_64_t) + uLCmd.pSeg64->nsects * sizeof(section_64_t))
289 return VERR_BAD_EXE_FORMAT;
290 if (!dbgDiggerDarwinIsValidSegOrSectName(uLCmd.pSeg64->segname, sizeof(uLCmd.pSeg64->segname)))
291 return VERR_INVALID_NAME;
292 if (!strcmp(uLCmd.pSeg64->segname, "__LINKEDIT"))
293 break; /* This usually is discarded or not loaded at all. */
294 if (cSegs >= RT_ELEMENTS(aSegs))
295 return VERR_BUFFER_OVERFLOW;
296 aSegs[cSegs].Address = uLCmd.pSeg64->vmaddr;
297 aSegs[cSegs].uRva = uLCmd.pSeg64->vmaddr - uModAddr;
298 aSegs[cSegs].cb = uLCmd.pSeg64->vmsize;
299 aSegs[cSegs].fFlags = uLCmd.pSeg64->flags; /* Abusing the flags field here... */
300 aSegs[cSegs].iSeg = cSegs;
301 AssertCompile(RTDBG_SEGMENT_NAME_LENGTH > sizeof(uLCmd.pSeg64->segname));
302 strcpy(aSegs[cSegs].szName, uLCmd.pSeg64->segname);
303 cSegs++;
304 break;
305
306 case LC_UUID:
307 if (cbCmd != sizeof(uuid_command_t))
308 return VERR_BAD_EXE_FORMAT;
309 if (RTUuidIsNull((PCRTUUID)&uLCmd.pUuid->uuid[0]))
310 return VERR_BAD_EXE_FORMAT;
311 memcpy(&Uuid, &uLCmd.pUuid->uuid[0], sizeof(uLCmd.pUuid->uuid));
312 break;
313
314 default:
315 /* Current known max plus a lot of slack. */
316 if (uLCmd.pGenric->cmd > LC_DYLIB_CODE_SIGN_DRS + 32)
317 return VERR_BAD_EXE_FORMAT;
318 break;
319 }
320
321 /* next */
322 cbLeft -= cbCmd;
323 uLCmd.pb += cbCmd;
324 }
325
326 if (cbLeft != 0)
327 return VERR_BAD_EXE_FORMAT;
328
329 /*
330 * Some post processing checks.
331 */
332 uint32_t iSeg;
333 for (iSeg = 0; iSeg < cSegs; iSeg++)
334 if (aSegs[iSeg].Address == uModAddr)
335 break;
336 if (iSeg >= cSegs)
337 return VERR_ADDRESS_CONFLICT;
338
339 /*
340 * Create a debug module.
341 */
342 RTDBGMOD hMod;
343 rc = RTDbgModCreateFromMachOImage(&hMod, pszName, NULL, f64Bit ? RTLDRARCH_AMD64 : RTLDRARCH_X86_32, 0 /*cbImage*/,
344 cSegs, aSegs, &Uuid, DBGFR3AsGetConfig(pUVM), RTDBGMOD_F_NOT_DEFERRED);
345
346 if (RT_FAILURE(rc))
347 {
348 /*
349 * Final fallback is a container module.
350 */
351 rc = RTDbgModCreate(&hMod, pszName, 0, 0);
352 if (RT_FAILURE(rc))
353 return rc;
354
355 uint64_t uRvaNext = 0;
356 for (iSeg = 0; iSeg < cSegs && RT_SUCCESS(rc); iSeg++)
357 {
358 if ( aSegs[iSeg].uRva > uRvaNext
359 && aSegs[iSeg].uRva - uRvaNext < _1M)
360 uRvaNext = aSegs[iSeg].uRva;
361 rc = RTDbgModSegmentAdd(hMod, aSegs[iSeg].uRva, aSegs[iSeg].cb, aSegs[iSeg].szName, 0, NULL);
362 if (aSegs[iSeg].cb > 0 && RT_SUCCESS(rc))
363 {
364 char szTmp[RTDBG_SEGMENT_NAME_LENGTH + sizeof("_start")];
365 strcat(strcpy(szTmp, aSegs[iSeg].szName), "_start");
366 rc = RTDbgModSymbolAdd(hMod, szTmp, iSeg, 0 /*uRva*/, 0 /*cb*/, 0 /*fFlags*/, NULL);
367 }
368 uRvaNext += aSegs[iSeg].cb;
369 }
370
371 if (RT_FAILURE(rc))
372 {
373 RTDbgModRelease(hMod);
374 return rc;
375 }
376 }
377
378 /* Tag the module. */
379 rc = RTDbgModSetTag(hMod, DIG_DARWIN_MOD_TAG);
380 AssertRC(rc);
381
382 /*
383 * Link the module.
384 */
385 RTDBGAS hAs = DBGFR3AsResolveAndRetain(pUVM, DBGF_AS_KERNEL);
386 if (hAs != NIL_RTDBGAS)
387 {
388 uint64_t uRvaNext = 0;
389 uint32_t cLinked = 0;
390 iSeg = cSegs;
391 while (iSeg-- > 0) /* HACK: Map in reverse order to avoid replacing __TEXT. */
392 if (aSegs[iSeg].cb)
393 {
394 /* Find matching segment in the debug module. */
395 uint32_t iDbgSeg = 0;
396 while (iDbgSeg < cSegs)
397 {
398 RTDBGSEGMENT SegInfo;
399 int rc3 = RTDbgModSegmentByIndex(hMod, iDbgSeg, &SegInfo);
400 if (RT_SUCCESS(rc3) && !strcmp(SegInfo.szName, aSegs[iSeg].szName))
401 break;
402 iDbgSeg++;
403 }
404 AssertMsgStmt(iDbgSeg < cSegs, ("%s\n", aSegs[iSeg].szName), continue);
405
406 /* Map it. */
407 int rc2 = RTDbgAsModuleLinkSeg(hAs, hMod, iDbgSeg, aSegs[iSeg].Address, RTDBGASLINK_FLAGS_REPLACE /*fFlags*/);
408 if (RT_SUCCESS(rc2))
409 cLinked++;
410 else if (RT_SUCCESS(rc))
411 rc = rc2;
412 }
413 if (RT_FAILURE(rc) && cLinked != 0)
414 rc = -rc;
415 }
416 else
417 rc = VERR_INTERNAL_ERROR;
418 RTDbgModRelease(hMod);
419 RTDbgAsRelease(hAs);
420
421 return rc;
422}
423
424/**
425 * @copydoc DBGFOSREG::pfnInit
426 */
427static DECLCALLBACK(int) dbgDiggerDarwinInit(PUVM pUVM, void *pvData)
428{
429 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
430 Assert(!pThis->fValid);
431
432 /*
433 * Add the kernel module (and later the other kernel modules we can find).
434 */
435 int rc = dbgDiggerDarwinAddModule(pThis, pUVM, pThis->AddrKernel.FlatPtr, "mach_kernel");
436 if (RT_SUCCESS(rc))
437 {
438 /** @todo */
439 pThis->fValid = true;
440 return VINF_SUCCESS;
441 }
442
443 return rc;
444}
445
446
447/**
448 * @copydoc DBGFOSREG::pfnProbe
449 */
450static DECLCALLBACK(bool) dbgDiggerDarwinProbe(PUVM pUVM, void *pvData)
451{
452 PDBGDIGGERDARWIN pThis = (PDBGDIGGERDARWIN)pvData;
453
454 /*
455 * Look for a section + segment combo that normally only occures in
456 * mach_kernel. Follow it up with probing of the rest of the executable
457 * header. We must search a largish area because the more recent versions
458 * of darwin have random load address for security raisins.
459 */
460 static struct { uint64_t uStart, uEnd; } const s_aRanges[] =
461 {
462 /* 64-bit: */
463 { UINT64_C(0xffffff8000000000), UINT64_C(0xffffff81ffffffff), },
464
465 /* 32-bit - always search for this because of the hybrid 32-bit kernel
466 with cpu in long mode that darwin used for a number of versions. */
467 { UINT64_C(0x00001000), UINT64_C(0x0ffff000), }
468 };
469 for (unsigned iRange = DBGFR3CpuGetMode(pUVM, 0 /*idCpu*/) != CPUMMODE_LONG;
470 iRange < RT_ELEMENTS(s_aRanges);
471 iRange++)
472 {
473 DBGFADDRESS KernelAddr;
474 for (DBGFR3AddrFromFlat(pUVM, &KernelAddr, s_aRanges[iRange].uStart);
475 KernelAddr.FlatPtr < s_aRanges[iRange].uEnd;
476 KernelAddr.FlatPtr += X86_PAGE_4K_SIZE)
477 {
478 static const uint8_t s_abNeedle[16 + 16] =
479 {
480 '_','_','t','e','x','t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::sectname */
481 '_','_','K','L','D', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* section_32_t::segname. */
482 };
483
484 int rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, s_aRanges[iRange].uEnd - KernelAddr.FlatPtr,
485 1, s_abNeedle, sizeof(s_abNeedle), &KernelAddr);
486 if (RT_FAILURE(rc))
487 break;
488 DBGFR3AddrSub(&KernelAddr, KernelAddr.FlatPtr & X86_PAGE_4K_OFFSET_MASK);
489
490 /*
491 * Read the first page of the image and check the headers.
492 */
493 union
494 {
495 uint8_t ab[X86_PAGE_4K_SIZE];
496 mach_header_64_t Hdr64;
497 mach_header_32_t Hdr32;
498 } uBuf;
499 rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, &KernelAddr, uBuf.ab, X86_PAGE_4K_SIZE);
500 if (RT_FAILURE(rc))
501 continue;
502 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, magic, mach_header_32_t, magic);
503 if ( uBuf.Hdr64.magic != IMAGE_MACHO64_SIGNATURE
504 && uBuf.Hdr32.magic != IMAGE_MACHO32_SIGNATURE)
505 continue;
506 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, cputype, mach_header_32_t, cputype);
507 bool f64Bit = uBuf.Hdr64.magic == IMAGE_MACHO64_SIGNATURE;
508 if (uBuf.Hdr32.cputype != (f64Bit ? CPU_TYPE_X86_64 : CPU_TYPE_I386))
509 continue;
510 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, filetype, mach_header_32_t, filetype);
511 if (uBuf.Hdr32.filetype != MH_EXECUTE)
512 continue;
513 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, ncmds, mach_header_32_t, ncmds);
514 if (uBuf.Hdr32.ncmds > 256)
515 continue;
516 AssertCompileMembersSameSizeAndOffset(mach_header_64_t, sizeofcmds, mach_header_32_t, sizeofcmds);
517 if (uBuf.Hdr32.sizeofcmds > X86_PAGE_4K_SIZE - sizeof(mach_header_64_t))
518 continue;
519
520 /* Seems good enough for now.
521
522 If the above causes false positives, check the segments and make
523 sure there is a kernel version string in the right one. */
524 pThis->AddrKernel = KernelAddr;
525
526 /*
527 * Finally, find the kernel version string.
528 */
529 rc = DBGFR3MemScan(pUVM, 0 /*idCpu*/, &KernelAddr, 32*_1M, 1, RT_STR_TUPLE("Darwin Kernel Version"),
530 &pThis->AddrKernelVersion);
531 if (RT_FAILURE(rc))
532 DBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelVersion, 0);
533 return true;
534 }
535 }
536 return false;
537}
538
539
540/**
541 * @copydoc DBGFOSREG::pfnDestruct
542 */
543static DECLCALLBACK(void) dbgDiggerDarwinDestruct(PUVM pUVM, void *pvData)
544{
545
546}
547
548
549/**
550 * @copydoc DBGFOSREG::pfnConstruct
551 */
552static DECLCALLBACK(int) dbgDiggerDarwinConstruct(PUVM pUVM, void *pvData)
553{
554 return VINF_SUCCESS;
555}
556
557
558const DBGFOSREG g_DBGDiggerDarwin =
559{
560 /* .u32Magic = */ DBGFOSREG_MAGIC,
561 /* .fFlags = */ 0,
562 /* .cbData = */ sizeof(DBGDIGGERDARWIN),
563 /* .szName = */ "Darwin",
564 /* .pfnConstruct = */ dbgDiggerDarwinConstruct,
565 /* .pfnDestruct = */ dbgDiggerDarwinDestruct,
566 /* .pfnProbe = */ dbgDiggerDarwinProbe,
567 /* .pfnInit = */ dbgDiggerDarwinInit,
568 /* .pfnRefresh = */ dbgDiggerDarwinRefresh,
569 /* .pfnTerm = */ dbgDiggerDarwinTerm,
570 /* .pfnQueryVersion = */ dbgDiggerDarwinQueryVersion,
571 /* .pfnQueryInterface = */ dbgDiggerDarwinQueryInterface,
572 /* .u32EndMagic = */ DBGFOSREG_MAGIC
573};
574
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette