Commit | Line | Data |
---|---|---|
0a30fbc4 | 1 | /* GNU/Linux/MIPS specific low level interface, for the remote server for GDB. |
21b0f40c | 2 | Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2005, 2006 |
0a30fbc4 DJ |
3 | Free Software Foundation, Inc. |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
6f0f660e EZ |
19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | Boston, MA 02110-1301, USA. */ | |
0a30fbc4 DJ |
21 | |
22 | #include "server.h" | |
58caa3dc | 23 | #include "linux-low.h" |
0a30fbc4 | 24 | |
21b0f40c DJ |
25 | #include <sys/ptrace.h> |
26 | ||
27 | #include "gdb_proc_service.h" | |
28 | ||
29 | #ifndef PTRACE_GET_THREAD_AREA | |
30 | #define PTRACE_GET_THREAD_AREA 25 | |
31 | #endif | |
32 | ||
0a30fbc4 DJ |
33 | #ifdef HAVE_SYS_REG_H |
34 | #include <sys/reg.h> | |
35 | #endif | |
36 | ||
2ec06d2e | 37 | #define mips_num_regs 90 |
0a30fbc4 DJ |
38 | |
39 | #include <asm/ptrace.h> | |
40 | ||
41 | /* Return the ptrace ``address'' of register REGNO. */ | |
42 | ||
43 | /* Matches mips_generic32_regs */ | |
2ec06d2e | 44 | static int mips_regmap[] = { |
0a30fbc4 DJ |
45 | 0, 1, 2, 3, 4, 5, 6, 7, |
46 | 8, 9, 10, 11, 12, 13, 14, 15, | |
47 | 16, 17, 18, 19, 20, 21, 22, 23, | |
48 | 24, 25, 26, 27, 28, 29, 30, 31, | |
49 | ||
50 | -1, MMLO, MMHI, BADVADDR, CAUSE, PC, | |
51 | ||
52 | FPR_BASE, FPR_BASE + 1, FPR_BASE + 2, FPR_BASE + 3, | |
53 | FPR_BASE + 4, FPR_BASE + 5, FPR_BASE + 6, FPR_BASE + 7, | |
54 | FPR_BASE + 8, FPR_BASE + 8, FPR_BASE + 10, FPR_BASE + 11, | |
55 | FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15, | |
56 | FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19, | |
57 | FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23, | |
58 | FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27, | |
59 | FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31, | |
60 | FPC_CSR, FPC_EIR, | |
61 | ||
62 | -1, -1, | |
63 | -1, -1, -1, -1, -1, -1, -1, -1, | |
64 | -1, -1, -1, -1, -1, -1, -1, -1, | |
65 | }; | |
66 | ||
67 | /* From mips-linux-nat.c. */ | |
68 | ||
69 | /* Pseudo registers can not be read. ptrace does not provide a way to | |
70 | read (or set) PS_REGNUM, and there's no point in reading or setting | |
71 | ZERO_REGNUM. We also can not set BADVADDR, CAUSE, or FCRIR via | |
72 | ptrace(). */ | |
73 | ||
2ec06d2e DJ |
74 | static int |
75 | mips_cannot_fetch_register (int regno) | |
0a30fbc4 | 76 | { |
2ec06d2e | 77 | if (mips_regmap[regno] == -1) |
0a30fbc4 DJ |
78 | return 1; |
79 | ||
aa32f823 | 80 | if (find_regno ("zero") == regno) |
0a30fbc4 DJ |
81 | return 1; |
82 | ||
83 | return 0; | |
84 | } | |
85 | ||
2ec06d2e DJ |
86 | static int |
87 | mips_cannot_store_register (int regno) | |
0a30fbc4 | 88 | { |
2ec06d2e | 89 | if (mips_regmap[regno] == -1) |
0a30fbc4 DJ |
90 | return 1; |
91 | ||
1d33e73a | 92 | if (find_regno ("zero") == regno) |
0a30fbc4 DJ |
93 | return 1; |
94 | ||
1d33e73a | 95 | if (find_regno ("cause") == regno) |
0a30fbc4 DJ |
96 | return 1; |
97 | ||
1d33e73a | 98 | if (find_regno ("bad") == regno) |
0a30fbc4 DJ |
99 | return 1; |
100 | ||
1d33e73a | 101 | if (find_regno ("fir") == regno) |
0a30fbc4 DJ |
102 | return 1; |
103 | ||
104 | return 0; | |
105 | } | |
2ec06d2e | 106 | |
0d62e5e8 DJ |
107 | static CORE_ADDR |
108 | mips_get_pc () | |
109 | { | |
110 | unsigned long pc; | |
111 | collect_register_by_name ("pc", &pc); | |
112 | return pc; | |
113 | } | |
114 | ||
115 | static void | |
116 | mips_set_pc (CORE_ADDR pc) | |
117 | { | |
118 | unsigned long newpc = pc; | |
119 | supply_register_by_name ("pc", &newpc); | |
120 | } | |
121 | ||
122 | /* Correct in either endianness. */ | |
123 | static const unsigned long mips_breakpoint = 0x0005000d; | |
124 | #define mips_breakpoint_len 4 | |
125 | ||
126 | /* We only place breakpoints in empty marker functions, and thread locking | |
127 | is outside of the function. So rather than importing software single-step, | |
128 | we can just run until exit. */ | |
129 | static CORE_ADDR | |
130 | mips_reinsert_addr () | |
131 | { | |
132 | unsigned long pc; | |
133 | collect_register_by_name ("ra", &pc); | |
134 | return pc; | |
135 | } | |
136 | ||
137 | static int | |
138 | mips_breakpoint_at (CORE_ADDR where) | |
139 | { | |
140 | unsigned long insn; | |
141 | ||
f450004a | 142 | (*the_target->read_memory) (where, (unsigned char *) &insn, 4); |
0d62e5e8 DJ |
143 | if (insn == mips_breakpoint) |
144 | return 1; | |
145 | ||
146 | /* If necessary, recognize more trap instructions here. GDB only uses the | |
147 | one. */ | |
148 | return 0; | |
149 | } | |
150 | ||
21b0f40c DJ |
151 | /* Fetch the thread-local storage pointer for libthread_db. */ |
152 | ||
153 | ps_err_e | |
154 | ps_get_thread_area (const struct ps_prochandle *ph, | |
155 | lwpid_t lwpid, int idx, void **base) | |
156 | { | |
157 | if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0) | |
158 | return PS_ERR; | |
159 | ||
160 | /* IDX is the bias from the thread pointer to the beginning of the | |
161 | thread descriptor. It has to be subtracted due to implementation | |
162 | quirks in libthread_db. */ | |
163 | *base = (void *) ((char *)*base - idx); | |
164 | ||
165 | return PS_OK; | |
166 | } | |
167 | ||
2ec06d2e DJ |
168 | struct linux_target_ops the_low_target = { |
169 | mips_num_regs, | |
170 | mips_regmap, | |
171 | mips_cannot_fetch_register, | |
172 | mips_cannot_store_register, | |
0d62e5e8 DJ |
173 | mips_get_pc, |
174 | mips_set_pc, | |
f450004a | 175 | (const unsigned char *) &mips_breakpoint, |
0d62e5e8 DJ |
176 | mips_breakpoint_len, |
177 | mips_reinsert_addr, | |
178 | 0, | |
179 | mips_breakpoint_at, | |
2ec06d2e | 180 | }; |