1/** \file
2 * \brief Architecture-independent parts of in-kernel GDB stub.
3 *
4 * This file implements the kernel-side GDB stubs for remote debugging when
5 * running on hardware. It is loosely based on the public domain i386-stub.c
6 * which is part of the GDB sources.
7 *
8 * The following gdb commands are supported:
9 *
10 *<table>
11 *<tr><td>command</td><td>function</td><td>Return value</td></tr>
12 *<tr><td>?</td><td>What was the last sigval ?</td><td>SNN (signal NN)</td></tr>
13 *<tr><td>g</td><td>return the value of the CPU registers</td><td>hex data or ENN</td></tr>
14 *<tr><td>G</td><td>set the value of the CPU registers</td><td>OK or ENN</td></tr>
15 *<tr><td>p</td><td>read the value of a single CPU register</td><td>hex data or ENN</td></tr>
16 *<tr><td>P</td><td>set the value of a single CPU register</td><td>OK or ENN</td></tr>
17 *<tr><td>mAA..AA,LLLL</td><td>Read LLLL bytes at address AA..AA</td><td>hex data or ENN</td></tr>
18 *<tr><td>MAA..AA,LLLL:</td><td>Write LLLL bytes at address AA.AA</td><td>OK or ENN</td></tr>
19 *<tr><td>c</td><td>Resume at current address</td><td>SNN (signal NN)</td></tr>
20 *<tr><td>cAA..AA</td><td>Continue at address AA..AA</td><td>SNN</td></tr>
21 *<tr><td>s</td><td>Step one instruction</td><td>SNN</td></tr>
22 *<tr><td>sAA..AA</td><td>Step one instruction from AA..AA</td><td>SNN</td></tr>
23 *<tr><td>D</td><td>GDB detached -- attempt to resume</td><td>(no reply)</td></tr>
24 *<tr><td>k</td><td>kill -- reboots the system</td><td>(no reply)</td></tr>
25 *</table>
26 *
27 * All commands and responses are sent with a packet which includes a
28 * checksum. A packet consists of $\<packet info\>#\<checksum\> where:
29 *
30 * - \<packet info\> :: characters representing the command or response
31 * - \<checksum\> :: two hex digits computed as mod-256 sum of \<packet info\>
32 *
33 * When a packet is received, it is first acknowledged with either '+' or '-'.
34 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
35 *
36 * Example:
37 * - Host: $m0,10#2a
38 * - Reply: +$00010203040506070809101112131415#42
39 */
40
41/*
42 * Copyright (c) 2007, ETH Zurich.
43 * All rights reserved.
44 *
45 * This file is distributed under the terms in the attached LICENSE file.
46 * If you do not find this file, copies can be found by writing to:
47 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
48 */
49
50#include <kernel.h>
51#include <barrelfish_kpi/cpu.h>
52#include <stdio.h>
53#include <string.h>
54#include <serial.h>
55#include <exec.h>
56#include <gdb_stub.h>
57#include <arch_gdb_stub.h>
58
59/** \brief Flag. Enables debug messages from the stub itself. */
60#define DEBUG_ENABLED true
61
62/** \brief Quick-and-dirty debug message macro. */
63#define DEBUG(...)                          \
64    if (DEBUG_ENABLED) {                    \
65        debug(SUBSYS_GDB, __VA_ARGS__);     \
66    }
67
68/** \brief Defines the maximum number of characters in in/outbound buffers.
69 *
70 * At least NUMREGBYTES * 2 are needed for register packets. */
71#define BUFMAX 512
72
73/** \brief Wrapper for debugger output. */
74static inline void myputchar(char c)
75{
76    serial_debug_putchar(c);
77}
78
79/** \brief Wrapper for debugger input. */
80static inline char mygetchar(void)
81{
82    return serial_debug_getchar();
83}
84
85/** \brief Convert an ASCII hex character to its numeric value.
86 * \return -1 if the character is invalid. */
87static int fromhex(char ch)
88{
89    if ((ch >= 'a') && (ch <= 'f')) {
90        return ch - 'a' + 10;
91    } else if ((ch >= '0') && (ch <= '9')) {
92        return ch - '0';
93    } else if ((ch >= 'A') && (ch <= 'F')) {
94        return ch - 'A' + 10;
95    } else {
96        return -1;
97    }
98}
99
100/** \brief Convert a number 0..15 to the corresponding hex character. */
101static char tohex(int i)
102{
103    static const char hexchars[] = "0123456789abcdef";
104    assert(i >= 0 && i <= 0xf);
105    return hexchars[i];
106}
107
108/** \brief Parse a hex-encoded integer
109 *
110 * Reads a hex-encoded integer into val, stopping at the first non-hex character
111 * \return first position after the end of the consumed characters
112 */
113static const char * NONNULL NTS parse_hex_val(const char * NONNULL NTS str,
114                                              uintptr_t * NONNULL val)
115{
116    uintptr_t ret = 0;
117
118    for (int pos = 0; true; pos++) {
119        int value = fromhex(str[pos]);
120        if (value >= 0) {
121            assert(pos < sizeof(uintptr_t) * 2); // overflow
122            ret = (ret << 4) | value;
123        } else {
124            *val = ret;
125            return &str[pos];
126        }
127    }
128}
129
130/** \brief Read memory region into a buffer as a hex string.
131 *
132 * Converts the memory pointed to by mem (of length memlen) into a hex string,
133 * placing the result into buf (of length buflen), and terminating with a \\0.
134 * \return Number of characters written on success, negative on failure.
135 * May fail if a page fault would be incurred.
136 */
137static int mem_to_hex(lvaddr_t mem, size_t memlen,
138                      char * NONNULL COUNT(buflen) buf, size_t buflen)
139{
140    int bufpos = 0;
141    uint8_t ch;
142    int r;
143
144    if (buflen < memlen * 2 + 1) {
145        return -1; // not enough space in output buffer
146    }
147
148    for (int mempos = 0; mempos < memlen; mempos++) {
149        r = gdb_arch_read_byte((uint8_t * SAFE NONNULL)TC(mem + mempos), &ch);
150        if (r != 0) {
151            return r;
152        }
153
154        buf[bufpos++] = tohex(ch >> 4);  // top bits of char
155        buf[bufpos++] = tohex(ch & 0xf); // bottom bits of char
156    }
157
158    buf[bufpos++] = '\0';
159    return bufpos;
160}
161
162/** \brief Copy data from hex string in buffer to raw memory region.
163 *
164 * Writes data in the provided hex string buffer into the given memory region.
165 * \return zero on success, negative on failure.
166 * May fail if a page fault would be incurred.
167 */
168static int hex_to_mem(const char * NONNULL NT COUNT(memlen * 2) buf,
169                      lvaddr_t mem, size_t memlen)
170{
171    for (int mempos = 0; mempos < memlen; mempos++) {
172        uint8_t ch;
173
174        assert(*buf != '\0');
175        ch = fromhex(*buf++) << 4;
176        assert(*buf != '\0');
177        ch += fromhex(*buf++);
178
179        int r = gdb_arch_write_byte(&((uint8_t * SAFE NONNULL)TC(mem))[mempos],
180                                    ch);
181        if (r != 0) {
182            return r;
183        }
184    }
185
186    return 0;
187}
188
189/** \brief Wait to receive a valid checksummed packet from GDB.
190 *
191 * Scans input for the sequence $\<packet info\>#\<checksum\>. If the
192 * checksum is valid, acknowledges it to the sender and returns the buffer.
193 * If invalid, reports failure to the sender and waits for the retransmission.
194 */
195static const char * NONNULL NTS getpacket(void)
196{
197    static char (NT buffer)[BUFMAX];
198    uint8_t checksum, xmitcsum;
199    int bufpos;
200    char ch = 0; /* shut up a useless deputy warning */
201
202    while (true) {
203        /* wait around for the start character, ignore all other characters */
204        while (mygetchar() != '$') {}
205
206retry:
207        checksum = 0;
208        bufpos = 0;
209
210        /* now, read until a # or end of buffer is found */
211        while (bufpos < BUFMAX - 1) {
212            ch = mygetchar();
213            if (ch == '$') {
214                goto retry; // invalid
215            } else if (ch == '#') {
216                break; // found start of checksum
217            }
218            checksum += ch;
219            buffer[bufpos++] = ch;
220        }
221        buffer[bufpos] = 0;
222
223        if (bufpos == BUFMAX - 1) {
224            DEBUG("Warning: Incoming buffer full in getpacket()");
225        }
226
227        if (ch == '#') {
228            xmitcsum = fromhex(mygetchar()) << 4;
229            xmitcsum += fromhex(mygetchar());
230
231            if (checksum != xmitcsum) {
232                DEBUG("bad checksum. My count=0x%x, sent=0x%x. buf='%s'",
233                      checksum, xmitcsum, buffer);
234                myputchar('-'); // failed checksum
235            } else {
236                myputchar('+'); // successful transfer
237                return buffer;
238            }
239        }
240    }
241}
242
243/** \brief Send the packet in the buffer, adding a checksum.
244 *
245 * Sends the packet, using the format: $\<packet info\>#\<checksum\>.
246 * Loops until it receives an acknowledgement response ('+') from GDB.
247 */
248static void putpacket(char * NONNULL NTS buffer)
249{
250    do {
251        uint8_t checksum = 0;
252        myputchar('$');
253
254        for (int pos = 0; buffer[pos] != '\0'; pos++) {
255            char ch = buffer[pos];
256            myputchar(ch);
257            checksum += ch;
258        }
259
260        myputchar('#');
261        myputchar(tohex(checksum >> 4));   // top bits of checksum
262        myputchar(tohex(checksum & 0xf));  // bottom bits of checksum
263    } while (mygetchar() != '+');
264}
265
266/** \brief Generic entry point to the GDB stub.
267 *
268 * Wait for a remote GDB to start talking to us, and then service its requests.
269 * This function should run on a different stack the main kernel, and does not
270 * return.
271 * \param signal_code Unix-style signal value indicating reason for interruption
272 * \param init_message Optional initial message to send to the remote GDB
273 */
274void gdb_stub_entry(int signal_code, char * OPT NTS init_message)
275{
276    const char * NONNULL NTS request;
277    const char * NONNULL NTS newpos;
278    static char (NT buffer)[BUFMAX];
279    static bool gdb_connected = false;
280    char *reply;
281    uintptr_t addr, length, regnum, value;
282    int r;
283
284    /* send initial message, if gdb is listening for it */
285    if (init_message && gdb_connected) {
286        putpacket(init_message);
287    } else if (!gdb_connected) {
288        printk(LOG_NOTE, "Waiting for GDB connection...\n");
289    }
290
291    /* loop handling requests */
292    while (true) {
293        request = getpacket();
294        gdb_connected = true;
295        reply = buffer;
296
297        switch (*request++) {
298
299        case '?':
300            /* Indicate reason target halted */
301            r = snprintf(buffer, sizeof(buffer), "S%02hhx", signal_code);
302            assert(r < sizeof(buffer));
303            if (r >= sizeof(buffer)) {
304                /* ensure termination */
305                buffer[sizeof(buffer) - 1] = '\0';
306            }
307            break;
308
309        case 'g':
310            /* Read general registers */
311            r = mem_to_hex((lvaddr_t)GDB_ARCH_REGADDR, GDB_ARCH_REGBYTES,
312                           buffer, sizeof(buffer));
313            if (r < 0) {
314                reply = "E03";
315            }
316            break;
317
318        case 'G':
319            /* Write general registers */
320            r = hex_to_mem(request, (lvaddr_t)GDB_ARCH_REGADDR,
321                           GDB_ARCH_REGBYTES);
322            if (r == 0) {
323                reply = "OK";
324            } else {
325                reply = "E03";
326            }
327            break;
328
329        case 'p':
330            /* Read a single register */
331            newpos = parse_hex_val(request, &regnum);
332            if (newpos == request) {
333                reply = "E01";
334                break;
335            }
336
337            r = gdb_arch_get_register(regnum, &value);
338            if (r != 0) {
339                reply = "E02";
340                break;
341            }
342
343            r = mem_to_hex((lvaddr_t)&value, sizeof(uintptr_t), buffer,
344                           sizeof(buffer));
345            if (r < 0) {
346                reply = "E03";
347            }
348            break;
349
350        case 'P':
351            /* Write a single register */
352            newpos = parse_hex_val(request, &regnum);
353            if (newpos == request || *newpos != '=') {
354                reply = "E01";
355                break;
356            }
357            request = newpos + 1;
358            newpos = parse_hex_val(request, &value);
359            if (newpos == request) {
360                reply = "E01";
361                break;
362            }
363
364            r = gdb_arch_set_register(regnum, value);
365            if (r == 0) {
366                reply = "OK";
367            } else {
368                reply = "E02";
369            }
370            break;
371
372        case 'm':
373            /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
374            request = parse_hex_val(request, &addr);
375            if (addr == 0 || *(request++) != ',') {
376                reply = "E01";
377                break;
378            }
379            request = parse_hex_val(request, &length);
380            if (length == 0) {
381                reply = "E01";
382                break;
383            }
384            r = mem_to_hex(addr, length, buffer, sizeof(buffer));
385            if (r < 0) {
386                reply = "E03";
387            }
388            break;
389
390        case 'M':
391            /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
392            request = parse_hex_val(request, &addr);
393            if (addr == 0 || *request++ != ',') {
394                reply = "E01";
395                break;
396            }
397            request = parse_hex_val(request, &length);
398            if (length == 0 || *request++ != ':') {
399                reply = "E01";
400                break;
401            }
402            r = hex_to_mem(request, addr, length);
403            if (r == 0) {
404                reply = "OK";
405            } else {
406                reply = "E03";
407            }
408            break;
409
410        case 's':
411            /* Single step */
412            parse_hex_val(request, &addr); // try to read optional parameter
413            gdb_arch_single_step(addr); // should not return
414            reply = "E02";
415            break;
416
417        case 'c':
418            /* Continue execution */
419            parse_hex_val(request, &addr); // try to read optional parameter
420            gdb_arch_continue(addr); // should not return
421            reply = "E02";
422            break;
423
424        case 'D':
425            /* GDB detached, try to continue */
426            printk(LOG_NOTE, "GDB has detached. Attempting to continue...");
427            gdb_connected = false;
428            gdb_arch_continue(0);
429            break;
430
431        case 'k':
432            /* Kill the program */
433            printk(LOG_NOTE, "Kill requested by remote GDB.\n");
434            reboot();
435            break;
436
437        default:
438            /* unsupported command */
439            reply = "";
440            break;
441        }
442
443        putpacket(reply);
444    }
445}
446