mirror of
https://github.com/systemd/systemd
synced 2026-04-12 10:04:50 +02:00
Compare commits
No commits in common. "da2862ef06f22fc8d31dafced6d2d6dc14f2ee0b" and "ff97eb4aac31477ea7cb4b37b9f41779a6cc27ee" have entirely different histories.
da2862ef06
...
ff97eb4aac
@ -330,43 +330,3 @@ To debug systemd components other than PID 1, set "program" to the full path of
|
|||||||
debug and set "processId" to "${command:pickProcess}". Now, when starting the debugger, VSCode will ask you
|
debug and set "processId" to "${command:pickProcess}". Now, when starting the debugger, VSCode will ask you
|
||||||
the PID of the process you want to debug. Run `systemctl show --property MainPID --value <component>` in the
|
the PID of the process you want to debug. Run `systemctl show --property MainPID --value <component>` in the
|
||||||
container to figure out the PID and enter it when asked and VSCode will attach to that process instead.
|
container to figure out the PID and enter it when asked and VSCode will attach to that process instead.
|
||||||
|
|
||||||
# Debugging systemd-boot
|
|
||||||
|
|
||||||
During boot, systemd-boot and the stub loader will output a message like `systemd-boot@0x0A,0x0B`,
|
|
||||||
providing the location of the text and data sections. These location can then be used to attach
|
|
||||||
to a QEMU session (provided it was run with `-s`) with these gdb commands:
|
|
||||||
|
|
||||||
```
|
|
||||||
(gdb) file build/src/boot/efi/systemd-bootx64.efi
|
|
||||||
(gdb) add-symbol-file build/src/boot/efi/systemd_boot.so 0x0A -s .data 0x0B
|
|
||||||
(gdb) set architecture i386:x86-64
|
|
||||||
(gdb) target remote :1234
|
|
||||||
```
|
|
||||||
|
|
||||||
This process can be automated by using the `debug-sd-boot.sh` script in the tools folder. If run
|
|
||||||
without arguments it will provide usage information.
|
|
||||||
|
|
||||||
If the debugger is too slow to attach to examine an early boot code passage, we can uncomment the
|
|
||||||
call to `debug_break()` inside of `efi_main()`. As soon as the debugger has control we can then run
|
|
||||||
`set variable wait = 0` or `return` to continue. Once the debugger has attached, setting breakpoints
|
|
||||||
will work like usual.
|
|
||||||
|
|
||||||
To debug systemd-boot in an IDE such as VSCode we can use a launch configuration like this:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "systemd-boot",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceFolder}/build/src/boot/efi/systemd-bootx64.efi",
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"MIMode": "gdb",
|
|
||||||
"miDebuggerServerAddress": ":1234",
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "shell mkfifo /tmp/sdboot.{in,out}" },
|
|
||||||
{ "text": "shell qemu-system-x86_64 [...] -s -serial pipe:/tmp/sdboot" },
|
|
||||||
{ "text": "shell ${workspaceFolder}/tools/debug-sd-boot.sh ${workspaceFolder}/build/src/boot/efi/systemd-bootx64.efi /tmp/sdboot.out systemd-boot.gdb" },
|
|
||||||
{ "text": "source /tmp/systemd-boot.gdb" },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|||||||
@ -2353,9 +2353,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|||||||
|
|
||||||
InitializeLib(image, sys_table);
|
InitializeLib(image, sys_table);
|
||||||
init_usec = time_usec();
|
init_usec = time_usec();
|
||||||
debug_hook(L"systemd-boot");
|
|
||||||
/* Uncomment the next line if you need to wait for debugger. */
|
|
||||||
// debug_break();
|
|
||||||
|
|
||||||
err = BS->OpenProtocol(image,
|
err = BS->OpenProtocol(image,
|
||||||
&LoadedImageProtocol,
|
&LoadedImageProtocol,
|
||||||
|
|||||||
@ -181,9 +181,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|||||||
EFI_STATUS err;
|
EFI_STATUS err;
|
||||||
|
|
||||||
InitializeLib(image, sys_table);
|
InitializeLib(image, sys_table);
|
||||||
debug_hook(L"systemd-stub");
|
|
||||||
/* Uncomment the next line if you need to wait for debugger. */
|
|
||||||
// debug_break();
|
|
||||||
|
|
||||||
err = BS->OpenProtocol(
|
err = BS->OpenProtocol(
|
||||||
image,
|
image,
|
||||||
|
|||||||
@ -738,20 +738,3 @@ UINT64 get_os_indications_supported(void) {
|
|||||||
|
|
||||||
return osind;
|
return osind;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EFI_DEBUG
|
|
||||||
__attribute__((noinline)) void debug_break(void) {
|
|
||||||
/* This is a poor programmer's breakpoint to wait until a debugger
|
|
||||||
* has attached to us. Just "set variable wait = 0" or "return" to continue. */
|
|
||||||
volatile BOOLEAN wait = TRUE;
|
|
||||||
while (wait)
|
|
||||||
/* Prefer asm based stalling so that gdb has a source location to present. */
|
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
|
||||||
asm volatile("pause");
|
|
||||||
#elif defined(__aarch64__)
|
|
||||||
asm volatile("wfi");
|
|
||||||
#else
|
|
||||||
BS->Stall(5000);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -159,13 +159,3 @@ static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UINT64 get_os_indications_supported(void);
|
UINT64 get_os_indications_supported(void);
|
||||||
|
|
||||||
#ifdef EFI_DEBUG
|
|
||||||
void debug_break(void);
|
|
||||||
extern UINT8 _text, _data;
|
|
||||||
/* Report the relocated position of text and data sections so that a debugger
|
|
||||||
* can attach to us. See debug-sd-boot.sh for how this can be done. */
|
|
||||||
# define debug_hook(identity) Print(identity L"@0x%x,0x%x\n", &_text, &_data)
|
|
||||||
#else
|
|
||||||
# define debug_hook(identity)
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -26,7 +26,6 @@
|
|||||||
#include "random-util.h"
|
#include "random-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "sync-util.h"
|
#include "sync-util.h"
|
||||||
#include "sha256.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "xattr-util.h"
|
#include "xattr-util.h"
|
||||||
|
|
||||||
@ -107,11 +106,9 @@ static int run(int argc, char *argv[]) {
|
|||||||
_cleanup_close_ int seed_fd = -1, random_fd = -1;
|
_cleanup_close_ int seed_fd = -1, random_fd = -1;
|
||||||
bool read_seed_file, write_seed_file, synchronous;
|
bool read_seed_file, write_seed_file, synchronous;
|
||||||
_cleanup_free_ void* buf = NULL;
|
_cleanup_free_ void* buf = NULL;
|
||||||
struct sha256_ctx hash_state;
|
|
||||||
uint8_t hash[32];
|
|
||||||
size_t buf_size;
|
size_t buf_size;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
ssize_t k, l;
|
ssize_t k;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
log_setup();
|
log_setup();
|
||||||
@ -245,16 +242,6 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
|
log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
|
||||||
}
|
}
|
||||||
/* If we're going to later write out a seed file, initialize a hash state with
|
|
||||||
* the contents of the seed file we just read, so that the new one can't regress
|
|
||||||
* in entropy. */
|
|
||||||
if (write_seed_file) {
|
|
||||||
sha256_init_ctx(&hash_state);
|
|
||||||
if (k < 0)
|
|
||||||
k = 0;
|
|
||||||
sha256_process_bytes(&k, sizeof(k), &hash_state);
|
|
||||||
sha256_process_bytes(buf, k, &hash_state);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write_seed_file) {
|
if (write_seed_file) {
|
||||||
@ -290,17 +277,6 @@ static int run(int argc, char *argv[]) {
|
|||||||
"Got EOF while reading from /dev/urandom.");
|
"Got EOF while reading from /dev/urandom.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we previously read in a seed file, then hash the new seed into the old one,
|
|
||||||
* and replace the last 32 bytes of the seed with the hash output, so that the
|
|
||||||
* new seed file can't regress in entropy. */
|
|
||||||
if (read_seed_file) {
|
|
||||||
sha256_process_bytes(&k, sizeof(k), &hash_state);
|
|
||||||
sha256_process_bytes(buf, k, &hash_state);
|
|
||||||
sha256_finish_ctx(&hash_state, hash);
|
|
||||||
l = MIN(k, 32);
|
|
||||||
memcpy((uint8_t *)buf + k - l, hash, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = loop_write(seed_fd, buf, (size_t) k, false);
|
r = loop_write(seed_fd, buf, (size_t) k, false);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to write new random seed file: %m");
|
return log_error_errno(r, "Failed to write new random seed file: %m");
|
||||||
|
|||||||
@ -1,85 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [[ $# -lt 2 ]]; then
|
|
||||||
echo "Usage: ${0} TARGET INPUT [GDBSCRIPT]"
|
|
||||||
echo "Debug systemd-boot/stub in QEMU."
|
|
||||||
echo
|
|
||||||
echo "TARGET should point to the EFI binary to be examined inside the"
|
|
||||||
echo "build directory (systemd-boot\$ARCH.efi or linux\$arch.efi.stub)."
|
|
||||||
echo
|
|
||||||
echo "INPUT should point to the QEMU serial output pipe. This is used to"
|
|
||||||
echo "extract the location of the symbols. For this to work, QEMU must"
|
|
||||||
echo "be run with '-s -serial pipe:PATH'. Note that QEMU will append"
|
|
||||||
echo ".in/.out to the path, while this script expects the out pipe directly."
|
|
||||||
echo
|
|
||||||
echo "If GDBSCRIPT is empty, gdb is run directly attached to the boot"
|
|
||||||
echo "loader, otherwise a script is generated in the given path that allows"
|
|
||||||
echo "attaching manually like this:"
|
|
||||||
echo " (gdb) source GDBSCRIPT"
|
|
||||||
echo " (gdb) target remote :1234"
|
|
||||||
echo
|
|
||||||
echo "Exmaple usage:"
|
|
||||||
echo " mkfifo /tmp/sdboot.{in,out}"
|
|
||||||
echo " qemu-system-x86_64 [...] -s -serial pipe:/tmp/sdboot"
|
|
||||||
echo " ./tools/debug-sd-boot.sh ./build/src/boot/efi/systemd-bootx64.efi \\"
|
|
||||||
echo " /tmp/sdboot.out"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
binary=$(realpath "${1}")
|
|
||||||
if [[ "${1}" =~ systemd-boot([[:alnum:]]+).efi ]]; then
|
|
||||||
target="systemd-boot"
|
|
||||||
symbols=$(realpath "$(dirname "${1}")/systemd_boot.so")
|
|
||||||
elif [[ "${1}" =~ linux([[:alnum:]]+).efi.stub ]]; then
|
|
||||||
target="systemd-stub"
|
|
||||||
symbols=$(realpath "$(dirname "${1}")/linux${BASH_REMATCH[1]}.elf.stub")
|
|
||||||
else
|
|
||||||
echo "Cannot detect EFI binary '${1}'."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "${BASH_REMATCH[1]}" in
|
|
||||||
ia32) arch="i386";;
|
|
||||||
x64) arch="i386:x86-64";;
|
|
||||||
aa64) arch="aarch64";;
|
|
||||||
arm|riscv64) arch="${BASH_REMATCH[1]}";;
|
|
||||||
*)
|
|
||||||
echo "Unknown EFI arch '${BASH_REMATCH[1]}'."
|
|
||||||
exit 1
|
|
||||||
esac
|
|
||||||
|
|
||||||
# system-boot will print out a line like this to inform us where gdb is supposed to
|
|
||||||
# look for .text and .data section:
|
|
||||||
# systemd-boot@0x0,0x0
|
|
||||||
while read -r line; do
|
|
||||||
if [[ "${line}" =~ ${target}@(0x[[:xdigit:]]+),(0x[[:xdigit:]]+) ]]; then
|
|
||||||
text="${BASH_REMATCH[1]}"
|
|
||||||
data="${BASH_REMATCH[2]}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done < "${2}"
|
|
||||||
|
|
||||||
if [[ -z "${text}" || -z "${data}" ]]; then
|
|
||||||
echo "Could not determine text and data location."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "${3}" ]]; then
|
|
||||||
gdb_script=$(mktemp /tmp/debug-sd-boot.XXXXXX.gdb)
|
|
||||||
trap 'rm -f "${gdb_script}"' EXIT
|
|
||||||
else
|
|
||||||
gdb_script="${3}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "file ${binary}
|
|
||||||
add-symbol-file ${symbols} ${text} -s .data ${data}
|
|
||||||
set architecture ${arch}" > "${gdb_script}"
|
|
||||||
|
|
||||||
if [[ -z "${3}" ]]; then
|
|
||||||
gdb -x "${gdb_script}" -ex "target remote :1234"
|
|
||||||
else
|
|
||||||
echo "GDB script written to '${gdb_script}'."
|
|
||||||
fi
|
|
||||||
Loading…
x
Reference in New Issue
Block a user