
Kernel ibrido che combina Mach, FreeBSD e IOKit per macOS e iOS. Fornisce servizi di sistema core, un framework per driver e l'applicazione di policy di sicurezza su x86_64 e ARM64.
Il kernel XNU fa parte del sistema operativo Darwin utilizzato nei sistemi operativi macOS e iOS. XNU è un acronimo per X is Not Unix. XNU è un kernel ibrido che combina il kernel Mach sviluppato alla Carnegie Mellon University con componenti di FreeBSD e un'API C++ per scrivere driver chiamata IOKit. XNU funziona su x86_64 e ARM64 per configurazioni sia a singolo processore che multiprocessore.
config - configurazioni per le API esportate per architettura e piattaforma supportateSETUP - Set di strumenti base usati per configurare il kernel, versioning e gestione dei kextsymbol.EXTERNAL_HEADERS - Header provenienti da altri progetti per evitare dipendenze cicliche durante la compilazione. Questi header dovrebbero essere sincronizzati regolarmente quando i sorgenti vengono aggiornati.libkern - Codice della libreria C++ IOKit per la gestione di driver e kext.libsa - Codice di bootstrap del kernel per l'avviolibsyscall - Interfaccia delle syscall per i programmi in spazio utentelibkdd - Sorgente per la libreria utente per l'analisi di dati del kernel come i dati chunked del kernel.makedefs - Regole e definizioni di alto livello per la compilazione del kernel.osfmk - Sottosistemi basati sul kernel Machpexpert - Codice specifico della piattaforma come gestione degli interrupt, atomiche, ecc.security - Interfacce delle policy di Mandatory Access Check e implementazioni correlate.bsd - Codice dei sottosistemi BSDtools - Un insieme di utilità per testare, eseguire il debug e profilare il kernel.DEVELOPMENTIl sistema make di xnu può compilare il kernel basandosi sulle variabili KERNEL_CONFIGS e ARCH_CONFIGS come argomenti.
Ecco la sintassi:```text
make SDKROOT= ARCH_CONFIGS= KERNEL_CONFIGS=
Where:
* `<sdkroot>`: percorso verso l'SDK macOS su disco. (predefinito a `/`)
* `<variant>`: può essere `debug`, `development`, `release`, `profile` e configura i flag di compilazione e gli assert in tutto il codice del kernel.
* `<arch>`: può essere l'architettura valida per cui compilare. (Ad es. `X86_64`)
Per compilare un kernel per la stessa architettura del sistema operativo in esecuzione, basta digitare```text
make SDKROOT=macosx.internal
Inoltre, c'è supporto per la configurazione delle architetture tramite ARCH_CONFIGS e configurazioni del kernel con 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"
> Nota: Per impostazione predefinita, l'architettura è impostata su quella della macchina di build, e la configurazione predefinita del kernel è impostata per la build di `DEVELOPMENT`.
Questo creerà anche un'immagine avviabile, kernel.[config], e un binario del kernel con simboli, kernel.[config].unstripped.
Per installare il kernel in una DSTROOT, usa il target `install_kernels`:```text
make install_kernels DSTROOT=/tmp/xnu-dst
Per un'esperienza di debug del kernel più soddisfacente, con accesso a tutte le variabili locali e agli argomenti, ma senza tutti i controlli aggiuntivi del kernel DEBUG, aggiungi qualcosa di simile al seguente al tuo comando make:```text CFLAGS_DEVELOPMENTARM64="-O0 -g -DKERNEL_STACK_MULTIPLIER=2" CXXFLAGS_DEVELOPMENTARM64="-O0 -g -DKERNEL_STACK_MULTIPLIER=2"
Ricorda di sostituire `DEVELOPMENT` e `ARM64` con la build e la piattaforma appropriate.
> Flag Extra: Puoi passare flag aggiuntivi al compilatore C dalla riga di comando con l'impostazione di build `EXTRA_CFLAGS`. Questi flag vengono aggiunti ai `CFLAGS` di base, e il valore predefinito dell'impostazione è una stringa vuota.
>
> Questa impostazione ti permette, ad esempio, di attivare selettivamente codice di debug protetto da una macro del preprocessore. Esempio di utilizzo...
>
> ```text
> make SDKROOT=macosx.internal PRODUCT_CONFIGS=j314s
> EXTRA_CFLAGS='-DKERNEL_STACK_MULTIPLIER=2'
> ```
* Per compilare con la configurazione del kernel RELEASE
```text
make KERNEL_CONFIGS=RELEASE SDKROOT=/percorso/del/SDK
```
### Compilazione del Binario del Kernel FAT
Definisci le architetture nel tuo ambiente o quando esegui un comando make.```text
make ARCH_CONFIGS="X86_64" exporthdrs all
Il sistema di build XNU può opzionalmente produrre output di build con formato a colori. Per abilitarlo, puoi impostare la variabile d'ambiente XNU_LOGCOLORS a y, oppure passare LOGCOLORS=y al comando make.
La versione di XNU è derivata dall'SDK o KDK leggendo il campo CFBundleVersion del file System/Library/Extensions/System.kext/Info.plist.
Questo può essere personalizzato impostando la variabile RC_DARWIN_KERNEL_VERSION nell'ambiente o sulla riga di comando di make.
Vedi doc/building/xnu_version.md per maggiori dettagli.
Per impostazione predefinita, viene creato un repository di informazioni di debug DWARF durante la fase di installazione; questo è un "bundle" chiamato kernel.development.<variant>.dSYM Per selezionare il vecchio formato di informazioni di debug STABS (dove le informazioni di debug sono incorporate nell'immagine kernel.development.unstripped), imposta la variabile d'ambiente BUILD_STABS.```sh export BUILD_STABS=1 make
## Costruzione dei KernelCaches
Per testare il kernel xnu, è necessario costruire un kernelcache che colleghi i kext e il kernel in un'unica immagine avviabile.
Per costruire un kernelcache è possibile utilizzare i seguenti meccanismi:
* Usando la generazione automatica del kernelcache con `kextd`.
Il demone kextd monitora continuamente le modifiche nella directory `/System/Library/Extensions`.
Quindi puoi configurare un nuovo kernel come
```text
cp BUILD/obj/DEVELOPMENT/X86_64/kernel.development /System/Library/Kernels/
touch /System/Library/Extensions
ps -e | grep kextd
```
* Invocando manualmente `kextcache` per costruire un nuovo kernelcache.
```text
kextcache -q -z -a x86_64 -l -n -c /var/tmp/kernelcache.test -K /var/tmp/kernel.test /System/Library/Extensions
```
## Avvio di un KernelCache su una macchina di destinazione
Il kernel di sviluppo e iBoot supportano la configurazione degli argomenti di avvio in modo da poter avviare in sicurezza un kernel di test e, in caso di problemi, tornare in sicurezza al kernelcache utilizzato in precedenza.
Di seguito sono riportati i passaggi per ottenere una tale configurazione:
1. Crea la cache del kernel usando il comando kextcache come `/kernelcache.test`
2. Copia le configurazioni di avvio esistenti in un file alternativo
```sh
cp /Library/Preferences/SystemConfiguration/com.apple.Boot.plist /next_boot.plist
```
3. Aggiorna il kernelcache e i boot-args per la tua configurazione
```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. Copia la nuova configurazione in `/Library/Preferences/SystemConfiguration/`
```sh
cp /next_boot.plist /Library/Preferences/SystemConfiguration/boot.plist
```
5. Benedici il volume con le nuove configurazioni.
```text
sudo -n bless --mount / --setBoot --nextonly --options "config=boot"
```
Il flag `--nextonly` specifica di utilizzare le configurazioni `boot.plist` solo per un avvio.
Quindi se il kernel va in panic, puoi facilmente riavviare e tornare al kernel originale.
## Creazione di tags e cscope
Configura il tuo ambiente di build e dalla directory principale, esegui:
make tags # this will build ctags and etags on a case-sensitive volume, only ctags on case-insensitive
make TAGS # this will build etags
make cscope # this will build cscope database
## Installazione di nuovi file header da XNU
XNU installa i file header nelle seguenti posizioni -
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` è utilizzato dalle estensioni del kernel.\
`System.framework`, `/usr/include` e `/usr/local/include` sono utilizzati dalle applicazioni a livello utente.\
`IOKit.framework` è utilizzato dai client IOKit in spazio utente.\
`/System/DriverKit/usr/include` è utilizzato dai driver in spazio utente.\
I file header nei `PrivateHeaders` dei framework sono disponibili solo per **Apple Internal Development**.
La directory contenente il file header dovrebbe avere un Makefile che crea l'elenco dei file da installare in diverse posizioni.
Se stai aggiungendo il primo file header in una directory, dovrai creare un Makefile simile a `xnu/bsd/sys/Makefile`.
Aggiungi il tuo file header alla corretta lista di file in base a dove desideri installarlo. Le posizioni predefinite in cui i file header vengono installati da ciascuna lista di file sono -
a. `DATAFILES` : Per rendere il file header disponibile a livello utente -
`$(DSTROOT)/usr/include`
`$(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders`
b. `DRIVERKIT_DATAFILES` : Per rendere il file header disponibile ai driver DriverKit in spazio utente -
`$(DSTROOT)/System/DriverKit/usr/include`
c. `PRIVATE_DATAFILES` : Per rendere il file header disponibile ad Apple internal a
livello utente -
`$(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders`
d. `EMBEDDED_PRIVATE_DATAFILES` : Per rendere il file header disponibile a livello
utente per macOS come `EXTRA_DATAFILES`, ma ad Apple internal a livello utente
per sistemi embedded come `EXTRA_PRIVATE_DATAFILES` -
`$(DSTROOT)/usr/include` (`EXTRA_DATAFILES`)
`$(DSTROOT)/usr/local/include` (`EXTRA_PRIVATE_DATAFILES`)
e. `KERNELFILES` : Per rendere il file header disponibile a livello kernel -
`$(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers`
`$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders`
f. `PRIVATE_KERNELFILES` : Per rendere il file header disponibile ad Apple internal
per le estensioni del kernel -
`$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders`
g. `MODULEMAPFILES` : Per rendere il file di module map disponibile a livello utente -
`$(DSTROOT)/usr/include`
h. `PRIVATE_MODULEMAPFILES` : Per rendere il file di module map disponibile ad Apple
internal a livello utente -
`$(DSTROOT)/usr/local/include`
i. `LIBCXX_DATAFILES` : Per rendere il file header disponibile ai client libcxx in-kernel:
`$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders/kernel_sdkroot`
j. `EXCLAVEKIT_DATAFILES` : Per rendere il file header disponibile ad Apple internal
per ExclaveKit SDK -
`$(DSTROOT)/System/ExclaveKit/usr/include`
k. `EXCLAVECORE_DATAFILES` : Per rendere il file header disponibile ad Apple internal
per ExclaveCore SDK -
`$(DSTROOT)/System/ExclaveCore/usr/include`
Il Makefile combina le liste di file menzionate sopra in diverse liste di installazione utilizzate dal sistema di build per installare i file header. Ci sono due tipi di liste di installazione: dipendenti dalla macchina e indipendenti dalla macchina. Queste liste sono indicate rispettivamente dalla presenza di `MD` e `MI` nell'impostazione di build. Se il tuo header è specifico per architettura, dovresti usare una lista di installazione dipendente dalla macchina (ad es. `INSTALL_MD_LIST`). Se il tuo header deve essere installato per tutte le architetture, dovresti usare una lista di installazione indipendente dalla macchina (ad es. `INSTALL_MI_LIST`).
Se la lista di installazione che ti interessa non esiste, creala aggiungendo le liste di file appropriate. Le liste di installazione predefinite, le loro liste di file membri e la loro posizione predefinita sono descritte di seguito -
a. `INSTALL_MI_LIST`, `INSTALL_MODULEMAP_MI_LIST` : Installa i file header e module map
in una posizione disponibile a tutti a livello utente.
Posizioni -
$(DSTROOT)/usr/include
Definizione -
INSTALL_MI_LIST = ${DATAFILES}
INSTALL_MODULEMAP_MI_LIST = ${MODULEMAPFILES}
b. `INSTALL_DRIVERKIT_MI_LIST` : Installa il file header in una posizione
disponibile ai driver DriverKit in spazio utente.
Posizioni -
$(DSTROOT)/System/DriverKit/usr/include
Definizione -
INSTALL_DRIVERKIT_MI_LIST = ${DRIVERKIT_DATAFILES}
c. `INSTALL_MI_LCL_LIST`, `INSTALL_MODULEMAP_MI_LCL_LIST` : Installa i file header e
module map in una posizione disponibile per Apple internal a livello utente.
Posizioni -
$(DSTROOT)/usr/local/include
Definizione -
INSTALL_MI_LCL_LIST =
INSTALL_MODULEMAP_MI_LCL_LIST = ${PRIVATE_MODULEMAPFILES}
d. `INSTALL_IF_MI_LIST` : Installa il file header in una posizione disponibile
a tutti per i client IOKit in spazio utente.
Posizioni -
$(DSTROOT)/System/Library/Frameworks/IOKit.framework/Headers
Definizione -
INSTALL_IF_MI_LIST = ${DATAFILES}
e. `INSTALL_IF_MI_LCL_LIST` : Installa il file header in una posizione
disponibile ad Apple internal per i client IOKit in spazio utente.
Posizioni -
$(DSTROOT)/System/Library/Frameworks/IOKit.framework/PrivateHeaders
Definizione -
INSTALL_IF_MI_LCL_LIST = ${DATAFILES} ${PRIVATE_DATAFILES}
f. `INSTALL_SF_MI_LCL_LIST` : Installa il file header in una posizione disponibile
per Apple internal a livello utente.
Posizioni -
$(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
Definizione -
INSTALL_SF_MI_LCL_LIST = ${DATAFILES} ${PRIVATE_DATAFILES}
g. `INSTALL_KF_MI_LIST` : Installa il file header in una posizione disponibile
a tutti per le estensioni del kernel.
Posizioni -
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers
Definizione -
INSTALL_KF_MI_LIST = ${KERNELFILES}
h. `INSTALL_KF_MI_LCL_LIST` : Installa il file header in una posizione
disponibile per Apple internal per le estensioni del kernel.
Posizioni -
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders
Definizione -
INSTALL_KF_MI_LCL_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES}
i. `EXPORT_MI_LIST` : Esporta il file header in tutto xnu (bsd/, osfmk/, ecc.)
solo per la compilazione. Non installa nulla nell'SDK.
Definizione -
EXPORT_MI_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES}
j. `INSTALL_KF_LIBCXX_MI_LIST` : Installa il file header per il supporto libc++ in-kernel.
Posizioni -
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders/kernel_sdkroot
Definizione -
INSTALL_KF_LIBCXX_MI_LIST = ${LIBCXX_DATAFILES}
k. `INSTALL_EXCLAVEKIT_MI_LIST` : Installa il file header in una posizione
disponibile per Apple internal per ExclaveKit.
Posizioni -
$(DSTROOT)/System/ExclaveKit/usr/include
Definizione -
INSTALL_EXCLAVEKIT_MI_LIST = ${EXCLAVEKIT_DATAFILES}
l. `INSTALL_EXCLAVECORE_MI_LIST` : Installa il file header in una posizione
disponibile per Apple internal per ExclaveCore.
Posizioni -
$(DSTROOT)/System/ExclaveCore/usr/include
Definizione -
INSTALL_EXCLAVECORE_MI_LIST = ${EXCLAVECORE_DATAFILES}
Se desideri installare il file header in una sottodirectory dei percorsi descritti in (1), specifica il nome della directory usando due variabili `INSTALL_MI_DIR` e `EXPORT_MI_DIR` come segue -```text
INSTALL_MI_DIR = dirname
EXPORT_MI_DIR = dirname
Se desideri installare il file di mappatura dei moduli in una sottodirectory, specifica il nome della directory utilizzando la variabile INSTALL_MODULEMAP_MI_DIR come segue -```text
INSTALL_MODULEMAP_MI_DIR = dirname
Un singolo file header può esistere in diverse posizioni utilizzando i passaggi menzionati sopra. Tuttavia potrebbe non essere desiderabile rendere disponibile tutto il codice del file header in tutte le posizioni. Ad esempio, si desidera esportare una funzione solo a livello kernel ma non a livello utente.
È possibile utilizzare la direttiva del pre-processore del linguaggio C (#ifdef, #endif, #ifndef) per controllare il testo generato prima che un file header venga installato. Il kernel include solo il codice se la macro condizionale è VERA e rimuove il codice per le condizioni FALSE dal file header.
Alcune macro predefinite e le loro descrizioni sono -
1. `PRIVATE` : Se definito, le definizioni racchiuse sono considerate Interfacce Private di Sistema. Queste sono visibili all'interno di xnu ed esposte negli header utente/kernel installati nelle sezioni "PrivateHeaders" di AppleInternal dei framework System e Kernel.
2. `KERNEL_PRIVATE` : Se definito, il codice racchiuso è disponibile a tutto il kernel xnu e alle estensioni kernel interne di Apple ed è omesso dagli header utente.
3. `BSD_KERNEL_PRIVATE` : Se definito, il codice racchiuso è visibile esclusivamente all'interno del modulo xnu/bsd.
4. `MACH_KERNEL_PRIVATE`: Se definito, il codice racchiuso è visibile esclusivamente all'interno del modulo xnu/osfmk.
5. `XNU_KERNEL_PRIVATE`: Se definito, il codice racchiuso è visibile esclusivamente all'interno di xnu.
6. `KERNEL` : Se definito, il codice racchiuso è disponibile all'interno di xnu e delle estensioni kernel e non è visibile nei file header a livello utente. Solo i file header installati nei seguenti percorsi avranno il codice -
```text
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers
$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders
```
7. `DRIVERKIT`: Se definito, il codice racchiuso è visibile esclusivamente negli header dell'SDK DriverKit utilizzati dai driver in spazio utente.
8. `EXCLAVEKIT`: Se definito, il codice racchiuso è visibile esclusivamente negli header dell'SDK ExclaveKit.
9. `EXCLAVECORE`: Se definito, il codice racchiuso è visibile esclusivamente negli header dell'SDK ExclaveCore.
10. `MODULES_SUPPORTED` Se definito, il codice racchiuso è visibile esclusivamente nelle posizioni che supportano moduli/Swift (cioè non System o Kernel frameworks).
## Convenzione sui nomi dei file header VM
I seguenti header VM seguono le seguenti convenzioni di denominazione:
* Gli header `*_internal.h` contengono componenti del sottosistema VM solo per uso da parte del codice VM.
* Gli header `*_xnu.h` contengono componenti del sottosistema VM solo per uso da parte di altro codice xnu.
* Gli header `*.h` contengono componenti del sottosistema VM esportati ai kext.
* L'header `vm_iokit.h` contiene componenti del sottosistema VM esportati al sottosistema iokit.
* L'header `vm_ubc.h` contiene componenti del sottosistema VM esportati al sottosistema ubc.
## Convenzione sui nomi dei file di mappatura dei moduli
Nel caso semplice, una sottodirectory di `usr/include` o `usr/local/include` può essere rappresentata da un modulo autonomo. In questo caso, imposta `INSTALL_MODULEMAP_MI_DIR` a `INSTALL_MI_DIR` e installa un file `module.modulemap` in quella posizione. `module.modulemap` viene utilizzato anche per i moduli privati in `usr/local/include`; `module.private.modulemap` non viene utilizzato. Avvertenza: per rimanere nel caso semplice, il nome del modulo deve essere esattamente uguale al nome della directory. Se ciò non è possibile, sarà necessario applicare il metodo seguente.
`xnu` contribuisce ai moduli definiti in CoreOSModuleMaps installando file di mappatura dei moduli che provengono da `usr/include/module.modulemap` e `usr/local/include/module.modulemap`. La convenzione di denominazione per i file di mappatura dei moduli di `xnu` è la seguente.
a. Idealmente il file di mappatura del modulo copre un'intera directory. Un file di mappatura del modulo che copre `usr/include/a/b/c` sarebbe denominato `a_b_c.modulemap`. `usr/local/include/a/b/c` sarebbe `a_b_c_private.modulemap`.
b. Alcuni header sono speciali e richiedono un proprio modulo. In tal caso, il file di mappatura del modulo sarebbe denominato in base al modulo che definisce. Un file di mappatura del modulo che definisce il modulo `One.Two.Three` sarebbe denominato `one_two_three.modulemap`.
## Compilazione Condizionale
`xnu` offre i seguenti meccanismi per compilare codice in modo condizionale:
1. *Caratteristiche della CPU* Se il codice che stai proteggendo ha caratteristiche specifiche che variano solo in base all'architettura della CPU target, utilizza questa opzione. Preferisci verificare le caratteristiche dell'architettura (ad es. `__LP64__`, `__LITTLE_ENDIAN__`, ecc.).
2. *Nuove Funzionalità* Se il codice che stai proteggendo, considerato nel suo insieme, implementa una funzionalità, dovresti definire una nuova funzionalità in `config/MASTER` e utilizzare il token del preprocessore `CONFIG` risultante (ad es. per una funzionalità chiamata `config_virtual_memory`, verifica `#if CONFIG_VIRTUAL_MEMORY`). Questa pratica garantisce che le funzionalità esistenti possano essere portate su altre piattaforme semplicemente cambiando un interruttore di funzionalità.
3. *Funzionalità Esistenti* È possibile utilizzare funzionalità esistenti se il tuo codice è fortemente legato ad esse (ad es. usa `SECURE_KERNEL` se il tuo codice implementa nuove funzionalità che sono esclusivamente rilevanti per il kernel trusted e aggiorna la definizione/comprensione di cosa significhi essere un kernel trusted).
Si consiglia di evitare di compilare in base alla piattaforma target. `xnu` non definisce le macro di piattaforma da `TargetConditionals.h` (`TARGET_OS_OSX`, `TARGET_OS_IOS`, ecc.).
## Debug di XNU
Per impostazione predefinita, il kernel si riavvia in caso di panico. Questo comportamento può essere sovrascritto dal boot-arg `debug` -- `debug=0x14e` farà sì che un panico attenda l'attacco di un debugger. Per avviare un kernel in modo che possa essere debuggato da una macchina collegata, sovrascrivi il boot-arg `kdp_match_name` con l'interfaccia `ifconfig` appropriata. Il debug Ethernet, Thunderbolt e seriale è supportato, a seconda dell'hardware.
Usa LLDB per fare debug del kernel:```text
xcrun -sdk macosx lldb <path-to-unstripped-kernel>
(lldb) gdb-remote [<host-ip>:]<port>
Le informazioni di debug per il kernel (dSYM) vengono fornite con una serie di macro per supportare il debug del kernel.
Per caricare automaticamente queste macro quando ci si connette al kernel, aggiungi quanto segue a ~/.lldbinit:```text
settings set target.load-script-from-symbol-file true
`tools/lldbmacros` contiene il sorgente di questi comandi.
Vedi il README in quella directory per il loro utilizzo, oppure usa l'aiuto integrato di LLDB con:```text
(lldb) help showcurrentstacks