|  | /* GNU/Linux on ARM target support. | 
|  |  | 
|  | Copyright (C) 1999-2023 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "defs.h" | 
|  | #include "target.h" | 
|  | #include "value.h" | 
|  | #include "gdbtypes.h" | 
|  | #include "gdbcore.h" | 
|  | #include "frame.h" | 
|  | #include "regcache.h" | 
|  | #include "solib-svr4.h" | 
|  | #include "osabi.h" | 
|  | #include "regset.h" | 
|  | #include "trad-frame.h" | 
|  | #include "tramp-frame.h" | 
|  | #include "breakpoint.h" | 
|  | #include "auxv.h" | 
|  | #include "xml-syscall.h" | 
|  | #include "expop.h" | 
|  |  | 
|  | #include "aarch32-tdep.h" | 
|  | #include "arch/arm.h" | 
|  | #include "arch/arm-get-next-pcs.h" | 
|  | #include "arch/arm-linux.h" | 
|  | #include "arm-tdep.h" | 
|  | #include "arm-linux-tdep.h" | 
|  | #include "linux-tdep.h" | 
|  | #include "glibc-tdep.h" | 
|  | #include "arch-utils.h" | 
|  | #include "inferior.h" | 
|  | #include "infrun.h" | 
|  | #include "gdbthread.h" | 
|  | #include "symfile.h" | 
|  |  | 
|  | #include "record-full.h" | 
|  | #include "linux-record.h" | 
|  |  | 
|  | #include "cli/cli-utils.h" | 
|  | #include "stap-probe.h" | 
|  | #include "parser-defs.h" | 
|  | #include "user-regs.h" | 
|  | #include <ctype.h> | 
|  | #include "elf/common.h" | 
|  |  | 
|  | /* Under ARM GNU/Linux the traditional way of performing a breakpoint | 
|  | is to execute a particular software interrupt, rather than use a | 
|  | particular undefined instruction to provoke a trap.  Upon execution | 
|  | of the software interrupt the kernel stops the inferior with a | 
|  | SIGTRAP, and wakes the debugger.  */ | 
|  |  | 
|  | static const gdb_byte arm_linux_arm_le_breakpoint[] = { 0x01, 0x00, 0x9f, 0xef }; | 
|  |  | 
|  | static const gdb_byte arm_linux_arm_be_breakpoint[] = { 0xef, 0x9f, 0x00, 0x01 }; | 
|  |  | 
|  | /* However, the EABI syscall interface (new in Nov. 2005) does not look at | 
|  | the operand of the swi if old-ABI compatibility is disabled.  Therefore, | 
|  | use an undefined instruction instead.  This is supported as of kernel | 
|  | version 2.5.70 (May 2003), so should be a safe assumption for EABI | 
|  | binaries.  */ | 
|  |  | 
|  | static const gdb_byte eabi_linux_arm_le_breakpoint[] = { 0xf0, 0x01, 0xf0, 0xe7 }; | 
|  |  | 
|  | static const gdb_byte eabi_linux_arm_be_breakpoint[] = { 0xe7, 0xf0, 0x01, 0xf0 }; | 
|  |  | 
|  | /* All the kernels which support Thumb support using a specific undefined | 
|  | instruction for the Thumb breakpoint.  */ | 
|  |  | 
|  | static const gdb_byte arm_linux_thumb_be_breakpoint[] = {0xde, 0x01}; | 
|  |  | 
|  | static const gdb_byte arm_linux_thumb_le_breakpoint[] = {0x01, 0xde}; | 
|  |  | 
|  | /* Because the 16-bit Thumb breakpoint is affected by Thumb-2 IT blocks, | 
|  | we must use a length-appropriate breakpoint for 32-bit Thumb | 
|  | instructions.  See also thumb_get_next_pc.  */ | 
|  |  | 
|  | static const gdb_byte arm_linux_thumb2_be_breakpoint[] = { 0xf7, 0xf0, 0xa0, 0x00 }; | 
|  |  | 
|  | static const gdb_byte arm_linux_thumb2_le_breakpoint[] = { 0xf0, 0xf7, 0x00, 0xa0 }; | 
|  |  | 
|  | /* Description of the longjmp buffer.  The buffer is treated as an array of | 
|  | elements of size ARM_LINUX_JB_ELEMENT_SIZE. | 
|  |  | 
|  | The location of saved registers in this buffer (in particular the PC | 
|  | to use after longjmp is called) varies depending on the ABI (in | 
|  | particular the FP model) and also (possibly) the C Library. | 
|  |  | 
|  | For glibc, eglibc, and uclibc the following holds:  If the FP model is | 
|  | SoftVFP or VFP (which implies EABI) then the PC is at offset 9 in the | 
|  | buffer.  This is also true for the SoftFPA model.  However, for the FPA | 
|  | model the PC is at offset 21 in the buffer.  */ | 
|  | #define ARM_LINUX_JB_ELEMENT_SIZE	ARM_INT_REGISTER_SIZE | 
|  | #define ARM_LINUX_JB_PC_FPA		21 | 
|  | #define ARM_LINUX_JB_PC_EABI		9 | 
|  |  | 
|  | /* | 
|  | Dynamic Linking on ARM GNU/Linux | 
|  | -------------------------------- | 
|  |  | 
|  | Note: PLT = procedure linkage table | 
|  | GOT = global offset table | 
|  |  | 
|  | As much as possible, ELF dynamic linking defers the resolution of | 
|  | jump/call addresses until the last minute.  The technique used is | 
|  | inspired by the i386 ELF design, and is based on the following | 
|  | constraints. | 
|  |  | 
|  | 1) The calling technique should not force a change in the assembly | 
|  | code produced for apps; it MAY cause changes in the way assembly | 
|  | code is produced for position independent code (i.e. shared | 
|  | libraries). | 
|  |  | 
|  | 2) The technique must be such that all executable areas must not be | 
|  | modified; and any modified areas must not be executed. | 
|  |  | 
|  | To do this, there are three steps involved in a typical jump: | 
|  |  | 
|  | 1) in the code | 
|  | 2) through the PLT | 
|  | 3) using a pointer from the GOT | 
|  |  | 
|  | When the executable or library is first loaded, each GOT entry is | 
|  | initialized to point to the code which implements dynamic name | 
|  | resolution and code finding.  This is normally a function in the | 
|  | program interpreter (on ARM GNU/Linux this is usually | 
|  | ld-linux.so.2, but it does not have to be).  On the first | 
|  | invocation, the function is located and the GOT entry is replaced | 
|  | with the real function address.  Subsequent calls go through steps | 
|  | 1, 2 and 3 and end up calling the real code. | 
|  |  | 
|  | 1) In the code: | 
|  |  | 
|  | b    function_call | 
|  | bl   function_call | 
|  |  | 
|  | This is typical ARM code using the 26 bit relative branch or branch | 
|  | and link instructions.  The target of the instruction | 
|  | (function_call is usually the address of the function to be called. | 
|  | In position independent code, the target of the instruction is | 
|  | actually an entry in the PLT when calling functions in a shared | 
|  | library.  Note that this call is identical to a normal function | 
|  | call, only the target differs. | 
|  |  | 
|  | 2) In the PLT: | 
|  |  | 
|  | The PLT is a synthetic area, created by the linker.  It exists in | 
|  | both executables and libraries.  It is an array of stubs, one per | 
|  | imported function call.  It looks like this: | 
|  |  | 
|  | PLT[0]: | 
|  | str     lr, [sp, #-4]!       @push the return address (lr) | 
|  | ldr     lr, [pc, #16]   @load from 6 words ahead | 
|  | add     lr, pc, lr      @form an address for GOT[0] | 
|  | ldr     pc, [lr, #8]!   @jump to the contents of that addr | 
|  |  | 
|  | The return address (lr) is pushed on the stack and used for | 
|  | calculations.  The load on the second line loads the lr with | 
|  | &GOT[3] - . - 20.  The addition on the third leaves: | 
|  |  | 
|  | lr = (&GOT[3] - . - 20) + (. + 8) | 
|  | lr = (&GOT[3] - 12) | 
|  | lr = &GOT[0] | 
|  |  | 
|  | On the fourth line, the pc and lr are both updated, so that: | 
|  |  | 
|  | pc = GOT[2] | 
|  | lr = &GOT[0] + 8 | 
|  | = &GOT[2] | 
|  |  | 
|  | NOTE: PLT[0] borrows an offset .word from PLT[1].  This is a little | 
|  | "tight", but allows us to keep all the PLT entries the same size. | 
|  |  | 
|  | PLT[n+1]: | 
|  | ldr     ip, [pc, #4]    @load offset from gotoff | 
|  | add     ip, pc, ip      @add the offset to the pc | 
|  | ldr     pc, [ip]        @jump to that address | 
|  | gotoff: .word   GOT[n+3] - . | 
|  |  | 
|  | The load on the first line, gets an offset from the fourth word of | 
|  | the PLT entry.  The add on the second line makes ip = &GOT[n+3], | 
|  | which contains either a pointer to PLT[0] (the fixup trampoline) or | 
|  | a pointer to the actual code. | 
|  |  | 
|  | 3) In the GOT: | 
|  |  | 
|  | The GOT contains helper pointers for both code (PLT) fixups and | 
|  | data fixups.  The first 3 entries of the GOT are special.  The next | 
|  | M entries (where M is the number of entries in the PLT) belong to | 
|  | the PLT fixups.  The next D (all remaining) entries belong to | 
|  | various data fixups.  The actual size of the GOT is 3 + M + D. | 
|  |  | 
|  | The GOT is also a synthetic area, created by the linker.  It exists | 
|  | in both executables and libraries.  When the GOT is first | 
|  | initialized , all the GOT entries relating to PLT fixups are | 
|  | pointing to code back at PLT[0]. | 
|  |  | 
|  | The special entries in the GOT are: | 
|  |  | 
|  | GOT[0] = linked list pointer used by the dynamic loader | 
|  | GOT[1] = pointer to the reloc table for this module | 
|  | GOT[2] = pointer to the fixup/resolver code | 
|  |  | 
|  | The first invocation of function call comes through and uses the | 
|  | fixup/resolver code.  On the entry to the fixup/resolver code: | 
|  |  | 
|  | ip = &GOT[n+3] | 
|  | lr = &GOT[2] | 
|  | stack[0] = return address (lr) of the function call | 
|  | [r0, r1, r2, r3] are still the arguments to the function call | 
|  |  | 
|  | This is enough information for the fixup/resolver code to work | 
|  | with.  Before the fixup/resolver code returns, it actually calls | 
|  | the requested function and repairs &GOT[n+3].  */ | 
|  |  | 
|  | /* The constants below were determined by examining the following files | 
|  | in the linux kernel sources: | 
|  |  | 
|  | arch/arm/kernel/signal.c | 
|  | - see SWI_SYS_SIGRETURN and SWI_SYS_RT_SIGRETURN | 
|  | include/asm-arm/unistd.h | 
|  | - see __NR_sigreturn, __NR_rt_sigreturn, and __NR_SYSCALL_BASE */ | 
|  |  | 
|  | #define ARM_LINUX_SIGRETURN_INSTR	0xef900077 | 
|  | #define ARM_LINUX_RT_SIGRETURN_INSTR	0xef9000ad | 
|  |  | 
|  | /* For ARM EABI, the syscall number is not in the SWI instruction | 
|  | (instead it is loaded into r7).  We recognize the pattern that | 
|  | glibc uses...  alternatively, we could arrange to do this by | 
|  | function name, but they are not always exported.  */ | 
|  | #define ARM_SET_R7_SIGRETURN		0xe3a07077 | 
|  | #define ARM_SET_R7_RT_SIGRETURN		0xe3a070ad | 
|  | #define ARM_EABI_SYSCALL		0xef000000 | 
|  |  | 
|  | /* Equivalent patterns for Thumb2.  */ | 
|  | #define THUMB2_SET_R7_SIGRETURN1	0xf04f | 
|  | #define THUMB2_SET_R7_SIGRETURN2	0x0777 | 
|  | #define THUMB2_SET_R7_RT_SIGRETURN1	0xf04f | 
|  | #define THUMB2_SET_R7_RT_SIGRETURN2	0x07ad | 
|  | #define THUMB2_EABI_SYSCALL		0xdf00 | 
|  |  | 
|  | /* OABI syscall restart trampoline, used for EABI executables too | 
|  | whenever OABI support has been enabled in the kernel.  */ | 
|  | #define ARM_OABI_SYSCALL_RESTART_SYSCALL 0xef900000 | 
|  | #define ARM_LDR_PC_SP_12		0xe49df00c | 
|  | #define ARM_LDR_PC_SP_4			0xe49df004 | 
|  |  | 
|  | /* Syscall number for sigreturn.  */ | 
|  | #define ARM_SIGRETURN 119 | 
|  | /* Syscall number for rt_sigreturn.  */ | 
|  | #define ARM_RT_SIGRETURN 173 | 
|  |  | 
|  | static CORE_ADDR | 
|  | arm_linux_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self); | 
|  |  | 
|  | /* Operation function pointers for get_next_pcs.  */ | 
|  | static struct arm_get_next_pcs_ops arm_linux_get_next_pcs_ops = { | 
|  | arm_get_next_pcs_read_memory_unsigned_integer, | 
|  | arm_linux_get_next_pcs_syscall_next_pc, | 
|  | arm_get_next_pcs_addr_bits_remove, | 
|  | arm_get_next_pcs_is_thumb, | 
|  | arm_linux_get_next_pcs_fixup, | 
|  | }; | 
|  |  | 
|  | static void | 
|  | arm_linux_sigtramp_cache (frame_info_ptr this_frame, | 
|  | struct trad_frame_cache *this_cache, | 
|  | CORE_ADDR func, int regs_offset) | 
|  | { | 
|  | CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); | 
|  | CORE_ADDR base = sp + regs_offset; | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < 16; i++) | 
|  | trad_frame_set_reg_addr (this_cache, i, base + i * 4); | 
|  |  | 
|  | trad_frame_set_reg_addr (this_cache, ARM_PS_REGNUM, base + 16 * 4); | 
|  |  | 
|  | /* The VFP or iWMMXt registers may be saved on the stack, but there's | 
|  | no reliable way to restore them (yet).  */ | 
|  |  | 
|  | /* Save a frame ID.  */ | 
|  | trad_frame_set_id (this_cache, frame_id_build (sp, func)); | 
|  | } | 
|  |  | 
|  | /* See arm-linux.h for stack layout details.  */ | 
|  | static void | 
|  | arm_linux_sigreturn_init (const struct tramp_frame *self, | 
|  | frame_info_ptr this_frame, | 
|  | struct trad_frame_cache *this_cache, | 
|  | CORE_ADDR func) | 
|  | { | 
|  | struct gdbarch *gdbarch = get_frame_arch (this_frame); | 
|  | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
|  | CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); | 
|  | ULONGEST uc_flags = read_memory_unsigned_integer (sp, 4, byte_order); | 
|  |  | 
|  | if (uc_flags == ARM_NEW_SIGFRAME_MAGIC) | 
|  | arm_linux_sigtramp_cache (this_frame, this_cache, func, | 
|  | ARM_UCONTEXT_SIGCONTEXT | 
|  | + ARM_SIGCONTEXT_R0); | 
|  | else | 
|  | arm_linux_sigtramp_cache (this_frame, this_cache, func, | 
|  | ARM_SIGCONTEXT_R0); | 
|  | } | 
|  |  | 
|  | static void | 
|  | arm_linux_rt_sigreturn_init (const struct tramp_frame *self, | 
|  | frame_info_ptr this_frame, | 
|  | struct trad_frame_cache *this_cache, | 
|  | CORE_ADDR func) | 
|  | { | 
|  | struct gdbarch *gdbarch = get_frame_arch (this_frame); | 
|  | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
|  | CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); | 
|  | ULONGEST pinfo = read_memory_unsigned_integer (sp, 4, byte_order); | 
|  |  | 
|  | if (pinfo == sp + ARM_OLD_RT_SIGFRAME_SIGINFO) | 
|  | arm_linux_sigtramp_cache (this_frame, this_cache, func, | 
|  | ARM_OLD_RT_SIGFRAME_UCONTEXT | 
|  | + ARM_UCONTEXT_SIGCONTEXT | 
|  | + ARM_SIGCONTEXT_R0); | 
|  | else | 
|  | arm_linux_sigtramp_cache (this_frame, this_cache, func, | 
|  | ARM_NEW_RT_SIGFRAME_UCONTEXT | 
|  | + ARM_UCONTEXT_SIGCONTEXT | 
|  | + ARM_SIGCONTEXT_R0); | 
|  | } | 
|  |  | 
|  | static void | 
|  | arm_linux_restart_syscall_init (const struct tramp_frame *self, | 
|  | frame_info_ptr this_frame, | 
|  | struct trad_frame_cache *this_cache, | 
|  | CORE_ADDR func) | 
|  | { | 
|  | struct gdbarch *gdbarch = get_frame_arch (this_frame); | 
|  | CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); | 
|  | CORE_ADDR pc = get_frame_memory_unsigned (this_frame, sp, 4); | 
|  | CORE_ADDR cpsr = get_frame_register_unsigned (this_frame, ARM_PS_REGNUM); | 
|  | ULONGEST t_bit = arm_psr_thumb_bit (gdbarch); | 
|  | int sp_offset; | 
|  |  | 
|  | /* There are two variants of this trampoline; with older kernels, the | 
|  | stub is placed on the stack, while newer kernels use the stub from | 
|  | the vector page.  They are identical except that the older version | 
|  | increments SP by 12 (to skip stored PC and the stub itself), while | 
|  | the newer version increments SP only by 4 (just the stored PC).  */ | 
|  | if (self->insn[1].bytes == ARM_LDR_PC_SP_4) | 
|  | sp_offset = 4; | 
|  | else | 
|  | sp_offset = 12; | 
|  |  | 
|  | /* Update Thumb bit in CPSR.  */ | 
|  | if (pc & 1) | 
|  | cpsr |= t_bit; | 
|  | else | 
|  | cpsr &= ~t_bit; | 
|  |  | 
|  | /* Remove Thumb bit from PC.  */ | 
|  | pc = gdbarch_addr_bits_remove (gdbarch, pc); | 
|  |  | 
|  | /* Save previous register values.  */ | 
|  | trad_frame_set_reg_value (this_cache, ARM_SP_REGNUM, sp + sp_offset); | 
|  | trad_frame_set_reg_value (this_cache, ARM_PC_REGNUM, pc); | 
|  | trad_frame_set_reg_value (this_cache, ARM_PS_REGNUM, cpsr); | 
|  |  | 
|  | /* Save a frame ID.  */ | 
|  | trad_frame_set_id (this_cache, frame_id_build (sp, func)); | 
|  | } | 
|  |  | 
|  | static struct tramp_frame arm_linux_sigreturn_tramp_frame = { | 
|  | SIGTRAMP_FRAME, | 
|  | 4, | 
|  | { | 
|  | { ARM_LINUX_SIGRETURN_INSTR, ULONGEST_MAX }, | 
|  | { TRAMP_SENTINEL_INSN } | 
|  | }, | 
|  | arm_linux_sigreturn_init | 
|  | }; | 
|  |  | 
|  | static struct tramp_frame arm_linux_rt_sigreturn_tramp_frame = { | 
|  | SIGTRAMP_FRAME, | 
|  | 4, | 
|  | { | 
|  | { ARM_LINUX_RT_SIGRETURN_INSTR, ULONGEST_MAX }, | 
|  | { TRAMP_SENTINEL_INSN } | 
|  | }, | 
|  | arm_linux_rt_sigreturn_init | 
|  | }; | 
|  |  | 
|  | static struct tramp_frame arm_eabi_linux_sigreturn_tramp_frame = { | 
|  | SIGTRAMP_FRAME, | 
|  | 4, | 
|  | { | 
|  | { ARM_SET_R7_SIGRETURN, ULONGEST_MAX }, | 
|  | { ARM_EABI_SYSCALL, ULONGEST_MAX }, | 
|  | { TRAMP_SENTINEL_INSN } | 
|  | }, | 
|  | arm_linux_sigreturn_init | 
|  | }; | 
|  |  | 
|  | static struct tramp_frame arm_eabi_linux_rt_sigreturn_tramp_frame = { | 
|  | SIGTRAMP_FRAME, | 
|  | 4, | 
|  | { | 
|  | { ARM_SET_R7_RT_SIGRETURN, ULONGEST_MAX }, | 
|  | { ARM_EABI_SYSCALL, ULONGEST_MAX }, | 
|  | { TRAMP_SENTINEL_INSN } | 
|  | }, | 
|  | arm_linux_rt_sigreturn_init | 
|  | }; | 
|  |  | 
|  | static struct tramp_frame thumb2_eabi_linux_sigreturn_tramp_frame = { | 
|  | SIGTRAMP_FRAME, | 
|  | 2, | 
|  | { | 
|  | { THUMB2_SET_R7_SIGRETURN1, ULONGEST_MAX }, | 
|  | { THUMB2_SET_R7_SIGRETURN2, ULONGEST_MAX }, | 
|  | { THUMB2_EABI_SYSCALL, ULONGEST_MAX }, | 
|  | { TRAMP_SENTINEL_INSN } | 
|  | }, | 
|  | arm_linux_sigreturn_init | 
|  | }; | 
|  |  | 
|  | static struct tramp_frame thumb2_eabi_linux_rt_sigreturn_tramp_frame = { | 
|  | SIGTRAMP_FRAME, | 
|  | 2, | 
|  | { | 
|  | { THUMB2_SET_R7_RT_SIGRETURN1, ULONGEST_MAX }, | 
|  | { THUMB2_SET_R7_RT_SIGRETURN2, ULONGEST_MAX }, | 
|  | { THUMB2_EABI_SYSCALL, ULONGEST_MAX }, | 
|  | { TRAMP_SENTINEL_INSN } | 
|  | }, | 
|  | arm_linux_rt_sigreturn_init | 
|  | }; | 
|  |  | 
|  | static struct tramp_frame arm_linux_restart_syscall_tramp_frame = { | 
|  | NORMAL_FRAME, | 
|  | 4, | 
|  | { | 
|  | { ARM_OABI_SYSCALL_RESTART_SYSCALL, ULONGEST_MAX }, | 
|  | { ARM_LDR_PC_SP_12, ULONGEST_MAX }, | 
|  | { TRAMP_SENTINEL_INSN } | 
|  | }, | 
|  | arm_linux_restart_syscall_init | 
|  | }; | 
|  |  | 
|  | static struct tramp_frame arm_kernel_linux_restart_syscall_tramp_frame = { | 
|  | NORMAL_FRAME, | 
|  | 4, | 
|  | { | 
|  | { ARM_OABI_SYSCALL_RESTART_SYSCALL, ULONGEST_MAX }, | 
|  | { ARM_LDR_PC_SP_4, ULONGEST_MAX }, | 
|  | { TRAMP_SENTINEL_INSN } | 
|  | }, | 
|  | arm_linux_restart_syscall_init | 
|  | }; | 
|  |  | 
|  | /* Core file and register set support.  */ | 
|  |  | 
|  | #define ARM_LINUX_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE) | 
|  |  | 
|  | void | 
|  | arm_linux_supply_gregset (const struct regset *regset, | 
|  | struct regcache *regcache, | 
|  | int regnum, const void *gregs_buf, size_t len) | 
|  | { | 
|  | struct gdbarch *gdbarch = regcache->arch (); | 
|  | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
|  | const gdb_byte *gregs = (const gdb_byte *) gregs_buf; | 
|  | int regno; | 
|  | CORE_ADDR reg_pc; | 
|  | gdb_byte pc_buf[ARM_INT_REGISTER_SIZE]; | 
|  |  | 
|  | for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) | 
|  | if (regnum == -1 || regnum == regno) | 
|  | regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno); | 
|  |  | 
|  | if (regnum == ARM_PS_REGNUM || regnum == -1) | 
|  | { | 
|  | if (arm_apcs_32) | 
|  | regcache->raw_supply (ARM_PS_REGNUM, | 
|  | gregs + ARM_INT_REGISTER_SIZE * ARM_CPSR_GREGNUM); | 
|  | else | 
|  | regcache->raw_supply (ARM_PS_REGNUM, | 
|  | gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM); | 
|  | } | 
|  |  | 
|  | if (regnum == ARM_PC_REGNUM || regnum == -1) | 
|  | { | 
|  | reg_pc = extract_unsigned_integer ( | 
|  | gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM, | 
|  | ARM_INT_REGISTER_SIZE, byte_order); | 
|  | reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc); | 
|  | store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order, | 
|  | reg_pc); | 
|  | regcache->raw_supply (ARM_PC_REGNUM, pc_buf); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | arm_linux_collect_gregset (const struct regset *regset, | 
|  | const struct regcache *regcache, | 
|  | int regnum, void *gregs_buf, size_t len) | 
|  | { | 
|  | gdb_byte *gregs = (gdb_byte *) gregs_buf; | 
|  | int regno; | 
|  |  | 
|  | for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) | 
|  | if (regnum == -1 || regnum == regno) | 
|  | regcache->raw_collect (regno, | 
|  | gregs + ARM_INT_REGISTER_SIZE * regno); | 
|  |  | 
|  | if (regnum == ARM_PS_REGNUM || regnum == -1) | 
|  | { | 
|  | if (arm_apcs_32) | 
|  | regcache->raw_collect (ARM_PS_REGNUM, | 
|  | gregs + ARM_INT_REGISTER_SIZE * ARM_CPSR_GREGNUM); | 
|  | else | 
|  | regcache->raw_collect (ARM_PS_REGNUM, | 
|  | gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM); | 
|  | } | 
|  |  | 
|  | if (regnum == ARM_PC_REGNUM || regnum == -1) | 
|  | regcache->raw_collect (ARM_PC_REGNUM, | 
|  | gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM); | 
|  | } | 
|  |  | 
|  | /* Support for register format used by the NWFPE FPA emulator.  */ | 
|  |  | 
|  | #define typeNone		0x00 | 
|  | #define typeSingle		0x01 | 
|  | #define typeDouble		0x02 | 
|  | #define typeExtended		0x03 | 
|  |  | 
|  | void | 
|  | supply_nwfpe_register (struct regcache *regcache, int regno, | 
|  | const gdb_byte *regs) | 
|  | { | 
|  | const gdb_byte *reg_data; | 
|  | gdb_byte reg_tag; | 
|  | gdb_byte buf[ARM_FP_REGISTER_SIZE]; | 
|  |  | 
|  | reg_data = regs + (regno - ARM_F0_REGNUM) * ARM_FP_REGISTER_SIZE; | 
|  | reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET]; | 
|  | memset (buf, 0, ARM_FP_REGISTER_SIZE); | 
|  |  | 
|  | switch (reg_tag) | 
|  | { | 
|  | case typeSingle: | 
|  | memcpy (buf, reg_data, 4); | 
|  | break; | 
|  | case typeDouble: | 
|  | memcpy (buf, reg_data + 4, 4); | 
|  | memcpy (buf + 4, reg_data, 4); | 
|  | break; | 
|  | case typeExtended: | 
|  | /* We want sign and exponent, then least significant bits, | 
|  | then most significant.  NWFPE does sign, most, least.  */ | 
|  | memcpy (buf, reg_data, 4); | 
|  | memcpy (buf + 4, reg_data + 8, 4); | 
|  | memcpy (buf + 8, reg_data + 4, 4); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | regcache->raw_supply (regno, buf); | 
|  | } | 
|  |  | 
|  | void | 
|  | collect_nwfpe_register (const struct regcache *regcache, int regno, | 
|  | gdb_byte *regs) | 
|  | { | 
|  | gdb_byte *reg_data; | 
|  | gdb_byte reg_tag; | 
|  | gdb_byte buf[ARM_FP_REGISTER_SIZE]; | 
|  |  | 
|  | regcache->raw_collect (regno, buf); | 
|  |  | 
|  | /* NOTE drow/2006-06-07: This code uses the tag already in the | 
|  | register buffer.  I've preserved that when moving the code | 
|  | from the native file to the target file.  But this doesn't | 
|  | always make sense.  */ | 
|  |  | 
|  | reg_data = regs + (regno - ARM_F0_REGNUM) * ARM_FP_REGISTER_SIZE; | 
|  | reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET]; | 
|  |  | 
|  | switch (reg_tag) | 
|  | { | 
|  | case typeSingle: | 
|  | memcpy (reg_data, buf, 4); | 
|  | break; | 
|  | case typeDouble: | 
|  | memcpy (reg_data, buf + 4, 4); | 
|  | memcpy (reg_data + 4, buf, 4); | 
|  | break; | 
|  | case typeExtended: | 
|  | memcpy (reg_data, buf, 4); | 
|  | memcpy (reg_data + 4, buf + 8, 4); | 
|  | memcpy (reg_data + 8, buf + 4, 4); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | arm_linux_supply_nwfpe (const struct regset *regset, | 
|  | struct regcache *regcache, | 
|  | int regnum, const void *regs_buf, size_t len) | 
|  | { | 
|  | const gdb_byte *regs = (const gdb_byte *) regs_buf; | 
|  | int regno; | 
|  |  | 
|  | if (regnum == ARM_FPS_REGNUM || regnum == -1) | 
|  | regcache->raw_supply (ARM_FPS_REGNUM, | 
|  | regs + NWFPE_FPSR_OFFSET); | 
|  |  | 
|  | for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) | 
|  | if (regnum == -1 || regnum == regno) | 
|  | supply_nwfpe_register (regcache, regno, regs); | 
|  | } | 
|  |  | 
|  | void | 
|  | arm_linux_collect_nwfpe (const struct regset *regset, | 
|  | const struct regcache *regcache, | 
|  | int regnum, void *regs_buf, size_t len) | 
|  | { | 
|  | gdb_byte *regs = (gdb_byte *) regs_buf; | 
|  | int regno; | 
|  |  | 
|  | for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) | 
|  | if (regnum == -1 || regnum == regno) | 
|  | collect_nwfpe_register (regcache, regno, regs); | 
|  |  | 
|  | if (regnum == ARM_FPS_REGNUM || regnum == -1) | 
|  | regcache->raw_collect (ARM_FPS_REGNUM, | 
|  | regs + ARM_INT_REGISTER_SIZE * ARM_FPS_REGNUM); | 
|  | } | 
|  |  | 
|  | /* Support VFP register format.  */ | 
|  |  | 
|  | #define ARM_LINUX_SIZEOF_VFP (32 * 8 + 4) | 
|  |  | 
|  | static void | 
|  | arm_linux_supply_vfp (const struct regset *regset, | 
|  | struct regcache *regcache, | 
|  | int regnum, const void *regs_buf, size_t len) | 
|  | { | 
|  | const gdb_byte *regs = (const gdb_byte *) regs_buf; | 
|  | int regno; | 
|  |  | 
|  | if (regnum == ARM_FPSCR_REGNUM || regnum == -1) | 
|  | regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8); | 
|  |  | 
|  | for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++) | 
|  | if (regnum == -1 || regnum == regno) | 
|  | regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8); | 
|  | } | 
|  |  | 
|  | static void | 
|  | arm_linux_collect_vfp (const struct regset *regset, | 
|  | const struct regcache *regcache, | 
|  | int regnum, void *regs_buf, size_t len) | 
|  | { | 
|  | gdb_byte *regs = (gdb_byte *) regs_buf; | 
|  | int regno; | 
|  |  | 
|  | if (regnum == ARM_FPSCR_REGNUM || regnum == -1) | 
|  | regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8); | 
|  |  | 
|  | for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++) | 
|  | if (regnum == -1 || regnum == regno) | 
|  | regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8); | 
|  | } | 
|  |  | 
|  | static const struct regset arm_linux_gregset = | 
|  | { | 
|  | NULL, arm_linux_supply_gregset, arm_linux_collect_gregset | 
|  | }; | 
|  |  | 
|  | static const struct regset arm_linux_fpregset = | 
|  | { | 
|  | NULL, arm_linux_supply_nwfpe, arm_linux_collect_nwfpe | 
|  | }; | 
|  |  | 
|  | static const struct regset arm_linux_vfpregset = | 
|  | { | 
|  | NULL, arm_linux_supply_vfp, arm_linux_collect_vfp | 
|  | }; | 
|  |  | 
|  | /* Iterate over core file register note sections.  */ | 
|  |  | 
|  | static void | 
|  | arm_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, | 
|  | iterate_over_regset_sections_cb *cb, | 
|  | void *cb_data, | 
|  | const struct regcache *regcache) | 
|  | { | 
|  | arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); | 
|  |  | 
|  | cb (".reg", ARM_LINUX_SIZEOF_GREGSET, ARM_LINUX_SIZEOF_GREGSET, | 
|  | &arm_linux_gregset, NULL, cb_data); | 
|  |  | 
|  | if (tdep->vfp_register_count > 0) | 
|  | cb (".reg-arm-vfp", ARM_LINUX_SIZEOF_VFP, ARM_LINUX_SIZEOF_VFP, | 
|  | &arm_linux_vfpregset, "VFP floating-point", cb_data); | 
|  | else if (tdep->have_fpa_registers) | 
|  | cb (".reg2", ARM_LINUX_SIZEOF_NWFPE, ARM_LINUX_SIZEOF_NWFPE, | 
|  | &arm_linux_fpregset, "FPA floating-point", cb_data); | 
|  | } | 
|  |  | 
|  | /* Determine target description from core file.  */ | 
|  |  | 
|  | static const struct target_desc * | 
|  | arm_linux_core_read_description (struct gdbarch *gdbarch, | 
|  | struct target_ops *target, | 
|  | bfd *abfd) | 
|  | { | 
|  | gdb::optional<gdb::byte_vector> auxv = target_read_auxv_raw (target); | 
|  | CORE_ADDR arm_hwcap = linux_get_hwcap (auxv, target, gdbarch); | 
|  |  | 
|  | if (arm_hwcap & HWCAP_VFP) | 
|  | { | 
|  | /* NEON implies VFPv3-D32 or no-VFP unit.  Say that we only support | 
|  | Neon with VFPv3-D32.  */ | 
|  | if (arm_hwcap & HWCAP_NEON) | 
|  | return aarch32_read_description (); | 
|  | else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) | 
|  | return arm_read_description (ARM_FP_TYPE_VFPV3, false); | 
|  |  | 
|  | return arm_read_description (ARM_FP_TYPE_VFPV2, false); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Copy the value of next pc of sigreturn and rt_sigrturn into PC, | 
|  | return 1.  In addition, set IS_THUMB depending on whether we | 
|  | will return to ARM or Thumb code.  Return 0 if it is not a | 
|  | rt_sigreturn/sigreturn syscall.  */ | 
|  | static int | 
|  | arm_linux_sigreturn_return_addr (frame_info_ptr frame, | 
|  | unsigned long svc_number, | 
|  | CORE_ADDR *pc, int *is_thumb) | 
|  | { | 
|  | /* Is this a sigreturn or rt_sigreturn syscall?  */ | 
|  | if (svc_number == 119 || svc_number == 173) | 
|  | { | 
|  | if (get_frame_type (frame) == SIGTRAMP_FRAME) | 
|  | { | 
|  | ULONGEST t_bit = arm_psr_thumb_bit (frame_unwind_arch (frame)); | 
|  | CORE_ADDR cpsr | 
|  | = frame_unwind_register_unsigned (frame, ARM_PS_REGNUM); | 
|  |  | 
|  | *is_thumb = (cpsr & t_bit) != 0; | 
|  | *pc = frame_unwind_caller_pc (frame); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Find the value of the next PC after a sigreturn or rt_sigreturn syscall | 
|  | based on current processor state.  In addition, set IS_THUMB depending | 
|  | on whether we will return to ARM or Thumb code.  */ | 
|  |  | 
|  | static CORE_ADDR | 
|  | arm_linux_sigreturn_next_pc (struct regcache *regcache, | 
|  | unsigned long svc_number, int *is_thumb) | 
|  | { | 
|  | ULONGEST sp; | 
|  | unsigned long sp_data; | 
|  | CORE_ADDR next_pc = 0; | 
|  | struct gdbarch *gdbarch = regcache->arch (); | 
|  | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
|  | int pc_offset = 0; | 
|  | int is_sigreturn = 0; | 
|  | CORE_ADDR cpsr; | 
|  |  | 
|  | gdb_assert (svc_number == ARM_SIGRETURN | 
|  | || svc_number == ARM_RT_SIGRETURN); | 
|  |  | 
|  | is_sigreturn = (svc_number == ARM_SIGRETURN); | 
|  | regcache_cooked_read_unsigned (regcache, ARM_SP_REGNUM, &sp); | 
|  | sp_data = read_memory_unsigned_integer (sp, 4, byte_order); | 
|  |  | 
|  | pc_offset = arm_linux_sigreturn_next_pc_offset (sp, sp_data, svc_number, | 
|  | is_sigreturn); | 
|  |  | 
|  | next_pc = read_memory_unsigned_integer (sp + pc_offset, 4, byte_order); | 
|  |  | 
|  | /* Set IS_THUMB according the CPSR saved on the stack.  */ | 
|  | cpsr = read_memory_unsigned_integer (sp + pc_offset + 4, 4, byte_order); | 
|  | *is_thumb = ((cpsr & arm_psr_thumb_bit (gdbarch)) != 0); | 
|  |  | 
|  | return next_pc; | 
|  | } | 
|  |  | 
|  | /* 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, | 
|  | thread_info *thread) | 
|  | { | 
|  | struct regcache *regs = get_thread_regcache (thread); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | static CORE_ADDR | 
|  | arm_linux_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self) | 
|  | { | 
|  | CORE_ADDR next_pc = 0; | 
|  | CORE_ADDR pc = regcache_read_pc (self->regcache); | 
|  | int is_thumb = arm_is_thumb (self->regcache); | 
|  | ULONGEST svc_number = 0; | 
|  |  | 
|  | if (is_thumb) | 
|  | { | 
|  | svc_number = regcache_raw_get_unsigned (self->regcache, 7); | 
|  | next_pc = pc + 2; | 
|  | } | 
|  | else | 
|  | { | 
|  | struct gdbarch *gdbarch = self->regcache->arch (); | 
|  | enum bfd_endian byte_order_for_code = | 
|  | gdbarch_byte_order_for_code (gdbarch); | 
|  | unsigned long this_instr = | 
|  | read_memory_unsigned_integer (pc, 4, byte_order_for_code); | 
|  |  | 
|  | unsigned long svc_operand = (0x00ffffff & this_instr); | 
|  | if (svc_operand)  /* OABI.  */ | 
|  | { | 
|  | svc_number = svc_operand - 0x900000; | 
|  | } | 
|  | else /* EABI.  */ | 
|  | { | 
|  | svc_number = regcache_raw_get_unsigned (self->regcache, 7); | 
|  | } | 
|  |  | 
|  | next_pc = pc + 4; | 
|  | } | 
|  |  | 
|  | if (svc_number == ARM_SIGRETURN || svc_number == ARM_RT_SIGRETURN) | 
|  | { | 
|  | /* SIGRETURN or RT_SIGRETURN may affect the arm thumb mode, so | 
|  | update IS_THUMB.   */ | 
|  | next_pc = arm_linux_sigreturn_next_pc (self->regcache, svc_number, | 
|  | &is_thumb); | 
|  | } | 
|  |  | 
|  | /* Addresses for calling Thumb functions have the bit 0 set.  */ | 
|  | if (is_thumb) | 
|  | next_pc = MAKE_THUMB_ADDR (next_pc); | 
|  |  | 
|  | return next_pc; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Insert a single step breakpoint at the next executed instruction.  */ | 
|  |  | 
|  | static std::vector<CORE_ADDR> | 
|  | arm_linux_software_single_step (struct regcache *regcache) | 
|  | { | 
|  | struct gdbarch *gdbarch = regcache->arch (); | 
|  | struct arm_get_next_pcs next_pcs_ctx; | 
|  |  | 
|  | /* If the target does have hardware single step, GDB doesn't have | 
|  | to bother software single step.  */ | 
|  | if (target_can_do_single_step () == 1) | 
|  | return {}; | 
|  |  | 
|  | arm_get_next_pcs_ctor (&next_pcs_ctx, | 
|  | &arm_linux_get_next_pcs_ops, | 
|  | gdbarch_byte_order (gdbarch), | 
|  | gdbarch_byte_order_for_code (gdbarch), | 
|  | 1, | 
|  | regcache); | 
|  |  | 
|  | std::vector<CORE_ADDR> next_pcs = arm_get_next_pcs (&next_pcs_ctx); | 
|  |  | 
|  | for (CORE_ADDR &pc_ref : next_pcs) | 
|  | pc_ref = gdbarch_addr_bits_remove (gdbarch, pc_ref); | 
|  |  | 
|  | return next_pcs; | 
|  | } | 
|  |  | 
|  | /* Support for displaced stepping of Linux SVC instructions.  */ | 
|  |  | 
|  | static void | 
|  | arm_linux_cleanup_svc (struct gdbarch *gdbarch, | 
|  | struct regcache *regs, | 
|  | arm_displaced_step_copy_insn_closure *dsc) | 
|  | { | 
|  | ULONGEST apparent_pc; | 
|  | int within_scratch; | 
|  |  | 
|  | regcache_cooked_read_unsigned (regs, ARM_PC_REGNUM, &apparent_pc); | 
|  |  | 
|  | within_scratch = (apparent_pc >= dsc->scratch_base | 
|  | && apparent_pc < (dsc->scratch_base | 
|  | + ARM_DISPLACED_MODIFIED_INSNS * 4 + 4)); | 
|  |  | 
|  | displaced_debug_printf ("PC is apparently %.8lx after SVC step %s", | 
|  | (unsigned long) apparent_pc, | 
|  | (within_scratch | 
|  | ? "(within scratch space)" | 
|  | : "(outside scratch space)")); | 
|  |  | 
|  | if (within_scratch) | 
|  | displaced_write_reg (regs, dsc, ARM_PC_REGNUM, | 
|  | dsc->insn_addr + dsc->insn_size, BRANCH_WRITE_PC); | 
|  | } | 
|  |  | 
|  | static int | 
|  | arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs, | 
|  | arm_displaced_step_copy_insn_closure *dsc) | 
|  | { | 
|  | CORE_ADDR return_to = 0; | 
|  |  | 
|  | frame_info_ptr frame; | 
|  | unsigned int svc_number = displaced_read_reg (regs, dsc, 7); | 
|  | int is_sigreturn = 0; | 
|  | int is_thumb; | 
|  |  | 
|  | frame = get_current_frame (); | 
|  |  | 
|  | is_sigreturn = arm_linux_sigreturn_return_addr(frame, svc_number, | 
|  | &return_to, &is_thumb); | 
|  | if (is_sigreturn) | 
|  | { | 
|  | struct symtab_and_line sal; | 
|  |  | 
|  | displaced_debug_printf ("found sigreturn/rt_sigreturn SVC call.  " | 
|  | "PC in frame = %lx", | 
|  | (unsigned long) get_frame_pc (frame)); | 
|  |  | 
|  | displaced_debug_printf ("unwind pc = %lx.  Setting momentary breakpoint.", | 
|  | (unsigned long) return_to); | 
|  |  | 
|  | gdb_assert (inferior_thread ()->control.step_resume_breakpoint | 
|  | == NULL); | 
|  |  | 
|  | sal = find_pc_line (return_to, 0); | 
|  | sal.pc = return_to; | 
|  | sal.section = find_pc_overlay (return_to); | 
|  | sal.explicit_pc = 1; | 
|  |  | 
|  | frame = get_prev_frame (frame); | 
|  |  | 
|  | if (frame) | 
|  | { | 
|  | inferior_thread ()->control.step_resume_breakpoint | 
|  | = set_momentary_breakpoint (gdbarch, sal, get_frame_id (frame), | 
|  | bp_step_resume).release (); | 
|  |  | 
|  | /* set_momentary_breakpoint invalidates FRAME.  */ | 
|  | frame = NULL; | 
|  |  | 
|  | /* We need to make sure we actually insert the momentary | 
|  | breakpoint set above.  */ | 
|  | insert_breakpoints (); | 
|  | } | 
|  | else | 
|  | displaced_debug_printf ("couldn't find previous frame to set momentary " | 
|  | "breakpoint for sigreturn/rt_sigreturn"); | 
|  | } | 
|  | else | 
|  | displaced_debug_printf ("found SVC call"); | 
|  |  | 
|  | /* Preparation: If we detect sigreturn, set momentary breakpoint at resume | 
|  | location, else nothing. | 
|  | Insn: unmodified svc. | 
|  | Cleanup: if pc lands in scratch space, pc <- insn_addr + insn_size | 
|  | else leave pc alone.  */ | 
|  |  | 
|  |  | 
|  | dsc->cleanup = &arm_linux_cleanup_svc; | 
|  | /* Pretend we wrote to the PC, so cleanup doesn't set PC to the next | 
|  | instruction.  */ | 
|  | dsc->wrote_to_pc = 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* The following two functions implement single-stepping over calls to Linux | 
|  | kernel helper routines, which perform e.g. atomic operations on architecture | 
|  | variants which don't support them natively. | 
|  |  | 
|  | When this function is called, the PC will be pointing at the kernel helper | 
|  | (at an address inaccessible to GDB), and r14 will point to the return | 
|  | address.  Displaced stepping always executes code in the copy area: | 
|  | so, make the copy-area instruction branch back to the kernel helper (the | 
|  | "from" address), and make r14 point to the breakpoint in the copy area.  In | 
|  | that way, we regain control once the kernel helper returns, and can clean | 
|  | up appropriately (as if we had just returned from the kernel helper as it | 
|  | would have been called from the non-displaced location).  */ | 
|  |  | 
|  | static void | 
|  | cleanup_kernel_helper_return (struct gdbarch *gdbarch, | 
|  | struct regcache *regs, | 
|  | arm_displaced_step_copy_insn_closure *dsc) | 
|  | { | 
|  | displaced_write_reg (regs, dsc, ARM_LR_REGNUM, dsc->tmp[0], CANNOT_WRITE_PC); | 
|  | displaced_write_reg (regs, dsc, ARM_PC_REGNUM, dsc->tmp[0], BRANCH_WRITE_PC); | 
|  | } | 
|  |  | 
|  | static void | 
|  | arm_catch_kernel_helper_return (struct gdbarch *gdbarch, CORE_ADDR from, | 
|  | CORE_ADDR to, struct regcache *regs, | 
|  | arm_displaced_step_copy_insn_closure *dsc) | 
|  | { | 
|  | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
|  |  | 
|  | dsc->numinsns = 1; | 
|  | dsc->insn_addr = from; | 
|  | dsc->cleanup = &cleanup_kernel_helper_return; | 
|  | /* Say we wrote to the PC, else cleanup will set PC to the next | 
|  | instruction in the helper, which isn't helpful.  */ | 
|  | dsc->wrote_to_pc = 1; | 
|  |  | 
|  | /* Preparation: tmp[0] <- r14 | 
|  | r14 <- <scratch space>+4 | 
|  | *(<scratch space>+8) <- from | 
|  | Insn: ldr pc, [r14, #4] | 
|  | Cleanup: r14 <- tmp[0], pc <- tmp[0].  */ | 
|  |  | 
|  | dsc->tmp[0] = displaced_read_reg (regs, dsc, ARM_LR_REGNUM); | 
|  | displaced_write_reg (regs, dsc, ARM_LR_REGNUM, (ULONGEST) to + 4, | 
|  | CANNOT_WRITE_PC); | 
|  | write_memory_unsigned_integer (to + 8, 4, byte_order, from); | 
|  |  | 
|  | dsc->modinsn[0] = 0xe59ef004;  /* ldr pc, [lr, #4].  */ | 
|  | } | 
|  |  | 
|  | /* Linux-specific displaced step instruction copying function.  Detects when | 
|  | the program has stepped into a Linux kernel helper routine (which must be | 
|  | handled as a special case).  */ | 
|  |  | 
|  | static displaced_step_copy_insn_closure_up | 
|  | arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch, | 
|  | CORE_ADDR from, CORE_ADDR to, | 
|  | struct regcache *regs) | 
|  | { | 
|  | std::unique_ptr<arm_displaced_step_copy_insn_closure> dsc | 
|  | (new arm_displaced_step_copy_insn_closure); | 
|  |  | 
|  | /* Detect when we enter an (inaccessible by GDB) Linux kernel helper, and | 
|  | stop at the return location.  */ | 
|  | if (from > 0xffff0000) | 
|  | { | 
|  | displaced_debug_printf ("detected kernel helper at %.8lx", | 
|  | (unsigned long) from); | 
|  |  | 
|  | arm_catch_kernel_helper_return (gdbarch, from, to, regs, dsc.get ()); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Override the default handling of SVC instructions.  */ | 
|  | dsc->u.svc.copy_svc_os = arm_linux_copy_svc; | 
|  |  | 
|  | arm_process_displaced_insn (gdbarch, from, to, regs, dsc.get ()); | 
|  | } | 
|  |  | 
|  | arm_displaced_init_closure (gdbarch, from, to, dsc.get ()); | 
|  |  | 
|  | /* This is a work around for a problem with g++ 4.8.  */ | 
|  | return displaced_step_copy_insn_closure_up (dsc.release ()); | 
|  | } | 
|  |  | 
|  | /* Implementation of `gdbarch_stap_is_single_operand', as defined in | 
|  | gdbarch.h.  */ | 
|  |  | 
|  | static int | 
|  | arm_stap_is_single_operand (struct gdbarch *gdbarch, const char *s) | 
|  | { | 
|  | return (*s == '#' || *s == '$' || isdigit (*s) /* Literal number.  */ | 
|  | || *s == '[' /* Register indirection or | 
|  | displacement.  */ | 
|  | || isalpha (*s)); /* Register value.  */ | 
|  | } | 
|  |  | 
|  | /* This routine is used to parse a special token in ARM's assembly. | 
|  |  | 
|  | The special tokens parsed by it are: | 
|  |  | 
|  | - Register displacement (e.g, [fp, #-8]) | 
|  |  | 
|  | It returns one if the special token has been parsed successfully, | 
|  | or zero if the current token is not considered special.  */ | 
|  |  | 
|  | static expr::operation_up | 
|  | arm_stap_parse_special_token (struct gdbarch *gdbarch, | 
|  | struct stap_parse_info *p) | 
|  | { | 
|  | if (*p->arg == '[') | 
|  | { | 
|  | /* Temporary holder for lookahead.  */ | 
|  | const char *tmp = p->arg; | 
|  | char *endp; | 
|  | /* Used to save the register name.  */ | 
|  | const char *start; | 
|  | char *regname; | 
|  | int len, offset; | 
|  | int got_minus = 0; | 
|  | long displacement; | 
|  |  | 
|  | ++tmp; | 
|  | start = tmp; | 
|  |  | 
|  | /* Register name.  */ | 
|  | while (isalnum (*tmp)) | 
|  | ++tmp; | 
|  |  | 
|  | if (*tmp != ',') | 
|  | return {}; | 
|  |  | 
|  | len = tmp - start; | 
|  | regname = (char *) alloca (len + 2); | 
|  |  | 
|  | offset = 0; | 
|  | if (isdigit (*start)) | 
|  | { | 
|  | /* If we are dealing with a register whose name begins with a | 
|  | digit, it means we should prefix the name with the letter | 
|  | `r', because GDB expects this name pattern.  Otherwise (e.g., | 
|  | we are dealing with the register `fp'), we don't need to | 
|  | add such a prefix.  */ | 
|  | regname[0] = 'r'; | 
|  | offset = 1; | 
|  | } | 
|  |  | 
|  | strncpy (regname + offset, start, len); | 
|  | len += offset; | 
|  | regname[len] = '\0'; | 
|  |  | 
|  | if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1) | 
|  | error (_("Invalid register name `%s' on expression `%s'."), | 
|  | regname, p->saved_arg); | 
|  |  | 
|  | ++tmp; | 
|  | tmp = skip_spaces (tmp); | 
|  | if (*tmp == '#' || *tmp == '$') | 
|  | ++tmp; | 
|  |  | 
|  | if (*tmp == '-') | 
|  | { | 
|  | ++tmp; | 
|  | got_minus = 1; | 
|  | } | 
|  |  | 
|  | displacement = strtol (tmp, &endp, 10); | 
|  | tmp = endp; | 
|  |  | 
|  | /* Skipping last `]'.  */ | 
|  | if (*tmp++ != ']') | 
|  | return {}; | 
|  | p->arg = tmp; | 
|  |  | 
|  | using namespace expr; | 
|  |  | 
|  | /* The displacement.  */ | 
|  | struct type *long_type = builtin_type (gdbarch)->builtin_long; | 
|  | if (got_minus) | 
|  | displacement = -displacement; | 
|  | operation_up disp = make_operation<long_const_operation> (long_type, | 
|  | displacement); | 
|  |  | 
|  | /* The register name.  */ | 
|  | operation_up reg | 
|  | = make_operation<register_operation> (regname); | 
|  |  | 
|  | operation_up sum | 
|  | = make_operation<add_operation> (std::move (reg), std::move (disp)); | 
|  |  | 
|  | /* Casting to the expected type.  */ | 
|  | struct type *arg_ptr_type = lookup_pointer_type (p->arg_type); | 
|  | sum = make_operation<unop_cast_operation> (std::move (sum), | 
|  | arg_ptr_type); | 
|  | return make_operation<unop_ind_operation> (std::move (sum)); | 
|  | } | 
|  |  | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | /* ARM process record-replay constructs: syscall, signal etc.  */ | 
|  |  | 
|  | static linux_record_tdep arm_linux_record_tdep; | 
|  |  | 
|  | /* arm_canonicalize_syscall maps from the native arm Linux set | 
|  | of syscall ids into a canonical set of syscall ids used by | 
|  | process record.  */ | 
|  |  | 
|  | static enum gdb_syscall | 
|  | arm_canonicalize_syscall (int syscall) | 
|  | { | 
|  | switch (syscall) | 
|  | { | 
|  | case 0: return gdb_sys_restart_syscall; | 
|  | case 1: return gdb_sys_exit; | 
|  | case 2: return gdb_sys_fork; | 
|  | case 3: return gdb_sys_read; | 
|  | case 4: return gdb_sys_write; | 
|  | case 5: return gdb_sys_open; | 
|  | case 6: return gdb_sys_close; | 
|  | case 8: return gdb_sys_creat; | 
|  | case 9: return gdb_sys_link; | 
|  | case 10: return gdb_sys_unlink; | 
|  | case 11: return gdb_sys_execve; | 
|  | case 12: return gdb_sys_chdir; | 
|  | case 13: return gdb_sys_time; | 
|  | case 14: return gdb_sys_mknod; | 
|  | case 15: return gdb_sys_chmod; | 
|  | case 16: return gdb_sys_lchown16; | 
|  | case 19: return gdb_sys_lseek; | 
|  | case 20: return gdb_sys_getpid; | 
|  | case 21: return gdb_sys_mount; | 
|  | case 22: return gdb_sys_oldumount; | 
|  | case 23: return gdb_sys_setuid16; | 
|  | case 24: return gdb_sys_getuid16; | 
|  | case 25: return gdb_sys_stime; | 
|  | case 26: return gdb_sys_ptrace; | 
|  | case 27: return gdb_sys_alarm; | 
|  | case 29: return gdb_sys_pause; | 
|  | case 30: return gdb_sys_utime; | 
|  | case 33: return gdb_sys_access; | 
|  | case 34: return gdb_sys_nice; | 
|  | case 36: return gdb_sys_sync; | 
|  | case 37: return gdb_sys_kill; | 
|  | case 38: return gdb_sys_rename; | 
|  | case 39: return gdb_sys_mkdir; | 
|  | case 40: return gdb_sys_rmdir; | 
|  | case 41: return gdb_sys_dup; | 
|  | case 42: return gdb_sys_pipe; | 
|  | case 43: return gdb_sys_times; | 
|  | case 45: return gdb_sys_brk; | 
|  | case 46: return gdb_sys_setgid16; | 
|  | case 47: return gdb_sys_getgid16; | 
|  | case 49: return gdb_sys_geteuid16; | 
|  | case 50: return gdb_sys_getegid16; | 
|  | case 51: return gdb_sys_acct; | 
|  | case 52: return gdb_sys_umount; | 
|  | case 54: return gdb_sys_ioctl; | 
|  | case 55: return gdb_sys_fcntl; | 
|  | case 57: return gdb_sys_setpgid; | 
|  | case 60: return gdb_sys_umask; | 
|  | case 61: return gdb_sys_chroot; | 
|  | case 62: return gdb_sys_ustat; | 
|  | case 63: return gdb_sys_dup2; | 
|  | case 64: return gdb_sys_getppid; | 
|  | case 65: return gdb_sys_getpgrp; | 
|  | case 66: return gdb_sys_setsid; | 
|  | case 67: return gdb_sys_sigaction; | 
|  | case 70: return gdb_sys_setreuid16; | 
|  | case 71: return gdb_sys_setregid16; | 
|  | case 72: return gdb_sys_sigsuspend; | 
|  | case 73: return gdb_sys_sigpending; | 
|  | case 74: return gdb_sys_sethostname; | 
|  | case 75: return gdb_sys_setrlimit; | 
|  | case 76: return gdb_sys_getrlimit; | 
|  | case 77: return gdb_sys_getrusage; | 
|  | case 78: return gdb_sys_gettimeofday; | 
|  | case 79: return gdb_sys_settimeofday; | 
|  | case 80: return gdb_sys_getgroups16; | 
|  | case 81: return gdb_sys_setgroups16; | 
|  | case 82: return gdb_sys_select; | 
|  | case 83: return gdb_sys_symlink; | 
|  | case 85: return gdb_sys_readlink; | 
|  | case 86: return gdb_sys_uselib; | 
|  | case 87: return gdb_sys_swapon; | 
|  | case 88: return gdb_sys_reboot; | 
|  | case 89: return gdb_old_readdir; | 
|  | case 90: return gdb_old_mmap; | 
|  | case 91: return gdb_sys_munmap; | 
|  | case 92: return gdb_sys_truncate; | 
|  | case 93: return gdb_sys_ftruncate; | 
|  | case 94: return gdb_sys_fchmod; | 
|  | case 95: return gdb_sys_fchown16; | 
|  | case 96: return gdb_sys_getpriority; | 
|  | case 97: return gdb_sys_setpriority; | 
|  | case 99: return gdb_sys_statfs; | 
|  | case 100: return gdb_sys_fstatfs; | 
|  | case 102: return gdb_sys_socketcall; | 
|  | case 103: return gdb_sys_syslog; | 
|  | case 104: return gdb_sys_setitimer; | 
|  | case 105: return gdb_sys_getitimer; | 
|  | case 106: return gdb_sys_stat; | 
|  | case 107: return gdb_sys_lstat; | 
|  | case 108: return gdb_sys_fstat; | 
|  | case 111: return gdb_sys_vhangup; | 
|  | case 113: /* sys_syscall */ | 
|  | return gdb_sys_no_syscall; | 
|  | case 114: return gdb_sys_wait4; | 
|  | case 115: return gdb_sys_swapoff; | 
|  | case 116: return gdb_sys_sysinfo; | 
|  | case 117: return gdb_sys_ipc; | 
|  | case 118: return gdb_sys_fsync; | 
|  | case 119: return gdb_sys_sigreturn; | 
|  | case 120: return gdb_sys_clone; | 
|  | case 121: return gdb_sys_setdomainname; | 
|  | case 122: return gdb_sys_uname; | 
|  | case 124: return gdb_sys_adjtimex; | 
|  | case 125: return gdb_sys_mprotect; | 
|  | case 126: return gdb_sys_sigprocmask; | 
|  | case 128: return gdb_sys_init_module; | 
|  | case 129: return gdb_sys_delete_module; | 
|  | case 131: return gdb_sys_quotactl; | 
|  | case 132: return gdb_sys_getpgid; | 
|  | case 133: return gdb_sys_fchdir; | 
|  | case 134: return gdb_sys_bdflush; | 
|  | case 135: return gdb_sys_sysfs; | 
|  | case 136: return gdb_sys_personality; | 
|  | case 138: return gdb_sys_setfsuid16; | 
|  | case 139: return gdb_sys_setfsgid16; | 
|  | case 140: return gdb_sys_llseek; | 
|  | case 141: return gdb_sys_getdents; | 
|  | case 142: return gdb_sys_select; | 
|  | case 143: return gdb_sys_flock; | 
|  | case 144: return gdb_sys_msync; | 
|  | case 145: return gdb_sys_readv; | 
|  | case 146: return gdb_sys_writev; | 
|  | case 147: return gdb_sys_getsid; | 
|  | case 148: return gdb_sys_fdatasync; | 
|  | case 149: return gdb_sys_sysctl; | 
|  | case 150: return gdb_sys_mlock; | 
|  | case 151: return gdb_sys_munlock; | 
|  | case 152: return gdb_sys_mlockall; | 
|  | case 153: return gdb_sys_munlockall; | 
|  | case 154: return gdb_sys_sched_setparam; | 
|  | case 155: return gdb_sys_sched_getparam; | 
|  | case 156: return gdb_sys_sched_setscheduler; | 
|  | case 157: return gdb_sys_sched_getscheduler; | 
|  | case 158: return gdb_sys_sched_yield; | 
|  | case 159: return gdb_sys_sched_get_priority_max; | 
|  | case 160: return gdb_sys_sched_get_priority_min; | 
|  | case 161: return gdb_sys_sched_rr_get_interval; | 
|  | case 162: return gdb_sys_nanosleep; | 
|  | case 163: return gdb_sys_mremap; | 
|  | case 164: return gdb_sys_setresuid16; | 
|  | case 165: return gdb_sys_getresuid16; | 
|  | case 168: return gdb_sys_poll; | 
|  | case 169: return gdb_sys_nfsservctl; | 
|  | case 170: return gdb_sys_setresgid; | 
|  | case 171: return gdb_sys_getresgid; | 
|  | case 172: return gdb_sys_prctl; | 
|  | case 173: return gdb_sys_rt_sigreturn; | 
|  | case 174: return gdb_sys_rt_sigaction; | 
|  | case 175: return gdb_sys_rt_sigprocmask; | 
|  | case 176: return gdb_sys_rt_sigpending; | 
|  | case 177: return gdb_sys_rt_sigtimedwait; | 
|  | case 178: return gdb_sys_rt_sigqueueinfo; | 
|  | case 179: return gdb_sys_rt_sigsuspend; | 
|  | case 180: return gdb_sys_pread64; | 
|  | case 181: return gdb_sys_pwrite64; | 
|  | case 182: return gdb_sys_chown; | 
|  | case 183: return gdb_sys_getcwd; | 
|  | case 184: return gdb_sys_capget; | 
|  | case 185: return gdb_sys_capset; | 
|  | case 186: return gdb_sys_sigaltstack; | 
|  | case 187: return gdb_sys_sendfile; | 
|  | case 190: return gdb_sys_vfork; | 
|  | case 191: return gdb_sys_getrlimit; | 
|  | case 192: return gdb_sys_mmap2; | 
|  | case 193: return gdb_sys_truncate64; | 
|  | case 194: return gdb_sys_ftruncate64; | 
|  | case 195: return gdb_sys_stat64; | 
|  | case 196: return gdb_sys_lstat64; | 
|  | case 197: return gdb_sys_fstat64; | 
|  | case 198: return gdb_sys_lchown; | 
|  | case 199: return gdb_sys_getuid; | 
|  | case 200: return gdb_sys_getgid; | 
|  | case 201: return gdb_sys_geteuid; | 
|  | case 202: return gdb_sys_getegid; | 
|  | case 203: return gdb_sys_setreuid; | 
|  | case 204: return gdb_sys_setregid; | 
|  | case 205: return gdb_sys_getgroups; | 
|  | case 206: return gdb_sys_setgroups; | 
|  | case 207: return gdb_sys_fchown; | 
|  | case 208: return gdb_sys_setresuid; | 
|  | case 209: return gdb_sys_getresuid; | 
|  | case 210: return gdb_sys_setresgid; | 
|  | case 211: return gdb_sys_getresgid; | 
|  | case 212: return gdb_sys_chown; | 
|  | case 213: return gdb_sys_setuid; | 
|  | case 214: return gdb_sys_setgid; | 
|  | case 215: return gdb_sys_setfsuid; | 
|  | case 216: return gdb_sys_setfsgid; | 
|  | case 217: return gdb_sys_getdents64; | 
|  | case 218: return gdb_sys_pivot_root; | 
|  | case 219: return gdb_sys_mincore; | 
|  | case 220: return gdb_sys_madvise; | 
|  | case 221: return gdb_sys_fcntl64; | 
|  | case 224: return gdb_sys_gettid; | 
|  | case 225: return gdb_sys_readahead; | 
|  | case 226: return gdb_sys_setxattr; | 
|  | case 227: return gdb_sys_lsetxattr; | 
|  | case 228: return gdb_sys_fsetxattr; | 
|  | case 229: return gdb_sys_getxattr; | 
|  | case 230: return gdb_sys_lgetxattr; | 
|  | case 231: return gdb_sys_fgetxattr; | 
|  | case 232: return gdb_sys_listxattr; | 
|  | case 233: return gdb_sys_llistxattr; | 
|  | case 234: return gdb_sys_flistxattr; | 
|  | case 235: return gdb_sys_removexattr; | 
|  | case 236: return gdb_sys_lremovexattr; | 
|  | case 237: return gdb_sys_fremovexattr; | 
|  | case 238: return gdb_sys_tkill; | 
|  | case 239: return gdb_sys_sendfile64; | 
|  | case 240: return gdb_sys_futex; | 
|  | case 241: return gdb_sys_sched_setaffinity; | 
|  | case 242: return gdb_sys_sched_getaffinity; | 
|  | case 243: return gdb_sys_io_setup; | 
|  | case 244: return gdb_sys_io_destroy; | 
|  | case 245: return gdb_sys_io_getevents; | 
|  | case 246: return gdb_sys_io_submit; | 
|  | case 247: return gdb_sys_io_cancel; | 
|  | case 248: return gdb_sys_exit_group; | 
|  | case 249: return gdb_sys_lookup_dcookie; | 
|  | case 250: return gdb_sys_epoll_create; | 
|  | case 251: return gdb_sys_epoll_ctl; | 
|  | case 252: return gdb_sys_epoll_wait; | 
|  | case 253: return gdb_sys_remap_file_pages; | 
|  | case 256: return gdb_sys_set_tid_address; | 
|  | case 257: return gdb_sys_timer_create; | 
|  | case 258: return gdb_sys_timer_settime; | 
|  | case 259: return gdb_sys_timer_gettime; | 
|  | case 260: return gdb_sys_timer_getoverrun; | 
|  | case 261: return gdb_sys_timer_delete; | 
|  | case 262: return gdb_sys_clock_settime; | 
|  | case 263: return gdb_sys_clock_gettime; | 
|  | case 264: return gdb_sys_clock_getres; | 
|  | case 265: return gdb_sys_clock_nanosleep; | 
|  | case 266: return gdb_sys_statfs64; | 
|  | case 267: return gdb_sys_fstatfs64; | 
|  | case 268: return gdb_sys_tgkill; | 
|  | case 269: return gdb_sys_utimes; | 
|  | /* | 
|  | case 270: return gdb_sys_arm_fadvise64_64; | 
|  | case 271: return gdb_sys_pciconfig_iobase; | 
|  | case 272: return gdb_sys_pciconfig_read; | 
|  | case 273: return gdb_sys_pciconfig_write; | 
|  | */ | 
|  | case 274: return gdb_sys_mq_open; | 
|  | case 275: return gdb_sys_mq_unlink; | 
|  | case 276: return gdb_sys_mq_timedsend; | 
|  | case 277: return gdb_sys_mq_timedreceive; | 
|  | case 278: return gdb_sys_mq_notify; | 
|  | case 279: return gdb_sys_mq_getsetattr; | 
|  | case 280: return gdb_sys_waitid; | 
|  | case 281: return gdb_sys_socket; | 
|  | case 282: return gdb_sys_bind; | 
|  | case 283: return gdb_sys_connect; | 
|  | case 284: return gdb_sys_listen; | 
|  | case 285: return gdb_sys_accept; | 
|  | case 286: return gdb_sys_getsockname; | 
|  | case 287: return gdb_sys_getpeername; | 
|  | case 288: return gdb_sys_socketpair; | 
|  | case 289: /* send */ return gdb_sys_no_syscall; | 
|  | case 290: return gdb_sys_sendto; | 
|  | case 291: return gdb_sys_recv; | 
|  | case 292: return gdb_sys_recvfrom; | 
|  | case 293: return gdb_sys_shutdown; | 
|  | case 294: return gdb_sys_setsockopt; | 
|  | case 295: return gdb_sys_getsockopt; | 
|  | case 296: return gdb_sys_sendmsg; | 
|  | case 297: return gdb_sys_recvmsg; | 
|  | case 298: return gdb_sys_semop; | 
|  | case 299: return gdb_sys_semget; | 
|  | case 300: return gdb_sys_semctl; | 
|  | case 301: return gdb_sys_msgsnd; | 
|  | case 302: return gdb_sys_msgrcv; | 
|  | case 303: return gdb_sys_msgget; | 
|  | case 304: return gdb_sys_msgctl; | 
|  | case 305: return gdb_sys_shmat; | 
|  | case 306: return gdb_sys_shmdt; | 
|  | case 307: return gdb_sys_shmget; | 
|  | case 308: return gdb_sys_shmctl; | 
|  | case 309: return gdb_sys_add_key; | 
|  | case 310: return gdb_sys_request_key; | 
|  | case 311: return gdb_sys_keyctl; | 
|  | case 312: return gdb_sys_semtimedop; | 
|  | case 313: /* vserver */ return gdb_sys_no_syscall; | 
|  | case 314: return gdb_sys_ioprio_set; | 
|  | case 315: return gdb_sys_ioprio_get; | 
|  | case 316: return gdb_sys_inotify_init; | 
|  | case 317: return gdb_sys_inotify_add_watch; | 
|  | case 318: return gdb_sys_inotify_rm_watch; | 
|  | case 319: return gdb_sys_mbind; | 
|  | case 320: return gdb_sys_get_mempolicy; | 
|  | case 321: return gdb_sys_set_mempolicy; | 
|  | case 322: return gdb_sys_openat; | 
|  | case 323: return gdb_sys_mkdirat; | 
|  | case 324: return gdb_sys_mknodat; | 
|  | case 325: return gdb_sys_fchownat; | 
|  | case 326: return gdb_sys_futimesat; | 
|  | case 327: return gdb_sys_fstatat64; | 
|  | case 328: return gdb_sys_unlinkat; | 
|  | case 329: return gdb_sys_renameat; | 
|  | case 330: return gdb_sys_linkat; | 
|  | case 331: return gdb_sys_symlinkat; | 
|  | case 332: return gdb_sys_readlinkat; | 
|  | case 333: return gdb_sys_fchmodat; | 
|  | case 334: return gdb_sys_faccessat; | 
|  | case 335: return gdb_sys_pselect6; | 
|  | case 336: return gdb_sys_ppoll; | 
|  | case 337: return gdb_sys_unshare; | 
|  | case 338: return gdb_sys_set_robust_list; | 
|  | case 339: return gdb_sys_get_robust_list; | 
|  | case 340: return gdb_sys_splice; | 
|  | /*case 341: return gdb_sys_arm_sync_file_range;*/ | 
|  | case 342: return gdb_sys_tee; | 
|  | case 343: return gdb_sys_vmsplice; | 
|  | case 344: return gdb_sys_move_pages; | 
|  | case 345: return gdb_sys_getcpu; | 
|  | case 346: return gdb_sys_epoll_pwait; | 
|  | case 347: return gdb_sys_kexec_load; | 
|  | /* | 
|  | case 348: return gdb_sys_utimensat; | 
|  | case 349: return gdb_sys_signalfd; | 
|  | case 350: return gdb_sys_timerfd_create; | 
|  | case 351: return gdb_sys_eventfd; | 
|  | */ | 
|  | case 352: return gdb_sys_fallocate; | 
|  | /* | 
|  | case 353: return gdb_sys_timerfd_settime; | 
|  | case 354: return gdb_sys_timerfd_gettime; | 
|  | case 355: return gdb_sys_signalfd4; | 
|  | */ | 
|  | case 356: return gdb_sys_eventfd2; | 
|  | case 357: return gdb_sys_epoll_create1; | 
|  | case 358: return gdb_sys_dup3; | 
|  | case 359: return gdb_sys_pipe2; | 
|  | case 360: return gdb_sys_inotify_init1; | 
|  | /* | 
|  | case 361: return gdb_sys_preadv; | 
|  | case 362: return gdb_sys_pwritev; | 
|  | case 363: return gdb_sys_rt_tgsigqueueinfo; | 
|  | case 364: return gdb_sys_perf_event_open; | 
|  | case 365: return gdb_sys_recvmmsg; | 
|  | case 366: return gdb_sys_accept4; | 
|  | case 367: return gdb_sys_fanotify_init; | 
|  | case 368: return gdb_sys_fanotify_mark; | 
|  | case 369: return gdb_sys_prlimit64; | 
|  | case 370: return gdb_sys_name_to_handle_at; | 
|  | case 371: return gdb_sys_open_by_handle_at; | 
|  | case 372: return gdb_sys_clock_adjtime; | 
|  | case 373: return gdb_sys_syncfs; | 
|  | case 374: return gdb_sys_sendmmsg; | 
|  | case 375: return gdb_sys_setns; | 
|  | case 376: return gdb_sys_process_vm_readv; | 
|  | case 377: return gdb_sys_process_vm_writev; | 
|  | case 378: return gdb_sys_kcmp; | 
|  | case 379: return gdb_sys_finit_module; | 
|  | */ | 
|  | case 384: return gdb_sys_getrandom; | 
|  | case 983041: /* ARM_breakpoint */ return gdb_sys_no_syscall; | 
|  | case 983042: /* ARM_cacheflush */ return gdb_sys_no_syscall; | 
|  | case 983043: /* ARM_usr26 */ return gdb_sys_no_syscall; | 
|  | case 983044: /* ARM_usr32 */ return gdb_sys_no_syscall; | 
|  | case 983045: /* ARM_set_tls */ return gdb_sys_no_syscall; | 
|  | default: return gdb_sys_no_syscall; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Record all registers but PC register for process-record.  */ | 
|  |  | 
|  | static int | 
|  | arm_all_but_pc_registers_record (struct regcache *regcache) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < ARM_PC_REGNUM; i++) | 
|  | { | 
|  | if (record_full_arch_list_add_reg (regcache, ARM_A1_REGNUM + i)) | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (record_full_arch_list_add_reg (regcache, ARM_PS_REGNUM)) | 
|  | return -1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Handler for arm system call instruction recording.  */ | 
|  |  | 
|  | static int | 
|  | arm_linux_syscall_record (struct regcache *regcache, unsigned long svc_number) | 
|  | { | 
|  | int ret = 0; | 
|  | enum gdb_syscall syscall_gdb; | 
|  |  | 
|  | syscall_gdb = arm_canonicalize_syscall (svc_number); | 
|  |  | 
|  | if (syscall_gdb == gdb_sys_no_syscall) | 
|  | { | 
|  | gdb_printf (gdb_stderr, | 
|  | _("Process record and replay target doesn't " | 
|  | "support syscall number %s\n"), | 
|  | plongest (svc_number)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (syscall_gdb == gdb_sys_sigreturn | 
|  | || syscall_gdb == gdb_sys_rt_sigreturn) | 
|  | { | 
|  | if (arm_all_but_pc_registers_record (regcache)) | 
|  | return -1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ret = record_linux_system_call (syscall_gdb, regcache, | 
|  | &arm_linux_record_tdep); | 
|  | if (ret != 0) | 
|  | return ret; | 
|  |  | 
|  | /* Record the return value of the system call.  */ | 
|  | if (record_full_arch_list_add_reg (regcache, ARM_A1_REGNUM)) | 
|  | return -1; | 
|  | /* Record LR.  */ | 
|  | if (record_full_arch_list_add_reg (regcache, ARM_LR_REGNUM)) | 
|  | return -1; | 
|  | /* Record CPSR.  */ | 
|  | if (record_full_arch_list_add_reg (regcache, ARM_PS_REGNUM)) | 
|  | return -1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Implement the skip_trampoline_code gdbarch method.  */ | 
|  |  | 
|  | static CORE_ADDR | 
|  | arm_linux_skip_trampoline_code (frame_info_ptr frame, CORE_ADDR pc) | 
|  | { | 
|  | CORE_ADDR target_pc = arm_skip_stub (frame, pc); | 
|  |  | 
|  | if (target_pc != 0) | 
|  | return target_pc; | 
|  |  | 
|  | return find_solib_trampoline_target (frame, pc); | 
|  | } | 
|  |  | 
|  | /* Implement the gcc_target_options gdbarch method.  */ | 
|  |  | 
|  | static std::string | 
|  | arm_linux_gcc_target_options (struct gdbarch *gdbarch) | 
|  | { | 
|  | /* GCC doesn't know "-m32".  */ | 
|  | return {}; | 
|  | } | 
|  |  | 
|  | static void | 
|  | arm_linux_init_abi (struct gdbarch_info info, | 
|  | struct gdbarch *gdbarch) | 
|  | { | 
|  | static const char *const stap_integer_prefixes[] = { "#", "$", "", NULL }; | 
|  | static const char *const stap_register_prefixes[] = { "r", NULL }; | 
|  | static const char *const stap_register_indirection_prefixes[] = { "[", | 
|  | NULL }; | 
|  | static const char *const stap_register_indirection_suffixes[] = { "]", | 
|  | NULL }; | 
|  | arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch); | 
|  |  | 
|  | linux_init_abi (info, gdbarch, 1); | 
|  |  | 
|  | tdep->lowest_pc = 0x8000; | 
|  | if (info.byte_order_for_code == BFD_ENDIAN_BIG) | 
|  | { | 
|  | if (tdep->arm_abi == ARM_ABI_AAPCS) | 
|  | tdep->arm_breakpoint = eabi_linux_arm_be_breakpoint; | 
|  | else | 
|  | tdep->arm_breakpoint = arm_linux_arm_be_breakpoint; | 
|  | tdep->thumb_breakpoint = arm_linux_thumb_be_breakpoint; | 
|  | tdep->thumb2_breakpoint = arm_linux_thumb2_be_breakpoint; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (tdep->arm_abi == ARM_ABI_AAPCS) | 
|  | tdep->arm_breakpoint = eabi_linux_arm_le_breakpoint; | 
|  | else | 
|  | tdep->arm_breakpoint = arm_linux_arm_le_breakpoint; | 
|  | tdep->thumb_breakpoint = arm_linux_thumb_le_breakpoint; | 
|  | tdep->thumb2_breakpoint = arm_linux_thumb2_le_breakpoint; | 
|  | } | 
|  | tdep->arm_breakpoint_size = sizeof (arm_linux_arm_le_breakpoint); | 
|  | tdep->thumb_breakpoint_size = sizeof (arm_linux_thumb_le_breakpoint); | 
|  | tdep->thumb2_breakpoint_size = sizeof (arm_linux_thumb2_le_breakpoint); | 
|  |  | 
|  | if (tdep->fp_model == ARM_FLOAT_AUTO) | 
|  | tdep->fp_model = ARM_FLOAT_FPA; | 
|  |  | 
|  | switch (tdep->fp_model) | 
|  | { | 
|  | case ARM_FLOAT_FPA: | 
|  | tdep->jb_pc = ARM_LINUX_JB_PC_FPA; | 
|  | break; | 
|  | case ARM_FLOAT_SOFT_FPA: | 
|  | case ARM_FLOAT_SOFT_VFP: | 
|  | case ARM_FLOAT_VFP: | 
|  | tdep->jb_pc = ARM_LINUX_JB_PC_EABI; | 
|  | break; | 
|  | default: | 
|  | internal_error | 
|  | (_("arm_linux_init_abi: Floating point model not supported")); | 
|  | break; | 
|  | } | 
|  | tdep->jb_elt_size = ARM_LINUX_JB_ELEMENT_SIZE; | 
|  |  | 
|  | set_solib_svr4_fetch_link_map_offsets | 
|  | (gdbarch, linux_ilp32_fetch_link_map_offsets); | 
|  |  | 
|  | /* Single stepping.  */ | 
|  | set_gdbarch_software_single_step (gdbarch, arm_linux_software_single_step); | 
|  |  | 
|  | /* Shared library handling.  */ | 
|  | set_gdbarch_skip_trampoline_code (gdbarch, arm_linux_skip_trampoline_code); | 
|  | set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); | 
|  |  | 
|  | /* Enable TLS support.  */ | 
|  | set_gdbarch_fetch_tls_load_module_address (gdbarch, | 
|  | svr4_fetch_objfile_link_map); | 
|  |  | 
|  | tramp_frame_prepend_unwinder (gdbarch, | 
|  | &arm_linux_sigreturn_tramp_frame); | 
|  | tramp_frame_prepend_unwinder (gdbarch, | 
|  | &arm_linux_rt_sigreturn_tramp_frame); | 
|  | tramp_frame_prepend_unwinder (gdbarch, | 
|  | &arm_eabi_linux_sigreturn_tramp_frame); | 
|  | tramp_frame_prepend_unwinder (gdbarch, | 
|  | &arm_eabi_linux_rt_sigreturn_tramp_frame); | 
|  | tramp_frame_prepend_unwinder (gdbarch, | 
|  | &thumb2_eabi_linux_sigreturn_tramp_frame); | 
|  | tramp_frame_prepend_unwinder (gdbarch, | 
|  | &thumb2_eabi_linux_rt_sigreturn_tramp_frame); | 
|  | tramp_frame_prepend_unwinder (gdbarch, | 
|  | &arm_linux_restart_syscall_tramp_frame); | 
|  | tramp_frame_prepend_unwinder (gdbarch, | 
|  | &arm_kernel_linux_restart_syscall_tramp_frame); | 
|  |  | 
|  | /* Core file support.  */ | 
|  | set_gdbarch_iterate_over_regset_sections | 
|  | (gdbarch, arm_linux_iterate_over_regset_sections); | 
|  | set_gdbarch_core_read_description (gdbarch, arm_linux_core_read_description); | 
|  |  | 
|  | /* Displaced stepping.  */ | 
|  | set_gdbarch_displaced_step_copy_insn (gdbarch, | 
|  | arm_linux_displaced_step_copy_insn); | 
|  | set_gdbarch_displaced_step_fixup (gdbarch, arm_displaced_step_fixup); | 
|  |  | 
|  | /* Reversible debugging, process record.  */ | 
|  | set_gdbarch_process_record (gdbarch, arm_process_record); | 
|  |  | 
|  | /* SystemTap functions.  */ | 
|  | set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes); | 
|  | set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes); | 
|  | set_gdbarch_stap_register_indirection_prefixes (gdbarch, | 
|  | stap_register_indirection_prefixes); | 
|  | set_gdbarch_stap_register_indirection_suffixes (gdbarch, | 
|  | stap_register_indirection_suffixes); | 
|  | set_gdbarch_stap_gdb_register_prefix (gdbarch, "r"); | 
|  | set_gdbarch_stap_is_single_operand (gdbarch, arm_stap_is_single_operand); | 
|  | set_gdbarch_stap_parse_special_token (gdbarch, | 
|  | arm_stap_parse_special_token); | 
|  |  | 
|  | /* `catch syscall' */ | 
|  | set_xml_syscall_file_name (gdbarch, "syscalls/arm-linux.xml"); | 
|  | set_gdbarch_get_syscall_number (gdbarch, arm_linux_get_syscall_number); | 
|  |  | 
|  | /* Syscall record.  */ | 
|  | tdep->arm_syscall_record = arm_linux_syscall_record; | 
|  |  | 
|  | /* Initialize the arm_linux_record_tdep.  */ | 
|  | /* These values are the size of the type that will be used in a system | 
|  | call.  They are obtained from Linux Kernel source.  */ | 
|  | arm_linux_record_tdep.size_pointer | 
|  | = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT; | 
|  | arm_linux_record_tdep.size__old_kernel_stat = 32; | 
|  | arm_linux_record_tdep.size_tms = 16; | 
|  | arm_linux_record_tdep.size_loff_t = 8; | 
|  | arm_linux_record_tdep.size_flock = 16; | 
|  | arm_linux_record_tdep.size_oldold_utsname = 45; | 
|  | arm_linux_record_tdep.size_ustat = 20; | 
|  | arm_linux_record_tdep.size_old_sigaction = 16; | 
|  | arm_linux_record_tdep.size_old_sigset_t = 4; | 
|  | arm_linux_record_tdep.size_rlimit = 8; | 
|  | arm_linux_record_tdep.size_rusage = 72; | 
|  | arm_linux_record_tdep.size_timeval = 8; | 
|  | arm_linux_record_tdep.size_timezone = 8; | 
|  | arm_linux_record_tdep.size_old_gid_t = 2; | 
|  | arm_linux_record_tdep.size_old_uid_t = 2; | 
|  | arm_linux_record_tdep.size_fd_set = 128; | 
|  | arm_linux_record_tdep.size_old_dirent = 268; | 
|  | arm_linux_record_tdep.size_statfs = 64; | 
|  | arm_linux_record_tdep.size_statfs64 = 84; | 
|  | arm_linux_record_tdep.size_sockaddr = 16; | 
|  | arm_linux_record_tdep.size_int | 
|  | = gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT; | 
|  | arm_linux_record_tdep.size_long | 
|  | = gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT; | 
|  | arm_linux_record_tdep.size_ulong | 
|  | = gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT; | 
|  | arm_linux_record_tdep.size_msghdr = 28; | 
|  | arm_linux_record_tdep.size_itimerval = 16; | 
|  | arm_linux_record_tdep.size_stat = 88; | 
|  | arm_linux_record_tdep.size_old_utsname = 325; | 
|  | arm_linux_record_tdep.size_sysinfo = 64; | 
|  | arm_linux_record_tdep.size_msqid_ds = 88; | 
|  | arm_linux_record_tdep.size_shmid_ds = 84; | 
|  | arm_linux_record_tdep.size_new_utsname = 390; | 
|  | arm_linux_record_tdep.size_timex = 128; | 
|  | arm_linux_record_tdep.size_mem_dqinfo = 24; | 
|  | arm_linux_record_tdep.size_if_dqblk = 68; | 
|  | arm_linux_record_tdep.size_fs_quota_stat = 68; | 
|  | arm_linux_record_tdep.size_timespec = 8; | 
|  | arm_linux_record_tdep.size_pollfd = 8; | 
|  | arm_linux_record_tdep.size_NFS_FHSIZE = 32; | 
|  | arm_linux_record_tdep.size_knfsd_fh = 132; | 
|  | arm_linux_record_tdep.size_TASK_COMM_LEN = 16; | 
|  | arm_linux_record_tdep.size_sigaction = 20; | 
|  | arm_linux_record_tdep.size_sigset_t = 8; | 
|  | arm_linux_record_tdep.size_siginfo_t = 128; | 
|  | arm_linux_record_tdep.size_cap_user_data_t = 12; | 
|  | arm_linux_record_tdep.size_stack_t = 12; | 
|  | arm_linux_record_tdep.size_off_t = arm_linux_record_tdep.size_long; | 
|  | arm_linux_record_tdep.size_stat64 = 96; | 
|  | arm_linux_record_tdep.size_gid_t = 4; | 
|  | arm_linux_record_tdep.size_uid_t = 4; | 
|  | arm_linux_record_tdep.size_PAGE_SIZE = 4096; | 
|  | arm_linux_record_tdep.size_flock64 = 24; | 
|  | arm_linux_record_tdep.size_user_desc = 16; | 
|  | arm_linux_record_tdep.size_io_event = 32; | 
|  | arm_linux_record_tdep.size_iocb = 64; | 
|  | arm_linux_record_tdep.size_epoll_event = 12; | 
|  | arm_linux_record_tdep.size_itimerspec | 
|  | = arm_linux_record_tdep.size_timespec * 2; | 
|  | arm_linux_record_tdep.size_mq_attr = 32; | 
|  | arm_linux_record_tdep.size_termios = 36; | 
|  | arm_linux_record_tdep.size_termios2 = 44; | 
|  | arm_linux_record_tdep.size_pid_t = 4; | 
|  | arm_linux_record_tdep.size_winsize = 8; | 
|  | arm_linux_record_tdep.size_serial_struct = 60; | 
|  | arm_linux_record_tdep.size_serial_icounter_struct = 80; | 
|  | arm_linux_record_tdep.size_hayes_esp_config = 12; | 
|  | arm_linux_record_tdep.size_size_t = 4; | 
|  | arm_linux_record_tdep.size_iovec = 8; | 
|  | arm_linux_record_tdep.size_time_t = 4; | 
|  |  | 
|  | /* These values are the second argument of system call "sys_ioctl". | 
|  | They are obtained from Linux Kernel source.  */ | 
|  | arm_linux_record_tdep.ioctl_TCGETS = 0x5401; | 
|  | arm_linux_record_tdep.ioctl_TCSETS = 0x5402; | 
|  | arm_linux_record_tdep.ioctl_TCSETSW = 0x5403; | 
|  | arm_linux_record_tdep.ioctl_TCSETSF = 0x5404; | 
|  | arm_linux_record_tdep.ioctl_TCGETA = 0x5405; | 
|  | arm_linux_record_tdep.ioctl_TCSETA = 0x5406; | 
|  | arm_linux_record_tdep.ioctl_TCSETAW = 0x5407; | 
|  | arm_linux_record_tdep.ioctl_TCSETAF = 0x5408; | 
|  | arm_linux_record_tdep.ioctl_TCSBRK = 0x5409; | 
|  | arm_linux_record_tdep.ioctl_TCXONC = 0x540a; | 
|  | arm_linux_record_tdep.ioctl_TCFLSH = 0x540b; | 
|  | arm_linux_record_tdep.ioctl_TIOCEXCL = 0x540c; | 
|  | arm_linux_record_tdep.ioctl_TIOCNXCL = 0x540d; | 
|  | arm_linux_record_tdep.ioctl_TIOCSCTTY = 0x540e; | 
|  | arm_linux_record_tdep.ioctl_TIOCGPGRP = 0x540f; | 
|  | arm_linux_record_tdep.ioctl_TIOCSPGRP = 0x5410; | 
|  | arm_linux_record_tdep.ioctl_TIOCOUTQ = 0x5411; | 
|  | arm_linux_record_tdep.ioctl_TIOCSTI = 0x5412; | 
|  | arm_linux_record_tdep.ioctl_TIOCGWINSZ = 0x5413; | 
|  | arm_linux_record_tdep.ioctl_TIOCSWINSZ = 0x5414; | 
|  | arm_linux_record_tdep.ioctl_TIOCMGET = 0x5415; | 
|  | arm_linux_record_tdep.ioctl_TIOCMBIS = 0x5416; | 
|  | arm_linux_record_tdep.ioctl_TIOCMBIC = 0x5417; | 
|  | arm_linux_record_tdep.ioctl_TIOCMSET = 0x5418; | 
|  | arm_linux_record_tdep.ioctl_TIOCGSOFTCAR = 0x5419; | 
|  | arm_linux_record_tdep.ioctl_TIOCSSOFTCAR = 0x541a; | 
|  | arm_linux_record_tdep.ioctl_FIONREAD = 0x541b; | 
|  | arm_linux_record_tdep.ioctl_TIOCINQ = arm_linux_record_tdep.ioctl_FIONREAD; | 
|  | arm_linux_record_tdep.ioctl_TIOCLINUX = 0x541c; | 
|  | arm_linux_record_tdep.ioctl_TIOCCONS = 0x541d; | 
|  | arm_linux_record_tdep.ioctl_TIOCGSERIAL = 0x541e; | 
|  | arm_linux_record_tdep.ioctl_TIOCSSERIAL = 0x541f; | 
|  | arm_linux_record_tdep.ioctl_TIOCPKT = 0x5420; | 
|  | arm_linux_record_tdep.ioctl_FIONBIO = 0x5421; | 
|  | arm_linux_record_tdep.ioctl_TIOCNOTTY = 0x5422; | 
|  | arm_linux_record_tdep.ioctl_TIOCSETD = 0x5423; | 
|  | arm_linux_record_tdep.ioctl_TIOCGETD = 0x5424; | 
|  | arm_linux_record_tdep.ioctl_TCSBRKP = 0x5425; | 
|  | arm_linux_record_tdep.ioctl_TIOCTTYGSTRUCT = 0x5426; | 
|  | arm_linux_record_tdep.ioctl_TIOCSBRK = 0x5427; | 
|  | arm_linux_record_tdep.ioctl_TIOCCBRK = 0x5428; | 
|  | arm_linux_record_tdep.ioctl_TIOCGSID = 0x5429; | 
|  | arm_linux_record_tdep.ioctl_TCGETS2 = 0x802c542a; | 
|  | arm_linux_record_tdep.ioctl_TCSETS2 = 0x402c542b; | 
|  | arm_linux_record_tdep.ioctl_TCSETSW2 = 0x402c542c; | 
|  | arm_linux_record_tdep.ioctl_TCSETSF2 = 0x402c542d; | 
|  | arm_linux_record_tdep.ioctl_TIOCGPTN = 0x80045430; | 
|  | arm_linux_record_tdep.ioctl_TIOCSPTLCK = 0x40045431; | 
|  | arm_linux_record_tdep.ioctl_FIONCLEX = 0x5450; | 
|  | arm_linux_record_tdep.ioctl_FIOCLEX = 0x5451; | 
|  | arm_linux_record_tdep.ioctl_FIOASYNC = 0x5452; | 
|  | arm_linux_record_tdep.ioctl_TIOCSERCONFIG = 0x5453; | 
|  | arm_linux_record_tdep.ioctl_TIOCSERGWILD = 0x5454; | 
|  | arm_linux_record_tdep.ioctl_TIOCSERSWILD = 0x5455; | 
|  | arm_linux_record_tdep.ioctl_TIOCGLCKTRMIOS = 0x5456; | 
|  | arm_linux_record_tdep.ioctl_TIOCSLCKTRMIOS = 0x5457; | 
|  | arm_linux_record_tdep.ioctl_TIOCSERGSTRUCT = 0x5458; | 
|  | arm_linux_record_tdep.ioctl_TIOCSERGETLSR = 0x5459; | 
|  | arm_linux_record_tdep.ioctl_TIOCSERGETMULTI = 0x545a; | 
|  | arm_linux_record_tdep.ioctl_TIOCSERSETMULTI = 0x545b; | 
|  | arm_linux_record_tdep.ioctl_TIOCMIWAIT = 0x545c; | 
|  | arm_linux_record_tdep.ioctl_TIOCGICOUNT = 0x545d; | 
|  | arm_linux_record_tdep.ioctl_TIOCGHAYESESP = 0x545e; | 
|  | arm_linux_record_tdep.ioctl_TIOCSHAYESESP = 0x545f; | 
|  | arm_linux_record_tdep.ioctl_FIOQSIZE = 0x5460; | 
|  |  | 
|  | /* These values are the second argument of system call "sys_fcntl" | 
|  | and "sys_fcntl64".  They are obtained from Linux Kernel source.  */ | 
|  | arm_linux_record_tdep.fcntl_F_GETLK = 5; | 
|  | arm_linux_record_tdep.fcntl_F_GETLK64 = 12; | 
|  | arm_linux_record_tdep.fcntl_F_SETLK64 = 13; | 
|  | arm_linux_record_tdep.fcntl_F_SETLKW64 = 14; | 
|  |  | 
|  | arm_linux_record_tdep.arg1 = ARM_A1_REGNUM; | 
|  | arm_linux_record_tdep.arg2 = ARM_A1_REGNUM + 1; | 
|  | arm_linux_record_tdep.arg3 = ARM_A1_REGNUM + 2; | 
|  | arm_linux_record_tdep.arg4 = ARM_A1_REGNUM + 3; | 
|  | arm_linux_record_tdep.arg5 = ARM_A1_REGNUM + 4; | 
|  | arm_linux_record_tdep.arg6 = ARM_A1_REGNUM + 5; | 
|  | arm_linux_record_tdep.arg7 = ARM_A1_REGNUM + 6; | 
|  |  | 
|  | set_gdbarch_gcc_target_options (gdbarch, arm_linux_gcc_target_options); | 
|  | } | 
|  |  | 
|  | void _initialize_arm_linux_tdep (); | 
|  | void | 
|  | _initialize_arm_linux_tdep () | 
|  | { | 
|  | gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_LINUX, | 
|  | arm_linux_init_abi); | 
|  | } |