blob: faf9eb48f268f3b5332a93bc24f5a44c8e5fc052 [file] [log] [blame]
Julius Werner50a81742014-05-15 11:57:38 -07001/*
2 * Copyright 2014 Google Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but without any warranty; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <exception.h>
20#include <gdb.h>
21#include <libpayload.h>
22
23struct gdb_regs
24{
25 u32 r[16];
26 struct fp_reg
27 {
28 u8 byte[12];
29 } __attribute__((packed)) f[8];
30 u32 fps;
31 u32 cpsr;
32} __attribute__((packed));
33
34static const u8 type_to_signal[] = {
35 [EXC_UNDEF] = GDB_SIGILL,
36 [EXC_SWI] = GDB_SIGTRAP,
37 [EXC_PABORT] = GDB_SIGSEGV,
38 [EXC_DABORT] = GDB_SIGSEGV,
39};
40
41/* Scratch value to write reentrant exception states to. We never read it. */
42static struct exception_state sentinel_exception_state;
43
44static int gdb_exception_hook(u32 type)
45{
46 /*
47 * If we were not resumed we are in deep trouble here. GDB probably told
48 * us to do something stupid and caused a reentrant exception. All we
49 * can do is just blindly send an error code and keep going. Eventually
50 * GDB will tell us to resume and we return right back to the original
51 * exception state ("jumping over" all the nested ones).
52 */
53 if (gdb_state.connected && !gdb_state.resumed) {
54 static const char error_code[] = "E22"; /* EINVAL? */
55 static const struct gdb_message tmp_reply = {
56 .buf = (u8 *)error_code,
57 .used = sizeof(error_code),
58 .size = sizeof(error_code),
59 };
60 gdb_send_reply(&tmp_reply);
61 gdb_command_loop(gdb_state.signal); /* preserve old signal */
62 } else {
63 if (type >= ARRAY_SIZE(type_to_signal) || !type_to_signal[type])
64 return 0;
65 exception_state_ptr = &sentinel_exception_state;
66 gdb_command_loop(type_to_signal[type]);
67 }
68
69 exception_state_ptr = &exception_state;
70 return 1;
71}
72
73void gdb_arch_init(void)
74{
75 exception_install_hook(&gdb_exception_hook);
76}
77
78void gdb_arch_enter(void)
79{
80 u32 *sp;
81
82 asm volatile ("mov %0, %%sp" : "=r"(sp) );
83
84 /* Avoid reentrant exceptions, just call the hook if in one already. */
85 if (sp >= exception_stack && sp <= exception_stack_end)
86 gdb_exception_hook(EXC_SWI);
87 else
88 asm volatile ("svc #0");
89}
90
91int gdb_arch_set_single_step(int on)
92{
93 /* GDB seems to only need this on x86, ARM works fine without it. */
94 return -1;
95}
96
97void gdb_arch_encode_regs(struct gdb_message *message)
98{
99 gdb_message_encode_bytes(message, exception_state.regs,
100 sizeof(exception_state.regs));
101 gdb_message_encode_zero_bytes(message,
102 offsetof(struct gdb_regs, cpsr) - offsetof(struct gdb_regs, f));
103 gdb_message_encode_bytes(message, &exception_state.cpsr,
104 sizeof(exception_state.cpsr));
105}
106
107void gdb_arch_decode_regs(int offset, struct gdb_message *message)
108{
109 const int cpsr_hex_offset = offsetof(struct gdb_regs, cpsr) * 2;
110 gdb_message_decode_bytes(message, offset,
111 exception_state.regs, sizeof(exception_state.regs));
112 gdb_message_decode_bytes(message, offset + cpsr_hex_offset,
113 &exception_state.cpsr, sizeof(exception_state.cpsr));
114}