VirtualBox

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

Last change on this file since 42586 was 41052, checked in by vboxsync, 13 years ago

Deal with 10.8 being PIE and not loaded at the link address.

  • 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 41052 2012-04-25 15:01:48Z 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 "internal/ldrMach-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" int osrelease;
398extern "C" int ostype;
399extern "C" void kdp_set_interface(void);
400
401
402/**
403 * Check the symbol table against symbols we known symbols.
404 *
405 * This is done to detect whether the on disk image and the in
406 * memory images matches. Mismatches could stem from user
407 * replacing the default kernel image on disk.
408 *
409 * @returns IPRT status code.
410 * @param pThis The internal scratch data.
411 */
412static int rtR0DbgKrnlDarwinCheckStandardSymbols(RTDBGKRNLINFOINT *pThis)
413{
414 static struct
415 {
416 const char *pszName;
417 uintptr_t uAddr;
418 } const s_aStandardCandles[] =
419 {
420#ifdef IN_RING0
421# define KNOWN_ENTRY(a_Sym) { #a_Sym, (uintptr_t)&a_Sym }
422#else
423# define KNOWN_ENTRY(a_Sym) { #a_Sym, 0 }
424#endif
425 /* IOKit: */
426 KNOWN_ENTRY(IOMalloc),
427 KNOWN_ENTRY(IOFree),
428 KNOWN_ENTRY(IOSleep),
429 KNOWN_ENTRY(IORWLockAlloc),
430 KNOWN_ENTRY(IORecursiveLockLock),
431 KNOWN_ENTRY(IOSimpleLockAlloc),
432 KNOWN_ENTRY(PE_cpu_halt),
433 KNOWN_ENTRY(gIOKitDebug),
434 KNOWN_ENTRY(gIOServicePlane),
435 KNOWN_ENTRY(ev_try_lock),
436
437 /* Libkern: */
438 KNOWN_ENTRY(OSAddAtomic),
439 KNOWN_ENTRY(OSBitAndAtomic),
440 KNOWN_ENTRY(OSBitOrAtomic),
441 KNOWN_ENTRY(OSBitXorAtomic),
442 KNOWN_ENTRY(OSCompareAndSwap),
443 KNOWN_ENTRY(OSMalloc),
444 KNOWN_ENTRY(OSlibkernInit),
445 KNOWN_ENTRY(bcmp),
446 KNOWN_ENTRY(copyout),
447 KNOWN_ENTRY(copyin),
448 KNOWN_ENTRY(kprintf),
449 KNOWN_ENTRY(printf),
450 KNOWN_ENTRY(lck_grp_alloc_init),
451 KNOWN_ENTRY(lck_mtx_alloc_init),
452 KNOWN_ENTRY(lck_rw_alloc_init),
453 KNOWN_ENTRY(lck_spin_alloc_init),
454 KNOWN_ENTRY(osrelease),
455 KNOWN_ENTRY(ostype),
456 KNOWN_ENTRY(panic),
457 KNOWN_ENTRY(strprefix),
458 KNOWN_ENTRY(sysctlbyname),
459 KNOWN_ENTRY(vsscanf),
460 KNOWN_ENTRY(page_mask),
461
462 /* Mach: */
463 KNOWN_ENTRY(absolutetime_to_nanoseconds),
464 KNOWN_ENTRY(assert_wait),
465 KNOWN_ENTRY(clock_delay_until),
466 KNOWN_ENTRY(clock_get_uptime),
467 KNOWN_ENTRY(current_task),
468 KNOWN_ENTRY(current_thread),
469 KNOWN_ENTRY(kernel_task),
470 KNOWN_ENTRY(lck_mtx_sleep),
471 KNOWN_ENTRY(lck_rw_sleep),
472 KNOWN_ENTRY(lck_spin_sleep),
473 KNOWN_ENTRY(mach_absolute_time),
474 KNOWN_ENTRY(semaphore_create),
475 KNOWN_ENTRY(task_reference),
476 KNOWN_ENTRY(thread_block),
477 KNOWN_ENTRY(thread_reference),
478 KNOWN_ENTRY(thread_terminate),
479 KNOWN_ENTRY(thread_wakeup_prim),
480
481 /* BSDKernel: */
482 KNOWN_ENTRY(buf_size),
483 KNOWN_ENTRY(copystr),
484 KNOWN_ENTRY(current_proc),
485 KNOWN_ENTRY(ifnet_hdrlen),
486 KNOWN_ENTRY(ifnet_set_promiscuous),
487 KNOWN_ENTRY(kauth_getuid),
488#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
489 KNOWN_ENTRY(kauth_cred_unref),
490#else
491 KNOWN_ENTRY(kauth_cred_rele),
492#endif
493 KNOWN_ENTRY(mbuf_data),
494 KNOWN_ENTRY(msleep),
495 KNOWN_ENTRY(nanotime),
496 KNOWN_ENTRY(nop_close),
497 KNOWN_ENTRY(proc_pid),
498 KNOWN_ENTRY(sock_accept),
499 KNOWN_ENTRY(sockopt_name),
500 //KNOWN_ENTRY(spec_write),
501 KNOWN_ENTRY(suword),
502 //KNOWN_ENTRY(sysctl_int),
503 KNOWN_ENTRY(uio_rw),
504 KNOWN_ENTRY(vfs_flags),
505 KNOWN_ENTRY(vfs_name),
506 KNOWN_ENTRY(vfs_statfs),
507 KNOWN_ENTRY(VNOP_READ),
508 KNOWN_ENTRY(uio_create),
509 KNOWN_ENTRY(uio_addiov),
510 KNOWN_ENTRY(uio_free),
511 KNOWN_ENTRY(vnode_get),
512 KNOWN_ENTRY(vnode_open),
513 KNOWN_ENTRY(vnode_ref),
514 KNOWN_ENTRY(vnode_rele),
515 KNOWN_ENTRY(vnop_close_desc),
516 KNOWN_ENTRY(wakeup),
517 KNOWN_ENTRY(wakeup_one),
518
519 /* Unsupported: */
520 KNOWN_ENTRY(kdp_set_interface),
521 KNOWN_ENTRY(pmap_find_phys),
522 KNOWN_ENTRY(vm_map),
523 KNOWN_ENTRY(vm_protect),
524 KNOWN_ENTRY(vm_region),
525 KNOWN_ENTRY(vm_map_wire),
526 KNOWN_ENTRY(PE_kputc),
527 KNOWN_ENTRY(kernel_map),
528 KNOWN_ENTRY(kernel_pmap),
529 };
530
531 for (unsigned i = 0; i < RT_ELEMENTS(s_aStandardCandles); i++)
532 {
533 uintptr_t uAddr = rtR0DbgKrnlDarwinLookup(pThis, s_aStandardCandles[i].pszName);
534#ifdef IN_RING0
535 if (uAddr != s_aStandardCandles[i].uAddr)
536#else
537 if (uAddr == 0)
538#endif
539 {
540 AssertLogRelMsgFailed(("%s (%p != %p)\n", s_aStandardCandles[i].pszName, uAddr, s_aStandardCandles[i].uAddr));
541 return VERR_INTERNAL_ERROR_2;
542 }
543 }
544 return VINF_SUCCESS;
545}
546
547
548/**
549 * Loads and validates the symbol and string tables.
550 *
551 * @returns IPRT status code.
552 * @param pThis The internal scratch data.
553 */
554static int rtR0DbgKrnlDarwinLoadSymTab(RTDBGKRNLINFOINT *pThis)
555{
556 /*
557 * Load the tables.
558 */
559 pThis->paSyms = (MY_NLIST *)RTMemAllocZ(pThis->cSyms * sizeof(MY_NLIST));
560 if (!pThis->paSyms)
561 return VERR_NO_MEMORY;
562
563 int rc = RTFileReadAt(pThis->hFile, pThis->offArch + pThis->offSyms,
564 pThis->paSyms, pThis->cSyms * sizeof(MY_NLIST), NULL);
565 if (RT_FAILURE(rc))
566 return rc;
567
568 pThis->pachStrTab = (char *)RTMemAllocZ(pThis->cbStrTab + 1);
569 if (!pThis->pachStrTab)
570 return VERR_NO_MEMORY;
571
572 rc = RTFileReadAt(pThis->hFile, pThis->offArch + pThis->offStrTab,
573 pThis->pachStrTab, pThis->cbStrTab, NULL);
574 if (RT_FAILURE(rc))
575 return rc;
576
577 /*
578 * The first string table symbol must be a zero length name.
579 */
580 if (pThis->pachStrTab[0] != '\0')
581 RETURN_VERR_BAD_EXE_FORMAT;
582
583 /*
584 * Validate the symbol table.
585 */
586 const char *pszPrev = "";
587 uint32_t const cSyms = pThis->cSyms;
588 MY_NLIST const *pSym = pThis->paSyms;
589 for (uint32_t iSym = 0; iSym < cSyms; iSym++, pSym++)
590 {
591 if ((uint32_t)pSym->n_un.n_strx >= pThis->cbStrTab)
592 RETURN_VERR_BAD_EXE_FORMAT;
593 const char *pszSym = &pThis->pachStrTab[(uint32_t)pSym->n_un.n_strx];
594#ifdef IN_RING3
595 RTAssertMsg2("%05i: %02x:%08llx %02x %04x %s\n", iSym, pSym->n_sect, (uint64_t)pSym->n_value, pSym->n_type, pSym->n_desc, pszSym);
596#endif
597
598 if (strcmp(pszSym, pszPrev) < 0)
599 RETURN_VERR_BAD_EXE_FORMAT; /* not sorted */
600
601 if (!(pSym->n_type & MACHO_N_STAB))
602 {
603 switch (pSym->n_type & MACHO_N_TYPE)
604 {
605 case MACHO_N_SECT:
606 if (pSym->n_sect == MACHO_NO_SECT)
607 RETURN_VERR_BAD_EXE_FORMAT;
608 if (pSym->n_sect > pThis->cSections)
609 RETURN_VERR_BAD_EXE_FORMAT;
610 if (pSym->n_desc & ~(REFERENCED_DYNAMICALLY))
611 RETURN_VERR_BAD_EXE_FORMAT;
612 if ( pSym->n_value < pThis->apSections[pSym->n_sect - 1]->addr
613 && strcmp(pszSym, "__mh_execute_header")) /* in 10.8 it's no longer absolute (PIE?). */
614 RETURN_VERR_BAD_EXE_FORMAT;
615 if ( pSym->n_value - pThis->apSections[pSym->n_sect - 1]->addr
616 > pThis->apSections[pSym->n_sect - 1]->size
617 && strcmp(pszSym, "__mh_execute_header")) /* see above. */
618 RETURN_VERR_BAD_EXE_FORMAT;
619 break;
620
621 case MACHO_N_ABS:
622 if ( pSym->n_sect != MACHO_NO_SECT
623 && ( strcmp(pszSym, "__mh_execute_header") /* n_sect=1 in 10.7/amd64 */
624 || pSym->n_sect > pThis->cSections) )
625 RETURN_VERR_BAD_EXE_FORMAT;
626 if (pSym->n_desc & ~(REFERENCED_DYNAMICALLY))
627 RETURN_VERR_BAD_EXE_FORMAT;
628 break;
629
630 case MACHO_N_UNDF:
631 /* No undefined or common symbols in the kernel. */
632 RETURN_VERR_BAD_EXE_FORMAT;
633
634 case MACHO_N_INDR:
635 /* No indirect symbols in the kernel. */
636 RETURN_VERR_BAD_EXE_FORMAT;
637
638 case MACHO_N_PBUD:
639 /* No prebound symbols in the kernel. */
640 RETURN_VERR_BAD_EXE_FORMAT;
641
642 default:
643 RETURN_VERR_BAD_EXE_FORMAT;
644 }
645 }
646 /* else: Ignore debug symbols. */
647 }
648
649 return VINF_SUCCESS;
650}
651
652
653/**
654 * Loads the load commands and validates them.
655 *
656 * @returns IPRT status code.
657 * @param pThis The internal scratch data.
658 */
659static int rtR0DbgKrnlDarwinLoadCommands(RTDBGKRNLINFOINT *pThis)
660{
661 pThis->offStrTab = 0;
662 pThis->cbStrTab = 0;
663 pThis->offSyms = 0;
664 pThis->cSyms = 0;
665 pThis->cSections = 0;
666
667 pThis->pLoadCmds = (load_command_t *)RTMemAlloc(pThis->cbLoadCmds);
668 if (!pThis->pLoadCmds)
669 return VERR_NO_MEMORY;
670
671 int rc = RTFileReadAt(pThis->hFile, pThis->offArch + sizeof(MY_MACHO_HEADER),
672 pThis->pLoadCmds, pThis->cbLoadCmds, NULL);
673 if (RT_FAILURE(rc))
674 return rc;
675
676 /*
677 * Validate the relevant commands, picking up sections and the symbol
678 * table location.
679 */
680 load_command_t const *pCmd = pThis->pLoadCmds;
681 for (uint32_t iCmd = 0; ; iCmd++)
682 {
683 /* cmd index & offset. */
684 uintptr_t offCmd = (uintptr_t)pCmd - (uintptr_t)pThis->pLoadCmds;
685 if (offCmd == pThis->cbLoadCmds && iCmd == pThis->cLoadCmds)
686 break;
687 if (offCmd + sizeof(*pCmd) > pThis->cbLoadCmds)
688 RETURN_VERR_BAD_EXE_FORMAT;
689 if (iCmd >= pThis->cLoadCmds)
690 RETURN_VERR_BAD_EXE_FORMAT;
691
692 /* cmdsize */
693 if (pCmd->cmdsize < sizeof(*pCmd))
694 RETURN_VERR_BAD_EXE_FORMAT;
695 if (pCmd->cmdsize > pThis->cbLoadCmds)
696 RETURN_VERR_BAD_EXE_FORMAT;
697 if (RT_ALIGN_32(pCmd->cmdsize, 4) != pCmd->cmdsize)
698 RETURN_VERR_BAD_EXE_FORMAT;
699
700 /* cmd */
701 switch (pCmd->cmd & ~LC_REQ_DYLD)
702 {
703 /* Validate and store the symbol table details. */
704 case LC_SYMTAB:
705 {
706 struct symtab_command const *pSymTab = (struct symtab_command const *)pCmd;
707 if (pSymTab->cmdsize != sizeof(*pSymTab))
708 RETURN_VERR_BAD_EXE_FORMAT;
709 if (pSymTab->nsyms > _1M)
710 RETURN_VERR_BAD_EXE_FORMAT;
711 if (pSymTab->strsize > _2M)
712 RETURN_VERR_BAD_EXE_FORMAT;
713
714 pThis->offStrTab = pSymTab->stroff;
715 pThis->cbStrTab = pSymTab->strsize;
716 pThis->offSyms = pSymTab->symoff;
717 pThis->cSyms = pSymTab->nsyms;
718 break;
719 }
720
721 /* Validate the segment. */
722#if ARCH_BITS == 32
723 case LC_SEGMENT_32:
724#elif ARCH_BITS == 64
725 case LC_SEGMENT_64:
726#else
727# error ARCH_BITS
728#endif
729 {
730 MY_SEGMENT_COMMAND const *pSeg = (MY_SEGMENT_COMMAND const *)pCmd;
731 if (pSeg->cmdsize < sizeof(*pSeg))
732 RETURN_VERR_BAD_EXE_FORMAT;
733
734 if (pSeg->segname[0] == '\0')
735 RETURN_VERR_BAD_EXE_FORMAT;
736
737 if (pSeg->nsects > MACHO_MAX_SECT)
738 RETURN_VERR_BAD_EXE_FORMAT;
739 if (pSeg->nsects * sizeof(MY_SECTION) + sizeof(*pSeg) != pSeg->cmdsize)
740 RETURN_VERR_BAD_EXE_FORMAT;
741
742 if (pSeg->flags & ~(SG_HIGHVM | SG_FVMLIB | SG_NORELOC | SG_PROTECTED_VERSION_1))
743 RETURN_VERR_BAD_EXE_FORMAT;
744
745 if (pSeg->vmaddr != 0)
746 {
747 if (pSeg->vmaddr + RT_ALIGN_Z(pSeg->vmsize, RT_BIT_32(12)) < pSeg->vmaddr)
748 RETURN_VERR_BAD_EXE_FORMAT;
749 }
750 else if (pSeg->vmsize)
751 RETURN_VERR_BAD_EXE_FORMAT;
752
753 if (pSeg->maxprot & ~VM_PROT_ALL)
754 RETURN_VERR_BAD_EXE_FORMAT;
755 if (pSeg->initprot & ~VM_PROT_ALL)
756 RETURN_VERR_BAD_EXE_FORMAT;
757
758 /* Validate the sections. */
759 uint32_t uAlignment = 0;
760 uintptr_t uAddr = pSeg->vmaddr;
761 MY_SECTION const *paSects = (MY_SECTION const *)(pSeg + 1);
762 for (uint32_t i = 0; i < pSeg->nsects; i++)
763 {
764 if (paSects[i].sectname[0] == '\0')
765 RETURN_VERR_BAD_EXE_FORMAT;
766 if (memcmp(paSects[i].segname, pSeg->segname, sizeof(pSeg->segname)))
767 RETURN_VERR_BAD_EXE_FORMAT;
768
769 switch (paSects[i].flags & SECTION_TYPE)
770 {
771 case S_REGULAR:
772 case S_CSTRING_LITERALS:
773 case S_NON_LAZY_SYMBOL_POINTERS:
774 case S_MOD_INIT_FUNC_POINTERS:
775 case S_MOD_TERM_FUNC_POINTERS:
776 case S_COALESCED:
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_4BYTE_LITERALS:
795 case S_8BYTE_LITERALS:
796 case S_16BYTE_LITERALS:
797 case S_DTRACE_DOF:
798 case S_LAZY_SYMBOL_POINTERS:
799 case S_LAZY_DYLIB_SYMBOL_POINTERS:
800 RETURN_VERR_LDR_UNEXPECTED;
801 case S_GB_ZEROFILL:
802 RETURN_VERR_LDR_UNEXPECTED;
803 default:
804 RETURN_VERR_BAD_EXE_FORMAT;
805 }
806
807 if (paSects[i].align > 12)
808 RETURN_VERR_BAD_EXE_FORMAT;
809 if (paSects[i].align > uAlignment)
810 uAlignment = paSects[i].align;
811
812 /* Add to the section table. */
813 if (pThis->cSections == MACHO_MAX_SECT)
814 RETURN_VERR_BAD_EXE_FORMAT;
815 pThis->apSections[pThis->cSections++] = &paSects[i];
816 }
817
818 if (RT_ALIGN_Z(pSeg->vmaddr, RT_BIT_32(uAlignment)) != pSeg->vmaddr)
819 RETURN_VERR_BAD_EXE_FORMAT;
820 if ( pSeg->filesize > RT_ALIGN_Z(pSeg->vmsize, RT_BIT_32(uAlignment))
821 && pSeg->vmsize != 0)
822 RETURN_VERR_BAD_EXE_FORMAT;
823 break;
824 }
825
826 case LC_UUID:
827 if (pCmd->cmdsize != sizeof(uuid_command))
828 RETURN_VERR_BAD_EXE_FORMAT;
829 break;
830
831 case LC_DYSYMTAB:
832 case LC_UNIXTHREAD:
833 case LC_CODE_SIGNATURE:
834 case LC_VERSION_MIN_MACOSX:
835 case LC_FUNCTION_STARTS:
836 case LC_MAIN:
837 case LC_DATA_IN_CODE:
838 case LC_SOURCE_VERSION:
839 break;
840
841 /* not observed */
842 case LC_SYMSEG:
843#if ARCH_BITS == 32
844 case LC_SEGMENT_64:
845#elif ARCH_BITS == 64
846 case LC_SEGMENT_32:
847#endif
848 case LC_ROUTINES_64:
849 case LC_ROUTINES:
850 case LC_THREAD:
851 case LC_LOADFVMLIB:
852 case LC_IDFVMLIB:
853 case LC_IDENT:
854 case LC_FVMFILE:
855 case LC_PREPAGE:
856 case LC_TWOLEVEL_HINTS:
857 case LC_PREBIND_CKSUM:
858 case LC_SEGMENT_SPLIT_INFO:
859 case LC_ENCRYPTION_INFO:
860 RETURN_VERR_LDR_UNEXPECTED;
861
862 /* no phones here yet */
863 case LC_VERSION_MIN_IPHONEOS:
864 RETURN_VERR_LDR_UNEXPECTED;
865
866 /* dylib */
867 case LC_LOAD_DYLIB:
868 case LC_ID_DYLIB:
869 case LC_LOAD_DYLINKER:
870 case LC_ID_DYLINKER:
871 case LC_PREBOUND_DYLIB:
872 case LC_LOAD_WEAK_DYLIB & ~LC_REQ_DYLD:
873 case LC_SUB_FRAMEWORK:
874 case LC_SUB_UMBRELLA:
875 case LC_SUB_CLIENT:
876 case LC_SUB_LIBRARY:
877 case LC_RPATH:
878 case LC_REEXPORT_DYLIB:
879 case LC_LAZY_LOAD_DYLIB:
880 case LC_DYLD_INFO:
881 case LC_DYLD_INFO_ONLY:
882 case LC_LOAD_UPWARD_DYLIB:
883 case LC_DYLD_ENVIRONMENT:
884 case LC_DYLIB_CODE_SIGN_DRS:
885 RETURN_VERR_LDR_UNEXPECTED;
886
887 default:
888 RETURN_VERR_BAD_EXE_FORMAT;
889 }
890
891 /* next */
892 pCmd = (load_command_t *)((uintptr_t)pCmd + pCmd->cmdsize);
893 }
894
895 return VINF_SUCCESS;
896}
897
898
899/**
900 * Loads the FAT and MACHO headers, noting down the relevant info.
901 *
902 * @returns IPRT status code.
903 * @param pThis The internal scratch data.
904 */
905static int rtR0DbgKrnlDarwinLoadFileHeaders(RTDBGKRNLINFOINT *pThis)
906{
907 uint32_t i;
908
909 pThis->offArch = 0;
910 pThis->cbArch = 0;
911
912 /*
913 * Read the first bit of the file, parse the FAT if found there.
914 */
915 int rc = RTFileReadAt(pThis->hFile, 0, pThis->abBuf, sizeof(fat_header_t) + sizeof(fat_arch_t) * 16, NULL);
916 if (RT_FAILURE(rc))
917 return rc;
918
919 fat_header_t *pFat = (fat_header *)pThis->abBuf;
920 fat_arch_t *paFatArches = (fat_arch_t *)(pFat + 1);
921
922 /* Correct FAT endian first. */
923 if (pFat->magic == IMAGE_FAT_SIGNATURE_OE)
924 {
925 pFat->magic = RT_BSWAP_U32(pFat->magic);
926 pFat->nfat_arch = RT_BSWAP_U32(pFat->nfat_arch);
927 i = RT_MIN(pFat->nfat_arch, 16);
928 while (i-- > 0)
929 {
930 paFatArches[i].cputype = RT_BSWAP_U32(paFatArches[i].cputype);
931 paFatArches[i].cpusubtype = RT_BSWAP_U32(paFatArches[i].cpusubtype);
932 paFatArches[i].offset = RT_BSWAP_U32(paFatArches[i].offset);
933 paFatArches[i].size = RT_BSWAP_U32(paFatArches[i].size);
934 paFatArches[i].align = RT_BSWAP_U32(paFatArches[i].align);
935 }
936 }
937
938 /* Lookup our architecture in the FAT. */
939 if (pFat->magic == IMAGE_FAT_SIGNATURE)
940 {
941 if (pFat->nfat_arch > 16)
942 RETURN_VERR_BAD_EXE_FORMAT;
943
944 for (i = 0; i < pFat->nfat_arch; i++)
945 {
946 if ( paFatArches[i].cputype == MY_CPU_TYPE
947 && paFatArches[i].cpusubtype == MY_CPU_SUBTYPE_ALL)
948 {
949 pThis->offArch = paFatArches[i].offset;
950 pThis->cbArch = paFatArches[i].size;
951 if (!pThis->cbArch)
952 RETURN_VERR_BAD_EXE_FORMAT;
953 if (pThis->offArch < sizeof(fat_header_t) + sizeof(fat_arch_t) * pFat->nfat_arch)
954 RETURN_VERR_BAD_EXE_FORMAT;
955 if (pThis->offArch + pThis->cbArch <= pThis->offArch)
956 RETURN_VERR_LDR_ARCH_MISMATCH;
957 break;
958 }
959 }
960 if (i >= pFat->nfat_arch)
961 RETURN_VERR_LDR_ARCH_MISMATCH;
962 }
963
964 /*
965 * Read the Mach-O header and validate it.
966 */
967 rc = RTFileReadAt(pThis->hFile, pThis->offArch, pThis->abBuf, sizeof(MY_MACHO_HEADER), NULL);
968 if (RT_FAILURE(rc))
969 return rc;
970 MY_MACHO_HEADER const *pHdr = (MY_MACHO_HEADER const *)pThis->abBuf;
971 if (pHdr->magic != MY_MACHO_MAGIC)
972 {
973 if ( pHdr->magic == IMAGE_MACHO32_SIGNATURE
974 || pHdr->magic == IMAGE_MACHO32_SIGNATURE_OE
975 || pHdr->magic == IMAGE_MACHO64_SIGNATURE
976 || pHdr->magic == IMAGE_MACHO64_SIGNATURE_OE)
977 RETURN_VERR_LDR_ARCH_MISMATCH;
978 RETURN_VERR_BAD_EXE_FORMAT;
979 }
980
981 if (pHdr->cputype != MY_CPU_TYPE)
982 RETURN_VERR_LDR_ARCH_MISMATCH;
983 if (pHdr->cpusubtype != MY_CPU_SUBTYPE_ALL)
984 RETURN_VERR_LDR_ARCH_MISMATCH;
985 if (pHdr->filetype != MH_EXECUTE)
986 RETURN_VERR_LDR_UNEXPECTED;
987 if (pHdr->ncmds < 4)
988 RETURN_VERR_LDR_UNEXPECTED;
989 if (pHdr->ncmds > 256)
990 RETURN_VERR_LDR_UNEXPECTED;
991 if (pHdr->sizeofcmds <= pHdr->ncmds * sizeof(load_command_t))
992 RETURN_VERR_LDR_UNEXPECTED;
993 if (pHdr->sizeofcmds >= _1M)
994 RETURN_VERR_LDR_UNEXPECTED;
995 if (pHdr->flags & ~MH_VALID_FLAGS)
996 RETURN_VERR_LDR_UNEXPECTED;
997
998 pThis->cLoadCmds = pHdr->ncmds;
999 pThis->cbLoadCmds = pHdr->sizeofcmds;
1000 return VINF_SUCCESS;
1001}
1002
1003
1004/**
1005 * Destructor.
1006 *
1007 * @param pThis The instance to destroy.
1008 */
1009static void rtR0DbgKrnlDarwinDtor(RTDBGKRNLINFOINT *pThis)
1010{
1011 pThis->u32Magic = ~RTDBGKRNLINFO_MAGIC;
1012
1013 RTMemFree(pThis->pachStrTab);
1014 pThis->pachStrTab = NULL;
1015
1016 RTMemFree(pThis->paSyms);
1017 pThis->paSyms = NULL;
1018
1019 RTMemFree(pThis);
1020}
1021
1022
1023RTR0DECL(int) RTR0DbgKrnlInfoOpen(PRTDBGKRNLINFO phKrnlInfo, uint32_t fFlags)
1024{
1025 AssertPtrReturn(phKrnlInfo, VERR_INVALID_POINTER);
1026 *phKrnlInfo = NIL_RTDBGKRNLINFO;
1027 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1028
1029 RTDBGKRNLINFOINT *pThis = (RTDBGKRNLINFOINT *)RTMemAllocZ(sizeof(*pThis));
1030 if (!pThis)
1031 return VERR_NO_MEMORY;
1032 pThis->hFile = NIL_RTFILE;
1033
1034 int rc = RTFileOpen(&pThis->hFile, "/mach_kernel", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1035 if (RT_SUCCESS(rc))
1036 rc = rtR0DbgKrnlDarwinLoadFileHeaders(pThis);
1037 if (RT_SUCCESS(rc))
1038 rc = rtR0DbgKrnlDarwinLoadCommands(pThis);
1039 if (RT_SUCCESS(rc))
1040 rc = rtR0DbgKrnlDarwinLoadSymTab(pThis);
1041 if (RT_SUCCESS(rc))
1042 {
1043#ifdef IN_RING0
1044 /*
1045 * Determine the load displacement (10.8 kernels are PIE).
1046 */
1047 uintptr_t uLinkAddr = rtR0DbgKrnlDarwinLookup(pThis, "kernel_map");
1048 if (uLinkAddr != 0)
1049 pThis->offLoad = (uintptr_t)&kernel_map - uLinkAddr;
1050#endif
1051 rc = rtR0DbgKrnlDarwinCheckStandardSymbols(pThis);
1052 }
1053
1054 rtR0DbgKrnlDarwinLoadDone(pThis);
1055 if (RT_SUCCESS(rc))
1056 {
1057 pThis->u32Magic = RTDBGKRNLINFO_MAGIC;
1058 pThis->cRefs = 1;
1059 *phKrnlInfo = pThis;
1060 }
1061 else
1062 rtR0DbgKrnlDarwinDtor(pThis);
1063 return rc;
1064}
1065
1066
1067RTR0DECL(uint32_t) RTR0DbgKrnlInfoRetain(RTDBGKRNLINFO hKrnlInfo)
1068{
1069 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
1070 AssertPtrReturn(pThis, UINT32_MAX);
1071 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
1072
1073 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1074 Assert(cRefs && cRefs < 100000);
1075 return cRefs;
1076}
1077
1078
1079RTR0DECL(uint32_t) RTR0DbgKrnlInfoRelease(RTDBGKRNLINFO hKrnlInfo)
1080{
1081 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
1082 if (pThis == NIL_RTDBGKRNLINFO)
1083 return 0;
1084 AssertPtrReturn(pThis, UINT32_MAX);
1085 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), UINT32_MAX);
1086
1087 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1088 if (cRefs == 0)
1089 rtR0DbgKrnlDarwinDtor(pThis);
1090 return cRefs;
1091}
1092
1093
1094RTR0DECL(int) RTR0DbgKrnlInfoQueryMember(RTDBGKRNLINFO hKrnlInfo, const char *pszStructure,
1095 const char *pszMember, size_t *poffMember)
1096{
1097 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
1098 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1099 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
1100 AssertPtrReturn(pszMember, VERR_INVALID_PARAMETER);
1101 AssertPtrReturn(pszStructure, VERR_INVALID_PARAMETER);
1102 AssertPtrReturn(poffMember, VERR_INVALID_PARAMETER);
1103 return VERR_NOT_FOUND;
1104}
1105
1106
1107RTR0DECL(int) RTR0DbgKrnlInfoQuerySymbol(RTDBGKRNLINFO hKrnlInfo, const char *pszModule,
1108 const char *pszSymbol, void **ppvSymbol)
1109{
1110 RTDBGKRNLINFOINT *pThis = hKrnlInfo;
1111 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1112 AssertMsgReturn(pThis->u32Magic == RTDBGKRNLINFO_MAGIC, ("%p: u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
1113 AssertPtrReturn(pszSymbol, VERR_INVALID_PARAMETER);
1114 AssertPtrNullReturn(ppvSymbol, VERR_INVALID_PARAMETER);
1115 AssertReturn(!pszModule, VERR_MODULE_NOT_FOUND);
1116
1117 uintptr_t uValue = rtR0DbgKrnlDarwinLookup(pThis, pszSymbol);
1118 if (ppvSymbol)
1119 *ppvSymbol = (void *)uValue;
1120 if (uValue)
1121 return VINF_SUCCESS;
1122 return VERR_SYMBOL_NOT_FOUND;
1123}
1124
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