VirtualBox

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

Last change on this file since 71883 was 69662, checked in by vboxsync, 7 years ago

dbgkrnlinfo-r0drv-darwin.cpp: Stop confusing doxygen with RTR0DECL redefinition.

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