From 2ecf3fa49f1c2e5031762e0558b1f0c8f37103b4 Mon Sep 17 00:00:00 2001 From: Jiong Wang Date: Thu, 6 Dec 2012 12:16:15 +0800 Subject: [PATCH 3/5] * tilegx-tdep.c (tilegx_write_pc): prevent kernel from restarting syscall for gdb hand call if we just interrupted a system call, the kernel might try to restart it when we resume the inferior, such as nanosleep. for gdb, we may resume the inferior because of a hand call. in this situation, we should prevent kernel from restarting syscall at $pc - 8, which is no longer the original place where syscall occured. --- gdb/tilegx-linux-nat.c | 2 +- gdb/tilegx-linux-tdep.c | 6 ++++-- gdb/tilegx-tdep.c | 32 ++++++++++++++++++++++++++++++-- gdb/tilegx-tdep.h | 4 ++-- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/gdb/tilegx-linux-nat.c b/gdb/tilegx-linux-nat.c index 23acba5..51dbf5e 100644 --- a/gdb/tilegx-linux-nat.c +++ b/gdb/tilegx-linux-nat.c @@ -65,7 +65,7 @@ static const int regmap[] = 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, -1, -1, -1, -1, -1, -1, -1, -1, - 56 + 56, 58 }; /* Transfering the general-purpose registers between GDB, inferiors diff --git a/gdb/tilegx-linux-tdep.c b/gdb/tilegx-linux-tdep.c index c5e0e80..19ad297 100644 --- a/gdb/tilegx-linux-tdep.c +++ b/gdb/tilegx-linux-tdep.c @@ -85,9 +85,11 @@ tilegx_linux_supply_regset (const struct regset *regset, int i; /* This logic must match that of struct pt_regs in "ptrace.h". */ - for (i = 0; i < TILEGX_NUM_EASY_REGS + 1; i++, ptr += tilegx_reg_size) + for (i = 0; i < TILEGX_NUM_EASY_REGS + 2; i++, ptr += tilegx_reg_size) { - int gri = (i < TILEGX_NUM_EASY_REGS) ? i : TILEGX_PC_REGNUM; + int gri = (i < TILEGX_NUM_EASY_REGS) + ? i : (i == TILEGX_NUM_EASY_REGS) + ? TILEGX_PC_REGNUM : TILEGX_FAULTNUM_REGNUM; if (regnum == gri || regnum == -1) regcache_raw_supply (regcache, gri, ptr); diff --git a/gdb/tilegx-tdep.c b/gdb/tilegx-tdep.c index 93969c9..bc8cd35 100644 --- a/gdb/tilegx-tdep.c +++ b/gdb/tilegx-tdep.c @@ -155,7 +155,7 @@ tilegx_register_name (struct gdbarch *gdbarch, int regnum) "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49", "r50", "r51", "r52", "tp", "sp", "lr", "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero", - "pc" + "pc", "faultnum", }; if (regnum < 0 || regnum >= TILEGX_NUM_REGS) @@ -782,6 +782,32 @@ tilegx_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) return 0; } +#define INT_SWINT_1_SIGRETURN (~0) +static void +tilegx_write_pc (struct regcache *regcache, CORE_ADDR pc) +{ + regcache_cooked_write_unsigned (regcache, TILEGX_PC_REGNUM, pc); + + /* We must be careful with modifying the program counter. If we + just interrupted a system call, the kernel might try to restart + it when we resume the inferior. On restarting the system call, + the kernel will try backing up the program counter even though it + no longer points at the system call. This typically results in a + SIGSEGV or SIGILL. We can prevent this by writing INT_SWINT_1_SIGRETURN + in the "faultnum" pseudo-register. + + Note that "faultnum" is saved when setting up a dummy call frame. + This means that it is properly restored when that frame is + popped, and that the interrupted system call will be restarted + when we resume the inferior on return from a function call from + within GDB. In all other cases the system call will not be + restarted. */ + regcache_cooked_write_unsigned (regcache, TILEGX_FAULTNUM_REGNUM, + INT_SWINT_1_SIGRETURN); +} + + + /* This is the implementation of gdbarch method breakpoint_from_pc. */ static const unsigned char * @@ -913,7 +939,8 @@ tilegx_cannot_reference_register (struct gdbarch *gdbarch, int regno) { if (regno >= 0 && regno < TILEGX_NUM_EASY_REGS) return 0; - else if (regno == TILEGX_PC_REGNUM) + else if (regno == TILEGX_PC_REGNUM + || regno == TILEGX_FAULTNUM_REGNUM) return 0; else return 1; @@ -996,6 +1023,7 @@ tilegx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* These values and methods are used when gdb calls a target function. */ set_gdbarch_push_dummy_call (gdbarch, tilegx_push_dummy_call); + set_gdbarch_write_pc (gdbarch, tilegx_write_pc); set_gdbarch_breakpoint_from_pc (gdbarch, tilegx_breakpoint_from_pc); set_gdbarch_return_value (gdbarch, tilegx_return_value); diff --git a/gdb/tilegx-tdep.h b/gdb/tilegx-tdep.h index 3ac18a5..5f99fd9 100644 --- a/gdb/tilegx-tdep.h +++ b/gdb/tilegx-tdep.h @@ -100,8 +100,8 @@ enum tilegx_regnum TILEGX_PC_REGNUM, TILEGX_NUM_PHYS_REGS = TILEGX_PC_REGNUM, /* 64 */ - - TILEGX_NUM_REGS /* 65 */ + TILEGX_FAULTNUM_REGNUM, + TILEGX_NUM_REGS, /* 66 */ }; enum { tilegx_reg_size = 8 }; -- 1.7.10.4