commit:     c1dc899d4cdece095925e2391aefce3b0ad3785f
Author:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
AuthorDate: Mon Oct 25 05:58:19 2021 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Mon Oct 25 05:58:19 2021 +0000
URL:        https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=c1dc899d

libsandbox: add sparc personality support

This allows tracing of sparc32 in a sparc64 multilib setup.

Although it doesn't quite work -- the syscall table needs to be
reloaded after the exec commits.  We leave that out for now since
there isn't actually a sparc32+sparc64 multilib port currently.

Bug: https://bugs.gentoo.org/293632
Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org>

 TODO                           |  3 ++
 configure.ac                   |  4 +++
 libsandbox/trace/linux/sparc.c | 70 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+)

diff --git a/TODO b/TODO
index 6b3df5a..f48068c 100644
--- a/TODO
+++ b/TODO
@@ -60,3 +60,6 @@ really only way around this would be to have sandbox set up
 a named pipe in $T and set the message path to that.  then
 it would poll that for data and take care of writing it to
 its open stderr.
+
+sparc32 tracing under sparc64 doesn't work quite right.  we need to reload the
+syscall table after the exec call finishes.  not sure any other port needs 
this.

diff --git a/configure.ac b/configure.ac
index fee0e4f..f43923c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -77,6 +77,10 @@ if test "x$enable_schizo" != "xno" ; then
                SB_CHECK_SCHIZO([s390x], [-m64])
                SB_CHECK_SCHIZO([s390], [-m31])
                ;;
+       sparc*linux*)
+               SB_CHECK_SCHIZO([sparc64], [-m64])
+               SB_CHECK_SCHIZO([sparc], [-m32])
+               ;;
        esac
        SB_SCHIZO_SETTINGS=${SB_SCHIZO_SETTINGS# }
        if test "x$enable_schizo" != "xno" ; then

diff --git a/libsandbox/trace/linux/sparc.c b/libsandbox/trace/linux/sparc.c
index cb1cb54..36d737a 100644
--- a/libsandbox/trace/linux/sparc.c
+++ b/libsandbox/trace/linux/sparc.c
@@ -13,6 +13,76 @@
 #define U_REG_G1 0
 #define U_REG_O0 7
 
+#undef _trace_possible
+#define _trace_possible _trace_possible
+
+#ifdef SB_SCHIZO
+
+static const struct syscall_entry syscall_table_32[] = {
+#ifdef SB_SCHIZO_sparc
+#define S(s) { SB_SYS_sparc_##s, SB_NR_##s, #s },
+#include "trace_syscalls_sparc.h"
+#undef S
+#endif
+       { SB_NR_UNDEF, SB_NR_UNDEF, NULL },
+};
+static const struct syscall_entry syscall_table_64[] = {
+#ifdef SB_SCHIZO_sparc64
+#define S(s) { SB_SYS_sparc64_##s, SB_NR_##s, #s },
+#include "trace_syscalls_sparc64.h"
+#undef S
+#endif
+       { SB_NR_UNDEF, SB_NR_UNDEF, NULL },
+};
+
+static bool pers_is_32(trace_regs *regs)
+{
+#ifdef __arch64__
+       /* Sparc does not make it easy to detect 32-bit vs 64-bit.
+        * Inspect the syscall trap insn to see which one it is.
+        */
+       unsigned long ret = do_ptrace(PTRACE_PEEKTEXT, (void *)regs->tpc, NULL);
+       return (ret >> 32) == 0x91d02010;
+#else
+       return true;
+#endif
+}
+
+static const struct syscall_entry *trace_check_personality(void *vregs)
+{
+       trace_regs *regs = vregs;
+       if (pers_is_32(regs))
+               return syscall_table_32;
+       else
+               return syscall_table_64;
+}
+
+static bool _trace_possible(const void *data)
+{
+#ifdef __arch64__
+       /* sparc64 can trace sparc32. */
+       return true;
+#else
+       /* sparc32 can only trace sparc32 :(. */
+       const Elf64_Ehdr *ehdr = data;
+       return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
+#endif
+}
+
+#else
+
+static bool _trace_possible(const void *data)
+{
+       const Elf64_Ehdr *ehdr = data;
+#ifdef __arch64__
+       return ehdr->e_ident[EI_CLASS] == ELFCLASS64;
+#else
+       return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
+#endif
+}
+
+#endif
+
 /* Sparc systems have swapped the addr/data args. */
 #undef trace_get_regs
 #undef trace_set_regs

Reply via email to