treewide: Move device_tree to commonlib
[coreboot2.git] / payloads / libpayload / gdb / stub.c
blob019f27fcacf04599b439ae44b6f4595577ce09a6
1 /*
2 * Copyright 2014 Google Inc.
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.
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.
15 #include <gdb.h>
16 #include <libpayload.h>
18 struct gdb_state gdb_state;
20 static u8 reply_buf[2048];
21 static u8 command_buf[2048];
23 static struct gdb_message command = {
24 .buf = command_buf,
25 .used = 0,
26 .size = sizeof(command_buf),
28 static struct gdb_message reply = {
29 .buf = reply_buf,
30 .used = 0,
31 .size = sizeof(reply_buf),
34 void gdb_command_loop(u8 signal)
36 if (gdb_state.resumed) {
37 /* We were just running. Send a stop reply. */
38 reply.used = 0;
39 gdb_message_add_string(&reply, "S");
40 gdb_message_encode_bytes(&reply, &signal, 1);
41 gdb_send_reply(&reply);
44 gdb_state.signal = signal;
45 gdb_state.resumed = 0;
46 gdb_state.connected = 1;
48 while (1) {
49 int i;
51 gdb_get_command(&command);
53 reply.used = 0;
54 for (i = 0; i < gdb_command_count; i++) {
55 int clen = strlen(gdb_commands[i].str);
56 if (!strncmp(gdb_commands[i].str, (char *)command.buf,
57 MIN(clen, command.used))) {
58 gdb_commands[i].handler(&command, clen, &reply);
59 break;
63 /* If we're resuming, we won't send a reply until we stop. */
64 if (gdb_state.resumed)
65 return;
67 gdb_send_reply(&reply);
71 static void gdb_output_write(const void *buffer, size_t count)
73 if (!gdb_state.resumed) {
74 /* Must be a die_if() in GDB (or a bug), so bail out and die. */
75 gdb_exit(-1);
76 if (CONFIG(LP_VIDEO_CONSOLE))
77 video_console_init();
78 puts("GDB died, redirecting its last words to the screen:\n");
79 console_write(buffer, count);
80 } else {
81 reply.used = 0;
82 reply.buf[reply.used++] = 'O';
83 gdb_message_encode_bytes(&reply, buffer, count);
84 gdb_send_reply(&reply);
88 static struct console_output_driver gdb_output_driver = {
89 .write = &gdb_output_write
92 static void gdb_init(void)
94 printf("Ready for GDB connection.\n");
95 gdb_transport_init();
96 gdb_arch_init();
97 console_add_output_driver(&gdb_output_driver);
100 void gdb_enter(void)
102 if (!gdb_state.connected)
103 gdb_init();
104 gdb_arch_enter();
107 void gdb_exit(s8 exit_status)
109 if (!gdb_state.connected)
110 return;
112 reply.used = 0;
113 gdb_message_add_string(&reply, "W");
114 gdb_message_encode_bytes(&reply, &exit_status, 1);
115 gdb_send_reply(&reply);
117 console_remove_output_driver(&gdb_output_write);
118 gdb_transport_teardown();
119 gdb_state.connected = 0;
120 printf("Detached from GDB connection.\n");
124 * This is a check architecture backends can run before entering the GDB command
125 * loop during exception handling. If it returns true, GDB was already running
126 * and must have caused an exception itself, which may happen if the GDB server
127 * tells us to do something stupid (e.g. write to an unmapped address). In that
128 * case, all we can do is blindly send a generic error code (since we're not
129 * sure which command caused the exception) and continue serving commands. When
130 * GDB eventually tells us to resume, we'll return from this function to the
131 * architecture backend which will have to do a "super exception return" that
132 * returns right back from the original (outermost) exception, "jumping over"
133 * all the intermediate exception frames we may have accumulated since. (This is
134 * the best we can do because our architecture backends generally don't support
135 * "full", unlimited exception reentrancy.)
137 int gdb_handle_reentrant_exception(void)
139 if (!gdb_state.connected || gdb_state.resumed)
140 return 0; /* This is not a reentrant exception. */
142 static const char error_code[] = "E22"; /* EINVAL? */
143 static const struct gdb_message tmp_reply = {
144 .buf = (u8 *)error_code,
145 .used = sizeof(error_code),
146 .size = sizeof(error_code),
148 gdb_send_reply(&tmp_reply);
149 gdb_command_loop(gdb_state.signal); /* preserve old signal */
150 return 1;