diff options
Diffstat (limited to 'gdb/arm-linux-tdep.c')
-rw-r--r-- | gdb/arm-linux-tdep.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index 1502bdcfe63..6ac61cc1a14 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -33,6 +33,7 @@ #include "tramp-frame.h" #include "breakpoint.h" #include "auxv.h" +#include "xml-syscall.h" #include "arm-tdep.h" #include "arm-linux-tdep.h" @@ -794,6 +795,59 @@ arm_linux_sigreturn_return_addr (struct frame_info *frame, return 0; } +/* At a ptrace syscall-stop, return the syscall number. This either + comes from the SWI instruction (OABI) or from r7 (EABI). + + When the function fails, it should return -1. */ + +static LONGEST +arm_linux_get_syscall_number (struct gdbarch *gdbarch, + ptid_t ptid) +{ + struct regcache *regs = get_thread_regcache (ptid); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + ULONGEST pc; + ULONGEST cpsr; + ULONGEST t_bit = arm_psr_thumb_bit (gdbarch); + int is_thumb; + ULONGEST svc_number = -1; + + regcache_cooked_read_unsigned (regs, ARM_PC_REGNUM, &pc); + regcache_cooked_read_unsigned (regs, ARM_PS_REGNUM, &cpsr); + is_thumb = (cpsr & t_bit) != 0; + + if (is_thumb) + { + regcache_cooked_read_unsigned (regs, 7, &svc_number); + } + else + { + enum bfd_endian byte_order_for_code = + gdbarch_byte_order_for_code (gdbarch); + + /* PC gets incremented before the syscall-stop, so read the + previous instruction. */ + unsigned long this_instr = + read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code); + + unsigned long svc_operand = (0x00ffffff & this_instr); + + if (svc_operand) + { + /* OABI */ + svc_number = svc_operand - 0x900000; + } + else + { + /* EABI */ + regcache_cooked_read_unsigned (regs, 7, &svc_number); + } + } + + return svc_number; +} + /* When FRAME is at a syscall instruction, return the PC of the next instruction to be executed. */ @@ -1294,6 +1348,10 @@ arm_linux_init_abi (struct gdbarch_info info, tdep->syscall_next_pc = arm_linux_syscall_next_pc; + /* `catch syscall' */ + set_xml_syscall_file_name ("syscalls/arm-linux.xml"); + set_gdbarch_get_syscall_number (gdbarch, arm_linux_get_syscall_number); + /* Syscall record. */ tdep->arm_swi_record = NULL; } |