]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/gdb/gdb_main.c
Merge OpenSSL 1.0.2m.
[FreeBSD/FreeBSD.git] / sys / gdb / gdb_main.c
1 /*-
2  * Copyright (c) 2004 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kdb.h>
33 #include <sys/kernel.h>
34 #include <sys/pcpu.h>
35 #include <sys/proc.h>
36 #include <sys/reboot.h>
37
38 #include <machine/gdb_machdep.h>
39 #include <machine/kdb.h>
40
41 #include <gdb/gdb.h>
42 #include <gdb/gdb_int.h>
43
44 static dbbe_init_f gdb_init;
45 static dbbe_trap_f gdb_trap;
46
47 KDB_BACKEND(gdb, gdb_init, NULL, NULL, gdb_trap);
48
49 static struct gdb_dbgport null_gdb_dbgport;
50 DATA_SET(gdb_dbgport_set, null_gdb_dbgport);
51 SET_DECLARE(gdb_dbgport_set, struct gdb_dbgport);
52
53 struct gdb_dbgport *gdb_cur = NULL;
54 int gdb_listening = 0;
55
56 static unsigned char gdb_bindata[64];
57
58 static int
59 gdb_init(void)
60 {
61         struct gdb_dbgport *dp, **iter;
62         int cur_pri, pri;
63
64         gdb_cur = NULL;
65         cur_pri = -1;
66         SET_FOREACH(iter, gdb_dbgport_set) {
67                 dp = *iter;
68                 pri = (dp->gdb_probe != NULL) ? dp->gdb_probe() : -1;
69                 dp->gdb_active = (pri >= 0) ? 0 : -1;
70                 if (pri > cur_pri) {
71                         cur_pri = pri;
72                         gdb_cur = dp;
73                 }
74         }
75         if (gdb_cur != NULL) {
76                 printf("GDB: debug ports:");
77                 SET_FOREACH(iter, gdb_dbgport_set) {
78                         dp = *iter;
79                         if (dp->gdb_active == 0)
80                                 printf(" %s", dp->gdb_name);
81                 }
82                 printf("\n");
83         } else
84                 printf("GDB: no debug ports present\n");
85         if (gdb_cur != NULL) {
86                 gdb_cur->gdb_init();
87                 printf("GDB: current port: %s\n", gdb_cur->gdb_name);
88         }
89         if (gdb_cur != NULL) {
90                 cur_pri = (boothowto & RB_GDB) ? 2 : 0;
91                 gdb_consinit();
92         } else
93                 cur_pri = -1;
94         return (cur_pri);
95 }
96
97 static void
98 gdb_do_mem_search(void)
99 {
100         size_t patlen;
101         intmax_t addr, size;
102         const unsigned char *found;
103
104         if (gdb_rx_varhex(&addr) || gdb_rx_char() != ';' ||
105             gdb_rx_varhex(&size) || gdb_rx_char() != ';' ||
106             gdb_rx_bindata(gdb_bindata, sizeof(gdb_bindata), &patlen)) {
107                 gdb_tx_err(EINVAL);
108                 return;
109         }
110         if (gdb_search_mem((char *)(uintptr_t)addr, size, gdb_bindata,
111             patlen, &found)) {
112                 if (found == 0ULL)
113                         gdb_tx_begin('0');
114                 else {
115                         gdb_tx_begin('1');
116                         gdb_tx_char(',');
117                         gdb_tx_hex((intmax_t)(uintptr_t)found, 8);
118                 }
119                 gdb_tx_end();
120         } else
121                 gdb_tx_err(EIO);
122 }
123
124 static int
125 gdb_trap(int type, int code)
126 {
127         jmp_buf jb;
128         struct thread *thr_iter;
129         void *prev_jb;
130
131         prev_jb = kdb_jmpbuf(jb);
132         if (setjmp(jb) != 0) {
133                 printf("%s bailing, hopefully back to ddb!\n", __func__);
134                 gdb_listening = 0;
135                 (void)kdb_jmpbuf(prev_jb);
136                 return (1);
137         }
138
139         gdb_listening = 0;
140         /*
141          * Send a T packet. We currently do not support watchpoints (the
142          * awatch, rwatch or watch elements).
143          */
144         gdb_tx_begin('T');
145         gdb_tx_hex(gdb_cpu_signal(type, code), 2);
146         gdb_tx_varhex(GDB_REG_PC);
147         gdb_tx_char(':');
148         gdb_tx_reg(GDB_REG_PC);
149         gdb_tx_char(';');
150         gdb_tx_str("thread:");
151         gdb_tx_varhex((long)kdb_thread->td_tid);
152         gdb_tx_char(';');
153         gdb_tx_end();                   /* XXX check error condition. */
154
155         thr_iter = NULL;
156         while (gdb_rx_begin() == 0) {
157                 /* printf("GDB: got '%s'\n", gdb_rxp); */
158                 switch (gdb_rx_char()) {
159                 case '?':       /* Last signal. */
160                         gdb_tx_begin('S');
161                         gdb_tx_hex(gdb_cpu_signal(type, code), 2);
162                         gdb_tx_end();
163                         break;
164                 case 'c': {     /* Continue. */
165                         uintmax_t addr;
166                         register_t pc;
167                         if (!gdb_rx_varhex(&addr)) {
168                                 pc = addr;
169                                 gdb_cpu_setreg(GDB_REG_PC, &pc);
170                         }
171                         kdb_cpu_clear_singlestep();
172                         gdb_listening = 1;
173                         return (1);
174                 }
175                 case 'C': {     /* Continue with signal. */
176                         uintmax_t addr, sig;
177                         register_t pc;
178                         if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' &&
179                             !gdb_rx_varhex(&addr)) {
180                                 pc = addr;
181                                 gdb_cpu_setreg(GDB_REG_PC, &pc);
182                         }
183                         kdb_cpu_clear_singlestep();
184                         gdb_listening = 1;
185                         return (1);
186                 }
187                 case 'D': {     /* Detach */
188                         gdb_tx_ok();
189                         kdb_cpu_clear_singlestep();
190                         return (1);
191                 }
192                 case 'g': {     /* Read registers. */
193                         size_t r;
194                         gdb_tx_begin(0);
195                         for (r = 0; r < GDB_NREGS; r++)
196                                 gdb_tx_reg(r);
197                         gdb_tx_end();
198                         break;
199                 }
200                 case 'G':       /* Write registers. */
201                         gdb_tx_err(0);
202                         break;
203                 case 'H': {     /* Set thread. */
204                         intmax_t tid;
205                         struct thread *thr;
206                         gdb_rx_char();
207                         if (gdb_rx_varhex(&tid)) {
208                                 gdb_tx_err(EINVAL);
209                                 break;
210                         }
211                         if (tid > 0) {
212                                 thr = kdb_thr_lookup(tid);
213                                 if (thr == NULL) {
214                                         gdb_tx_err(ENOENT);
215                                         break;
216                                 }
217                                 kdb_thr_select(thr);
218                         }
219                         gdb_tx_ok();
220                         break;
221                 }
222                 case 'k':       /* Kill request. */
223                         kdb_cpu_clear_singlestep();
224                         gdb_listening = 1;
225                         return (1);
226                 case 'm': {     /* Read memory. */
227                         uintmax_t addr, size;
228                         if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' ||
229                             gdb_rx_varhex(&size)) {
230                                 gdb_tx_err(EINVAL);
231                                 break;
232                         }
233                         gdb_tx_begin(0);
234                         if (gdb_tx_mem((char *)(uintptr_t)addr, size))
235                                 gdb_tx_end();
236                         else
237                                 gdb_tx_err(EIO);
238                         break;
239                 }
240                 case 'M': {     /* Write memory. */
241                         uintmax_t addr, size;
242                         if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' ||
243                             gdb_rx_varhex(&size) || gdb_rx_char() != ':') {
244                                 gdb_tx_err(EINVAL);
245                                 break;
246                         }
247                         if (gdb_rx_mem((char *)(uintptr_t)addr, size) == 0)
248                                 gdb_tx_err(EIO);
249                         else
250                                 gdb_tx_ok();
251                         break;
252                 }
253                 case 'P': {     /* Write register. */
254                         char *val;
255                         uintmax_t reg;
256                         val = gdb_rxp;
257                         if (gdb_rx_varhex(&reg) || gdb_rx_char() != '=' ||
258                             !gdb_rx_mem(val, gdb_cpu_regsz(reg))) {
259                                 gdb_tx_err(EINVAL);
260                                 break;
261                         }
262                         gdb_cpu_setreg(reg, val);
263                         gdb_tx_ok();
264                         break;
265                 }
266                 case 'q':       /* General query. */
267                         if (gdb_rx_equal("fThreadInfo")) {
268                                 thr_iter = kdb_thr_first();
269                                 gdb_tx_begin('m');
270                                 gdb_tx_hex((long)thr_iter->td_tid, 8);
271                                 gdb_tx_end();
272                         } else if (gdb_rx_equal("sThreadInfo")) {
273                                 if (thr_iter == NULL) {
274                                         gdb_tx_err(ENXIO);
275                                         break;
276                                 }
277                                 thr_iter = kdb_thr_next(thr_iter);
278                                 if (thr_iter != NULL) {
279                                         gdb_tx_begin('m');
280                                         gdb_tx_hex((long)thr_iter->td_tid, 8);
281                                         gdb_tx_end();
282                                 } else {
283                                         gdb_tx_begin('l');
284                                         gdb_tx_end();
285                                 }
286                         } else if (gdb_rx_equal("Search:memory:")) {
287                                 gdb_do_mem_search();
288                         } else if (!gdb_cpu_query())
289                                 gdb_tx_empty();
290                         break;
291                 case 's': {     /* Step. */
292                         uintmax_t addr;
293                         register_t pc;
294                         if (!gdb_rx_varhex(&addr)) {
295                                 pc = addr;
296                                 gdb_cpu_setreg(GDB_REG_PC, &pc);
297                         }
298                         kdb_cpu_set_singlestep();
299                         gdb_listening = 1;
300                         return (1);
301                 }
302                 case 'S': {     /* Step with signal. */
303                         uintmax_t addr, sig;
304                         register_t pc;
305                         if (!gdb_rx_varhex(&sig) && gdb_rx_char() == ';' &&
306                             !gdb_rx_varhex(&addr)) {
307                                 pc = addr;
308                                 gdb_cpu_setreg(GDB_REG_PC, &pc);
309                         }
310                         kdb_cpu_set_singlestep();
311                         gdb_listening = 1;
312                         return (1);
313                 }
314                 case 'T': {     /* Thread alive. */
315                         intmax_t tid;
316                         if (gdb_rx_varhex(&tid)) {
317                                 gdb_tx_err(EINVAL);
318                                 break;
319                         }
320                         if (kdb_thr_lookup(tid) != NULL)
321                                 gdb_tx_ok();
322                         else
323                                 gdb_tx_err(ENOENT);
324                         break;
325                 }
326                 case -1:
327                         /* Empty command. Treat as unknown command. */
328                         /* FALLTHROUGH */
329                 default:
330                         /* Unknown command. Send empty response. */
331                         gdb_tx_empty();
332                         break;
333                 }
334         }
335         (void)kdb_jmpbuf(prev_jb);
336         return (0);
337 }