1 | /* |
2 | * ARM gdb server stub |
3 | * |
4 | * Copyright (c) 2003-2005 Fabrice Bellard |
5 | * Copyright (c) 2013 SUSE LINUX Products GmbH |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2 of the License, or (at your option) any later version. |
11 | * |
12 | * This library 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 GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | #include "qemu/osdep.h" |
21 | #include "cpu.h" |
22 | #include "exec/gdbstub.h" |
23 | |
24 | typedef struct RegisterSysregXmlParam { |
25 | CPUState *cs; |
26 | GString *s; |
27 | } RegisterSysregXmlParam; |
28 | |
29 | /* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect |
30 | whatever the target description contains. Due to a historical mishap |
31 | the FPA registers appear in between core integer regs and the CPSR. |
32 | We hack round this by giving the FPA regs zero size when talking to a |
33 | newer gdb. */ |
34 | |
35 | int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) |
36 | { |
37 | ARMCPU *cpu = ARM_CPU(cs); |
38 | CPUARMState *env = &cpu->env; |
39 | |
40 | if (n < 16) { |
41 | /* Core integer register. */ |
42 | return gdb_get_reg32(mem_buf, env->regs[n]); |
43 | } |
44 | if (n < 24) { |
45 | /* FPA registers. */ |
46 | if (gdb_has_xml) { |
47 | return 0; |
48 | } |
49 | memset(mem_buf, 0, 12); |
50 | return 12; |
51 | } |
52 | switch (n) { |
53 | case 24: |
54 | /* FPA status register. */ |
55 | if (gdb_has_xml) { |
56 | return 0; |
57 | } |
58 | return gdb_get_reg32(mem_buf, 0); |
59 | case 25: |
60 | /* CPSR */ |
61 | return gdb_get_reg32(mem_buf, cpsr_read(env)); |
62 | } |
63 | /* Unknown register. */ |
64 | return 0; |
65 | } |
66 | |
67 | int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
68 | { |
69 | ARMCPU *cpu = ARM_CPU(cs); |
70 | CPUARMState *env = &cpu->env; |
71 | uint32_t tmp; |
72 | |
73 | tmp = ldl_p(mem_buf); |
74 | |
75 | /* Mask out low bit of PC to workaround gdb bugs. This will probably |
76 | cause problems if we ever implement the Jazelle DBX extensions. */ |
77 | if (n == 15) { |
78 | tmp &= ~1; |
79 | } |
80 | |
81 | if (n < 16) { |
82 | /* Core integer register. */ |
83 | env->regs[n] = tmp; |
84 | return 4; |
85 | } |
86 | if (n < 24) { /* 16-23 */ |
87 | /* FPA registers (ignored). */ |
88 | if (gdb_has_xml) { |
89 | return 0; |
90 | } |
91 | return 12; |
92 | } |
93 | switch (n) { |
94 | case 24: |
95 | /* FPA status register (ignored). */ |
96 | if (gdb_has_xml) { |
97 | return 0; |
98 | } |
99 | return 4; |
100 | case 25: |
101 | /* CPSR */ |
102 | cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub); |
103 | return 4; |
104 | } |
105 | /* Unknown register. */ |
106 | return 0; |
107 | } |
108 | |
109 | static void arm_gen_one_xml_reg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml, |
110 | ARMCPRegInfo *ri, uint32_t ri_key, |
111 | int bitsize) |
112 | { |
113 | g_string_append_printf(s, "<reg name=\"%s\"" , ri->name); |
114 | g_string_append_printf(s, " bitsize=\"%d\"" , bitsize); |
115 | g_string_append_printf(s, " group=\"cp_regs\"/>" ); |
116 | dyn_xml->num_cpregs++; |
117 | dyn_xml->cpregs_keys[dyn_xml->num_cpregs - 1] = ri_key; |
118 | } |
119 | |
120 | static void arm_register_sysreg_for_xml(gpointer key, gpointer value, |
121 | gpointer p) |
122 | { |
123 | uint32_t ri_key = *(uint32_t *)key; |
124 | ARMCPRegInfo *ri = value; |
125 | RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p; |
126 | GString *s = param->s; |
127 | ARMCPU *cpu = ARM_CPU(param->cs); |
128 | CPUARMState *env = &cpu->env; |
129 | DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_xml; |
130 | |
131 | if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) { |
132 | if (arm_feature(env, ARM_FEATURE_AARCH64)) { |
133 | if (ri->state == ARM_CP_STATE_AA64) { |
134 | arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64); |
135 | } |
136 | } else { |
137 | if (ri->state == ARM_CP_STATE_AA32) { |
138 | if (!arm_feature(env, ARM_FEATURE_EL3) && |
139 | (ri->secure & ARM_CP_SECSTATE_S)) { |
140 | return; |
141 | } |
142 | if (ri->type & ARM_CP_64BIT) { |
143 | arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64); |
144 | } else { |
145 | arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 32); |
146 | } |
147 | } |
148 | } |
149 | } |
150 | } |
151 | |
152 | int arm_gen_dynamic_xml(CPUState *cs) |
153 | { |
154 | ARMCPU *cpu = ARM_CPU(cs); |
155 | GString *s = g_string_new(NULL); |
156 | RegisterSysregXmlParam param = {cs, s}; |
157 | |
158 | cpu->dyn_xml.num_cpregs = 0; |
159 | cpu->dyn_xml.cpregs_keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs)); |
160 | g_string_printf(s, "<?xml version=\"1.0\"?>" ); |
161 | g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">" ); |
162 | g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">" ); |
163 | g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m); |
164 | g_string_append_printf(s, "</feature>" ); |
165 | cpu->dyn_xml.desc = g_string_free(s, false); |
166 | return cpu->dyn_xml.num_cpregs; |
167 | } |
168 | |
169 | const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname) |
170 | { |
171 | ARMCPU *cpu = ARM_CPU(cs); |
172 | |
173 | if (strcmp(xmlname, "system-registers.xml" ) == 0) { |
174 | return cpu->dyn_xml.desc; |
175 | } |
176 | return NULL; |
177 | } |
178 | |