
Hybridkernel, der Mach, FreeBSD und IOKit für macOS und iOS kombiniert. Bietet Kern-OS-Dienste, Treiberframework und Durchsetzung von Sicherheitsrichtlinien auf x86_64 und ARM64.
Der XNU-Kernel ist Teil des Darwin-Betriebssystems für die Verwendung in macOS- und iOS-Betriebssystemen. XNU ist ein Akronym für X is Not Unix. XNU ist ein Hybridkernel, der den an der Carnegie Mellon University entwickelten Mach-Kernel mit Komponenten von FreeBSD und einer C++-API zum Schreiben von Treibern namens IOKit kombiniert. XNU läuft auf x86_64 und ARM64 sowohl für Einzelprozessor- als auch für Mehrprozessorkonfigurationen.
config - Konfigurationen für exportierte APIs für unterstützte Architekturen und PlattformenSETUP - Grundlegende Werkzeuge zur Konfiguration des Kernels, Versionierung und Kextsymbol-Verwaltung.EXTERNAL_HEADERS - Header aus anderen Projekten, um Abhängigkeitszyklen beim Bauen zu vermeiden. Diese Header sollten regelmäßig synchronisiert werden, wenn die Quelle aktualisiert wird.libkern - C++-IOKit-Bibliothekscode für die Behandlung von Treibern und Kexts.libsa - Kernel-Bootstrap-Code für den Startlibsyscall - Systemaufruf-Bibliotheksschnittstelle für Userspace-Programmelibkdd - Quelle für die Benutzerbibliothek zum Parsen von Kernel-Daten wie Kernel-Chunked-Daten.makedefs - Top-Level-Regeln und Definitionen für den Kernel-Build.osfmk - Mach-Kernel-basierte Subsystemepexpert - Plattformspezifischer Code wie Interrupt-Handling, Atomare Operationen usw.security - Mandatory Access Check Policy-Schnittstellen und zugehörige Implementierung.bsd - BSD-Subsysteme-Codetools - Eine Reihe von Dienstprogrammen zum Testen, Debuggen und Profilen des Kernels.DEVELOPMENT-KernelsDas XNU-Make-System kann Kernel basierend auf den Variablen KERNEL_CONFIGS und ARCH_CONFIGS als Argumente bauen.
Hier ist die Syntax:```text
make SDKROOT= ARCH_CONFIGS= KERNEL_CONFIGS=
Wo:
* `<sdkroot>`: Pfad zum macOS SDK auf der Festplatte. (Standardwert ist `/`)
* `<variant>`: kann `debug`, `development`, `release`, `profile` sein und konfiguriert Compiler-Flags und Asserts im gesamten Kernel-Code.
* `<arch>`: kann eine gültige Architektur sein, für die gebaut wird. (Z.B. `X86_64`)
Um einen Kernel für die gleiche Architektur wie das laufende Betriebssystem zu bauen, tippen Sie einfach:```text
make SDKROOT=macosx.internal
Zusätzlich gibt es Unterstützung für die Konfiguration von Architekturen über ARCH_CONFIGS und Kernel-Konfigurationen mit KERNEL_CONFIGS.```text
make SDKROOT=macosx.internal ARCH_CONFIGS=X86_64 KERNEL_CONFIGS=DEVELOPMENT
make SDKROOT=macosx.internal ARCH_CONFIGS=X86_64 KERNEL_CONFIGS="RELEASE DEVELOPMENT DEBUG"
> Hinweis: Standardmäßig ist die Architektur auf die Architektur des Build-Rechners eingestellt, und die Standard-Kernel-Konfiguration ist so eingestellt, dass sie für `DEVELOPMENT` erstellt wird.
Dadurch wird auch ein bootfähiges Image, kernel.[config] und ein Kernel-Binärprogramm mit Symbolen, kernel.[config].unstripped, erstellt.
Um den Kernel in ein DSTROOT zu installieren, verwenden Sie das Ziel `install_kernels`:```text
make install_kernels DSTROOT=/tmp/xnu-dst
Für eine zufriedenstellendere Kernel-Debugging-Erfahrung mit Zugriff auf alle lokalen Variablen und Argumente, aber ohne all die zusätzlichen Überprüfungen des DEBUG-Kernels, fügen Sie etwas wie das Folgende zu Ihrem make-Befehl hinzu:```text CFLAGS_DEVELOPMENTARM64="-O0 -g -DKERNEL_STACK_MULTIPLIER=2" CXXFLAGS_DEVELOPMENTARM64="-O0 -g -DKERNEL_STACK_MULTIPLIER=2"
Denken Sie daran, `DEVELOPMENT` und `ARM64` durch den entsprechenden Build und die entsprechende Plattform zu ersetzen.
> Zusätzliche Flags: Sie können dem C-Compiler über die Befehlszeile zusätzliche Flags mit der Build-Einstellung `EXTRA_CFLAGS` übergeben. Diese Flags werden an die Basis-`CFLAGS` angehängt, und der Standardwert für die Einstellung ist eine leere Zeichenfolge.
>
> Diese Einstellung ermöglicht es Ihnen, z.B. selektiv Debug-Code zu aktivieren, der durch ein Preprocessor-Makro geschützt ist. Beispielverwendung...
>
> ```text
> make SDKROOT=macosx.internal PRODUCT_CONFIGS=j314s
> EXTRA_CFLAGS='-DKERNEL_STACK_MULTIPLIER=2'
> ```
* So bauen Sie mit RELEASE-Kernelkonfiguration
```text
make KERNEL_CONFIGS=RELEASE SDKROOT=/path/to/SDK
```
### FAT-Kernel-Binärdatei erstellen
Definieren Sie Architekturen in Ihrer Umgebung oder beim Ausführen eines make-Befehls.```text
make ARCH_CONFIGS="X86_64" exporthdrs all
Das XNU-Buildsystem kann optional farblich formatierte Build-Ausgaben ausgeben. Um dies zu aktivieren, können Sie entweder die Umgebungsvariable XNU_LOGCOLORS auf y setzen oder LOGCOLORS=y an den make-Befehl übergeben.
Die xnu-Version wird vom SDK oder KDK abgeleitet, indem die CFBundleVersion aus deren System/Library/Extensions/System.kext/Info.plist-Datei gelesen wird.
Dies kann durch Setzen der Variable RC_DARWIN_KERNEL_VERSION in der Umgebung oder in der make-Befehlszeile angepasst werden.
Weitere Einzelheiten finden Sie in doc/building/xnu_version.md.
Standardmäßig wird während der Installationsphase ein DWARF-Debug-Informations-Repository erstellt; dies ist ein "Bundle" namens kernel.development.<variant>.dSYM Um das ältere STABS-Debug-Informationsformat auszuwählen (bei dem Debug-Informationen in das Abbild kernel.development.unstripped eingebettet sind), setzen Sie die Umgebungsvariable BUILD_STABS.```sh export BUILD_STABS=1 make
## Erstellen von KernelCaches
Um den xnu-Kernel zu testen, müssen Sie einen Kernelcache erstellen, der die Kexts und den Kernel zu einem einzigen bootfähigen Image zusammenbindet.
Um einen Kernelcache zu erstellen, können Sie die folgenden Mechanismen nutzen:
* Verwendung der automatischen Kernelcache-Generierung mit `kextd`.
Der Daemon kextd überwacht ständig Änderungen im Verzeichnis `/System/Library/Extensions`.
So können Sie einen neuen Kernel einrichten:
```text
cp BUILD/obj/DEVELOPMENT/X86_64/kernel.development /System/Library/Kernels/
touch /System/Library/Extensions
ps -e | grep kextd
```
* Manuelles Aufrufen von `kextcache` zum Erstellen eines neuen Kernelcaches.
```text
kextcache -q -z -a x86_64 -l -n -c /var/tmp/kernelcache.test -K /var/tmp/kernel.test /System/Library/Extensions
```
## Booten eines KernelCaches auf einem Zielrechner
Der Entwicklungskernel und iBoot unterstützen die Konfiguration von Boot-Argumenten, sodass wir sicher in einen Testkernel booten können und bei Problemen sicher auf den zuvor verwendeten Kernelcache zurückfallen können.
Die folgenden Schritte führen zu einer solchen Einrichtung:
1. Erstellen Sie den Kernelcache mit dem Befehl kextcache als `/kernelcache.test`
2. Kopieren Sie vorhandene Boot-Konfigurationen in eine alternative Datei
```sh
cp /Library/Preferences/SystemConfiguration/com.apple.Boot.plist /next_boot.plist
```
3. Aktualisieren Sie den Kernelcache und die Boot-Argumente für Ihre Einrichtung
```sh
plutil -insert "Kernel Cache" -string "kernelcache.test" /next_boot.plist
plutil -replace "Kernel Flags" -string "debug=0x144 -v kernelsuffix=test " /next_boot.plist
```
4. Kopieren Sie die neue Konfiguration nach `/Library/Preferences/SystemConfiguration/`
```sh
cp /next_boot.plist /Library/Preferences/SystemConfiguration/boot.plist
```
5. Segnen Sie das Volume mit den neuen Konfigurationen.
```text
sudo -n bless --mount / --setBoot --nextonly --options "config=boot"
```
Das Flag `--nextonly` gibt an, dass die Konfigurationen aus `boot.plist` nur für einen Bootvorgang verwendet werden sollen.
Bei einem Kernel-Panic können Sie so einfach einen Neustart durchführen und zum ursprünglichen Kernel zurückkehren.
## Erstellen von Tags und cscope
Richten Sie Ihre Build-Umgebung ein und führen Sie vom Hauptverzeichnis aus Folgendes aus:
make tags # dies erstellt ctags und etags auf einem case-sensitiven Volume, nur ctags auf case-insensitiven
make TAGS # dies erstellt etags
make cscope # dies erstellt die cscope-Datenbank
## Installieren neuer Header-Dateien aus XNU
XNU installiert Header-Dateien an den folgenden Speicherorten –
a. $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers
b. $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders
c. $(DSTROOT)/usr/include/
d. $(DSTROOT)/usr/local/include/
e. $(DSTROOT)/System/DriverKit/usr/include/
f. $(DSTROOT)/System/Library/Frameworks/IOKit.framework/Headers
g. $(DSTROOT)/System/Library/Frameworks/IOKit.framework/PrivateHeaders
h. $(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
`Kernel.framework` wird von Kernel-Erweiterungen verwendet.\
Das `System.framework`, `/usr/include` und `/usr/local/include` werden von Benutzerprogrammen verwendet. \
`IOKit.framework` wird von IOKit-Benutzerbereichsclients verwendet. \
`/System/DriverKit/usr/include` wird von Benutzerbereichs-Treibern verwendet. \
Die Header-Dateien in `PrivateHeaders` des Frameworks sind nur für **Apple Internal Development** verfügbar.
Das Verzeichnis, das die Header-Datei enthält, sollte ein Makefile haben, das die Liste der Dateien erstellt, die an verschiedenen Speicherorten installiert werden sollen.
Wenn Sie die erste Header-Datei in einem Verzeichnis hinzufügen, müssen Sie ein Makefile ähnlich wie `xnu/bsd/sys/Makefile` erstellen.
Fügen Sie Ihre Header-Datei zur richtigen Dateiliste hinzu, je nachdem, wo Sie sie installieren möchten.
Die Standard-Speicherorte, an denen die Header-Dateien aus jeder Dateiliste installiert werden, sind –
a. `DATAFILES` : Um die Header-Datei auf Benutzerebene verfügbar zu machen –
`$(DSTROOT)/usr/include`
`$(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders`
b. `DRIVERKIT_DATAFILES` : Um die Header-Datei für DriverKit-Benutzerbereichs-Treiber verfügbar zu machen –
`$(DSTROOT)/System/DriverKit/usr/include`
c. `PRIVATE_DATAFILES` : Um die Header-Datei für Apple-intern auf Benutzerebene verfügbar zu machen –
`$(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders`
d. `EMBEDDED_PRIVATE_DATAFILES` : Um die Header-Datei auf Benutzerebene für macOS als `EXTRA_DATAFILES` verfügbar zu machen, aber für Apple-intern auf Benutzerebene für eingebettete Betriebssysteme als `EXTRA_PRIVATE_DATAFILES` –
`$(DSTROOT)/usr/include` (`EXTRA_DATAFILES`)
`$(DSTROOT)/usr/local/include` (`EXTRA_PRIVATE_DATAFILES`)
e. `KERNELFILES` : Um die Header-Datei auf Kernel-Ebene verfügbar zu machen –
`$(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers`
`$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders`
f. `PRIVATE_KERNELFILES` : Um die Header-Datei für Apple-intern für Kernel-Erweiterungen verfügbar zu machen –
`$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders`
g. `MODULEMAPFILES` : Um die Module-Map-Datei auf Benutzerebene verfügbar zu machen –
`$(DSTROOT)/usr/include`
h. `PRIVATE_MODULEMAPFILES` : Um die Module-Map-Datei für Apple-intern auf Benutzerebene verfügbar zu machen –
`$(DSTROOT)/usr/local/include`
i. `LIBCXX_DATAFILES` : Um die Header-Datei für In-Kernel-libcxx-Clients verfügbar zu machen:
`$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders/kernel_sdkroot`
j. `EXCLAVEKIT_DATAFILES` : Um die Header-Datei für das Apple-interne ExclaveKit SDK verfügbar zu machen –
`$(DSTROOT)/System/ExclaveKit/usr/include`
k. `EXCLAVECORE_DATAFILES` : Um die Header-Datei für das Apple-interne ExclaveCore SDK verfügbar zu machen –
`$(DSTROOT)/System/ExclaveCore/usr/include`
Das Makefile kombiniert die oben genannten Dateilisten zu verschiedenen Installationslisten, die vom Build-System zum Installieren der Header-Dateien verwendet werden. Es gibt zwei Arten von Installationslisten: maschinenabhängig und maschinenunabhängig. Diese Listen werden durch das Vorhandensein von `MD` und `MI` in den Build-Einstellungen angezeigt. Wenn Ihr Header architekturspezifisch ist, sollten Sie eine maschinenabhängige Installationsliste verwenden (z. B. `INSTALL_MD_LIST`). Wenn Ihr Header für alle Architekturen installiert werden soll, sollten Sie eine maschinenunabhängige Installationsliste verwenden (z. B. `INSTALL_MI_LIST`).
Wenn die gewünschte Installationsliste nicht vorhanden ist, erstellen Sie sie durch Hinzufügen der entsprechenden Dateilisten. Die Standard-Installationslisten, ihre Dateilisten und ihre Standard-Speicherorte werden unten beschrieben –
a. `INSTALL_MI_LIST`, `INSTALL_MODULEMAP_MI_LIST` : Installiert Header- und Module-Map-Dateien an einem Ort, der für alle auf Benutzerebene verfügbar ist.
Locations -
$(DSTROOT)/usr/include
Definition -
INSTALL_MI_LIST = ${DATAFILES}
INSTALL_MODULEMAP_MI_LIST = ${MODULEMAPFILES}
b. `INSTALL_DRIVERKIT_MI_LIST` : Installiert die Header-Datei an einem Ort, der für DriverKit-Benutzerbereichs-Treiber verfügbar ist.
Locations -
$(DSTROOT)/System/DriverKit/usr/include
Definition -
INSTALL_DRIVERKIT_MI_LIST = ${DRIVERKIT_DATAFILES}
c. `INSTALL_MI_LCL_LIST`, `INSTALL_MODULEMAP_MI_LCL_LIST` : Installiert Header- und Module-Map-Dateien an einem Ort, der für Apple-intern auf Benutzerebene verfügbar ist.
Locations -
$(DSTROOT)/usr/local/include
Definition -
INSTALL_MI_LCL_LIST =
INSTALL_MODULEMAP_MI_LCL_LIST = ${PRIVATE_MODULEMAPFILES}
d. `INSTALL_IF_MI_LIST` : Installiert die Header-Datei an einem Ort, der für alle für IOKit-Benutzerbereichsclients verfügbar ist.
Locations -
$(DSTROOT)/System/Library/Frameworks/IOKit.framework/Headers
Definition -
INSTALL_IF_MI_LIST = ${DATAFILES}
e. `INSTALL_IF_MI_LCL_LIST` : Installiert die Header-Datei an einem Ort, der für Apple-intern für IOKit-Benutzerbereichsclients verfügbar ist.
Locations -
$(DSTROOT)/System/Library/Frameworks/IOKit.framework/PrivateHeaders
Definition -
INSTALL_IF_MI_LCL_LIST = ${DATAFILES} ${PRIVATE_DATAFILES}
f. `INSTALL_SF_MI_LCL_LIST` : Installiert die Header-Datei an einem Ort, der für Apple-intern auf Benutzerebene verfügbar ist.
Locations -
$(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
Definition -
INSTALL_SF_MI_LCL_LIST = ${DATAFILES} ${PRIVATE_DATAFILES}
g. `INSTALL_KF_MI_LIST` : Installiert die Header-Datei an einem Ort, der für alle für Kernel-Erweiterungen verfügbar ist.
Locations -
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers
Definition -
INSTALL_KF_MI_LIST = ${KERNELFILES}
h. `INSTALL_KF_MI_LCL_LIST` : Installiert die Header-Datei an einem Ort, der für Apple-intern für Kernel-Erweiterungen verfügbar ist.
Locations -
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders
Definition -
INSTALL_KF_MI_LCL_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES}
i. `EXPORT_MI_LIST` : Exportiert die Header-Datei in alle Teile von xnu (bsd/, osfmk/, etc.) nur zur Kompilierung. Installiert nichts in das SDK.
Definition -
EXPORT_MI_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES}
j. `INSTALL_KF_LIBCXX_MI_LIST` : Installiert die Header-Datei für In-Kernel-libc++-Unterstützung.
Locations -
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders/kernel_sdkroot
Definition -
INSTALL_KF_LIBCXX_MI_LIST = ${LIBCXX_DATAFILES}
k. `INSTALL_EXCLAVEKIT_MI_LIST` : Installiert die Header-Datei an einem Ort, der für Apple-intern für ExclaveKit verfügbar ist.
Locations -
$(DSTROOT)/System/ExclaveKit/usr/include
Definition -
INSTALL_EXCLAVEKIT_MI_LIST = ${EXCLAVEKIT_DATAFILES}
l. `INSTALL_EXCLAVECORE_MI_LIST` : Installiert die Header-Datei an einem Ort, der für Apple-intern für ExclaveCore verfügbar ist.
Locations -
$(DSTROOT)/System/ExclaveCore/usr/include
Definition -
INSTALL_EXCLAVECORE_MI_LIST = ${EXCLAVECORE_DATAFILES}
Wenn Sie die Header-Datei in einem Unterverzeichnis der in (1) beschriebenen Pfade installieren möchten, geben Sie den Verzeichnisnamen mit den beiden Variablen `INSTALL_MI_DIR` und `EXPORT_MI_DIR` wie folgt an –```text
INSTALL_MI_DIR = dirname
EXPORT_MI_DIR = dirname
Wenn Sie die Modul-Map-Datei in einem Unterverzeichnis installieren möchten, geben Sie den
Verzeichnisnamen mit der Variable INSTALL_MODULEMAP_MI_DIR wie folgt an -```text
INSTALL_MODULEMAP_MI_DIR = dirname
Eine einzelne Header-Datei kann mit den oben genannten Schritten an verschiedenen Speicherorten existieren. Es kann jedoch unerwünscht sein, den gesamten Code in der Header-Datei an allen Speicherorten verfügbar zu machen. Beispielsweise möchten Sie eine Funktion möglicherweise nur auf Kernel-Ebene, nicht aber auf Benutzerebene exportieren.
Sie können die Präprozessordirektive der Sprache C (#ifdef, #endif, #ifndef) verwenden, um den Text zu steuern, der generiert wird, bevor eine Header-Datei installiert wird. Der Kernel bezieht den Code nur ein, wenn das bedingte Makro WAHR ist, und entfernt Code für FALSCHE Bedingungen aus der Header-Datei.
Einige vordefinierte Makros und ihre Beschreibungen sind:
1. `PRIVATE` : Wenn definiert, gelten die eingeschlossenen Definitionen als System Private Interfaces. Diese sind innerhalb von xnu sichtbar und werden in Benutzer-/Kernel-Headern offengelegt, die in den AppleInternal "PrivateHeaders"-Abschnitten der System- und Kernel-Frameworks installiert sind.
2. `KERNEL_PRIVATE` : Wenn definiert, ist der eingeschlossene Code für das gesamte xnu-Kernel und Apple-interne Kernel-Erweiterungen verfügbar und wird aus Benutzer-Headern ausgeschlossen.
3. `BSD_KERNEL_PRIVATE` : Wenn definiert, ist der eingeschlossene Code ausschließlich innerhalb des xnu/bsd-Moduls sichtbar.
4. `MACH_KERNEL_PRIVATE`: Wenn definiert, ist der eingeschlossene Code ausschließlich innerhalb des xnu/osfmk-Moduls sichtbar.
5. `XNU_KERNEL_PRIVATE`: Wenn definiert, ist der eingeschlossene Code ausschließlich innerhalb von xnu sichtbar.
6. `KERNEL` : Wenn definiert, ist der eingeschlossene Code innerhalb von xnu und Kernel-Erweiterungen verfügbar und in Header-Dateien auf Benutzerebene nicht sichtbar. Nur die Header-Dateien, die in den folgenden Pfaden installiert sind, enthalten den Code:
```text
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders
```
7. `DRIVERKIT`: Wenn definiert, ist der eingeschlossene Code ausschließlich in den DriverKit SDK-Headern sichtbar, die von Userspace-Treibern verwendet werden.
8. `EXCLAVEKIT`: Wenn definiert, ist der eingeschlossene Code ausschließlich in den ExclaveKit SDK-Headern sichtbar.
9. `EXCLAVECORE`: Wenn definiert, ist der eingeschlossene Code ausschließlich in den ExclaveCore SDK-Headern sichtbar.
10. `MODULES_SUPPORTED` Wenn definiert, ist der eingeschlossene Code ausschließlich an Speicherorten sichtbar, die Modules/Swift unterstützen (d.h. nicht System- oder Kernel-Frameworks).
## VM-Header-Datei-Namenskonvention
Die VM-Header folgen den folgenden Namenskonventionen:
* `*_internal.h`-Header enthalten Komponenten des VM-Subsystems, die nur für die Verwendung durch VM-Code bestimmt sind.
* `*_xnu.h`-Header enthalten Komponenten des VM-Subsystems, die nur für die Verwendung durch anderen xnu-Code bestimmt sind.
* `*.h`-Header enthalten Komponenten des VM-Subsystems, die an Kexts exportiert werden.
* `vm_iokit.h`-Header enthält Komponenten des VM-Subsystems, die an das iokit-Subsystem exportiert werden.
* `vm_ubc.h`-Header enthält Komponenten des VM-Subsystems, die an das ubc-Subsystem exportiert werden.
## Modul-Map-Datei-Namenskonvention
Im einfachen Fall kann ein Unterverzeichnis von `usr/include` oder `usr/local/include` durch ein eigenständiges Modul dargestellt werden. Wenn dies der Fall ist, setzen Sie `INSTALL_MODULEMAP_MI_DIR` auf `INSTALL_MI_DIR` und installieren Sie dort eine `module.modulemap`-Datei. `module.modulemap` wird auch für private Module in `usr/local/include` verwendet; `module.private.modulemap` wird nicht verwendet. Vorsicht: Um im einfachen Fall zu bleiben, muss der Modulname genau dem Verzeichnisnamen entsprechen. Falls dies nicht möglich ist, muss die folgende Methode angewendet werden.
`xnu` trägt zu den in CoreOSModuleMaps definierten Modulen bei, indem es Modul-Map-Dateien installiert, die aus `usr/include/module.modulemap` und `usr/local/include/module.modulemap` stammen. Die Namenskonvention für die `xnu`-Modul-Map-Dateien ist wie folgt.
a. Idealerweise deckt die Modul-Map-Datei ein gesamtes Verzeichnis ab. Eine Modul-Map-Datei, die `usr/include/a/b/c` abdeckt, würde `a_b_c.modulemap` heißen. `usr/local/include/a/b/c` wäre `a_b_c_private.modulemap`.
b. Einige Header sind speziell und benötigen ein eigenes Modul. In diesem Fall würde die Modul-Map-Datei nach dem Modul benannt, das sie definiert. Eine Modul-Map-Datei, die das Modul `One.Two.Three` definiert, würde `one_two_three.modulemap` heißen.
## Bedingte Kompilierung
`xnu` bietet die folgenden Mechanismen zur bedingten Kompilierung von Code:
1. *CPU-Eigenschaften* Wenn der Code, den Sie schützen, spezifische Eigenschaften hat, die nur basierend auf der Ziel-CPU-Architektur variieren, verwenden Sie diese Option. Bevorzugen Sie die Prüfung auf Merkmale der Architektur (z.B. `__LP64__`, `__LITTLE_ENDIAN__` usw.).
2. *Neue Funktionen* Wenn der Code, den Sie schützen, zusammengenommen eine Funktion implementiert, sollten Sie eine neue Funktion in `config/MASTER` definieren und das resultierende `CONFIG`-Präprozessor-Token verwenden (z.B. für eine Funktion namens `config_virtual_memory` prüfen Sie auf `#if CONFIG_VIRTUAL_MEMORY`). Diese Vorgehensweise stellt sicher, dass vorhandene Funktionen durch einfaches Ändern eines Funktionsschalters auf andere Plattformen übertragen werden können.
3. *Vorhandene Funktionen* Sie können vorhandene Funktionen verwenden, wenn Ihr Code stark an sie gebunden ist (z.B. verwenden Sie `SECURE_KERNEL`, wenn Ihr Code neue Funktionalität implementiert, die ausschließlich für den vertrauenswürdigen Kernel relevant ist und die Definition/das Verständnis dessen aktualisiert, was ein vertrauenswürdiger Kernel bedeutet).
Es wird empfohlen, die Kompilierung nicht auf Basis der Zielplattform durchzuführen. `xnu` definiert die Plattform-Makros aus `TargetConditionals.h` (`TARGET_OS_OSX`, `TARGET_OS_IOS` usw.) nicht.
## Debugging von XNU
Standardmäßig startet der Kernel bei einem Panik neu. Dieses Verhalten kann durch das boot-arg `debug` überschrieben werden – `debug=0x14e` bewirkt, dass ein Panik darauf wartet, dass ein Debugger angehängt wird. Um einen Kernel so zu booten, dass er von einer angeschlossenen Maschine debuggt werden kann, überschreiben Sie das boot-arg `kdp_match_name` mit der entsprechenden `ifconfig`-Schnittstelle. Ethernet-, Thunderbolt- und serielles Debugging werden unterstützt, abhängig von der Hardware.
Verwenden Sie LLDB, um den Kernel zu debuggen:```text
xcrun -sdk macosx lldb <path-to-unstripped-kernel>
(lldb) gdb-remote [<host-ip>:]<port>
Die Debug-Informationen für den Kernel (dSYM) enthalten eine Reihe von Makros zur Unterstützung des Kernel-Debuggings.
Um diese Makros automatisch zu laden, wenn eine Verbindung zum Kernel hergestellt wird, fügen Sie Folgendes zu ~/.lldbinit hinzu:```text
settings set target.load-script-from-symbol-file true
`tools/lldbmacros` enthält den Quellcode für diese Befehle.
Siehe die README in diesem Verzeichnis für deren Verwendung, oder nutzen Sie die integrierte LLDB-Hilfe mit:```text
(lldb) help showcurrentstacks