Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 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 | */ |
Peter Maydell | 74c21bd | 2015-12-07 16:23:44 +0000 | [diff] [blame] | 20 | #include "qemu/osdep.h" |
Andreas Färber | 5b50e79 | 2013-06-29 04:18:45 +0200 | [diff] [blame] | 21 | #include "qemu-common.h" |
Paolo Bonzini | 33c1187 | 2016-03-15 16:58:45 +0100 | [diff] [blame] | 22 | #include "cpu.h" |
Andreas Färber | 5b50e79 | 2013-06-29 04:18:45 +0200 | [diff] [blame] | 23 | #include "exec/gdbstub.h" |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 24 | |
Abdallah Bouassida | 200bf5b | 2018-05-18 17:48:07 +0100 | [diff] [blame] | 25 | typedef struct RegisterSysregXmlParam { |
| 26 | CPUState *cs; |
| 27 | GString *s; |
| 28 | } RegisterSysregXmlParam; |
| 29 | |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 30 | /* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect |
| 31 | whatever the target description contains. Due to a historical mishap |
| 32 | the FPA registers appear in between core integer regs and the CPSR. |
| 33 | We hack round this by giving the FPA regs zero size when talking to a |
| 34 | newer gdb. */ |
| 35 | |
Andreas Färber | 5b50e79 | 2013-06-29 04:18:45 +0200 | [diff] [blame] | 36 | int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 37 | { |
Andreas Färber | 5b50e79 | 2013-06-29 04:18:45 +0200 | [diff] [blame] | 38 | ARMCPU *cpu = ARM_CPU(cs); |
| 39 | CPUARMState *env = &cpu->env; |
| 40 | |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 41 | if (n < 16) { |
| 42 | /* Core integer register. */ |
Andreas Färber | 986a299 | 2013-07-07 13:05:05 +0200 | [diff] [blame] | 43 | return gdb_get_reg32(mem_buf, env->regs[n]); |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 44 | } |
| 45 | if (n < 24) { |
| 46 | /* FPA registers. */ |
| 47 | if (gdb_has_xml) { |
| 48 | return 0; |
| 49 | } |
| 50 | memset(mem_buf, 0, 12); |
| 51 | return 12; |
| 52 | } |
| 53 | switch (n) { |
| 54 | case 24: |
| 55 | /* FPA status register. */ |
| 56 | if (gdb_has_xml) { |
| 57 | return 0; |
| 58 | } |
Andreas Färber | 986a299 | 2013-07-07 13:05:05 +0200 | [diff] [blame] | 59 | return gdb_get_reg32(mem_buf, 0); |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 60 | case 25: |
| 61 | /* CPSR */ |
Andreas Färber | 986a299 | 2013-07-07 13:05:05 +0200 | [diff] [blame] | 62 | return gdb_get_reg32(mem_buf, cpsr_read(env)); |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 63 | } |
| 64 | /* Unknown register. */ |
| 65 | return 0; |
| 66 | } |
| 67 | |
Andreas Färber | 5b50e79 | 2013-06-29 04:18:45 +0200 | [diff] [blame] | 68 | int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 69 | { |
Andreas Färber | 5b50e79 | 2013-06-29 04:18:45 +0200 | [diff] [blame] | 70 | ARMCPU *cpu = ARM_CPU(cs); |
| 71 | CPUARMState *env = &cpu->env; |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 72 | uint32_t tmp; |
| 73 | |
| 74 | tmp = ldl_p(mem_buf); |
| 75 | |
| 76 | /* Mask out low bit of PC to workaround gdb bugs. This will probably |
| 77 | cause problems if we ever implement the Jazelle DBX extensions. */ |
| 78 | if (n == 15) { |
| 79 | tmp &= ~1; |
| 80 | } |
| 81 | |
| 82 | if (n < 16) { |
| 83 | /* Core integer register. */ |
| 84 | env->regs[n] = tmp; |
| 85 | return 4; |
| 86 | } |
| 87 | if (n < 24) { /* 16-23 */ |
| 88 | /* FPA registers (ignored). */ |
| 89 | if (gdb_has_xml) { |
| 90 | return 0; |
| 91 | } |
| 92 | return 12; |
| 93 | } |
| 94 | switch (n) { |
| 95 | case 24: |
| 96 | /* FPA status register (ignored). */ |
| 97 | if (gdb_has_xml) { |
| 98 | return 0; |
| 99 | } |
| 100 | return 4; |
| 101 | case 25: |
| 102 | /* CPSR */ |
Peter Maydell | 50866ba | 2016-02-23 15:36:43 +0000 | [diff] [blame] | 103 | cpsr_write(env, tmp, 0xffffffff, CPSRWriteByGDBStub); |
Andreas Färber | 58850da | 2013-07-07 12:32:15 +0200 | [diff] [blame] | 104 | return 4; |
| 105 | } |
| 106 | /* Unknown register. */ |
| 107 | return 0; |
| 108 | } |
Abdallah Bouassida | 200bf5b | 2018-05-18 17:48:07 +0100 | [diff] [blame] | 109 | |
| 110 | static void arm_gen_one_xml_reg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml, |
| 111 | ARMCPRegInfo *ri, uint32_t ri_key, |
| 112 | int bitsize) |
| 113 | { |
| 114 | g_string_append_printf(s, "<reg name=\"%s\"", ri->name); |
| 115 | g_string_append_printf(s, " bitsize=\"%d\"", bitsize); |
| 116 | g_string_append_printf(s, " group=\"cp_regs\"/>"); |
| 117 | dyn_xml->num_cpregs++; |
| 118 | dyn_xml->cpregs_keys[dyn_xml->num_cpregs - 1] = ri_key; |
| 119 | } |
| 120 | |
| 121 | static void arm_register_sysreg_for_xml(gpointer key, gpointer value, |
| 122 | gpointer p) |
| 123 | { |
| 124 | uint32_t ri_key = *(uint32_t *)key; |
| 125 | ARMCPRegInfo *ri = value; |
| 126 | RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p; |
| 127 | GString *s = param->s; |
| 128 | ARMCPU *cpu = ARM_CPU(param->cs); |
| 129 | CPUARMState *env = &cpu->env; |
| 130 | DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_xml; |
| 131 | |
| 132 | if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) { |
| 133 | if (arm_feature(env, ARM_FEATURE_AARCH64)) { |
| 134 | if (ri->state == ARM_CP_STATE_AA64) { |
| 135 | arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64); |
| 136 | } |
| 137 | } else { |
| 138 | if (ri->state == ARM_CP_STATE_AA32) { |
| 139 | if (!arm_feature(env, ARM_FEATURE_EL3) && |
| 140 | (ri->secure & ARM_CP_SECSTATE_S)) { |
| 141 | return; |
| 142 | } |
| 143 | if (ri->type & ARM_CP_64BIT) { |
| 144 | arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64); |
| 145 | } else { |
| 146 | arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 32); |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | int arm_gen_dynamic_xml(CPUState *cs) |
| 154 | { |
| 155 | ARMCPU *cpu = ARM_CPU(cs); |
| 156 | GString *s = g_string_new(NULL); |
| 157 | RegisterSysregXmlParam param = {cs, s}; |
| 158 | |
| 159 | cpu->dyn_xml.num_cpregs = 0; |
Paolo Bonzini | 7e3ef27 | 2018-05-31 14:50:52 +0100 | [diff] [blame] | 160 | cpu->dyn_xml.cpregs_keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs)); |
Abdallah Bouassida | 200bf5b | 2018-05-18 17:48:07 +0100 | [diff] [blame] | 161 | g_string_printf(s, "<?xml version=\"1.0\"?>"); |
| 162 | g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); |
| 163 | g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">"); |
| 164 | g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m); |
| 165 | g_string_append_printf(s, "</feature>"); |
| 166 | cpu->dyn_xml.desc = g_string_free(s, false); |
| 167 | return cpu->dyn_xml.num_cpregs; |
| 168 | } |
| 169 | |
| 170 | const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname) |
| 171 | { |
| 172 | ARMCPU *cpu = ARM_CPU(cs); |
| 173 | |
| 174 | if (strcmp(xmlname, "system-registers.xml") == 0) { |
| 175 | return cpu->dyn_xml.desc; |
| 176 | } |
| 177 | return NULL; |
| 178 | } |