stub.c
1 /* 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 15 #include <gdb.h> 16 #include <libpayload.h> 17 18 struct gdb_state gdb_state; 19 20 static u8 reply_buf[2048]; 21 static u8 command_buf[2048]; 22 23 static struct gdb_message command = { 24 .buf = command_buf, 25 .used = 0, 26 .size = sizeof(command_buf), 27 }; 28 static struct gdb_message reply = { 29 .buf = reply_buf, 30 .used = 0, 31 .size = sizeof(reply_buf), 32 }; 33 34 void gdb_command_loop(u8 signal) 35 { 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); 42 43 } 44 gdb_state.signal = signal; 45 gdb_state.resumed = 0; 46 gdb_state.connected = 1; 47 48 while (1) { 49 int i; 50 51 gdb_get_command(&command); 52 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; 60 } 61 } 62 63 /* If we're resuming, we won't send a reply until we stop. */ 64 if (gdb_state.resumed) 65 return; 66 67 gdb_send_reply(&reply); 68 } 69 } 70 71 static void gdb_output_write(const void *buffer, size_t count) 72 { 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); 85 } 86 } 87 88 static struct console_output_driver gdb_output_driver = { 89 .write = &gdb_output_write 90 }; 91 92 static void gdb_init(void) 93 { 94 printf("Ready for GDB connection.\n"); 95 gdb_transport_init(); 96 gdb_arch_init(); 97 console_add_output_driver(&gdb_output_driver); 98 } 99 100 void gdb_enter(void) 101 { 102 if (!gdb_state.connected) 103 gdb_init(); 104 gdb_arch_enter(); 105 } 106 107 void gdb_exit(s8 exit_status) 108 { 109 if (!gdb_state.connected) 110 return; 111 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); 116 117 console_remove_output_driver(&gdb_output_write); 118 gdb_transport_teardown(); 119 gdb_state.connected = 0; 120 printf("Detached from GDB connection.\n"); 121 } 122 123 /* 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.) 136 */ 137 int gdb_handle_reentrant_exception(void) 138 { 139 if (!gdb_state.connected || gdb_state.resumed) 140 return 0; /* This is not a reentrant exception. */ 141 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), 147 }; 148 gdb_send_reply(&tmp_reply); 149 gdb_command_loop(gdb_state.signal); /* preserve old signal */ 150 return 1; 151 }