mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-25 11:11:35 +01:00
baremetal: get exit status working with on_exit :-)
This commit is contained in:
34
README.adoc
34
README.adoc
@@ -11916,7 +11916,7 @@ svc 0x00123456
|
||||
|
||||
and we can see from the docs that `0x18` stands for the `SYS_EXIT` command.
|
||||
|
||||
This is also how we implement the `exit(0)` system call in C for QEMU for link:baremetal/exit.c[] through the Newlib via the function `_exit` at link:baremetal/lib/kwargs['c'][].
|
||||
This is also how we implement the `exit(0)` system call in C for QEMU for link:baremetal/exit0.c[] through the Newlib via the function `_exit` at link:baremetal/lib/kwargs['c'][].
|
||||
|
||||
Other magic operations we can do with semihosting besides exiting the on the host include:
|
||||
|
||||
@@ -11990,7 +11990,7 @@ sudo apt-get install gcc-arm-none-eabi qemu-system-arm
|
||||
|
||||
However, there are as usual limitations to using prebuilts:
|
||||
|
||||
* certain examples fail to build with the Ubuntu packaged toolchain. E.g.: link:baremetal/exit.c[] fails with:
|
||||
* certain examples fail to build with the Ubuntu packaged toolchain. E.g.: link:baremetal/exit0.c[] fails with:
|
||||
+
|
||||
....
|
||||
/usr/lib/gcc/arm-none-eabi/6.3.1/../../../arm-none-eabi/lib/libg.a(lib_a-fini.o): In function `__libc_fini_array':
|
||||
@@ -14001,20 +14001,42 @@ For other arch / emulator combinations, we know how to do it:
|
||||
* gem5: <<m5-fail>> works on all archs
|
||||
* user mode: QEMU forwards exit status, gem5 we do some log parsing: <<gem5-syscall-emulation-exit-status>>
|
||||
|
||||
For this reason, we just parse the terminal output for a magic failure string to check if tests failed.
|
||||
Since we can't do it for QEMU arm, the only reliable solution is to just parse the guest serial output for a magic failure string to check if tests failed.
|
||||
|
||||
In order to cover all archs, our run scripts parse the serial output looking for a line line containing only exactly the magic regular expression:
|
||||
Our run scripts parse the serial output looking for a line line containing only exactly the magic regular expression:
|
||||
|
||||
....
|
||||
lkmc_exit_status_(\d+)
|
||||
....
|
||||
|
||||
and then exit with the given regular expression.
|
||||
and then exit with the given regular expression, e.g.:
|
||||
|
||||
....
|
||||
./run --arch aarch64 baremetal
|
||||
....
|
||||
|
||||
This magic output string is notably generated by:
|
||||
|
||||
* the `exit()` baremetal function when `status != 1`. This is in turn called by failed assertions for example from `lkmc_assert_fail`, which is used by <<baremetal-tests>>
|
||||
* link:rootfs_overlay/lkmc/test_fail.sh[], which is used by <<test-userland-in-full-system>>
|
||||
* the `exit()` baremetal function when `status != 1`.
|
||||
+
|
||||
Unfortunately the only way we found to set this up was with `on_exit`: link:https://github.com/cirosantilli/linux-kernel-module-cheat/issues/59[].
|
||||
+
|
||||
Trying to patch `_exit` directly fails since at that point some de-initialization has already happened which prevents the print.
|
||||
+
|
||||
So setup this `on_exit` automatically from all our <<baremetal-bootloaders>>, so it just works automatically for the examples that use the bootloaders: https://stackoverflow.com/questions/44097610/pass-parameter-to-atexit/49659697#49659697
|
||||
+
|
||||
The following examples end up testing that our setup is working:
|
||||
+
|
||||
* link:baremetal/lkmc_assert_fail.c[]
|
||||
* link:baremetal/return1.c[]
|
||||
* link:baremetal/return2.c[]
|
||||
* link:baremetal/exit0.c[]
|
||||
* link:baremetal/exit1.c[]
|
||||
* link:baremetal/arch/arm/return1.S[]
|
||||
* link:baremetal/arch/aarch64/return1.S[]
|
||||
|
||||
Beware that on Linux kernel simulations, you cannot even echo that string from userland, since userland stdout shows up on the serial.
|
||||
|
||||
==== Non-automated tests
|
||||
|
||||
|
||||
5
baremetal/arch/aarch64/return1.S
Normal file
5
baremetal/arch/aarch64/return1.S
Normal file
@@ -0,0 +1,5 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
.global main
|
||||
main:
|
||||
mov x0, 1
|
||||
ret
|
||||
5
baremetal/arch/arm/return1.S
Normal file
5
baremetal/arch/arm/return1.S
Normal file
@@ -0,0 +1,5 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
.global main
|
||||
main:
|
||||
mov r0, #1
|
||||
bx lr
|
||||
@@ -1,6 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
exit(0);
|
||||
}
|
||||
7
baremetal/exit0.c
Normal file
7
baremetal/exit0.c
Normal file
@@ -0,0 +1,7 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
exit(0);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <stdio.h>
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -14,6 +14,12 @@ mystart:
|
||||
/* Prepare the stack for main, mandatory for C code. */
|
||||
ldr x0, =stack_top
|
||||
mov sp, x0
|
||||
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
adr x0, lkmc_baremetal_on_exit_callback
|
||||
bl on_exit
|
||||
|
||||
/* Run main. */
|
||||
bl main
|
||||
|
||||
/* If main returns, exit. */
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
#include <lkmc.h>
|
||||
|
||||
.global mystart
|
||||
mystart:
|
||||
/* Prepare the stack for main, mandatory for C code. */
|
||||
ldr sp, =stack_top
|
||||
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
ldr r0, =lkmc_baremetal_on_exit_callback
|
||||
bl on_exit
|
||||
|
||||
/* Run main. */
|
||||
bl main
|
||||
|
||||
/* If main returns, exit. */
|
||||
bl exit
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
int main(void) { return 1; }
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#magic-failure-string */
|
||||
int main(void) { return 2; }
|
||||
|
||||
9
lkmc.c
9
lkmc.c
@@ -12,11 +12,16 @@ void lkmc_assert(bool condition) {
|
||||
}
|
||||
|
||||
void lkmc_assert_fail(void) {
|
||||
printf("%s\n", __func__);
|
||||
puts("lkmc_exit_status_1");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void lkmc_baremetal_on_exit_callback(int status, void *arg) {
|
||||
(void)arg;
|
||||
if (status != 0) {
|
||||
printf("lkmc_exit_status_%d\n", status);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#define LKMC_SYSREG_READ_WRITE(type, name) \
|
||||
type LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, name), _read(void)) { \
|
||||
|
||||
1
lkmc.h
1
lkmc.h
@@ -11,6 +11,7 @@
|
||||
|
||||
void lkmc_assert(bool);
|
||||
void lkmc_assert_fail();
|
||||
void lkmc_baremetal_on_exit_callback(int status, void *arg);
|
||||
#endif
|
||||
|
||||
/* https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg */
|
||||
|
||||
@@ -1,21 +1,5 @@
|
||||
#include <lkmc.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void atexit_cb(void) {
|
||||
puts("atexit");
|
||||
}
|
||||
|
||||
void onexit_cb(int status, void *arg) {
|
||||
printf("status %d\n", status);
|
||||
}
|
||||
|
||||
void __attribute__ ((constructor)) premain() {
|
||||
printf("premain2()\n");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
atexit(atexit_cb);
|
||||
on_exit(onexit_cb, NULL);
|
||||
lkmc_assert_fail();
|
||||
}
|
||||
|
||||
@@ -220,6 +220,7 @@ path_properties_tuples = (
|
||||
'semihost_exit.S': {'requires_semihosting': True},
|
||||
}
|
||||
),
|
||||
'return1.S': {'exit_status': 1},
|
||||
'semihost_exit.S': {'requires_semihosting': True},
|
||||
},
|
||||
|
||||
@@ -235,12 +236,13 @@ path_properties_tuples = (
|
||||
'semihost_exit.S': {'requires_semihosting': True},
|
||||
}
|
||||
),
|
||||
'return1.S': {'exit_status': 1},
|
||||
'semihost_exit.S': {'requires_semihosting': True},
|
||||
},
|
||||
)
|
||||
}
|
||||
),
|
||||
'assert_fail.c': {'exit_status': 1},
|
||||
'lkmc_assert_fail.c': {'exit_status': 1},
|
||||
'exit1.c': {'exit_status': 1},
|
||||
'infinite_loop.c': {'more_than_1s': True},
|
||||
'lib': (
|
||||
|
||||
@@ -55,9 +55,9 @@ If given, run only the given tests. Otherwise, run all tests.
|
||||
'run_obj': self.import_path_main('run'),
|
||||
'test_id': path_relative_root,
|
||||
}
|
||||
if path_relative_root != os.path.join('baremetal', 'assert_fail.c'):
|
||||
# if path_relative_root != os.path.join('baremetal', 'lkmc_assert_fail.c'):
|
||||
# Workaround fro: https://github.com/cirosantilli/linux-kernel-module-cheat/issues/59
|
||||
test_args['expected_exit_status'] = 0
|
||||
# test_args['expected_exit_status'] = 0
|
||||
error = thread_pool.submit(test_args)
|
||||
if error is not None:
|
||||
if self.env['quit_on_fail']:
|
||||
|
||||
Reference in New Issue
Block a user