diff --git a/ocamltest/builtin_actions.ml b/ocamltest/builtin_actions.ml index 367985ba9d5e..ded3512e11fc 100644 --- a/ocamltest/builtin_actions.ml +++ b/ocamltest/builtin_actions.ml @@ -139,6 +139,15 @@ let not_bsd = make "not on a BSD system" "on a BSD system") +let linux_system = "linux" + +let linux = make + ~name:"linux" + ~description:"Pass if running on a Linux system" + (Actions_helpers.pass_or_skip (Ocamltest_config.system = linux_system) + "on a Linux system" + "not on a Linux system") + let macos_system = "macosx" let macos = make @@ -368,6 +377,7 @@ let _ = not_bsd; macos; not_macos_amd64_tsan; + linux; arch32; arch64; has_symlink; diff --git a/ocamltest/ocaml_actions.ml b/ocamltest/ocaml_actions.ml index 7382348d9a33..a971b434f96c 100644 --- a/ocamltest/ocaml_actions.ml +++ b/ocamltest/ocaml_actions.ml @@ -555,6 +555,7 @@ let debug debugger_type log env = | GDB -> [ Ocaml_commands.gdb_run; Ocaml_flags.gdb_default_flags; + "-x " ^ (Environments.safe_lookup Ocaml_variables.debugger_script env); program ] | Bytecode -> [ Ocaml_commands.ocamlrun_ocamldebug; @@ -589,10 +590,16 @@ let debug debugger_type log env = end let ocamldebug = - Actions.make ~name:"ocamldebug" ~description:"Run ocamldebug on the program" (debug Bytecode) + Actions.make ~name:"ocamldebug" + ~description:"Run ocamldebug on the program" (debug Bytecode) -let lldb = Actions.make ~name:"lldb" ~description:"Run LLDB on the program" (debug LLDB) -let gdb = Actions.make ~name:"gdb" ~description:"Run GDB on the program" (debug GDB) +let lldb = + Actions.make ~name:"lldb" + ~description:"Run LLDB on the program" (debug LLDB) + +let gdb = + Actions.make ~name:"gdb" + ~description:"Run GDB on the program" (debug GDB) let objinfo log env = let tools_directory = Ocaml_directories.tools in diff --git a/ocamltest/ocaml_flags.ml b/ocamltest/ocaml_flags.ml index fd9d550572b5..a0175821a9ba 100644 --- a/ocamltest/ocaml_flags.ml +++ b/ocamltest/ocaml_flags.ml @@ -61,4 +61,4 @@ let ocamlobjinfo_default_flags = "-null-crc" let lldb_default_flags = "--no-use-colors" -let gdb_default_flags = "" +let gdb_default_flags = "--quiet --batch" diff --git a/testsuite/tests/native-debugger/gdb-script b/testsuite/tests/native-debugger/gdb-script new file mode 100644 index 000000000000..f4b0d3fe6783 --- /dev/null +++ b/testsuite/tests/native-debugger/gdb-script @@ -0,0 +1,15 @@ +break *(&caml_start_program+0) +break caml_program +break ocaml_to_c +break meander.ml:5 +set debuginfod enabled off +run +backtrace +continue +backtrace +continue +backtrace +continue +backtrace +continue +quit diff --git a/testsuite/tests/native-debugger/has_gdb.sh b/testsuite/tests/native-debugger/has_gdb.sh new file mode 100755 index 000000000000..b51d3382148c --- /dev/null +++ b/testsuite/tests/native-debugger/has_gdb.sh @@ -0,0 +1,7 @@ +#!/bin/sh +if ! which gdb > /dev/null 2>&1; then + echo "gdb not available" > ${ocamltest_response} + exit ${TEST_SKIP} +else + exit ${TEST_PASS} +fi diff --git a/testsuite/tests/native-debugger/linux-gdb-amd64-test.ml b/testsuite/tests/native-debugger/linux-gdb-amd64-test.ml new file mode 100644 index 000000000000..7a1bad349ed7 --- /dev/null +++ b/testsuite/tests/native-debugger/linux-gdb-amd64-test.ml @@ -0,0 +1,19 @@ +(* TEST + native-compiler; + linux; + arch_amd64; + script = "sh ${test_source_directory}/has_gdb.sh"; + script; + readonly_files = "meander.ml meander_c.c lldb_test.py"; + setup-ocamlopt.byte-build-env; + program = "${test_build_directory}/meander"; + flags = "-g"; + all_modules = "meander.ml meander_c.c"; + ocamlopt.byte; + debugger_script = "${test_source_directory}/gdb-script"; + gdb; + script = "sh ${test_source_directory}/sanitize.sh ${test_source_directory} \ + ${test_build_directory} ${ocamltest_response} linux-gdb-amd64-test"; + script; + check-program-output; + *) diff --git a/testsuite/tests/native-debugger/linux-gdb-amd64-test.reference b/testsuite/tests/native-debugger/linux-gdb-amd64-test.reference new file mode 100644 index 000000000000..1b678fe1ee30 --- /dev/null +++ b/testsuite/tests/native-debugger/linux-gdb-amd64-test.reference @@ -0,0 +1,60 @@ +Breakpoint 1 at 0x00000000000000 +Breakpoint 2 at 0x00000000000000 +Breakpoint 3 at 0x00000000000000: file meander_c.c, line 4. +Breakpoint 4 at 0x00000000000000: file meander.ml, line 5. +[Thread debugging using libthread_db enabled] +Using host libthread_db library "/lib/$ARCH-linux-gnu/libthread_db.so.1". + +Breakpoint 1, +#0 +#1 0x00000000000000 in caml_startup_common (pooling=, argv=0x00000000000000) at runtime/startup_nat.c:128 +#2 caml_startup_common (argv=0x00000000000000, pooling=) at runtime/startup_nat.c:87 +#3 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#4 caml_startup (argv=) at runtime/startup_nat.c:140 +#5 caml_main (argv=) at runtime/startup_nat.c:147 +#6 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 2, 0x00000000000000 in caml_program () +#0 0x00000000000000 in caml_program () +#1 +#2 0x00000000000000 in caml_startup_common (pooling=, argv=0x00000000000000) at runtime/startup_nat.c:128 +#3 caml_startup_common (argv=0x00000000000000, pooling=) at runtime/startup_nat.c:87 +#4 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#5 caml_startup (argv=) at runtime/startup_nat.c:140 +#6 caml_main (argv=) at runtime/startup_nat.c:147 +#7 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 3, ocaml_to_c (unit=1) at meander_c.c:4 +4 value ocaml_to_c (value unit) { +#0 ocaml_to_c (unit=1) at meander_c.c:4 +#1 +#2 0x00000000000000 in camlMeander.omain_278 () at meander.ml:10 +#3 0x00000000000000 in camlMeander.entry () at meander.ml:13 +#4 0x00000000000000 in caml_program () +#5 +#6 0x00000000000000 in caml_startup_common (pooling=, argv=0x00000000000000) at runtime/startup_nat.c:128 +#7 caml_startup_common (argv=0x00000000000000, pooling=) at runtime/startup_nat.c:87 +#8 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#9 caml_startup (argv=) at runtime/startup_nat.c:140 +#10 caml_main (argv=) at runtime/startup_nat.c:147 +#11 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 4, camlMeander.c_to_ocaml_273 () at meander.ml:5 +5 let c_to_ocaml () = raise E1 +#0 camlMeander.c_to_ocaml_273 () at meander.ml:5 +#1 +#2 0x00000000000000 in caml_callback_exn (closure=, arg=, arg@entry=1) at runtime/callback.c:206 +#3 0x00000000000000 in caml_callback (closure=, arg=arg@entry=1) at runtime/callback.c:347 +#4 0x00000000000000 in ocaml_to_c (unit=) at meander_c.c:5 +#5 +#6 0x00000000000000 in camlMeander.omain_278 () at meander.ml:10 +#7 0x00000000000000 in camlMeander.entry () at meander.ml:13 +#8 0x00000000000000 in caml_program () +#9 +#10 0x00000000000000 in caml_startup_common (pooling=, argv=0x00000000000000) at runtime/startup_nat.c:128 +#11 caml_startup_common (argv=0x00000000000000, pooling=) at runtime/startup_nat.c:87 +#12 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#13 caml_startup (argv=) at runtime/startup_nat.c:140 +#14 caml_main (argv=) at runtime/startup_nat.c:147 +#15 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 +[Inferior 1 (process XXXX) exited normally] diff --git a/testsuite/tests/native-debugger/linux-gdb-arm64-test.ml b/testsuite/tests/native-debugger/linux-gdb-arm64-test.ml new file mode 100644 index 000000000000..dc8e2dbc09f0 --- /dev/null +++ b/testsuite/tests/native-debugger/linux-gdb-arm64-test.ml @@ -0,0 +1,19 @@ +(* TEST + native-compiler; + linux; + arch_arm64; + script = "sh ${test_source_directory}/has_gdb.sh"; + script; + readonly_files = "meander.ml meander_c.c lldb_test.py"; + setup-ocamlopt.byte-build-env; + program = "${test_build_directory}/meander"; + flags = "-g"; + all_modules = "meander.ml meander_c.c"; + ocamlopt.byte; + debugger_script = "${test_source_directory}/gdb-script"; + gdb; + script = "sh ${test_source_directory}/sanitize.sh ${test_source_directory} \ + ${test_build_directory} ${ocamltest_response} linux-gdb-arm64-test"; + script; + check-program-output; + *) diff --git a/testsuite/tests/native-debugger/linux-gdb-arm64-test.reference b/testsuite/tests/native-debugger/linux-gdb-arm64-test.reference new file mode 100644 index 000000000000..4fc59bf7d49c --- /dev/null +++ b/testsuite/tests/native-debugger/linux-gdb-arm64-test.reference @@ -0,0 +1,60 @@ +Breakpoint 1 at 0x00000000000000 +Breakpoint 2 at 0x00000000000000 +Breakpoint 3 at 0x00000000000000: file meander_c.c, line 5. +Breakpoint 4 at 0x00000000000000: file meander.ml, line 5. +[Thread debugging using libthread_db enabled] +Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1". + +Breakpoint 1, +#0 +#1 0x00000000000000 in caml_startup_common (pooling=0, argv=0x00000000000000) at runtime/startup_nat.c:128 +#2 caml_startup_common (argv=0x00000000000000, pooling=0) at runtime/startup_nat.c:87 +#3 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#4 caml_startup (argv=) at runtime/startup_nat.c:140 +#5 caml_main (argv=) at runtime/startup_nat.c:147 +#6 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 2, 0x00000000000000 in caml_program () +#0 0x00000000000000 in caml_program () +#1 +#2 0x00000000000000 in caml_startup_common (pooling=0, argv=0x00000000000000) at runtime/startup_nat.c:128 +#3 caml_startup_common (argv=0x00000000000000, pooling=0) at runtime/startup_nat.c:87 +#4 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#5 caml_startup (argv=) at runtime/startup_nat.c:140 +#6 caml_main (argv=) at runtime/startup_nat.c:147 +#7 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 3, ocaml_to_c (unit=1) at meander_c.c:5 +5 caml_callback(*caml_named_value +#0 ocaml_to_c (unit=1) at meander_c.c:5 +#1 +#2 0x00000000000000 in camlMeander.omain_278 () at meander.ml:10 +#3 0x00000000000000 in camlMeander.entry () at meander.ml:13 +#4 0x00000000000000 in caml_program () +#5 +#6 0x00000000000000 in caml_startup_common (pooling=4, argv=0x00000000000000) at runtime/startup_nat.c:128 +#7 caml_startup_common (argv=0x00000000000000, pooling=4) at runtime/startup_nat.c:87 +#8 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#9 caml_startup (argv=) at runtime/startup_nat.c:140 +#10 caml_main (argv=) at runtime/startup_nat.c:147 +#11 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 4, camlMeander.c_to_ocaml_273 () at meander.ml:5 +5 let c_to_ocaml () = raise E1 +#0 camlMeander.c_to_ocaml_273 () at meander.ml:5 +#1 +#2 0x00000000000000 in caml_callback_exn (closure=, arg=, arg@entry=1) at runtime/callback.c:206 +#3 0x00000000000000 in caml_callback (closure=, arg=arg@entry=1) at runtime/callback.c:347 +#4 0x00000000000000 in ocaml_to_c (unit=) at meander_c.c:5 +#5 +#6 0x00000000000000 in camlMeander.omain_278 () at meander.ml:10 +#7 0x00000000000000 in camlMeander.entry () at meander.ml:13 +#8 0x00000000000000 in caml_program () +#9 +#10 0x00000000000000 in caml_startup_common (pooling=4, argv=0x00000000000000) at runtime/startup_nat.c:128 +#11 caml_startup_common (argv=0x00000000000000, pooling=4) at runtime/startup_nat.c:87 +#12 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#13 caml_startup (argv=) at runtime/startup_nat.c:140 +#14 caml_main (argv=) at runtime/startup_nat.c:147 +#15 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 +[Inferior 1 (process XXXX) exited normally] diff --git a/testsuite/tests/native-debugger/linux-gdb-riscv-test.ml b/testsuite/tests/native-debugger/linux-gdb-riscv-test.ml new file mode 100644 index 000000000000..a1d6090c4657 --- /dev/null +++ b/testsuite/tests/native-debugger/linux-gdb-riscv-test.ml @@ -0,0 +1,19 @@ +(* TEST + native-compiler; + linux; + arch_riscv; + script = "sh ${test_source_directory}/has_gdb.sh"; + script; + readonly_files = "meander.ml meander_c.c lldb_test.py"; + setup-ocamlopt.byte-build-env; + program = "${test_build_directory}/meander"; + flags = "-g"; + all_modules = "meander.ml meander_c.c"; + ocamlopt.byte; + debugger_script = "${test_source_directory}/gdb-script"; + gdb; + script = "sh ${test_source_directory}/sanitize.sh ${test_source_directory} \ + ${test_build_directory} ${ocamltest_response} linux-gdb-riscv-test"; + script; + check-program-output; + *) diff --git a/testsuite/tests/native-debugger/linux-gdb-riscv-test.reference b/testsuite/tests/native-debugger/linux-gdb-riscv-test.reference new file mode 100644 index 000000000000..dac6df7789f9 --- /dev/null +++ b/testsuite/tests/native-debugger/linux-gdb-riscv-test.reference @@ -0,0 +1,60 @@ +Breakpoint 1 at 0x00000000000000 +Breakpoint 2 at 0x00000000000000 +Breakpoint 3 at 0x00000000000000: file meander_c.c, line 5. +Breakpoint 4 at 0x00000000000000: file meander.ml, line 5. +[Thread debugging using libthread_db enabled] +Using host libthread_db library "/lib/$ARCH-linux-gnu/libthread_db.so.1". + +Breakpoint 1, +#0 +#1 0x00000000000000 in caml_startup_common (pooling=, argv=0x00000000000000) at runtime/startup_nat.c:128 +#2 caml_startup_common (argv=0x00000000000000, pooling=) at runtime/startup_nat.c:87 +#3 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#4 caml_startup (argv=) at runtime/startup_nat.c:140 +#5 caml_main (argv=) at runtime/startup_nat.c:147 +#6 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 2, 0x00000000000000 in caml_program () +#0 0x00000000000000 in caml_program () +#1 +#2 0x00000000000000 in caml_startup_common (pooling=, argv=0x00000000000000) at runtime/startup_nat.c:128 +#3 caml_startup_common (argv=0x00000000000000, pooling=) at runtime/startup_nat.c:87 +#4 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#5 caml_startup (argv=) at runtime/startup_nat.c:140 +#6 caml_main (argv=) at runtime/startup_nat.c:147 +#7 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 3, ocaml_to_c (unit=1) at meander_c.c:5 +5 caml_callback(*caml_named_value +#0 ocaml_to_c (unit=1) at meander_c.c:5 +#1 +#2 0x00000000000000 in camlMeander.omain_278 () at meander.ml:10 +#3 0x00000000000000 in camlMeander.entry () at meander.ml:13 +#4 0x00000000000000 in caml_program () +#5 +#6 0x00000000000000 in caml_startup_common (pooling=, argv=0x00000000000000) at runtime/startup_nat.c:128 +#7 caml_startup_common (argv=0x00000000000000, pooling=) at runtime/startup_nat.c:87 +#8 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#9 caml_startup (argv=) at runtime/startup_nat.c:140 +#10 caml_main (argv=) at runtime/startup_nat.c:147 +#11 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 + +Breakpoint 4, camlMeander.c_to_ocaml_273 () at meander.ml:5 +5 let c_to_ocaml () = raise E1 +#0 camlMeander.c_to_ocaml_273 () at meander.ml:5 +#1 +#2 0x00000000000000 in caml_callback_exn (closure=, arg=, arg@entry=1) at runtime/callback.c:206 +#3 0x00000000000000 in caml_callback (closure=, arg=arg@entry=1) at runtime/callback.c:347 +#4 0x00000000000000 in ocaml_to_c (unit=) at meander_c.c:5 +#5 +#6 0x00000000000000 in camlMeander.omain_278 () at meander.ml:10 +#7 0x00000000000000 in camlMeander.entry () at meander.ml:13 +#8 0x00000000000000 in caml_program () +#9 +#10 0x00000000000000 in caml_startup_common (pooling=, argv=0x00000000000000) at runtime/startup_nat.c:128 +#11 caml_startup_common (argv=0x00000000000000, pooling=) at runtime/startup_nat.c:87 +#12 0x00000000000000 in caml_startup_exn (argv=) at runtime/startup_nat.c:135 +#13 caml_startup (argv=) at runtime/startup_nat.c:140 +#14 caml_main (argv=) at runtime/startup_nat.c:147 +#15 0x00000000000000 in main (argc=, argv=) at runtime/main.c:37 +[Inferior 1 (process XXXX) exited normally] diff --git a/testsuite/tests/native-debugger/meander.ml b/testsuite/tests/native-debugger/meander.ml new file mode 100644 index 000000000000..af213f36386a --- /dev/null +++ b/testsuite/tests/native-debugger/meander.ml @@ -0,0 +1,13 @@ +external ocaml_to_c + : unit -> int = "ocaml_to_c" +exception E1 +exception E2 +let c_to_ocaml () = raise E1 +let _ = Callback.register + "c_to_ocaml" c_to_ocaml +let omain () = + try (* h1 *) + try (* h2 *) ocaml_to_c () + with E2 -> 0 + with E1 -> 42 +let _ = assert (omain () = 42) diff --git a/testsuite/tests/native-debugger/meander_c.c b/testsuite/tests/native-debugger/meander_c.c new file mode 100644 index 000000000000..72d8f6cf5ee6 --- /dev/null +++ b/testsuite/tests/native-debugger/meander_c.c @@ -0,0 +1,8 @@ +#include +#include + +value ocaml_to_c (value unit) { + caml_callback(*caml_named_value + ("c_to_ocaml"), Val_unit); + return Val_int(0); +} diff --git a/testsuite/tests/native-debugger/sanitize.awk b/testsuite/tests/native-debugger/sanitize.awk new file mode 100644 index 000000000000..67e66c249e87 --- /dev/null +++ b/testsuite/tests/native-debugger/sanitize.awk @@ -0,0 +1,31 @@ +# Replace sections of LLDB output +# This primarily looks for hex addresses, process ids, filepaths and +# other specific details of the machine the test is running on. +{ + # Replace single quoted file paths + gsub(/'(.*)'/,"'XXXX'") + + # Replace target create for executable + gsub(/target create "(.*)"/,"target create \"XXXX\"") + + # Replace hex addresses, not offset values less than 4 digits. + gsub(/0x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]+/, "0x00000000000000") + + # Sanitise executable name in image lookup + gsub("5 matches found in /(.*):$", "5 matches found in XXXX") + + # Replace debug process forked by lldb + gsub("Process ([0-9]+)", "Process XXXX") + + # Replace debug process forked by gdb + gsub("[Inferior 1 (process [0-9]+) exited normally]", "[Inferior 1 (process XXXX) exited normally]") + + # Replace architecture identifiers + gsub("(x86_64)", "$ARCH") + gsub("(arm64)", "$ARCH") + gsub("(riscv64)", "$ARCH") + + # Replace printed match results + gsub("1 match found in /(.*):$", "1 match found in \"XXXX\":") + print $0 +} diff --git a/testsuite/tests/native-debugger/sanitize.sh b/testsuite/tests/native-debugger/sanitize.sh new file mode 100755 index 000000000000..6c297de90b29 --- /dev/null +++ b/testsuite/tests/native-debugger/sanitize.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +test_source_directory="$1" +test_build_directory="$2" +ocamltest_response="$3" +test_name="$4" + +awk -f ${test_source_directory}/sanitize.awk \ + ${test_build_directory}/${test_name}.opt.output > ${test_build_directory}/${test_name}.opt.awk.output + +mv ${test_build_directory}/${test_name}.opt.output ${test_build_directory}/${test_name}.opt.output.bak +cp ${test_build_directory}/${test_name}.opt.awk.output ${test_build_directory}/${test_name}.opt.output