1160581Sobrien/* 2160581Sobrien * Copyright (c) 2004 Marcel Moolenaar 3160581Sobrien * All rights reserved. 4160581Sobrien * 5160581Sobrien * Redistribution and use in source and binary forms, with or without 6160581Sobrien * modification, are permitted provided that the following conditions 7160581Sobrien * are met: 8160581Sobrien * 9160581Sobrien * 1. Redistributions of source code must retain the above copyright 10160581Sobrien * notice, this list of conditions and the following disclaimer. 11160581Sobrien * 2. Redistributions in binary form must reproduce the above copyright 12160581Sobrien * notice, this list of conditions and the following disclaimer in the 13160581Sobrien * documentation and/or other materials provided with the distribution. 14160581Sobrien * 15160581Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16160581Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17160581Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18160581Sobrien * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19160581Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20160581Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21160581Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22160581Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23160581Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24160581Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25160581Sobrien */ 26160581Sobrien 27160581Sobrien#include <sys/cdefs.h> 28160581Sobrien__FBSDID("$FreeBSD: releng/11.0/gnu/usr.bin/gdb/kgdb/trgt_arm.c 298358 2016-04-20 17:58:13Z wma $"); 29160581Sobrien 30160581Sobrien#include <sys/types.h> 31162303Simp#ifndef CROSS_DEBUGGER 32160581Sobrien#include <machine/pcb.h> 33160581Sobrien#include <machine/frame.h> 34162303Simp#include <machine/armreg.h> 35162303Simp#endif 36160581Sobrien#include <err.h> 37160581Sobrien#include <kvm.h> 38160581Sobrien#include <string.h> 39160581Sobrien 40160581Sobrien#include <defs.h> 41160581Sobrien#include <target.h> 42160581Sobrien#include <gdbthread.h> 43160581Sobrien#include <inferior.h> 44160581Sobrien#include <regcache.h> 45160581Sobrien#include <frame-unwind.h> 46160581Sobrien#include <arm-tdep.h> 47160581Sobrien 48160581Sobrien#include "kgdb.h" 49160581Sobrien 50246893SmarcelCORE_ADDR 51246893Smarcelkgdb_trgt_core_pcb(u_int cpuid) 52246893Smarcel{ 53261788Sjmg#ifndef CROSS_DEBUGGER 54246893Smarcel return (kgdb_trgt_stop_pcb(cpuid, sizeof(struct pcb))); 55261788Sjmg#else 56261788Sjmg return -1; 57261788Sjmg#endif 58246893Smarcel} 59246893Smarcel 60160581Sobrienvoid 61160581Sobrienkgdb_trgt_fetch_registers(int regno __unused) 62160581Sobrien{ 63162303Simp#ifndef CROSS_DEBUGGER 64160581Sobrien struct kthr *kt; 65160581Sobrien struct pcb pcb; 66290193Szbb int i; 67163440Sjhb 68178713Sjhb kt = kgdb_thr_lookup_tid(ptid_get_pid(inferior_ptid)); 69160581Sobrien if (kt == NULL) 70160581Sobrien return; 71160581Sobrien if (kvm_read(kvm, kt->pcb, &pcb, sizeof(pcb)) != sizeof(pcb)) { 72160581Sobrien warnx("kvm_read: %s", kvm_geterr(kvm)); 73160581Sobrien memset(&pcb, 0, sizeof(pcb)); 74160581Sobrien } 75276190Sian for (i = ARM_A1_REGNUM + 4; i <= ARM_SP_REGNUM; i++) { 76276190Sian supply_register(i, (char *)&pcb.pcb_regs.sf_r4 + 77276190Sian (i - (ARM_A1_REGNUM + 4 )) * 4); 78160581Sobrien } 79290193Szbb supply_register(ARM_PC_REGNUM, (char *)&pcb.pcb_regs.sf_pc); 80290193Szbb supply_register(ARM_LR_REGNUM, (char *)&pcb.pcb_regs.sf_lr); 81162303Simp#endif 82160581Sobrien} 83160581Sobrien 84160581Sobrienvoid 85160581Sobrienkgdb_trgt_store_registers(int regno __unused) 86160581Sobrien{ 87160581Sobrien fprintf_unfiltered(gdb_stderr, "XXX: %s\n", __func__); 88160581Sobrien} 89160581Sobrien 90178670Sjhbvoid 91178670Sjhbkgdb_trgt_new_objfile(struct objfile *objfile) 92178670Sjhb{ 93178670Sjhb} 94178670Sjhb 95162303Simp#ifndef CROSS_DEBUGGER 96160581Sobrienstruct kgdb_frame_cache { 97160581Sobrien CORE_ADDR fp; 98160581Sobrien CORE_ADDR sp; 99298358Swma CORE_ADDR pc; 100160581Sobrien}; 101160581Sobrien 102160581Sobrienstatic int kgdb_trgt_frame_offset[26] = { 103160581Sobrien offsetof(struct trapframe, tf_r0), 104160581Sobrien offsetof(struct trapframe, tf_r1), 105160581Sobrien offsetof(struct trapframe, tf_r2), 106160581Sobrien offsetof(struct trapframe, tf_r3), 107160581Sobrien offsetof(struct trapframe, tf_r4), 108160581Sobrien offsetof(struct trapframe, tf_r5), 109160581Sobrien offsetof(struct trapframe, tf_r6), 110160581Sobrien offsetof(struct trapframe, tf_r7), 111160581Sobrien offsetof(struct trapframe, tf_r8), 112160581Sobrien offsetof(struct trapframe, tf_r9), 113160581Sobrien offsetof(struct trapframe, tf_r10), 114160581Sobrien offsetof(struct trapframe, tf_r11), 115160581Sobrien offsetof(struct trapframe, tf_r12), 116160581Sobrien offsetof(struct trapframe, tf_svc_sp), 117160581Sobrien offsetof(struct trapframe, tf_svc_lr), 118160581Sobrien offsetof(struct trapframe, tf_pc), 119160581Sobrien -1, -1, -1, -1, -1, -1, -1, -1, -1, 120160581Sobrien offsetof(struct trapframe, tf_spsr) 121160581Sobrien}; 122160581Sobrien 123160581Sobrienstatic struct kgdb_frame_cache * 124160581Sobrienkgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache) 125160581Sobrien{ 126160581Sobrien char buf[MAX_REGISTER_SIZE]; 127160581Sobrien struct kgdb_frame_cache *cache; 128160581Sobrien 129160581Sobrien cache = *this_cache; 130160581Sobrien if (cache == NULL) { 131160581Sobrien cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache); 132160581Sobrien *this_cache = cache; 133160581Sobrien frame_unwind_register(next_frame, ARM_SP_REGNUM, buf); 134160581Sobrien cache->sp = extract_unsigned_integer(buf, 135160581Sobrien register_size(current_gdbarch, ARM_SP_REGNUM)); 136160581Sobrien frame_unwind_register(next_frame, ARM_FP_REGNUM, buf); 137160581Sobrien cache->fp = extract_unsigned_integer(buf, 138160581Sobrien register_size(current_gdbarch, ARM_FP_REGNUM)); 139298358Swma cache->pc = frame_func_unwind(next_frame); 140160581Sobrien } 141160581Sobrien return (cache); 142160581Sobrien} 143160581Sobrien 144162303Simpstatic int is_undef; 145162303Simp 146160581Sobrienstatic void 147160581Sobrienkgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache, 148160581Sobrien struct frame_id *this_id) 149160581Sobrien{ 150160581Sobrien struct kgdb_frame_cache *cache; 151160581Sobrien 152160581Sobrien cache = kgdb_trgt_frame_cache(next_frame, this_cache); 153298358Swma *this_id = frame_id_build(cache->sp, cache->pc); 154160581Sobrien} 155160581Sobrien 156160581Sobrienstatic void 157160581Sobrienkgdb_trgt_trapframe_prev_register(struct frame_info *next_frame, 158160581Sobrien void **this_cache, int regnum, int *optimizedp, enum lval_type *lvalp, 159160581Sobrien CORE_ADDR *addrp, int *realnump, void *valuep) 160160581Sobrien{ 161160581Sobrien char dummy_valuep[MAX_REGISTER_SIZE]; 162160581Sobrien struct kgdb_frame_cache *cache; 163160581Sobrien int ofs, regsz; 164298358Swma CORE_ADDR sp; 165160581Sobrien 166160581Sobrien regsz = register_size(current_gdbarch, regnum); 167160581Sobrien 168160581Sobrien if (valuep == NULL) 169160581Sobrien valuep = dummy_valuep; 170160581Sobrien memset(valuep, 0, regsz); 171160581Sobrien *optimizedp = 0; 172160581Sobrien *addrp = 0; 173160581Sobrien *lvalp = not_lval; 174160581Sobrien *realnump = -1; 175160581Sobrien 176160581Sobrien ofs = (regnum >= 0 && regnum <= ARM_PS_REGNUM) 177160581Sobrien ? kgdb_trgt_frame_offset[regnum] : -1; 178160581Sobrien if (ofs == -1) 179160581Sobrien return; 180160581Sobrien 181160581Sobrien cache = kgdb_trgt_frame_cache(next_frame, this_cache); 182298358Swma sp = cache->sp; 183163440Sjhb 184298358Swma ofs = kgdb_trgt_frame_offset[regnum]; 185298358Swma *addrp = sp + ofs; 186160581Sobrien *lvalp = lval_memory; 187160581Sobrien target_read_memory(*addrp, valuep, regsz); 188160581Sobrien} 189160581Sobrien 190160581Sobrienstatic const struct frame_unwind kgdb_trgt_trapframe_unwind = { 191160581Sobrien UNKNOWN_FRAME, 192160581Sobrien &kgdb_trgt_trapframe_this_id, 193160581Sobrien &kgdb_trgt_trapframe_prev_register 194160581Sobrien}; 195162303Simp#endif 196160581Sobrien 197160581Sobrienconst struct frame_unwind * 198160581Sobrienkgdb_trgt_trapframe_sniffer(struct frame_info *next_frame) 199160581Sobrien{ 200162303Simp#ifndef CROSS_DEBUGGER 201160581Sobrien char *pname; 202160581Sobrien CORE_ADDR pc; 203160581Sobrien 204160581Sobrien pc = frame_pc_unwind(next_frame); 205160581Sobrien pname = NULL; 206160581Sobrien find_pc_partial_function(pc, &pname, NULL, NULL); 207162303Simp if (pname == NULL) { 208162303Simp is_undef = 0; 209160581Sobrien return (NULL); 210162303Simp } 211162303Simp if (!strcmp(pname, "undefinedinstruction")) 212162303Simp is_undef = 1; 213160581Sobrien if (strcmp(pname, "Laddress_exception_entry") == 0 || 214160581Sobrien strcmp(pname, "undefined_entry") == 0 || 215160581Sobrien strcmp(pname, "exception_exit") == 0 || 216162303Simp strcmp(pname, "Laddress_exception_msg") == 0 || 217160581Sobrien strcmp(pname, "irq_entry") == 0) 218160581Sobrien return (&kgdb_trgt_trapframe_unwind); 219162303Simp if (!strcmp(pname, "undefinedinstruction")) 220162303Simp is_undef = 1; 221162303Simp else 222162303Simp is_undef = 0; 223162303Simp#endif 224160581Sobrien return (NULL); 225160581Sobrien} 226298358Swma 227298358Swma/* 228298358Swma * This function ensures, that the PC is inside the 229298358Swma * function section which is understood by GDB. 230298358Swma * 231298358Swma * Return 0 when fixup is necessary, -1 otherwise. 232298358Swma */ 233298358Swmaint 234298358Swmakgdb_trgt_pc_fixup(CORE_ADDR *pc) 235298358Swma{ 236298358Swma#ifndef CROSS_DEBUGGER 237298358Swma struct minimal_symbol *msymbol; 238298358Swma int valpc; 239298358Swma 240298358Swma /* 241298358Swma * exception_exit and swi_exit are special. These functions 242298358Swma * are artificially injected into the stack to be executed 243298358Swma * as the last entry in calling chain when all functions exit. 244298358Swma * Treat them differently. 245298358Swma */ 246298358Swma msymbol = lookup_minimal_symbol_by_pc(*pc); 247298358Swma if (msymbol != NULL) { 248298358Swma if (strcmp(DEPRECATED_SYMBOL_NAME(msymbol), "exception_exit") == 0) 249298358Swma return (0); 250298358Swma if (strcmp(DEPRECATED_SYMBOL_NAME(msymbol), "swi_exit") == 0) 251298358Swma return (0); 252298358Swma } 253298358Swma 254298358Swma /* 255298358Swma * kdb_enter contains an invalid instruction which is supposed 256298358Swma * to generate a trap. BFD does not understand it and treats 257298358Swma * this part of function as a separate function. Move PC 258298358Swma * two instruction earlier to be inside kdb_enter section. 259298358Swma */ 260298358Swma target_read_memory(*pc - 4, (char*)&valpc, 4); 261298358Swma if (valpc == 0xe7ffffff) { 262298358Swma *pc = *pc - 8; 263298358Swma return (0); 264298358Swma } 265298358Swma 266298358Swma /* 267298358Swma * When the panic/vpanic is the last (noreturn) function, 268298358Swma * the bottom of the calling function looks as below. 269298358Swma * mov lr, pc 270298358Swma * b panic 271298358Swma * Normally, GDB is not able to detect function boundaries, 272298358Swma * so move the PC two instruction earlier where it can deal 273298358Swma * with it. 274298358Swma * Match this pair of instructions: mov lr, pc followed with 275298358Swma * non-linked branch. 276298358Swma */ 277298358Swma if ((valpc & 0xff000000) == 0xea000000) { 278298358Swma target_read_memory(*pc - 8, (char*)&valpc, 4); 279298358Swma if (valpc == 0xe1a0e00f) { 280298358Swma *pc -= 8; 281298358Swma return (0); 282298358Swma } 283298358Swma } 284298358Swma#endif 285298358Swma return (-1); 286298358Swma} 287