VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/darwin/dbgkrnlinfo-r0drv-darwin.cpp@ 48905

Last change on this file since 48905 was 48905, checked in by vboxsync, 11 years ago

Promoted Runtime/include/internal/ldrMach-O.h to include/iprt/formats/mach-o.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.3 KB
Line 
1/* $Id: dbgkrnlinfo-r0drv-darwin.cpp 48905 2013-10-05 16:39:36Z vboxsync $ */
2/** @file
3 * IPRT - Kernel Debug Information, R0 Driver, Darwin.
4 */
5
6/*
7 * Copyright (C) 2011-2012 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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#ifdef IN_RING0
32# include "the-darwin-kernel.h"
33# include <sys/kauth.h>
34RT_C_DECLS_BEGIN /* Buggy 10.4 headers, fixed in 10.5. */
35# include <sys/kpi_mbuf.h>
36# include <net/kpi_interfacefilter.h>
37# include <sys/kpi_socket.h>
38# include <sys/kpi_socketfilter.h>
39RT_C_DECLS_END
40# include <sys/buf.h>
41# include <sys/vm.h>
42# include <sys/vnode_if.h>
43/*# include <sys/sysctl.h>*/
44# include <sys/systm.h>
45# include <vfs/vfs_support.h>
46/*# include <miscfs/specfs/specdev.h>*/
47#endif
48
49#include "internal/iprt.h"
50#include <iprt/dbg.h>
51
52#include <iprt/asm.h>
53#include <iprt/assert.h>
54#include <iprt/err.h>
55#include <iprt/assert.h>
56#include <iprt/file.h>
57#include <iprt/log.h>
58#include <iprt/mem.h>
59#include <iprt/string.h>
60#include <iprt/formats/mach-o.h>
61#include "internal/magics.h"
62
63/** @def MY_CPU_TYPE
64 * The CPU type targeted by the compiler. */
65/** @def MY_CPU_TYPE
66 * The "ALL" CPU subtype targeted by the compiler. */
67/** @def MY_MACHO_HEADER
68 * The Mach-O header targeted by the compiler. */
69/** @def MY_MACHO_MAGIC
70 * The Mach-O header magic we're targeting. */
71/** @def MY_SEGMENT_COMMAND
72 * The segment command targeted by the compiler. */
73/** @def MY_SECTION
74 * The section struture targeted by the compiler. */
75/** @def MY_NLIST
76 * The symbol table entry targeted by the compiler. */
77#ifdef RT_ARCH_X86
78# define MY_CPU_TYPE CPU_TYPE_I386
79# define MY_CPU_SUBTYPE_ALL CPU_SUBTYPE_I386_ALL
80# define MY_MACHO_HEADER mach_header_32_t
81# define MY_MACHO_MAGIC IMAGE_MACHO32_SIGNATURE
82# define MY_SEGMENT_COMMAND segment_command_32_t
83# define MY_SECTION section_32_t
84# define MY_NLIST macho_nlist_32_t
85
86#elif defined(RT_ARCH_AMD64)
87# define MY_CPU_TYPE CPU_TYPE_X86_64
88# define MY_CPU_SUBTYPE_ALL CPU_SUBTYPE_X86_64_ALL
89# define MY_MACHO_HEADER mach_header_64_t
90# define MY_MACHO_MAGIC IMAGE_MACHO64_SIGNATURE
91# define MY_SEGMENT_COMMAND segment_command_64_t
92# define MY_SECTION section_64_t
93# define MY_NLIST macho_nlist_64_t
94
95#else
96# error "Port me!"
97#endif
98
99/** @name Return macros for make it simpler to track down too paranoid code.
100 * @{
101 */
102#ifdef DEBUG
103# define RETURN_VERR_BAD_EXE_FORMAT \
104 do { Assert(!g_fBreakpointOnError); return VERR_BAD_EXE_FORMAT; } while (0)
105# define RETURN_VERR_LDR_UNEXPECTED \
106 do { Assert(!g_fBreakpointOnError); return VERR_LDR_UNEXPECTED; } while (0)
107# define RETURN_VERR_LDR_ARCH_MISMATCH \
108 do { Assert(!g_fBreakpointOnError); return VERR_LDR_ARCH_MISMATCH; } while (0)
109#else
110# define RETURN_VERR_BAD_EXE_FORMAT do { return VERR_BAD_EXE_FORMAT; } while (0)
111# define RETURN_VERR_LDR_UNEXPECTED do { return VERR_LDR_UNEXPECTED; } while (0)
112# define RETURN_VERR_LDR_ARCH_MISMATCH do { return VERR_LDR_ARCH_MISMATCH; } while (0)
113#endif
114/** @} */
115
116#define VERR_LDR_UNEXPECTED (-641)
117
118
119/*******************************************************************************
120* Structures and Typedefs *
121*******************************************************************************/
122/**
123 * Our internal representation of the mach_kernel after loading it's symbols
124 * and successfully resolving their addresses.
125 */
126typedef struct RTDBGKRNLINFOINT
127{
128 /** Magic value (RTDBGKRNLINFO_MAGIC). */
129 uint32_t u32Magic;
130 /** Reference counter. */
131 uint32_t volatile cRefs;
132
133 /** @name Result.
134 * @{ */
135 /** Pointer to the string table. */
136 char *pachStrTab;
137 /** The size of the string table. */
138 uint32_t cbStrTab;
139 /** The file offset of the string table. */
140 uint32_t offStrTab;
141 /** Pointer to the symbol table. */
142 MY_NLIST *paSyms;
143 /** The size of the symbol table. */
144 uint32_t cSyms;
145 /** The file offset of the symbol table. */
146 uint32_t offSyms;
147 /** Offset between link address and actual load address. */
148 uintptr_t offLoad;
149 /** @} */
150
151 /** @name Used during loading.
152 * @{ */
153 /** The file handle. */
154 RTFILE hFile;
155 /** The architecture image offset (fat_arch_t::offset). */
156 uint64_t offArch;
157 /** The architecture image size (fat_arch_t::size). */
158 uint32_t cbArch;
159 /** The number of load commands (mach_header_XX_t::ncmds). */
160 uint32_t cLoadCmds;
161 /** The size of the load commands. */
162 uint32_t cbLoadCmds;
163 /** The load commands. */
164 load_command_t *pLoadCmds;
165 /** Section pointer table (points into the load commands). */
166 MY_SECTION const *apSections[MACHO_MAX_SECT];
167 /** The number of sections. */
168 uint32_t cSections;
169 /** @} */
170
171 /** Buffer space. */
172 char abBuf[_4K];
173} RTDBGKRNLINFOINT;
174
175
176/*******************************************************************************
177* Structures and Typedefs *
178*******************************************************************************/
179#ifdef DEBUG
180static bool g_fBreakpointOnError = false;
181#endif
182
183
184#ifdef IN_RING0
185
186/** Default file permissions for newly created files. */
187#if defined(S_IRUSR) && defined(S_IWUSR)
188# define RT_FILE_PERMISSION (S_IRUSR | S_IWUSR)
189#else
190# define RT_FILE_PERMISSION (00600)
191#endif
192
193/**
194 * Darwin kernel file handle data.
195 */
196typedef struct RTFILEINT
197{
198 /** Magic value (RTFILE_MAGIC). */
199 uint32_t u32Magic;
200 /** The open mode flags passed to the kernel API. */
201 int fOpenMode;
202 /** The open flags passed to RTFileOpen. */
203 uint64_t fOpen;
204 /** The VFS context in which the file was opened. */
205 vfs_context_t hVfsCtx;
206 /** The vnode returned by vnode_open. */
207 vnode_t hVnode;
208} RTFILEINT;
209/** Magic number for RTFILEINT::u32Magic (To Be Determined). */
210#define RTFILE_MAGIC UINT32_C(0x01020304)
211
212
213RTDECL(int) RTFileOpen(PRTFILE phFile, const char *pszFilename, uint64_t fOpen)
214{
215 RTFILEINT *pThis = (RTFILEINT *)RTMemAllocZ(sizeof(*pThis));
216 if (!pThis)
217 return VERR_NO_MEMORY;
218
219 errno_t rc;
220 pThis->u32Magic = RTFILE_MAGIC;
221 pThis->fOpen = fOpen;
222 pThis->hVfsCtx = vfs_context_current();
223 if (pThis->hVfsCtx != NULL)
224 {
225 int fCMode = (fOpen & RTFILE_O_CREATE_MODE_MASK)
226 ? (fOpen & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT
227 : RT_FILE_PERMISSION;
228 int fVnFlags = 0; /* VNODE_LOOKUP_XXX */
229 int fOpenMode = 0;
230 if (fOpen & RTFILE_O_NON_BLOCK)
231 fOpenMode |= O_NONBLOCK;
232 if (fOpen & RTFILE_O_WRITE_THROUGH)
233 fOpenMode |= O_SYNC;
234
235 /* create/truncate file */
236 switch (fOpen & RTFILE_O_ACTION_MASK)
237 {
238 case RTFILE_O_OPEN: break;
239 case RTFILE_O_OPEN_CREATE: fOpenMode |= O_CREAT; break;
240 case RTFILE_O_CREATE: fOpenMode |= O_CREAT | O_EXCL; break;
241 case RTFILE_O_CREATE_REPLACE: fOpenMode |= O_CREAT | O_TRUNC; break; /** @todo replacing needs fixing, this is *not* a 1:1 mapping! */
242 }
243 if (fOpen & RTFILE_O_TRUNCATE)
244 fOpenMode |= O_TRUNC;
245
246 switch (fOpen & RTFILE_O_ACCESS_MASK)
247 {
248 case RTFILE_O_READ:
249 fOpenMode |= FREAD;
250 break;
251 case RTFILE_O_WRITE:
252 fOpenMode |= fOpen & RTFILE_O_APPEND ? O_APPEND | FWRITE : FWRITE;
253 break;
254 case RTFILE_O_READWRITE:
255 fOpenMode |= fOpen & RTFILE_O_APPEND ? O_APPEND | FWRITE | FREAD : FWRITE | FREAD;
256 break;
257 default:
258 AssertMsgFailed(("RTFileOpen received an invalid RW value, fOpen=%#x\n", fOpen));
259 return VERR_INVALID_PARAMETER;
260 }
261
262 pThis->fOpenMode = fOpenMode;
263 rc = vnode_open(pszFilename, fOpenMode, fCMode, fVnFlags, &pThis->hVnode, pThis->hVfsCtx);
264 if (rc == 0)
265 {
266 *phFile = pThis;
267 return VINF_SUCCESS;
268 }
269
270 rc = RTErrConvertFromErrno(rc);
271 }
272 else
273 rc = VERR_INTERNAL_ERROR_5;
274 RTMemFree(pThis);
275
276 return rc;
277}
278
279
280RTDECL(int) RTFileClose(RTFILE hFile)
281{
282 if (hFile == NIL_RTFILE)
283 return VINF_SUCCESS;
284
285 RTFILEINT *pThis = hFile;
286 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
287 AssertReturn(pThis->u32Magic == RTFILE_MAGIC, VERR_INVALID_HANDLE);
288 pThis->u32Magic = ~RTFILE_MAGIC;
289
290 errno_t rc = vnode_close(pThis->hVnode, pThis->fOpenMode & (FREAD | FWRITE), pThis->hVfsCtx);
291
292 RTMemFree(pThis);
293 return RTErrConvertFromErrno(rc);
294}
295
296
297RTDECL(int) RTFileReadAt(RTFILE hFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
298{
299 RTFILEINT *pThis = hFile;
300 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
301 AssertReturn(pThis->u32Magic == RTFILE_MAGIC, VERR_INVALID_HANDLE);
302
303 off_t offNative = (off_t)off;
304 AssertReturn((RTFOFF)offNative == off, VERR_OUT_OF_RANGE);
305
306#if 0 /* Added in 10.6, grr. */
307 errno_t rc;
308 if (!pcbRead)
309 rc = vn_rdwr(UIO_READ, pThis->hVnode, (char *)pvBuf, cbToRead, offNative, UIO_SYSSPACE, 0 /*ioflg*/,
310 vfs_context_ucred(pThis->hVfsCtx), NULL, vfs_context_proc(pThis->hVfsCtx));
311 else
312 {
313 int cbLeft = 0;
314 rc = vn_rdwr(UIO_READ, pThis->hVnode, (char *)pvBuf, cbToRead, offNative, UIO_SYSSPACE, 0 /*ioflg*/,
315 vfs_context_ucred(pThis->hVfsCtx), &cbLeft, vfs_context_proc(pThis->hVfsCtx));
316 *pcbRead = cbToRead - cbLeft;
317 }
318 return !rc ? VINF_SUCCESS : RTErrConvertFromErrno(rc);
319
320#else
321 uio_t hUio = uio_create(1, offNative, UIO_SYSSPACE, UIO_READ);
322 if (!hUio)
323 return VERR_NO_MEMORY;
324 errno_t rc;
325 if (uio_addiov(hUio, (user_addr_t)(uintptr_t)pvBuf, cbToRead) == 0)
326 {
327 rc = VNOP_READ(pThis->hVnode, hUio, 0 /*ioflg*/, pThis->hVfsCtx);
328 if (pcbRead)
329 *pcbRead = cbToRead - uio_resid(hUio);
330 else if (!rc && uio_resid(hUio))
331 rc = VERR_FILE_IO_ERROR;
332 }
333 else
334 rc = VERR_INTERNAL_ERROR_3;
335 uio_free(hUio);
336 return rc;
337
338#endif
339}
340
341#endif
342
343
344/**
345 * Close and free up resources we no longer needs.
346 *
347 * @param pThis The internal scratch data.
348 */
349static void rtR0DbgKrnlDarwinLoadDone(RTDBGKRNLINFOINT *pThis)
350{
351 RTFileClose(pThis->hFile);
352 pThis->hFile = NIL_RTFILE;
353
354 RTMemFree(pThis->pLoadCmds);
355 pThis->pLoadCmds = NULL;
356 memset((void *)&pThis->apSections[0], 0, sizeof(pThis->apSections[0]) * MACHO_MAX_SECT);
357}
358
359
360/**
361 * Looks up a kernel symbol.
362 *
363 * @returns The symbol address on success, 0 on failure.
364 * @param pThis The internal scratch data.
365 * @param pszSymbol The symbol to resolve. Automatically prefixed
366 * with an underscore.
367 */
368static uintptr_t rtR0DbgKrnlDarwinLookup(RTDBGKRNLINFOINT *pThis, const char *pszSymbol)
369{
370 uint32_t const cSyms = pThis->cSyms;
371 MY_NLIST const *pSym = pThis->paSyms;
372
373#if 1
374 /* linear search. */
375 for (uint32_t iSym = 0; iSym < cSyms; iSym++, pSym++)
376 {
377 if (pSym->n_type & MACHO_N_STAB)
378 continue;
379
380 const char *pszTabName= &pThis->pachStrTab[(uint32_t)pSym->n_un.n_strx];
381 if ( *pszTabName == '_'
382 && strcmp(pszTabName + 1, pszSymbol) == 0)
383 return pSym->n_value + pThis->offLoad;
384 }
385#else
386 /** @todo binary search. */
387
388#endif
389 return 0;
390}
391
392
393/* Rainy day: Find the right headers for these symbols ... if there are any. */
394extern "C" void ev_try_lock(void);
395extern "C" void OSMalloc(void);
396extern "C" void OSlibkernInit(void);
397extern "C" void kdp_set_interface(void);
398
399
400/**
401 * Check the symbol table against symbols we known symbols.
402 *
403 * This is done to detect whether the on disk image and the in
404 * memory images matches. Mismatches could stem from user
405 * replacing the default kernel image on disk.
406 *
407 * @returns IPRT status code.
408 * @param pThis The internal scratch data.
409 */
410static int rtR0DbgKrnlDarwinCheckStandardSymbols(RTDBGKRNLINFOINT *pThis)
411{
412 static struct
413 {
414 const char *pszName;
415 uintptr_t uAddr;
416 } const s_aStandardCandles[] =
417 {
418#ifdef IN_RING0
419# define KNOWN_ENTRY(a_Sym) { #a_Sym, (uintptr_t)&a_Sym }
420#else
421# define KNOWN_ENTRY(a_Sym) { #a_Sym, 0 }
422#endif
423 /* IOKit: */
424 KNOWN_ENTRY(IOMalloc),
425 KNOWN_ENTRY(IOFree),
426 KNOWN_ENTRY(IOSleep),
427 KNOWN_ENTRY(IORWLockAlloc),
428 KNOWN_ENTRY(IORecursiveLockLock),
429 KNOWN_ENTRY(IOSimpleLockAlloc),
430 KNOWN_ENTRY(PE_cpu_halt),
431 KNOWN_ENTRY(gIOKitDebug),
432 KNOWN_ENTRY(gIOServicePlane),
433 KNOWN_ENTRY(ev_try_lock),
434
435 /* Libkern: */
436 KNOWN_ENTRY(OSAddAtomic),
437 KNOWN_ENTRY(OSBitAndAtomic),
438 KNOWN_ENTRY(OSBitOrAtomic),
439 KNOWN_ENTRY(OSBitXorAtomic),
440 KNOWN_ENTRY(OSCompareAndSwap),
441 KNOWN_ENTRY(OSMalloc),
442 KNOWN_ENTRY(OSlibkernInit),
443 KNOWN_ENTRY(bcmp),
444 KNOWN_ENTRY(copyout),
445 KNOWN_ENTRY(copyin),
446 KNOWN_ENTRY(kprintf),
447 KNOWN_ENTRY(printf),
448 KNOWN_ENTRY(lck_grp_alloc_init),
449 KNOWN_ENTRY(lck_mtx_alloc_init),
450 KNOWN_ENTRY(lck_rw_alloc_init),
451 KNOWN_ENTRY(lck_spin_alloc_init),
452 KNOWN_ENTRY(osrelease),
453 KNOWN_ENTRY(ostype),
454 KNOWN_ENTRY(panic),
455 KNOWN_ENTRY(strprefix),
456 KNOWN_ENTRY(sysctlbyname),
457 KNOWN_ENTRY(vsscanf),
458 KNOWN_ENTRY(page_mask),
459
460 /* Mach: */
461 KNOWN_ENTRY(absolutetime_to_nanoseconds),
462 KNOWN_ENTRY(assert_wait),
463 KNOWN_ENTRY(clock_delay_until),
464 KNOWN_ENTRY(clock_get_uptime),
465 KNOWN_ENTRY(current_task),
466 KNOWN_ENTRY(current_thread),
467 KNOWN_ENTRY(kernel_task),
468 KNOWN_ENTRY(lck_mtx_sleep),
469 KNOWN_ENTRY(lck_rw_sleep),
470 KNOWN_ENTRY(lck_spin_sleep),
471 KNOWN_ENTRY(mach_absolute_time),
472 KNOWN_ENTRY(semaphore_create),
473 KNOWN_ENTRY(task_reference),
474 KNOWN_ENTRY(thread_block),
475 KNOWN_ENTRY(thread_reference),
476 KNOWN_ENTRY(thread_terminate),
477 KNOWN_ENTRY(thread_wakeup_prim),
478
479 /* BSDKernel: */
480 KNOWN_ENTRY(buf_size),
481 KNOWN_ENTRY(copystr),
482 KNOWN_ENTRY(current_proc),
483 KNOWN_ENTRY(ifnet_hdrlen),
484 KNOWN_ENTRY(ifnet_set_promiscuous),
485 KNOWN_ENTRY(kauth_getuid),
486#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
487 KNOWN_ENTRY(kauth_cred_unref),
488#else
489 KNOWN_ENTRY(kauth_cred_rele),
490#endif
491 KNOWN_ENTRY(mbuf_data),
492 KNOWN_ENTRY(msleep),
493 KNOWN_ENTRY(nanotime),
494 KNOWN_ENTRY(nop_close),
495 KNOWN_ENTRY(proc_pid),
496 KNOWN_ENTRY(sock_accept),
497 KNOWN_ENTRY(sockopt_name),
498 //KNOWN_ENTRY(spec_write),
499 KNOWN_ENTRY(suword),
500 //KNOWN_ENTRY(sysctl_int),
501 KNOWN_ENTRY(uio_rw),
502 KNOWN_ENTRY(vfs_flags),
503 KNOWN_ENTRY(vfs_name),
504 KNOWN_ENTRY(vfs_statfs),
505 KNOWN_ENTRY(VNOP_READ),
506 KNOWN_ENTRY(uio_create),
507 KNOWN_ENTRY(uio_addiov),
508 KNOWN_ENTRY(uio_free),
509 KNOWN_ENTRY(vnode_get),
510 KNOWN_ENTRY(vnode_open),
511 KNOWN_ENTRY(vnode_ref),
512 KNOWN_ENTRY(vnode_rele),
513 KNOWN_ENTRY(vnop_close_desc),
514 KNOWN_ENTRY(wakeup),
515 KNOWN_ENTRY(wakeup_one),
516
517 /* Unsupported: */
518 KNOWN_ENTRY(kdp_set_interface),
519 KNOWN_ENTRY(pmap_find_phys),
520 KNOWN_ENTRY(vm_map),
521 KNOWN_ENTRY(vm_protect),
522 KNOWN_ENTRY(vm_region),
523 KNOWN_ENTRY(vm_map_wire),
524 KNOWN_ENTRY(PE_kputc),
525 KNOWN_ENTRY(kernel_map),
526 KNOWN_ENTRY(kernel_pmap),
527 };
528
529 for (unsigned i = 0; i < RT_ELEMENTS(s_aStandardCandles); i++)
530 {
531 uintptr_t uAddr = rtR0DbgKrnlDarwinLookup(pThis, s_aStandardCandles[i].pszName);
532#ifdef IN_RING0
533 if (uAddr != s_aStandardCandles[i].uAddr)
534#else
535 if (uAddr == 0)
536#endif
537 {
538 AssertLogRelMsgFailed(("%s (%p != %p)\n", s_aStandardCandles[i].pszName, uAddr, s_aStandardCandles[i].uAddr));
539 return VERR_INTERNAL_ERROR_2;
540 }
541 }
542 return VINF_SUCCESS;
543}
544
545
546/**
547 * Loads and validates the symbol and string tables.
548 *
549 * @returns IPRT status code.
550 * @param pThis The internal scratch data.
551 */
552static int rtR0DbgKrnlDarwinLoadSymTab(RTDBGKRNLINFOINT *pThis)
553{
554 /*
555 * Load the tables.
556 */
557 pThis->paSyms = (MY_NLIST *)RTMemAllocZ(pThis->cSyms * sizeof(MY_NLIST));
558 if (!pThis->paSyms)
559 return VERR_NO_MEMORY;
560
561 int rc = RTFileReadAt(pThis->hFile, pThis->offArch + pThis->offSyms,
562 pThis->paSyms, pThis->cSyms * sizeof(MY_NLIST), NULL);
563 if (RT_FAILURE(rc))
564 return rc;
565
566 pThis->pachStrTab = (char *)RTMemAllocZ(pThis->cbStrTab + 1);
567 if (!pThis->pachStrTab)
568 return VERR_NO_MEMORY;
569
570 rc = RTFileReadAt(pThis->hFile, pThis->offArch + pThis->offStrTab,
571 pThis->pachStrTab, pThis->cbStrTab, NULL);
572 if (RT_FAILURE(rc))
573 return rc;
574
575 /*
576 * The first string table symbol must be a zero length name.
577 */
578 if (pThis->pachStrTab[0] != '\0')
579 RETURN_VERR_BAD_EXE_FORMAT;
580
581 /*
582 * Validate the symbol table.
583 */
584 const char *pszPrev = "";
585 uint32_t const cSyms = pThis->cSyms;
586 MY_NLIST const *pSym = pThis->paSyms;
587 for (uint32_t iSym = 0; iSym < cSyms; iSym++, pSym++)
588 {
589 if ((uint32_t)pSym->n_un.n_strx >= pThis->cbStrTab)
590 RETURN_VERR_BAD_EXE_FORMAT;
591 const char *pszSym = &pThis->pachStrTab[(uint32_t)pSym->n_un.n_strx];
592#ifdef IN_RING3
593 RTAssertMsg2("%05i: %02x:%08llx %02x %04x %s\n", iSym, pSym->n_sect, (uint64_t)pSym->n_value, pSym->n_type, pSym->n_desc, pszSym);
594#endif
595
596 if (strcmp(pszSym, pszPrev) < 0)
597 RETURN_VERR_BAD_EXE_FORMAT; /* not sorted */
598
599 if (!(pSym->n_type & MACHO_N_STAB))
600 {
601 switch (pSym->n_type & MACHO_N_TYPE)
602 {
603 case MACHO_N_SECT:
604 if (pSym->n_sect == MACHO_NO_SECT)
605 RETURN_VERR_BAD_EXE_FORMAT;
606 if (pSym->n_sect > pThis->cSections)
607 RETURN_VERR_BAD_EXE_FORMAT;
608 if (pSym->n_desc & ~(REFERENCED_DYNAMICALLY))
609 RETURN_VERR_BAD_EXE_FORMAT;
610 if ( pSym->n_value < pThis->apSections[pSym->n_sect - 1]->addr
611 && strcmp(pszSym, "__mh_execute_header")) /* in 10.8 it's no longer absolute (PIE?). */
612 RETURN_VERR_BAD_EXE_FORMAT;
613 if ( pSym->n_value - pThis->apSections[pSym->n_sect - 1]->addr
614 > pThis->apSections[pSym->n_sect - 1]->size
615 && strcmp(pszSym, "__mh_execute_header")) /* see above. */
616 RETURN_VERR_BAD_EXE_FORMAT;
617 break;
618
619 case MACHO_N_ABS:
620 if ( pSym->n_sect != MACHO_NO_SECT
621 && ( strcmp(pszSym, "__mh_execute_header") /* n_sect=1 in 10.7/amd64 */
622 || pSym->n_sect > pThis->cSections) )
623 RETURN_VERR_BAD_EXE_FORMAT;
624 if (pSym->n_desc & ~(REFERENCED_DYNAMICALLY))
625 RETURN_VERR_BAD_EXE_FORMAT;
626 break;
627
628 case MACHO_N_UNDF:
629 /* No undefined or common symbols in the kernel. */
630 RETURN_VERR_BAD_EXE_FORMAT;
631
632 case MACHO_N_INDR:
633 /* No indirect symbols in the kernel. */
634 RETURN_VERR_BAD_EXE_FORMAT;
635
636 case MACHO_N_PBUD:
637 /* No prebound symbols in the kernel. */
638 RETURN_VERR_BAD_EXE_FORMAT;
639
640 default:
641 RETURN_VERR_BAD_EXE_FORMAT;
642 }
643 }
644 /* else: Ignore debug symbols. */
645 }
646
647 return VINF_SUCCESS;
648}
649
650
651/**
652 * Loads the load commands and validates them.
653 *
654 * @returns IPRT status code.
655 * @param pThis The internal scratch data.
656 */
657static int rtR0DbgKrnlDarwinLoadCommands(RTDBGKRNLINFOINT *pThis)
658{
659 pThis->offStrTab = 0;
660 pThis->cbStrTab = 0;
661 pThis->offSyms = 0;
662 pThis->cSyms = 0;
663 pThis->cSections = 0;
664
665 pThis->pLoadCmds = (load_command_t *)RTMemAlloc(pThis->cbLoadCmds);
666 if (!pThis->pLoadCmds)
667 return VERR_NO_MEMORY;
668
669 int rc = RTFileReadAt(pThis->hFile, pThis->offArch + sizeof(MY_MACHO_HEADER),
670 pThis->pLoadCmds, pThis->cbLoadCmds, NULL);
671 if (RT_FAILURE(rc))
672 return rc;
673
674 /*
675 * Validate the relevant commands, picking up sections and the symbol
676 * table location.
677 */
678 load_command_t const *pCmd = pThis->pLoadCmds;
679 for (uint32_t iCmd = 0; ; iCmd++)
680 {
681 /* cmd index & offset. */
682 uintptr_t offCmd = (uintptr_t)pCmd - (uintptr_t)pThis->pLoadCmds;
683 if (offCmd == pThis->cbLoadCmds && iCmd == pThis->cLoadCmds)
684 break;
685 if (offCmd + sizeof(*pCmd) > pThis->cbLoadCmds)
686 RETURN_VERR_BAD_EXE_FORMAT;
687 if (iCmd >= pThis->cLoadCmds)
688 RETURN_VERR_BAD_EXE_FORMAT;
689
690 /* cmdsize */
691 if (pCmd->cmdsize < sizeof(*pCmd))
692 RETURN_VERR_BAD_EXE_FORMAT;
693 if (pCmd->cmdsize > pThis->cbLoadCmds)
694 RETURN_VERR_BAD_EXE_FORMAT;
695 if (RT_ALIGN_32(pCmd->cmdsize, 4) != pCmd->cmdsize)
696 RETURN_VERR_BAD_EXE_FORMAT;
697
698 /* cmd */
699 switch (pCmd->cmd & ~LC_REQ_DYLD)
700 {
701 /* Validate and store the symbol table details. */
702 case LC_SYMTAB:
703 {
704 struct symtab_command const *pSymTab = (struct symtab_command const *)pCmd;
705 if (pSymTab->cmdsize != sizeof(*pSymTab))
706 RETURN_VERR_BAD_EXE_FORMAT;
707 if (pSymTab->nsyms > _1M)
708 RETURN_VERR_BAD_EXE_FORMAT;
709 if (pSymTab->strsize > _2M)
710 RETURN_VERR_BAD_EXE_FORMAT;
711
712 pThis->offStrTab = pSymTab->stroff;
713 pThis->cbStrTab = pSymTab->strsize;
714 pThis->offSyms = pSymTab->symoff;
715 pThis->cSyms = pSymTab->nsyms;
716 break;
717 }
718
719 /* Validate the segment. */
720#if ARCH_BITS == 32
721 case LC_SEGMENT_32:
722#elif ARCH_BITS == 64
723 case LC_SEGMENT_64:
724#else
725# error ARCH_BITS
726#endif
727 {
728 MY_SEGMENT_COMMAND const *pSeg = (MY_SEGMENT_COMMAND const *)pCmd;
729 if (pSeg->cmdsize < sizeof(*pSeg))
730 RETURN_VERR_BAD_EXE_FORMAT;
731
732 if (pSeg->segname[0] == '\0')
733 RETURN_VERR_BAD_EXE_FORMAT;
734
735 if (pSeg->nsects > MACHO_MAX_SECT)
736 RETURN_VERR_BAD_EXE_FORMAT;
737 if (pSeg->nsects * sizeof(MY_SECTION) + sizeof(*pSeg) != pSeg->cmdsize)
738 RETURN_VERR_BAD_EXE_FORMAT;
739
740 if (pSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
741 RETURN_VERR_BAD_EXE_FORMAT;
742
743 if ( pSeg->vmaddr != 0
744 || !strcmp(pSeg->segname, "__PAGEZERO"))
745 {
746 if (pSeg->vmaddr + RT_ALIGN_Z(pSeg->vmsize, RT_BIT_32(12)) < pSeg->vmaddr)
747 RETURN_VERR_BAD_EXE_FORMAT;
748 }
749 else if (pSeg->vmsize)
750 RETURN_VERR_BAD_EXE_FORMAT;
751
752 if (pSeg->maxprot & ~VM_PROT_ALL)
753 RETURN_VERR_BAD_EXE_FORMAT;
754 if (pSeg->initprot & ~VM_PROT_ALL)
755 RETURN_VERR_BAD_EXE_FORMAT;
756
757 /* Validate the sections. */
758 uint32_t uAlignment = 0;
759 uintptr_t uAddr = pSeg->vmaddr;
760 MY_SECTION const *paSects = (MY_SECTION const *)(pSeg + 1);
761 for (uint32_t i = 0; i < pSeg->nsects; i++)
762 {
763 if (paSects[i].sectname[0] == '\0')
764 RETURN_VERR_BAD_EXE_FORMAT;
765 if (memcmp(paSects[i].segname, pSeg->segname, sizeof(pSeg->segname)))
766 RETURN_VERR_BAD_EXE_FORMAT;
767
768 switch (paSects[i].flags & SECTION_TYPE)
769 {
770 case S_REGULAR:
771 case S_CSTRING_LITERALS:
772 case S_NON_LAZY_SYMBOL_POINTERS:
773 case S_MOD_INIT_FUNC_POINTERS:
774 case S_MOD_TERM_FUNC_POINTERS:
775 case S_COALESCED:
776 case S_4BYTE_LITERALS:
777 if ( pSeg->filesize != 0
778 ? paSects[i].offset - pSeg->fileoff >= pSeg->filesize
779 : paSects[i].offset - pSeg->fileoff != pSeg->filesize)
780 RETURN_VERR_BAD_EXE_FORMAT;
781 if ( paSects[i].addr != 0
782 && paSects[i].offset - pSeg->fileoff != paSects[i].addr - pSeg->vmaddr)
783 RETURN_VERR_BAD_EXE_FORMAT;
784 break;
785
786 case S_ZEROFILL:
787 if (paSects[i].offset != 0)
788 RETURN_VERR_BAD_EXE_FORMAT;
789 break;
790
791 /* not observed */
792 case S_SYMBOL_STUBS:
793 case S_INTERPOSING:
794 case S_8BYTE_LITERALS:
795 case S_16BYTE_LITERALS:
796 case S_DTRACE_DOF:
797 case S_LAZY_SYMBOL_POINTERS:
798 case S_LAZY_DYLIB_SYMBOL_POINTERS:
799 RETURN_VERR_LDR_UNEXPECTED;
800 case S_GB_ZEROFILL:
801 RETURN_VERR_LDR_UNEXPECTED;
802 default:
803 RETURN_VERR_BAD_EXE_FORMAT;
804 }
805
806 if (paSects[i].align > 12)
807 RETURN_VERR_BAD_EXE_FORMAT;
808 if (paSects[i].align > uAlignment)
809 uAlignment = paSects[i].align;
810
811 /* Add to the section table. */
812 if (pThis->cSections == MACHO_MAX_SECT)
813 RETURN_VERR_BAD_EXE_FORMAT;
814 pThis->apSections[pThis->cSections++] = &paSects[i];
815 }
816
817 if (RT_ALIGN_Z(pSeg->vmaddr, RT_BIT_32(uAlignment)) != pSeg->vmaddr)
818 RETURN_VERR_BAD_EXE_FORMAT;
819 if ( pSeg->filesize > RT_ALIGN_Z(pSeg->vmsize, RT_BIT_32(uAlignment))
820 && pSeg->vmsize != 0)
821 RETURN_VERR_BAD_EXE_FORMAT;
822 break;
823 }
824
825 case LC_UUID:
826 if (pCmd->cmdsize != sizeof(uuid_command))
827 RETURN_VERR_BAD_EXE_FORMAT;
828 break;
829
830 case LC_DYSYMTAB:
831 case LC_UNIXTHREAD:
832 case LC_CODE_SIGNATURE:
833 case LC_VERSION_MIN_MACOSX:
834 case LC_FUNCTION_STARTS:
835 case LC_MAIN:
836 case LC_DATA_IN_CODE:
837 case LC_SOURCE_VERSION:
838 break;
839
840 /* not observed */
841 case LC_SYMSEG:
842#if ARCH_BITS == 32
843 case LC_SEGMENT_64:
844#elif ARCH_BITS == 64
845 case LC_SEGMENT_32:
846#endif
847 case LC_ROUTINES_64:
848 case LC_ROUTINES:
849 case LC_THREAD:
850 case LC_LOADFVMLIB:
851 case LC_IDFVMLIB:
852 case LC_IDENT:
853 case LC_FVMFILE:
854 case LC_PREPAGE:
855 case LC_TWOLEVEL_HINTS:
856 case LC_PREBIND_CKSUM:
857 case LC_SEGMENT_SPLIT_INFO:
858 case LC_ENCRYPTION_INFO:
859 RETURN_VERR_LDR_UNEXPECTED;
860
861 /* no phones here yet */
862 case LC_VERSION_MIN_IPHONEOS:
863 RETURN_VERR_LDR_UNEXPECTED;
864
865 /* dylib */
866 case LC_LOAD_DYLIB:
867 case LC_ID_DYLIB:
868 case LC_LOAD_DYLINKER:
869 case LC_ID_DYLINKER:
870 case LC_PREBOUND_DYLIB:
871 case LC_LOAD_WEAK_DYLIB & ~LC_REQ_DYLD:
872 case LC_SUB_FRAMEWORK:
873 case LC_SUB_UMBRELLA:
874 case LC_SUB_CLIENT:
875 case LC_SUB_LIBRARY:
876 case LC_RPATH:
877 case LC_REEXPORT_DYLIB:
878 case LC_LAZY_LOAD_DYLIB:
879 case LC_DYLD_INFO:
880 case LC_DYLD_INFO_ONLY:
881 case LC_LOAD_UPWARD_DYLIB:
882 case LC_DYLD_ENVIRONMENT:
883 case LC_DYLIB_CODE_SIGN_DRS:
884 RETURN_VERR_LDR_UNEXPECTED;
885
886 default:
887 RETURN_VERR_BAD_EXE_FORMAT;
888 }
889
890 /* next */
891 pCmd = (load_command_t *)((uintptr_t)pCmd + pCmd->cmdsize);
892 }
893
894 return VINF_SUCCESS;
895}
896
897
898/**
899 * Loads the FAT and MACHO headers, noting down the relevant info.
900 *
901 * @returns IPRT status code.
902 * @param pThis The internal scratch data.
903 */
904static int rtR0DbgKrnlDarwinLoadFileHeaders(RTDBGKRNLINFOINT *pThis)
905{
906 uint32_t i;
907
908 pThis->offArch = 0;
909 pThis->cbArch = 0;
910
911 /*
912 * Read the first bit of the file, parse the FAT if found there.
913 */
914 int rc = RTFileReadAt(pThis->hFile, 0, pThis->abBuf, sizeof(fat_header_t) + sizeof(fat_arch_t) * 16, NULL);
915 if (RT_FAILURE(rc))
916 return rc;
917
918 fat_header_t *pFat = (fat_header *)pThis->abBuf;
919 fat_arch_t *paFatArches = (fat_arch_t *)(pFat + 1);
920
921 /* Correct FAT endian first. */
922 if (pFat->magic == IMAGE_FAT_SIGNATURE_OE)
923 {
924 pFat->magic = RT_BSWAP_U32(pFat->magic);
925 pFat->nfat_arch = RT_BSWAP_U32(pFat->nfat_arch);
926 i = RT_MIN(pFat->nfat_arch, 16);
927 while (i-- > 0)
928 {
929 paFatArches[i].cputype = RT_BSWAP_U32(paFatArches[i].cputype);
930 paFatArches[i].cpusubtype = RT_BSWAP_U32(paFatArches[i].cpusubtype);
931 paFatArches[i].offset = RT_BSWAP_U32(paFatArches[i].offset);
932 paFatArches[i].size = RT_BSWAP_U32(paFatArches[i].size);
933 paFatArches[i].align = RT_BSWAP_U32(paFatArches[i].align);
934 }
935 }
936
937 /* Lookup our architecture in the FAT. */
938 if (pFat->magic == IMAGE_FAT_SIGNATURE)
939 {
940 if (pFat->nfat_arch > 16)
941 RETURN_VERR_BAD_EXE_FORMAT;
942
943 for (i = 0; i < pFat->nfat_arch; i++)
944 {
945 if ( paFatArches[i].cputype == MY_CPU_TYPE
946 && paFatArches[i].cpusubtype == MY_CPU_SUBTYPE_ALL)
947 {
948 pThis->offArch = paFatArches[i].offset;
949 pThis->cbArch = paFatArches[i].size;
950 if (!pThis->cbArch)
951 RETURN_VERR_BAD_EXE_FORMAT;
952 if (pThis->offArch < sizeof(fat_header_t) + sizeof(fat_arch_t) * pFat->nfat_arch)
953 RETURN_VERR_BAD_EXE_FORMAT;
954 if (pThis->offArch + pThis->cbArch <= pThis->offArch)
955 RETURN_VERR_LDR_ARCH_MISMATCH;
956 break;
957 }
958 }
959 if (i >= pFat->nfat_arch)
960 RETURN_VERR_LDR_ARCH_MISMATCH;
961 }
962
963 /*
964 * Read the Mach-O header and validate it.
965 */
966 rc = RTFileReadAt(pThis->hFile, pThis->offArch, pThis->abBuf, sizeof(MY_MACHO_HEADER), NULL);
967 if (RT_FAILURE(rc))
968 return rc;
969 MY_MACHO_HEADER const *pHdr = (MY_MACHO_HEADER const *)pThis->abBuf;
970 if (pHdr->magic != MY_MACHO_MAGIC)
971 {
972 if ( pHdr->magic == IMAGE_MACHO32_SIGNATURE
973 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
974 || pHdr->magic == IMAGE_MACHO64_SIGNATURE
975 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE)
976 RETURN_VERR_LDR_ARCH_MISMATCH;
977 RETURN_VERR_BAD_EXE_FORMAT;
978 }
979
980 if (pHdr->cputype != MY_CPU_TYPE)
981 RETURN_VERR_LDR_ARCH_MISMATCH;
982 if (pHdr->cpusubtype != MY_CPU_SUBTYPE_ALL)
983 RETURN_VERR_LDR_ARCH_MISMATCH;
984 if (pHdr->filetype != MH_EXECUTE)
985 RETURN_VERR_LDR_UNEXPECTED;
986 if (pHdr->ncmds < 4)
987 RETURN_VERR_LDR_UNEXPECTED;
988 if (pHdr->ncmds > 256)
989 RETURN_VERR_LDR_UNEXPECTED;
990 if (pHdr->sizeofcmds <= pHdr->ncmds * sizeof(load_command_t))
991 RETURN_VERR_LDR_UNEXPECTED;
992 if (pHdr->sizeofcmds >= _1M)
993 RETURN_VERR_LDR_UNEXPECTED;
994 if (pHdr->flags & ~MH_VALID_FLAGS)
995 RETURN_VERR_LDR_UNEXPECTED;
996
997 pThis->cLoadCmds = pHdr->ncmds;
998 pThis->cbLoadCmds = pHdr->sizeofcmds;
999 return VINF_SUCCESS;
1000}
1001
1002
1003/**
1004 * Destructor.
1005 *
1006 * @param pThis The instance to destroy.
1007 */
1008static void rtR0DbgKrnlDarwinDtor(RTDBGKRNLINFOINT *pThis)
1009{
1010 pThis->u32Magic = ~RTDBGKRNLINFO_MAGIC;
1011
1012 RTMemFree(pThis->pachStrTab);
1013 pThis->pachStrTab = NULL;
1014
1015 RTMemFree(pThis->paSyms);
1016 pThis->paSyms = NULL;
1017
1018 RTMemFree(pThis);
1019}
1020
1021
1022RTR0DECL(int) RTR0DbgKrnlInfoOpen(PRTDBGKRNLINFO phKrnlInfo, uint32_t fFlags)
1023{
1024 AssertPtrReturn(phKrnlInfo, VERR_INVALID_POINTER);
1025 *phKrnlInfo = NIL_RTDBGKRNLINFO;
1026 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1027
1028 RTDBGKRNLINFOINT *pThis = (RTDBGKRNLINFOINT *)RTMemAllocZ(sizeof(*pThis));
1029 if (!pThis)
1030 return VERR_NO_MEMORY;
1031 pThis->hFile = NIL_RTFILE;
1032
1033 int rc = RTFileOpen(&pThis->hFile, "/mach_kernel", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1034 if (RT_SUCCESS(rc))
1035 rc = rtR0DbgKrnlDarwinLoadFileHeaders(pThis);
1036 if (RT_SUCCESS(rc))
1037 rc = rtR0DbgKrnlDarwinLoadCommands(pThis);
1038 if (RT_SUCCESS(rc))
1039 rc = rtR0DbgKrnlDarwinLoadSymTab(pThis);
1040 if (RT_SUCCESS(rc))
1041 {
1042#ifdef IN_RING0
1043 /*
1044 * Determine the load displacement (10.8 kernels are PIE).
1045 */
1046 uintptr_t uLinkAddr = rtR0DbgKrnlDarwinLookup(pThis, "kernel_map");
1047 if (uLinkAddr != 0)
1048 pThis->offLoad = (uintptr_t)&kernel_map - uLinkAddr;
1049#endif
1050 rc = rtR0DbgKrnlDarwinCheckStandardSymbols(pThis);
1051 }
1052
1053 rtR0DbgKrnlDarwinLoadDone(pThis);
1054 if (RT_SUCCESS(rc))
1055 {
1056 pThis->u32Magic = RTDBGKRNLINFO_MAGIC;
1057 pThis->cRefs = 1;
1058 *phKrnlInfo = pThis;
1059 }
1060 else
1061 rtR0DbgKrnlDarwinDtor(pThis);
1062 return rc;
1063}
1064
1065
1066RTR0DECL(uint32_t) RTR0DbgKrnlInfoRetain(RTDBGKRNLINFO hKrnlInfo)
1067{
1068 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
1069 AssertPtrReturn(pThis, UINT32_MAX);
1070 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
1071
1072 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1073 Assert(cRefs && cRefs < 100000);
1074 return cRefs;
1075}
1076
1077
1078RTR0DECL(uint32_t) RTR0DbgKrnlInfoRelease(RTDBGKRNLINFO hKrnlInfo)
1079{
1080 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
1081 if (pThis == NIL_RTDBGKRNLINFO)
1082 return 0;
1083 AssertPtrReturn(pThis, UINT32_MAX);
1084 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
1085
1086 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1087 if (cRefs == 0)
1088 rtR0DbgKrnlDarwinDtor(pThis);
1089 return cRefs;
1090}
1091
1092
1093RTR0DECL(int) RTR0DbgKrnlInfoQueryMember(RTDBGKRNLINFO hKrnlInfo, const char *pszStructure,
1094 const char *pszMember, size_t *poffMember)
1095{
1096 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
1097 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1098 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
1099 AssertPtrReturn(pszMember, VERR_INVALID_PARAMETER);
1100 AssertPtrReturn(pszStructure, VERR_INVALID_PARAMETER);
1101 AssertPtrReturn(poffMember, VERR_INVALID_PARAMETER);
1102 return VERR_NOT_FOUND;
1103}
1104
1105
1106RTR0DECL(int) RTR0DbgKrnlInfoQuerySymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule,
1107 const char *pszSymbol, void **ppvSymbol)
1108{
1109 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
1110 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1111 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
1112 AssertPtrReturn(pszSymbol, VERR_INVALID_PARAMETER);
1113 AssertPtrNullReturn(ppvSymbol, VERR_INVALID_PARAMETER);
1114 AssertReturn(!pszModule, VERR_MODULE_NOT_FOUND);
1115
1116 uintptr_t uValue = rtR0DbgKrnlDarwinLookup(pThis, pszSymbol);
1117 if (ppvSymbol)
1118 *ppvSymbol = (void *)uValue;
1119 if (uValue)
1120 return VINF_SUCCESS;
1121 return VERR_SYMBOL_NOT_FOUND;
1122}
1123
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