[gdb/tdep] Rewrite i386_canonicalize_syscall

On openSUSE Tumbleweed x86_64, with target board unix/-m32 and test-case
gdb.reverse/recvmsg-reverse.exp, I run into:
...
(gdb) continue^M
Continuing.^M
Process record and replay target doesn't support syscall number 360^M
Process record: failed to record execution log.^M
^M
Program stopped.^M
0xf7fc5575 in __kernel_vsyscall ()^M
(gdb) FAIL: $exp: continue to breakpoint: marker2
...

The syscall number 360 in i386 is for syscall socketpair, as we can see in
arch/x86/entry/syscalls/syscall_32.tbl:
...
<number>  <abi>  <name>      <entry point>
360       i386   socketpair  sys_socketpair
...

Function i386_canonicalize_syscall assumes that any syscall below 500 maps to
an identically valued enum in enum gdb_syscall:
...
static enum gdb_syscall
i386_canonicalize_syscall (int syscall)
{
  enum { i386_syscall_max = 499 };

  if (syscall <= i386_syscall_max)
    return (enum gdb_syscall) syscall;
  else
    return gdb_sys_no_syscall;
}
...

However, that's not the case.  The value of gdb_sys_socketpair is not 360,
but 512:
...
enum gdb_syscall {
  ...
  gdb_sys_getrandom = 355,
  gdb_sys_statx = 383,
  ...
  gdb_sys_socketpair = 512,
...

Consequently, when record_linux_system_call is called with
syscall == i386_canonicalize_syscall (360), we hit the default case here:
....
  switch (syscall)
    {
    ...
    default:
      gdb_printf (gdb_stderr,
                  _("Process record and replay target doesn't "
                    "support syscall number %d\n"), syscall);
      return -1;
      break;
    }
...
rather than hitting the case for gdb_sys_socketpair.

I initially wrote a trivial fix for this, changing the value of
gdb_sys_socketpair to 360.  However, Andreas Schwab pointed out that there are
other functions (ppc_canonicalize_syscall and s390_canonicalize_syscall) that
make assumptions about specific values of enum gdb_syscall, and fixing this
for i386 may break things for ppc or s390.

So instead, I decided to rewrite i386_canonicalize_syscall to match the
approach taken in aarch64_canonicalize_syscall, which allows
gdb_sys_socketpair to keep the same value.

So, fix this by:
- adding a new table file gdb/i386-syscalls.def, using a SYSCALL entry for
  each syscall, generated from arch/x86/entry/syscalls/syscall_32.tbl,
- using gdb/i386-syscalls.def to define enum i386_syscall, and
- using macros SYSCALL_MAP, SYSCALL_MAP_RENAME and UNSUPPORTED_SYSCALL_MAP to
  define the mapping from enum i386_syscall to enum gdb_syscall in
  i386_canonicalize_syscall.

I've created the mapping as follows:
- I used arch/x86/entry/syscalls/syscall_32.tbl to generate an initial mapping
  using SYSCALL_MAP for each syscall,
- I attempted to compile this and used the compilation errors about
  non-existing gdb_sys_ values to change those entries to
  UNSUPPORTED_SYSCALL_MAP, which got me a compiling version,
- I reviewed the UNSUPPORTED_SYSCALL_MAP entries, changing to
  SYSCALL_MAP_RENAME where necessary,
- I then reviewed syscalls below 500 that mapped to a gdb_syscall value below
  500, but not the same, and fixed those using SYSCALL_MAP_RENAME, and
- reviewed the mapping for gdb_syscall entries >= 500.

On the resulting mapping, I was able to do the following sanity check:
...
  for (int i = 0; i < 500; ++i)
    {
      int res = i386_canonicalize_syscall (i);
      if (res == i)
	continue;
      if (res == -1)
	continue;
      if (res >= 500)
	continue;
      gdb_assert_not_reached ("");
    }
}
...
to make sure that any syscall below 500 either:
- maps to the same number,
- is unsupported, or
- maps to a number >= 500.

Coming back to our original problem, the socket pair syscall is addressed by
an entry:
...
      SYSCALL_MAP (socketpair);
...
which maps i386_sys_socketpair (360) to gdb_sys_socketpair (512).

Tested on x86_64-linux with target board unix/-m32.

Approved-By: Guinevere Larsen <guinevere@redhat.com>

PR tdep/32770
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32770
2 files changed