+2015-06-17  Mike Frysinger  <vapier@gentoo.org>
+
+       * sim-syscall.c: Include errno.h and targ-vals.h.
+       (sim_syscall_multi, sim_syscall): Define.
+       * sim-syscall.h (sim_syscall_multi, sim_syscall): Declare.
+       * syscall.c (cb_syscall): Extend comment.
+
 2015-06-17  Mike Frysinger  <vapier@gentoo.org>
 
        * Make-common.in (SIM_NEW_COMMON_OBJS): Add sim-syscall.o.
 
 
 #include "config.h"
 
+#include <errno.h>
+
 #include "sim-main.h"
 #include "sim-syscall.h"
+#include "targ-vals.h"
 \f
 /* Read/write functions for system call interface.  */
 
 
   return sim_core_write_buffer (sd, cpu, write_map, buf, taddr, bytes);
 }
+\f
+/* Main syscall callback for simulators.  */
+
+void
+sim_syscall_multi (SIM_CPU *cpu, int func, long arg1, long arg2, long arg3,
+                  long arg4, long *result, long *result2, int *errcode)
+{
+  SIM_DESC sd = CPU_STATE (cpu);
+  host_callback *cb = STATE_CALLBACK (sd);
+  CB_SYSCALL sc;
+  char unknown_syscall[30];
+  const char *syscall;
+
+  CB_SYSCALL_INIT (&sc);
+
+  sc.func = func;
+  sc.arg1 = arg1;
+  sc.arg2 = arg2;
+  sc.arg3 = arg3;
+  sc.arg4 = arg4;
+
+  sc.p1 = (PTR) sd;
+  sc.p2 = (PTR) cpu;
+  sc.read_mem = sim_syscall_read_mem;
+  sc.write_mem = sim_syscall_write_mem;
+
+  if (cb_syscall (cb, &sc) != CB_RC_OK)
+    {
+      /* The cb_syscall func never returns an error, so this is more of a
+        sanity check.  */
+      sim_engine_abort (sd, cpu, sim_pc_get (cpu), "cb_syscall failed");
+    }
+
+  syscall = cb_target_str_syscall (cb, func);
+  if (!syscall)
+    {
+      sprintf (unknown_syscall, "syscall_%i", func);
+      syscall = unknown_syscall;
+    }
+
+  if (sc.result == -1)
+    TRACE_SYSCALL (cpu, "%s[%i](%#lx, %#lx, %#lx) = %li (error = %s[%i])",
+                  syscall, func, arg1, arg2, arg3, sc.result,
+                  cb_target_str_errno (cb, sc.errcode), sc.errcode);
+  else
+    TRACE_SYSCALL (cpu, "%s[%i](%#lx, %#lx, %#lx) = %li",
+                  syscall, func, arg1, arg2, arg3, sc.result);
+
+  if (cb_target_to_host_syscall (cb, func) == CB_SYS_exit)
+    sim_engine_halt (sd, cpu, NULL, sim_pc_get (cpu), sim_exited, arg1);
+  else if (sc.result == -1)
+    {
+      cb->last_errno = errno;
+      sc.errcode = cb->get_errno (cb);
+    }
+
+  *result = sc.result;
+  *result2 = sc.result2;
+  *errcode = sc.errcode;
+}
+
+long
+sim_syscall (SIM_CPU *cpu, int func, long arg1, long arg2, long arg3, long arg4)
+{
+  long result, result2;
+  int errcode;
+
+  sim_syscall_multi (cpu, func, arg1, arg2, arg3, arg4, &result, &result2,
+                    &errcode);
+  if (result == -1)
+    return -errcode;
+  else
+    return result;
+}
 
 #ifndef SIM_SYSCALL_H
 #define SIM_SYSCALL_H
 
+/* Perform a syscall on the behalf of the target program.  The error/result are
+   normalized into a single value (like a lot of operating systems do).  If you
+   want the split values, see the other function below.
+
+   Note: While cb_syscall requires you handle the exit syscall yourself, that is
+   not the case with these helpers.
+
+   Note: Types here match the gdb callback interface.  */
+long sim_syscall (SIM_CPU *, int func, long arg1, long arg2, long arg3,
+                 long arg4);
+
+/* Same as sim_syscall, but return the split values by referenced.  */
+void sim_syscall_multi (SIM_CPU *, int func, long arg1, long arg2, long arg3,
+                       long arg4, long *result, long *result2, int *errcode);
+
 /* Simple memory callbacks for cb_syscall's read_mem/write_mem that assume
    cb_syscall's p1 and p2 are set to the SIM_DESC and SIM_CPU respectively.  */
 int sim_syscall_read_mem (host_callback *, struct cb_syscall *, unsigned long,
 
 #endif /* wip */
 
     case CB_SYS_exit :
-      /* Caller must catch and handle.  */
+      /* Caller must catch and handle; see sim_syscall as an example.  */
       break;
 
     case CB_SYS_open :
 
+2015-06-17  Mike Frysinger  <vapier@gentoo.org>
+
+       * traps.c (lm32bf_scall_insn): Replace call to cb_syscall with
+       sim_syscall_multi.
+
 2015-06-17  Mike Frysinger  <vapier@gentoo.org>
 
        * traps.c: Include sim-syscall.h.
 
       || (GET_H_GR (8) == TARGET_SYS_exit))
     {
       /* Delegate system call to host O/S.  */
-      CB_SYSCALL s;
-      CB_SYSCALL_INIT (&s);
-      s.p1 = (PTR) sd;
-      s.p2 = (PTR) current_cpu;
-      s.read_mem = sim_syscall_read_mem;
-      s.write_mem = sim_syscall_write_mem;
-      /* Extract parameters.  */
-      s.func = GET_H_GR (8);
-      s.arg1 = GET_H_GR (1);
-      s.arg2 = GET_H_GR (2);
-      s.arg3 = GET_H_GR (3);
-      /* Halt the simulator if the requested system call is _exit.  */
-      if (s.func == TARGET_SYS_exit)
-       sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, s.arg1);
+      long result, result2;
+      int errcode;
+
       /* Perform the system call.  */
-      cb_syscall (cb, &s);
+      sim_syscall_multi (current_cpu, GET_H_GR (8), GET_H_GR (1), GET_H_GR (2),
+                        GET_H_GR (3), GET_H_GR (4), &result, &result2,
+                        &errcode);
       /* Store the return value in the CPU's registers.  */
-      SET_H_GR (1, s.result);
-      SET_H_GR (2, s.result2);
-      SET_H_GR (3, s.errcode);
+      SET_H_GR (1, result);
+      SET_H_GR (2, result2);
+      SET_H_GR (3, errcode);
+
       /* Skip over scall instruction.  */
       return pc + 4;
     }
 
+2015-06-17  Mike Frysinger  <vapier@gentoo.org>
+
+       * traps.c (m32r_trap): Replace call to cb_syscall with
+       sim_syscall_multi.
+       * traps-linux.c (m32r_trap): Likewise.
+
 2015-06-17  Mike Frysinger  <vapier@gentoo.org>
 
        * traps-linux.c: Include sim-syscall.h.
 
     {
     case TRAP_ELF_SYSCALL :
       {
-        CB_SYSCALL s;
- 
-        CB_SYSCALL_INIT (&s);
-        s.func = m32rbf_h_gr_get (current_cpu, 0);
-        s.arg1 = m32rbf_h_gr_get (current_cpu, 1);
-        s.arg2 = m32rbf_h_gr_get (current_cpu, 2);
-        s.arg3 = m32rbf_h_gr_get (current_cpu, 3);
- 
-        if (s.func == TARGET_SYS_exit)
-          {
-            sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, s.arg1);
-          }
- 
-        s.p1 = (PTR) sd;
-        s.p2 = (PTR) current_cpu;
-        s.read_mem = sim_syscall_read_mem;
-        s.write_mem = sim_syscall_write_mem;
-        cb_syscall (cb, &s);
-        m32rbf_h_gr_set (current_cpu, 2, s.errcode);
-        m32rbf_h_gr_set (current_cpu, 0, s.result);
-        m32rbf_h_gr_set (current_cpu, 1, s.result2);
-        break;
+       long result, result2;
+       int errcode;
+
+       sim_syscall_multi (current_cpu,
+                          m32rbf_h_gr_get (current_cpu, 0),
+                          m32rbf_h_gr_get (current_cpu, 1),
+                          m32rbf_h_gr_get (current_cpu, 2),
+                          m32rbf_h_gr_get (current_cpu, 3),
+                          m32rbf_h_gr_get (current_cpu, 4),
+                          &result, &result2, &errcode);
+
+       m32rbf_h_gr_set (current_cpu, 2, errcode);
+       m32rbf_h_gr_set (current_cpu, 0, result);
+       m32rbf_h_gr_set (current_cpu, 1, result2);
+       break;
       }
 
     case TRAP_LINUX_SYSCALL :
 
     {
     case TRAP_SYSCALL :
       {
-       CB_SYSCALL s;
-
-       CB_SYSCALL_INIT (&s);
-       s.func = m32rbf_h_gr_get (current_cpu, 0);
-       s.arg1 = m32rbf_h_gr_get (current_cpu, 1);
-       s.arg2 = m32rbf_h_gr_get (current_cpu, 2);
-       s.arg3 = m32rbf_h_gr_get (current_cpu, 3);
-
-       if (s.func == TARGET_SYS_exit)
-         {
-           sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, s.arg1);
-         }
-
-       s.p1 = (PTR) sd;
-       s.p2 = (PTR) current_cpu;
-       s.read_mem = sim_syscall_read_mem;
-       s.write_mem = sim_syscall_write_mem;
-       cb_syscall (cb, &s);
-       m32rbf_h_gr_set (current_cpu, 2, s.errcode);
-       m32rbf_h_gr_set (current_cpu, 0, s.result);
-       m32rbf_h_gr_set (current_cpu, 1, s.result2);
+       long result, result2;
+       int errcode;
+
+       sim_syscall_multi (current_cpu,
+                          m32rbf_h_gr_get (current_cpu, 0),
+                          m32rbf_h_gr_get (current_cpu, 1),
+                          m32rbf_h_gr_get (current_cpu, 2),
+                          m32rbf_h_gr_get (current_cpu, 3),
+                          m32rbf_h_gr_get (current_cpu, 4),
+                          &result, &result2, &errcode);
+
+       m32rbf_h_gr_set (current_cpu, 2, errcode);
+       m32rbf_h_gr_set (current_cpu, 0, result);
+       m32rbf_h_gr_set (current_cpu, 1, result2);
        break;
       }
 
 
+2015-06-17  Mike Frysinger  <vapier@gentoo.org>
+
+       * interp.c (handle_trap1): Replace call to cb_syscall with
+       sim_syscall.
+
 2015-06-17  Mike Frysinger  <vapier@gentoo.org>
 
        * interp.c: Include sim-syscall.h.
 
 static void
 handle_trap1 (SIM_DESC sd)
 {
-  host_callback *cb = STATE_CALLBACK (sd);
-  CB_SYSCALL sc;
-
-  CB_SYSCALL_INIT (&sc);
-
-  sc.func = cpu.gr[TRAPCODE];
-  sc.arg1 = cpu.gr[PARM1];
-  sc.arg2 = cpu.gr[PARM2];
-  sc.arg3 = cpu.gr[PARM3];
-  sc.arg4 = cpu.gr[PARM4];
-
-  sc.p1 = (PTR) sd;
-  sc.p2 = (PTR) STATE_CPU (sd, 0);
-  sc.read_mem = sim_syscall_read_mem;
-  sc.write_mem = sim_syscall_write_mem;
-
-  cb_syscall (cb, &sc);
-
   /* XXX: We don't pass back the actual errno value.  */
-  cpu.gr[RET1] = sc.result;
+  cpu.gr[RET1] = sim_syscall (STATE_CPU (sd, 0), cpu.gr[TRAPCODE],
+                             cpu.gr[PARM1], cpu.gr[PARM2], cpu.gr[PARM3],
+                             cpu.gr[PARM4]);
 }
 
 static void
 
+2015-06-17  Mike Frysinger  <vapier@gentoo.org>
+
+       * op_utils.c (do_syscall): Replace call to cb_syscall with
+       sim_syscall_multi.
+
 2015-06-17  Mike Frysinger  <vapier@gentoo.org>
 
        * mn10300_sim.h (syscall_read_mem, syscall_write_mem): Delete.
 
 INLINE_SIM_MAIN (void)
 do_syscall (void)
 {
+  /* Registers passed to trap 0.  */
+
+  /* Function number.  */
+  reg_t func = State.regs[0];
+  /* Parameters.  */
+  reg_t parm1 = State.regs[1];
+  reg_t parm2 = load_word (State.regs[REG_SP] + 12);
+  reg_t parm3 = load_word (State.regs[REG_SP] + 16);
+  reg_t parm4 = load_word (State.regs[REG_SP] + 20);
 
   /* We use this for simulated system calls; we may need to change
      it to a reserved instruction if we conflict with uses at
   int save_errno = errno;      
   errno = 0;
 
-/* Registers passed to trap 0 */
-
-/* Function number.  */
-#define FUNC   (State.regs[0])
-
-/* Parameters.  */
-#define PARM1   (State.regs[1])
-#define PARM2   (load_word (State.regs[REG_SP] + 12))
-#define PARM3   (load_word (State.regs[REG_SP] + 16))
-
-/* Registers set by trap 0 */
-
-#define RETVAL State.regs[0]   /* return value */
-#define RETERR State.regs[1]   /* return error code */
-
-  if ( FUNC == TARGET_SYS_exit )
+  if (func == TARGET_SYS_exit)
     {
-      /* EXIT - caller can look in PARM1 to work out the reason */
+      /* EXIT - caller can look in parm1 to work out the reason */
       sim_engine_halt (simulator, STATE_CPU (simulator, 0), NULL, PC,
-                      (PARM1 == 0xdead ? SIM_SIGABRT : sim_exited), PARM1);
+                      (parm1 == 0xdead ? SIM_SIGABRT : sim_exited), parm1);
     }
   else
     {
-      CB_SYSCALL syscall;
-
-      CB_SYSCALL_INIT (&syscall);
-      syscall.arg1 = PARM1;
-      syscall.arg2 = PARM2;
-      syscall.arg3 = PARM3;
-      syscall.func = FUNC;
-      syscall.p1 = (PTR) simulator;
-      syscall.p2 = (PTR) STATE_CPU (simulator, 0);
-      syscall.read_mem = sim_syscall_read_mem;
-      syscall.write_mem = sim_syscall_write_mem;
-      cb_syscall (STATE_CALLBACK (simulator), &syscall);
-      RETERR = syscall.errcode;
-      RETVAL = syscall.result;
-    }
+      long result, result2;
+      int errcode;
 
+      sim_syscall_multi (STATE_CPU (simulator, 0), func, parm1, parm2,
+                        parm3, parm4, &result, &result2, &errcode);
+
+      /* Registers set by trap 0.  */
+      State.regs[0] = errcode;
+      State.regs[1] = result;
+    }
 
   errno = save_errno;
 }
-
 
+2015-06-17  Mike Frysinger  <vapier@gentoo.org>
+
+       * msp430-sim.c (maybe_perform_syscall): Replace call to cb_syscall
+       with sim_syscall.
+
 2015-06-17  Mike Frysinger  <vapier@gentoo.org>
 
        * msp430-sim.c: Include sim-syscall.h.
 
     {
       /* Syscall!  */
       int syscall_num = call_addr & 0x3f;
-      host_callback *cb = STATE_CALLBACK (sd);
-      CB_SYSCALL sc;
-
-      CB_SYSCALL_INIT (&sc);
-
-      sc.func = syscall_num;
-      sc.arg1 = MSP430_CPU (sd)->state.regs[12];
-      sc.arg2 = MSP430_CPU (sd)->state.regs[13];
-      sc.arg3 = MSP430_CPU (sd)->state.regs[14];
-      sc.arg4 = MSP430_CPU (sd)->state.regs[15];
-
-      if (TRACE_SYSCALL_P (MSP430_CPU (sd)))
-       {
-         const char *syscall_name = "*unknown*";
-
-         switch (syscall_num)
-           {
-           case TARGET_SYS_exit:
-             syscall_name = "exit(%d)";
-             break;
-           case TARGET_SYS_open:
-             syscall_name = "open(%#x,%#x)";
-             break;
-           case TARGET_SYS_close:
-             syscall_name = "close(%d)";
-             break;
-           case TARGET_SYS_read:
-             syscall_name = "read(%d,%#x,%d)";
-             break;
-           case TARGET_SYS_write:
-             syscall_name = "write(%d,%#x,%d)";
-             break;
-           }
-         trace_generic (sd, MSP430_CPU (sd), TRACE_SYSCALL_IDX,
-                        syscall_name, sc.arg1, sc.arg2, sc.arg3, sc.arg4);
-       }
-
-      /* Handle SYS_exit here.  */
-      if (syscall_num == 1)
-       {
-         sim_engine_halt (sd, MSP430_CPU (sd), NULL,
-                          MSP430_CPU (sd)->state.regs[0],
-                          sim_exited, sc.arg1);
-         return 1;
-       }
-
-      sc.p1 = sd;
-      sc.p2 = MSP430_CPU (sd);
-      sc.read_mem = sim_syscall_read_mem;
-      sc.write_mem = sim_syscall_write_mem;
-
-      cb_syscall (cb, &sc);
-
-      TRACE_SYSCALL (MSP430_CPU (sd), "returns %ld", sc.result);
-
-      MSP430_CPU (sd)->state.regs[12] = sc.result;
+      int arg1 = MSP430_CPU (sd)->state.regs[12];
+      int arg2 = MSP430_CPU (sd)->state.regs[13];
+      int arg3 = MSP430_CPU (sd)->state.regs[14];
+      int arg4 = MSP430_CPU (sd)->state.regs[15];
+
+      MSP430_CPU (sd)->state.regs[12] = sim_syscall (MSP430_CPU (sd),
+                                                    syscall_num, arg1, arg2,
+                                                    arg3, arg4);
       return 1;
     }