Commit | Line | Data |
---|---|---|
1525d545 | 1 | /* GNU/Linux/Xtensa specific low level interface, for the remote server for GDB. |
0fb0cc75 | 2 | Copyright 2007, 2008, 2009 Free Software Foundation, Inc. |
1525d545 MG |
3 | |
4 | This file is part of GDB. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | ||
20 | #include "server.h" | |
21 | #include "linux-low.h" | |
22 | ||
d05b4ac3 UW |
23 | /* Defined in auto-generated file reg-xtensa.c. */ |
24 | void init_registers_xtensa (void); | |
25 | ||
1525d545 MG |
26 | #include <sys/ptrace.h> |
27 | #include <xtensa-config.h> | |
28 | ||
29 | #include "xtensa-xtregs.c" | |
30 | ||
31 | enum regnum { | |
32 | R_PC=0, R_PS, | |
33 | R_LBEG, R_LEND, R_LCOUNT, | |
34 | R_SAR, | |
35 | R_WS, R_WB, | |
1b3f6016 | 36 | R_A0 = 64 |
1525d545 MG |
37 | }; |
38 | ||
39 | static void | |
40 | xtensa_fill_gregset (void *buf) | |
41 | { | |
42 | elf_greg_t* rset = (elf_greg_t*)buf; | |
43 | int ar0_regnum; | |
44 | char *ptr; | |
45 | int i; | |
46 | ||
47 | /* Take care of AR registers. */ | |
48 | ||
49 | ar0_regnum = find_regno ("ar0"); | |
50 | ptr = (char*)&rset[R_A0]; | |
51 | ||
52 | for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++) | |
53 | { | |
54 | collect_register (i, ptr); | |
55 | ptr += register_size(i); | |
56 | } | |
57 | ||
58 | /* Loop registers, if hardware has it. */ | |
59 | ||
60 | #if XCHAL_HAVE_LOOP | |
61 | collect_register_by_name ("lbeg", (char*)&rset[R_LBEG]); | |
62 | collect_register_by_name ("lend", (char*)&rset[R_LEND]); | |
63 | collect_register_by_name ("lcount", (char*)&rset[R_LCOUNT]); | |
64 | #endif | |
65 | ||
66 | collect_register_by_name ("sar", (char*)&rset[R_SAR]); | |
67 | collect_register_by_name ("pc", (char*)&rset[R_PC]); | |
68 | collect_register_by_name ("ps", (char*)&rset[R_PS]); | |
69 | collect_register_by_name ("windowbase", (char*)&rset[R_WB]); | |
70 | collect_register_by_name ("windowstart", (char*)&rset[R_WS]); | |
71 | } | |
72 | ||
73 | static void | |
74 | xtensa_store_gregset (const void *buf) | |
75 | { | |
76 | const elf_greg_t* rset = (const elf_greg_t*)buf; | |
77 | int ar0_regnum; | |
78 | char *ptr; | |
79 | int i; | |
80 | ||
81 | /* Take care of AR registers. */ | |
82 | ||
83 | ar0_regnum = find_regno ("ar0"); | |
84 | ptr = (char *)&rset[R_A0]; | |
85 | ||
86 | for (i = ar0_regnum; i < ar0_regnum + XCHAL_NUM_AREGS; i++) | |
87 | { | |
88 | supply_register (i, ptr); | |
89 | ptr += register_size(i); | |
90 | } | |
91 | ||
92 | /* Loop registers, if hardware has it. */ | |
93 | ||
94 | #if XCHAL_HAVE_LOOP | |
95 | supply_register_by_name ("lbeg", (char*)&rset[R_LBEG]); | |
96 | supply_register_by_name ("lend", (char*)&rset[R_LEND]); | |
97 | supply_register_by_name ("lcount", (char*)&rset[R_LCOUNT]); | |
98 | #endif | |
99 | ||
100 | supply_register_by_name ("sar", (char*)&rset[R_SAR]); | |
101 | supply_register_by_name ("pc", (char*)&rset[R_PC]); | |
102 | supply_register_by_name ("ps", (char*)&rset[R_PS]); | |
103 | supply_register_by_name ("windowbase", (char*)&rset[R_WB]); | |
104 | supply_register_by_name ("windowstart", (char*)&rset[R_WS]); | |
105 | } | |
106 | ||
107 | /* Xtensa GNU/Linux PTRACE interface includes extended register set. */ | |
108 | ||
109 | static void | |
110 | xtensa_fill_xtregset (void *buf) | |
111 | { | |
112 | const xtensa_regtable_t *ptr; | |
113 | ||
114 | for (ptr = xtensa_regmap_table; ptr->name; ptr++) | |
115 | { | |
116 | collect_register_by_name (ptr->name, | |
117 | (char*)buf + ptr->ptrace_offset); | |
118 | } | |
119 | } | |
120 | ||
121 | static void | |
122 | xtensa_store_xtregset (const void *buf) | |
123 | { | |
124 | const xtensa_regtable_t *ptr; | |
125 | ||
126 | for (ptr = xtensa_regmap_table; ptr->name; ptr++) | |
127 | { | |
128 | supply_register_by_name (ptr->name, | |
129 | (char*)buf + ptr->ptrace_offset); | |
130 | } | |
131 | } | |
132 | ||
133 | struct regset_info target_regsets[] = { | |
134 | { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t), | |
135 | GENERAL_REGS, | |
136 | xtensa_fill_gregset, xtensa_store_gregset }, | |
137 | { PTRACE_GETXTREGS, PTRACE_SETXTREGS, XTENSA_ELF_XTREG_SIZE, | |
138 | EXTENDED_REGS, | |
139 | xtensa_fill_xtregset, xtensa_store_xtregset }, | |
140 | { 0, 0, -1, -1, NULL, NULL } | |
141 | }; | |
142 | ||
143 | #if XCHAL_HAVE_BE | |
144 | #define XTENSA_BREAKPOINT {0xd2,0x0f} | |
145 | #else | |
146 | #define XTENSA_BREAKPOINT {0x2d,0xf0} | |
147 | #endif | |
148 | ||
149 | static const unsigned char xtensa_breakpoint[] = XTENSA_BREAKPOINT; | |
150 | #define xtensa_breakpoint_len 2 | |
151 | ||
152 | static CORE_ADDR | |
153 | xtensa_get_pc (void) | |
154 | { | |
155 | unsigned long pc; | |
156 | ||
157 | collect_register_by_name ("pc", &pc); | |
158 | return pc; | |
159 | } | |
160 | ||
161 | static void | |
162 | xtensa_set_pc (CORE_ADDR pc) | |
163 | { | |
164 | unsigned long newpc = pc; | |
165 | supply_register_by_name ("pc", &newpc); | |
166 | } | |
167 | ||
168 | static int | |
169 | xtensa_breakpoint_at (CORE_ADDR where) | |
170 | { | |
171 | unsigned long insn; | |
172 | ||
173 | (*the_target->read_memory) (where, (unsigned char *) &insn, | |
174 | xtensa_breakpoint_len); | |
175 | return memcmp((char *)&insn, xtensa_breakpoint, xtensa_breakpoint_len) == 0; | |
176 | } | |
177 | ||
178 | struct linux_target_ops the_low_target = { | |
d05b4ac3 | 179 | init_registers_xtensa, |
1525d545 MG |
180 | 0, |
181 | 0, | |
182 | 0, | |
183 | 0, | |
184 | xtensa_get_pc, | |
185 | xtensa_set_pc, | |
186 | xtensa_breakpoint, | |
187 | xtensa_breakpoint_len, | |
188 | NULL, | |
189 | 0, | |
190 | xtensa_breakpoint_at, | |
191 | }; |