1 /* Includes {{{ */
2 #if HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5
6 #if HAVE_STDIO_H
7 #include <stdio.h>
8 #endif /* HAVE_STDIO_H */
9
10 #if HAVE_UNISTD_H
11 #include <unistd.h>
12 #endif /* HAVE_UNISTD_H */
13
14 #if HAVE_SIGNAL_H
15 #include <signal.h> /* sig_atomic_t */
16 #endif
17
18 #if HAVE_STRING_H
19 #include <string.h>
20 #endif /* HAVE_STRING_H */
21
22 #if HAVE_SYS_WAIT_H
23 #include <sys/wait.h>
24 #endif
25
26 #define __STDC_FORMAT_MACROS
27 #include <inttypes.h>
28
29 #include <list>
30 #include <sstream>
31
32 #include "tgdb.h"
33 #include "fork_util.h"
34 #include "io.h"
35 #include "terminal.h"
36 #include "pseudo.h" /* SLAVE_SIZE constant */
37 #include "sys_util.h"
38 #include "stretchy.h"
39 #include "cgdb_clog.h"
40 #include "gdbwire.h"
41
42 /* }}} */
43
44 /* struct tgdb {{{ */
45
46 typedef struct tgdb_request *tgdb_request_ptr;
47 typedef std::list<tgdb_request_ptr> tgdb_request_ptr_list;
48
49 /**
50 * The TGDB context data structure.
51 */
52 struct tgdb {
53 /** Reading from this will read from the debugger's output */
54 int debugger_stdout;
55
56 /** Writing to this will write to the debugger's stdin */
57 int debugger_stdin;
58
59 /**
60 * The gdb new-ui mi console file descriptor.
61 *
62 * Writing to this will write to the gdb/mi interpreter.
63 * Reading from it will read the output of the gdb/mi interpreter.
64 */
65 int gdb_mi_ui_fd;
66
67 /** The master, slave and slavename of the new-ui pty device */
68 pty_pair_ptr new_ui_pty_pair;
69
70 /** The pid of child process */
71 pid_t debugger_pid;
72
73 /** The list of command requests to process */
74 tgdb_request_ptr_list *command_requests;
75
76 /**
77 * If set to 1, libtgdb thinks the lower level subsystem is capable of
78 * receiving another command. It needs this so that it doesn't send 2
79 * commands to the lower level before it can say it can't receive a command.
80 * At some point, maybe this can be removed?
81 * When its set to 0, libtgdb thinks it can not send the lower level another
82 * command.
83 *
84 * Basically whether gdb is at prompt or not. */
85 int is_gdb_ready_for_next_command;
86
87 /** If ^c was hit by user */
88 sig_atomic_t control_c;
89
90 tgdb_callbacks callbacks;
91
92 // commands structure
93 // The current command request type that is executing. NULL to start.
94 enum tgdb_request_type current_request_type;
95
96 // The disassemble command output.
97 char **disasm;
98 uint64_t address_start, address_end;
99
100 // The gdbwire context to talk to GDB with.
101 struct gdbwire *wire;
102
103 // True if the disassemble command supports /s, otherwise false.
104 int disassemble_supports_s_mode;
105
106 // True if GDB supports the 'new-ui' command, otherwise false.
107 // If gdb prints out,
108 // Undefined command: "new-ui". Try "help".
109 // on the console output, then it does not support the new-ui command.
110 // Otherwise it is assumed that it does support the command.
111 bool gdb_supports_new_ui_command;
112
113 // Temporary buffer used to store the line by line console output
114 // in order to search for the unsupported new ui string above.
115 std::string *undefined_new_ui_command;
116 };
117
118 // This is the type of request
119 struct tgdb_request {
120 enum tgdb_request_type header;
121
122 union {
123 struct {
124 // The null terminated console command to pass to GDB
125 const char *command;
126 } console_command;
127
128 struct {
129 const char *slavename;
130 } tty_command;
131
132 struct {
133 // This is the command that libtgdb should run through the debugger
134 enum tgdb_command_type c;
135 } debugger_command;
136
137 struct {
138 // The filename to set the breakpoint in
139 const char *file;
140 // The corresponding line number
141 int line;
142 // The address to set breakpoint in (if file is null)
143 uint64_t addr;
144 // The action to take
145 enum tgdb_breakpoint_action b;
146 } modify_breakpoint;
147
148 struct {
149 int lines;
150 } disassemble;
151
152 struct {
153 int source;
154 int raw;
155 } disassemble_func;
156 } choice;
157 };
158
159 /* }}} */
160
161 /* Temporary prototypes {{{ */
162 struct tgdb_response *tgdb_create_response(enum tgdb_response_type header);
163 void tgdb_send_response(struct tgdb *tgdb, struct tgdb_response *response);
164 static void tgdb_run_request(struct tgdb *tgdb, struct tgdb_request *request);
165 static void tgdb_unqueue_and_deliver_command(struct tgdb *tgdb);
166 void tgdb_run_or_queue_request(struct tgdb *tgdb,
167 struct tgdb_request *request, bool priority);
168
169 /* }}} */
170
171 // Command Functions {{{
172 static void
tgdb_commands_send_breakpoints(struct tgdb * tgdb,struct tgdb_breakpoint * breakpoints)173 tgdb_commands_send_breakpoints(struct tgdb *tgdb,
174 struct tgdb_breakpoint *breakpoints)
175 {
176 struct tgdb_response *response = (struct tgdb_response *)
177 tgdb_create_response(TGDB_UPDATE_BREAKPOINTS);
178
179 response->choice.update_breakpoints.breakpoints = breakpoints;
180
181 tgdb_send_response(tgdb, response);
182 }
183
tgdb_commands_process_breakpoint(struct tgdb_breakpoint * & breakpoints,struct gdbwire_mi_breakpoint * breakpoint)184 static void tgdb_commands_process_breakpoint(
185 struct tgdb_breakpoint *&breakpoints,
186 struct gdbwire_mi_breakpoint *breakpoint)
187 {
188 bool file_location_avialable =
189 (breakpoint->fullname || breakpoint->file) && breakpoint->line != 0;
190 bool assembly_location_available = breakpoint->address &&
191 !breakpoint->pending && !breakpoint->multi;
192
193 if (file_location_avialable || assembly_location_available) {
194 struct tgdb_breakpoint tb;
195
196 if (file_location_avialable) {
197 tb.path = (breakpoint->fullname)?
198 cgdb_strdup(breakpoint->fullname):
199 cgdb_strdup(breakpoint->file);
200 tb.line = breakpoint->line;
201 } else {
202 tb.path = 0;
203 tb.line = 0;
204 }
205
206 if (assembly_location_available) {
207 uint64_t address = 0;
208 cgdb_hexstr_to_u64(breakpoint->address, &address);
209 tb.addr = address;
210 } else {
211 tb.addr = 0;
212 }
213
214 tb.enabled = breakpoint->enabled;
215 sbpush(breakpoints, tb);
216 }
217 }
218
tgdb_commands_process_breakpoints(struct tgdb * tgdb,struct gdbwire_mi_result_record * result_record)219 static void tgdb_commands_process_breakpoints(struct tgdb *tgdb,
220 struct gdbwire_mi_result_record *result_record)
221 {
222 enum gdbwire_result result;
223 struct gdbwire_mi_command *mi_command = 0;
224 result = gdbwire_get_mi_command(GDBWIRE_MI_BREAK_INFO,
225 result_record, &mi_command);
226 if (result == GDBWIRE_OK) {
227 struct tgdb_breakpoint *breakpoints = NULL;
228 struct gdbwire_mi_breakpoint *breakpoint =
229 mi_command->variant.break_info.breakpoints;
230 while (breakpoint) {
231 tgdb_commands_process_breakpoint(breakpoints, breakpoint);
232
233 if (breakpoint->multi) {
234 struct gdbwire_mi_breakpoint *multi_bkpt =
235 breakpoint->multi_breakpoints;
236 while (multi_bkpt) {
237 tgdb_commands_process_breakpoint(breakpoints, multi_bkpt);
238 multi_bkpt = multi_bkpt->next;
239 }
240 }
241
242 breakpoint = breakpoint->next;
243 }
244
245 tgdb_commands_send_breakpoints(tgdb, breakpoints);
246
247 gdbwire_mi_command_free(mi_command);
248 }
249 }
250
tgdb_commands_send_source_files(struct tgdb * tgdb,char ** source_files)251 static void tgdb_commands_send_source_files(struct tgdb *tgdb,
252 char **source_files)
253 {
254 struct tgdb_response *response =
255 tgdb_create_response(TGDB_UPDATE_SOURCE_FILES);
256 response->choice.update_source_files.source_files = source_files;
257 tgdb_send_response(tgdb, response);
258 }
259
260 /* This function is capable of parsing the output of 'info source'.
261 * It can get both the absolute and relative path to the source file.
262 */
263 static void
tgdb_commands_process_info_sources(struct tgdb * tgdb,struct gdbwire_mi_result_record * result_record)264 tgdb_commands_process_info_sources(struct tgdb *tgdb,
265 struct gdbwire_mi_result_record *result_record)
266 {
267 enum gdbwire_result result;
268 struct gdbwire_mi_command *mi_command = 0;
269 result = gdbwire_get_mi_command(GDBWIRE_MI_FILE_LIST_EXEC_SOURCE_FILES,
270 result_record, &mi_command);
271 if (result == GDBWIRE_OK) {
272 char **source_files = NULL;
273 struct gdbwire_mi_source_file *files =
274 mi_command->variant.file_list_exec_source_files.files;
275 while (files) {
276 char *file = (files->fullname)?files->fullname:files->file;
277 sbpush(source_files, strdup(file));
278 files = files->next;
279 }
280
281 tgdb_commands_send_source_files(tgdb, source_files);
282
283 gdbwire_mi_command_free(mi_command);
284 }
285 }
286
send_disassemble_func_complete_response(struct tgdb * tgdb,struct gdbwire_mi_result_record * result_record)287 static void send_disassemble_func_complete_response(struct tgdb *tgdb,
288 struct gdbwire_mi_result_record *result_record)
289 {
290 tgdb_response_type type =
291 (tgdb->current_request_type == TGDB_REQUEST_DISASSEMBLE_PC) ?
292 TGDB_DISASSEMBLE_PC : TGDB_DISASSEMBLE_FUNC;
293 struct tgdb_response *response =
294 tgdb_create_response(type);
295
296 response->choice.disassemble_function.error =
297 (result_record->result_class == GDBWIRE_MI_ERROR);
298
299 response->choice.disassemble_function.disasm = tgdb->disasm;
300 response->choice.disassemble_function.addr_start = tgdb->address_start;
301 response->choice.disassemble_function.addr_end = tgdb->address_end;
302
303 tgdb->disasm = NULL;
304 tgdb->address_start = 0;
305 tgdb->address_end = 0;
306
307 tgdb_send_response(tgdb, response);
308 }
309
310 static void
tgdb_commands_send_source_file(struct tgdb * tgdb,const char * fullname,const char * file,uint64_t address,const char * from,const char * func,int line)311 tgdb_commands_send_source_file(struct tgdb *tgdb, const char *fullname,
312 const char *file, uint64_t address, const char *from,
313 const char *func, int line)
314 {
315 /* This section allocates a new structure to add into the queue
316 * All of its members will need to be freed later.
317 */
318 struct tgdb_file_position *tfp = (struct tgdb_file_position *)
319 cgdb_malloc(sizeof (struct tgdb_file_position));
320 struct tgdb_response *response =
321 tgdb_create_response(TGDB_UPDATE_FILE_POSITION);
322
323 if (fullname || file) {
324 tfp->path = (fullname)?cgdb_strdup(fullname):cgdb_strdup(file);
325 } else {
326 tfp->path = 0;
327 }
328 tfp->addr = address;
329 tfp->from = (from)?cgdb_strdup(from):0;
330 tfp->func = (func)?cgdb_strdup(func):0;
331 tfp->line_number = line;
332
333 response->choice.update_file_position.file_position = tfp;
334
335 tgdb_send_response(tgdb, response);
336 }
337
tgdb_commands_process_info_source(struct tgdb * tgdb,struct gdbwire_mi_result_record * result_record)338 static void tgdb_commands_process_info_source(struct tgdb *tgdb,
339 struct gdbwire_mi_result_record *result_record)
340 {
341 enum gdbwire_result result;
342 struct gdbwire_mi_command *mi_command = 0;
343 result = gdbwire_get_mi_command(GDBWIRE_MI_FILE_LIST_EXEC_SOURCE_FILE,
344 result_record, &mi_command);
345 if (result == GDBWIRE_OK) {
346 tgdb_commands_send_source_file(tgdb,
347 mi_command->variant.file_list_exec_source_file.fullname,
348 mi_command->variant.file_list_exec_source_file.file,
349 0, 0, 0,
350 mi_command->variant.file_list_exec_source_file.line);
351
352 gdbwire_mi_command_free(mi_command);
353 }
354 }
355
tgdb_commands_process_info_frame(struct tgdb * tgdb,struct gdbwire_mi_result_record * result_record)356 static void tgdb_commands_process_info_frame(struct tgdb *tgdb,
357 struct gdbwire_mi_result_record *result_record)
358 {
359 bool require_source = false;
360 enum gdbwire_result result;
361 struct gdbwire_mi_command *mi_command = 0;
362 result = gdbwire_get_mi_command(GDBWIRE_MI_STACK_INFO_FRAME,
363 result_record, &mi_command);
364 if (result == GDBWIRE_OK) {
365 struct gdbwire_mi_stack_frame *frame =
366 mi_command->variant.stack_info_frame.frame;
367 uint64_t address = 0;
368 cgdb_hexstr_to_u64(frame->address, &address);
369
370 if (frame->address || frame->file || frame->fullname) {
371 tgdb_commands_send_source_file(tgdb, frame->fullname, frame->file,
372 address, frame->from, frame->func, frame->line);
373 } else {
374 require_source = true;
375 }
376
377 gdbwire_mi_command_free(mi_command);
378 } else {
379 require_source = true;
380 }
381
382 if (require_source) {
383 tgdb_request_ptr request;
384 request = (tgdb_request_ptr) cgdb_malloc(sizeof (struct tgdb_request));
385 request->header = TGDB_REQUEST_INFO_SOURCE_FILE;
386 tgdb_run_or_queue_request(tgdb, request, true);
387 }
388 }
389
gdbwire_stream_record_callback(void * context,struct gdbwire_mi_stream_record * stream_record)390 static void gdbwire_stream_record_callback(void *context,
391 struct gdbwire_mi_stream_record *stream_record)
392 {
393 struct tgdb *tgdb = (struct tgdb*)context;
394
395 switch (tgdb->current_request_type) {
396 case TGDB_REQUEST_BREAKPOINTS:
397 case TGDB_REQUEST_INFO_FRAME:
398 /**
399 * When using GDB with annotate=2 and also using interpreter-exec,
400 * GDB spits out the annotations in the MI output. All of these
401 * annotations can be ignored.
402 */
403 break;
404 case TGDB_REQUEST_DISASSEMBLE_PC:
405 case TGDB_REQUEST_DISASSEMBLE_FUNC:
406 if (stream_record->kind == GDBWIRE_MI_CONSOLE) {
407 uint64_t address;
408 int result;
409 char *str = stream_record->cstring;
410 size_t length = strlen(str);
411 char *colon = 0, colon_char = 0;
412
413 if (str[length-1] == '\n') {
414 str[length-1] = 0;
415 }
416
417 /* Trim the gdb current location pointer off */
418 if (length > 2 && str[0] == '=' && str[1] == '>') {
419 str[0] = ' ';
420 str[1] = ' ';
421 }
422
423 sbpush(tgdb->disasm, cgdb_strdup(str));
424
425 colon = strchr((char*)str, ':');
426 if (colon) {
427 colon_char = *colon;
428 *colon = 0;
429 }
430
431 result = cgdb_hexstr_to_u64(str, &address);
432
433 if (colon) {
434 *colon = colon_char;
435 }
436
437 if (result == 0 && address) {
438 tgdb->address_start = tgdb->address_start ?
439 MIN(address, tgdb->address_start) : address;
440 tgdb->address_end = MAX(address, tgdb->address_end);
441 }
442 }
443 break;
444 case TGDB_REQUEST_DATA_DISASSEMBLE_MODE_QUERY:
445 case TGDB_REQUEST_INFO_SOURCES:
446 case TGDB_REQUEST_INFO_SOURCE_FILE:
447 case TGDB_REQUEST_TTY:
448 case TGDB_REQUEST_DEBUGGER_COMMAND:
449 case TGDB_REQUEST_MODIFY_BREAKPOINT:
450 break;
451 }
452 }
453
454 static void
source_position_changed(struct tgdb * tgdb,gdbwire_mi_result * result)455 source_position_changed(struct tgdb *tgdb, gdbwire_mi_result *result)
456 {
457 std::string frame("frame");
458 std::string addr("addr");
459 std::string fullname("fullname");
460 std::string line("line");
461
462 while (result) {
463 if (frame == result->variable &&
464 result->kind == GDBWIRE_MI_TUPLE) {
465
466 uint64_t addr_value = 0;
467 bool addr_value_set = false;
468
469 std::string fullname_value;
470 bool fullname_value_set = false;
471
472 int line_value = 0;
473 bool line_value_set = false;
474
475 struct gdbwire_mi_result *fresult = result->variant.result;
476
477 while (fresult) {
478 if (addr == fresult->variable) {
479 addr_value = std::stoull(
480 fresult->variant.cstring, 0, 16);
481 addr_value_set = true;
482 } else if (fullname == fresult->variable) {
483 fullname_value = fresult->variant.cstring;
484 fullname_value_set = true;
485 } else if (line == fresult->variable) {
486 line_value = std::stoi(fresult->variant.cstring);
487 line_value_set = true;
488 }
489 fresult = fresult->next;
490 }
491
492 if(addr_value_set || (fullname_value_set && line_value_set)) {
493 tgdb_commands_send_source_file(tgdb, fullname_value.c_str(),
494 NULL, addr_value, NULL, NULL, line_value);
495 }
496 }
497
498 result = result->next;
499 }
500 }
501
502 void tgdb_breakpoints_changed(void *context);
gdbwire_async_record_callback(void * context,struct gdbwire_mi_async_record * async_record)503 static void gdbwire_async_record_callback(void *context,
504 struct gdbwire_mi_async_record *async_record)
505 {
506 struct tgdb *tgdb = (struct tgdb*)context;
507
508 switch (async_record->async_class) {
509 case GDBWIRE_MI_ASYNC_STOPPED:
510 case GDBWIRE_MI_ASYNC_THREAD_SELECTED:
511 source_position_changed(tgdb, async_record->result);
512 break;
513 case GDBWIRE_MI_ASYNC_BREAKPOINT_CREATED:
514 case GDBWIRE_MI_ASYNC_BREAKPOINT_MODIFIED:
515 case GDBWIRE_MI_ASYNC_BREAKPOINT_DELETED:
516 tgdb_breakpoints_changed(tgdb);
517 break;
518 default:
519 break;
520 }
521 }
522
gdbwire_result_record_callback(void * context,struct gdbwire_mi_result_record * result_record)523 static void gdbwire_result_record_callback(void *context,
524 struct gdbwire_mi_result_record *result_record)
525 {
526 struct tgdb *tgdb = (struct tgdb*)context;
527
528 switch (tgdb->current_request_type) {
529 case TGDB_REQUEST_BREAKPOINTS:
530 tgdb_commands_process_breakpoints(tgdb, result_record);
531 break;
532 case TGDB_REQUEST_INFO_SOURCES:
533 tgdb_commands_process_info_sources(tgdb, result_record);
534 break;
535 case TGDB_REQUEST_DISASSEMBLE_PC:
536 case TGDB_REQUEST_DISASSEMBLE_FUNC:
537 send_disassemble_func_complete_response(tgdb, result_record);
538 break;
539 case TGDB_REQUEST_DATA_DISASSEMBLE_MODE_QUERY:
540 /**
541 * If the mode was to high, than the result record would be
542 * an error, meaning the mode is not supported. Otherwise,
543 * the mode is supported.
544 */
545 if (result_record->result_class == GDBWIRE_MI_DONE) {
546 tgdb->disassemble_supports_s_mode = 1;
547 clog_info(CLOG_CGDB, "disassemble supports s mode");
548 }
549 break;
550 case TGDB_REQUEST_INFO_SOURCE_FILE:
551 tgdb_commands_process_info_source(tgdb, result_record);
552 break;
553 case TGDB_REQUEST_INFO_FRAME:
554 tgdb_commands_process_info_frame(tgdb, result_record);
555 break;
556 case TGDB_REQUEST_TTY:
557 case TGDB_REQUEST_DEBUGGER_COMMAND:
558 case TGDB_REQUEST_MODIFY_BREAKPOINT:
559 break;
560 }
561 }
562
563 void tgdb_console_at_prompt(void *context);
gdbwire_prompt_callback(void * context,const char * prompt)564 static void gdbwire_prompt_callback(void *context, const char *prompt)
565 {
566 struct tgdb *tgdb = (struct tgdb*)context;
567 tgdb_console_at_prompt(tgdb);
568 }
569
gdbwire_parse_error_callback(void * context,const char * mi,const char * token,struct gdbwire_mi_position position)570 static void gdbwire_parse_error_callback(void *context, const char *mi,
571 const char *token, struct gdbwire_mi_position position)
572 {
573 clog_error(CLOG_CGDB,
574 "gdbwire parse error\n"
575 " mi text=[%s]\n"
576 " token=[%s]\n"
577 " start col=[%d]\n"
578 " end col=[%d]\n",
579 mi, token, position.start_column, position.end_column);
580 }
581
582 static struct gdbwire_callbacks wire_callbacks =
583 {
584 0,
585 gdbwire_stream_record_callback,
586 gdbwire_async_record_callback,
587 gdbwire_result_record_callback,
588 gdbwire_prompt_callback,
589 gdbwire_parse_error_callback
590 };
591
free_char_star(void * item)592 int free_char_star(void *item)
593 {
594 char *s = (char *) item;
595
596 free(s);
597 s = NULL;
598
599 return 0;
600 }
601
tgdb_commands_process(struct tgdb * tgdb,const std::string & str)602 void tgdb_commands_process(struct tgdb *tgdb, const std::string &str)
603 {
604 gdbwire_push_data(tgdb->wire, str.data(), str.size());
605 }
606
tgdb_commands_set_current_request_type(struct tgdb * tgdb,enum tgdb_request_type type)607 void tgdb_commands_set_current_request_type(struct tgdb *tgdb,
608 enum tgdb_request_type type)
609 {
610 tgdb->current_request_type = type;
611 }
612
tgdb_commands_disassemble_supports_s_mode(struct tgdb * tgdb)613 int tgdb_commands_disassemble_supports_s_mode(struct tgdb *tgdb)
614 {
615 return tgdb->disassemble_supports_s_mode;
616 }
617
618 // }}}
619
initialize_tgdb_context(tgdb_callbacks callbacks)620 static struct tgdb *initialize_tgdb_context(tgdb_callbacks callbacks)
621 {
622 struct tgdb *tgdb = (struct tgdb *) cgdb_malloc(sizeof (struct tgdb));
623
624 tgdb->control_c = 0;
625
626 tgdb->debugger_stdout = -1;
627 tgdb->debugger_stdin = -1;
628
629 tgdb->gdb_mi_ui_fd = -1;
630
631 tgdb->new_ui_pty_pair = NULL;
632
633 tgdb->command_requests = new tgdb_request_ptr_list();
634
635 tgdb->is_gdb_ready_for_next_command = 0;
636
637 tgdb->callbacks = callbacks;
638
639 tgdb->disasm = NULL;
640 tgdb->address_start = 0;
641 tgdb->address_end = 0;
642
643 wire_callbacks.context = (void*)tgdb;
644 tgdb->wire = gdbwire_create(wire_callbacks);
645
646 tgdb->disassemble_supports_s_mode = 0;
647 tgdb->gdb_supports_new_ui_command = true;
648 tgdb->undefined_new_ui_command = new std::string();
649
650 return tgdb;
651 }
652
653 /*******************************************************************************
654 * This is the basic initialization
655 ******************************************************************************/
656
tgdb_issue_request(struct tgdb * tgdb,enum tgdb_request_type type,bool priority)657 static void tgdb_issue_request(struct tgdb *tgdb, enum tgdb_request_type type,
658 bool priority)
659 {
660 tgdb_request_ptr request_ptr;
661 request_ptr = (tgdb_request_ptr)cgdb_malloc(sizeof (struct tgdb_request));
662 request_ptr->header = type;
663 tgdb_run_or_queue_request(tgdb, request_ptr, priority);
664 }
665
tgdb_breakpoints_changed(void * context)666 void tgdb_breakpoints_changed(void *context)
667 {
668 struct tgdb *tgdb = (struct tgdb*)context;
669 tgdb_issue_request(tgdb, TGDB_REQUEST_BREAKPOINTS, true);
670 }
671
tgdb_source_location_changed(void * context)672 static void tgdb_source_location_changed(void *context)
673 {
674 struct tgdb *tgdb = (struct tgdb*)context;
675 tgdb_request_current_location(tgdb);
676 }
677
tgdb_command_error(void * context,const std::string & msg)678 static void tgdb_command_error(void *context, const std::string &msg)
679 {
680 struct tgdb *tgdb = (struct tgdb*)context;
681
682 /* Send cgdb the error message */
683 tgdb->callbacks.console_output_callback(tgdb->callbacks.context, msg);
684 }
685
tgdb_console_at_prompt(void * context)686 void tgdb_console_at_prompt(void *context)
687 {
688 struct tgdb *tgdb = (struct tgdb*)context;
689
690 tgdb->is_gdb_ready_for_next_command = 1;
691
692 if (tgdb->command_requests->size() > 0) {
693 tgdb_unqueue_and_deliver_command(tgdb);
694 }
695 }
696
697 /**
698 * Free the tgdb request pointer data.
699 *
700 * @param request_ptr
701 * The request pointer to destroy.
702 */
tgdb_request_destroy(tgdb_request_ptr request_ptr)703 static void tgdb_request_destroy(tgdb_request_ptr request_ptr)
704 {
705 if (!request_ptr)
706 return;
707
708 switch (request_ptr->header) {
709 case TGDB_REQUEST_INFO_SOURCES:
710 break;
711 case TGDB_REQUEST_DEBUGGER_COMMAND:
712 break;
713 case TGDB_REQUEST_MODIFY_BREAKPOINT:
714 free((char *) request_ptr->choice.modify_breakpoint.file);
715 request_ptr->choice.modify_breakpoint.file = NULL;
716 break;
717 case TGDB_REQUEST_DISASSEMBLE_PC:
718 case TGDB_REQUEST_DISASSEMBLE_FUNC:
719 break;
720 default:
721 break;
722 }
723
724 free(request_ptr);
725 request_ptr = NULL;
726 }
727
728
729 /* Creating and Destroying a libtgdb context. {{{*/
730
tgdb_initialize(tgdb_callbacks callbacks)731 struct tgdb *tgdb_initialize(tgdb_callbacks callbacks)
732 {
733 /* Initialize the libtgdb context */
734 struct tgdb *tgdb = initialize_tgdb_context(callbacks);
735
736 // create the new ui pty pair
737 // initialize the size to the gdb window size
738 tgdb->new_ui_pty_pair = pty_pair_create();
739 if (!tgdb->new_ui_pty_pair) {
740 clog_error(CLOG_CGDB, "pty_pair_create failed");
741 return NULL;
742 }
743
744 tgdb->gdb_mi_ui_fd = pty_pair_get_masterfd(tgdb->new_ui_pty_pair);
745 tty_set_echo(tgdb->gdb_mi_ui_fd, 0);
746
747 /* Need to get source information before breakpoint information otherwise
748 * the TGDB_UPDATE_BREAKPOINTS event will be ignored in process_commands()
749 * because there are no source files to add the breakpoints to.
750 */
751 tgdb_request_current_location(tgdb);
752
753 /* gdb may already have some breakpoints when it starts. This could happen
754 * if the user puts breakpoints in there .gdbinit.
755 * This makes sure that TGDB asks for the breakpoints on start up.
756 */
757 tgdb_issue_request(tgdb, TGDB_REQUEST_BREAKPOINTS, true);
758
759 /**
760 * Query if disassemble supports the /s flag
761 */
762 tgdb_issue_request(tgdb, TGDB_REQUEST_DATA_DISASSEMBLE_MODE_QUERY, true);
763
764 return tgdb;
765 }
766
tgdb_start_gdb(struct tgdb * tgdb,const char * debugger,int argc,char ** argv,int gdb_win_rows,int gdb_win_cols,int * gdb_console_fd,int * gdb_mi_fd)767 int tgdb_start_gdb(struct tgdb *tgdb,
768 const char *debugger, int argc, char **argv,
769 int gdb_win_rows, int gdb_win_cols, int *gdb_console_fd,
770 int *gdb_mi_fd)
771 {
772 tgdb->debugger_pid = invoke_debugger(debugger, argc, argv,
773 gdb_win_rows, gdb_win_cols,
774 &tgdb->debugger_stdin, &tgdb->debugger_stdout,
775 pty_pair_get_slavename(tgdb->new_ui_pty_pair));
776
777 /* Couldn't invoke process */
778 if (tgdb->debugger_pid == -1)
779 return -1;
780
781 *gdb_console_fd = tgdb->debugger_stdout;
782 *gdb_mi_fd = tgdb->gdb_mi_ui_fd;
783
784 return 0;
785 }
786
tgdb_shutdown(struct tgdb * tgdb)787 int tgdb_shutdown(struct tgdb *tgdb)
788 {
789 delete tgdb->undefined_new_ui_command;
790
791 tgdb_request_ptr_list::iterator iter = tgdb->command_requests->begin();
792 for (; iter != tgdb->command_requests->end(); ++iter) {
793 tgdb_request_destroy(*iter);
794 }
795
796 delete tgdb->command_requests;
797 tgdb->command_requests = 0;
798
799 if (tgdb->debugger_stdin != -1) {
800 cgdb_close(tgdb->debugger_stdin);
801 tgdb->debugger_stdin = -1;
802 }
803
804 gdbwire_destroy(tgdb->wire);
805
806 return 0;
807 }
808
tgdb_close_logfiles()809 void tgdb_close_logfiles()
810 {
811 clog_info(CLOG_CGDB, "Closing logfile.");
812 clog_free(CLOG_CGDB_ID);
813
814 clog_info(CLOG_GDBIO, "Closing logfile.");
815 clog_free(CLOG_GDBIO_ID);
816
817 clog_info(CLOG_GDBMIIO, "Closing logfile.");
818 clog_free(CLOG_GDBMIIO_ID);
819 }
820
821 /* }}}*/
822
tgdb_get_client_command(struct tgdb * tgdb,enum tgdb_command_type c)823 static const char *tgdb_get_client_command(struct tgdb *tgdb,
824 enum tgdb_command_type c)
825 {
826 switch (c) {
827 case TGDB_CONTINUE:
828 return "continue";
829 case TGDB_FINISH:
830 return "finish";
831 case TGDB_NEXT:
832 return "next";
833 case TGDB_NEXTI:
834 return "nexti";
835 case TGDB_START:
836 return "start";
837 case TGDB_RUN:
838 return "run";
839 case TGDB_KILL:
840 return "kill";
841 case TGDB_STEP:
842 return "step";
843 case TGDB_STEPI:
844 return "stepi";
845 case TGDB_UNTIL:
846 return "until";
847 case TGDB_UP:
848 return "up";
849 case TGDB_DOWN:
850 return "down";
851 }
852
853 return NULL;
854 }
855
tgdb_client_modify_breakpoint_call(struct tgdb * tgdb,const char * file,int line,uint64_t addr,enum tgdb_breakpoint_action b)856 static char *tgdb_client_modify_breakpoint_call(struct tgdb *tgdb,
857 const char *file, int line, uint64_t addr, enum tgdb_breakpoint_action b)
858 {
859 const char *action;
860
861 switch (b)
862 {
863 default:
864 case TGDB_BREAKPOINT_ADD:
865 action = "break";
866 break;
867 case TGDB_BREAKPOINT_DELETE:
868 action ="clear";
869 break;
870 case TGDB_TBREAKPOINT_ADD:
871 action = "tbreak";
872 break;
873 }
874
875 if (file)
876 return sys_aprintf("%s \"%s\":%d", action, file, line);
877
878 return sys_aprintf("%s *0x%" PRIx64, action, addr);
879 }
880
881 /*******************************************************************************
882 * This is the main_loop stuff for tgdb-base
883 ******************************************************************************/
884
885 /**
886 * Run a command request if gdb is idle, otherwise queue it.
887 *
888 * @param tgdb
889 * The TGDB context to use.
890 *
891 * @param request
892 * The command request
893 *
894 * @param priority
895 * True if this is a priority request, false otherwise.
896 */
tgdb_run_or_queue_request(struct tgdb * tgdb,struct tgdb_request * request,bool priority)897 void tgdb_run_or_queue_request(struct tgdb *tgdb,
898 struct tgdb_request *request, bool priority)
899 {
900 int can_issue;
901
902 // Debugger commands currently get executed in the gdb console
903 // rather than the gdb mi channel. The gdb console is no longer
904 // queued by CGDB, rather CGDB passes everything along to it that the
905 // user types. So always issue debugger commands for now.
906 if (request->header == TGDB_REQUEST_DEBUGGER_COMMAND) {
907 can_issue = 1;
908 } else {
909 can_issue = tgdb->is_gdb_ready_for_next_command;
910 }
911
912 if (can_issue) {
913 tgdb_run_request(tgdb, request);
914 } else {
915 if (priority) {
916 tgdb->command_requests->push_front(request);
917 } else {
918 tgdb->command_requests->push_back(request);
919 }
920 }
921 }
922
923 int tgdb_get_gdb_command(struct tgdb *tgdb, tgdb_request_ptr request,
924 std::string &command);
925
926 /**
927 * Send a command to gdb.
928 *
929 * @param tgdb
930 * An instance of tgdb
931 *
932 * @param request
933 * The command request to issue the command for
934 */
tgdb_run_request(struct tgdb * tgdb,struct tgdb_request * request)935 static void tgdb_run_request(struct tgdb *tgdb, struct tgdb_request *request)
936 {
937 std::string command;
938
939 tgdb->is_gdb_ready_for_next_command = 0;
940
941 tgdb_get_gdb_command(tgdb, request, command);
942
943 /* Add a newline to the end of the command if it doesn't exist */
944 if (*command.rbegin() != '\n') {
945 command.push_back('\n');
946 }
947
948 /* Send what we're doing to log file */
949 std::string str = sys_quote_nonprintables(command.c_str(), -1);
950 clog_debug(CLOG_GDBMIIO, "%s", str.c_str());
951
952 /* A command for the debugger */
953 tgdb_commands_set_current_request_type(tgdb, request->header);
954
955 if (request->header == TGDB_REQUEST_DEBUGGER_COMMAND) {
956 // since debugger commands are sent to the debugger's stdin
957 // and not to the new-ui mi window, then we don't have to wait
958 // for gdb to respond with an mi prompt. CGDB can send as many
959 // commands as it likes, just as if the user typed it at the console
960 tgdb->is_gdb_ready_for_next_command = 1;
961 io_writen(tgdb->debugger_stdin, command.c_str(), command.size());
962 } else {
963 io_writen(tgdb->gdb_mi_ui_fd, command.c_str(), command.size());
964 }
965
966 tgdb_request_destroy(request);
967 }
968
969 /**
970 * TGDB will search it's command queue's and determine what the next command
971 * to deliever to GDB should be.
972 *
973 * \return
974 * 0 on success, -1 on error
975 */
tgdb_unqueue_and_deliver_command(struct tgdb * tgdb)976 static void tgdb_unqueue_and_deliver_command(struct tgdb *tgdb)
977 {
978 if (tgdb->command_requests->size() > 0) {
979 struct tgdb_request *request = tgdb->command_requests->front();
980 tgdb->command_requests->pop_front();
981 tgdb_run_request(tgdb, request);
982 // TODO: free request?
983 }
984 }
985
tgdb_send_char(struct tgdb * tgdb,char c)986 int tgdb_send_char(struct tgdb *tgdb, char c)
987 {
988 if (io_write_byte(tgdb->debugger_stdin, c) == -1) {
989 clog_error(CLOG_CGDB, "io_write_byte failed");
990 return -1;
991 }
992
993 return 0;
994 }
995
996 /**
997 * TGDB is going to quit.
998 *
999 * \param tgdb
1000 * The tgdb context
1001 *
1002 * \return
1003 * 0 on success or -1 on error
1004 */
tgdb_add_quit_command(struct tgdb * tgdb,bool new_ui_unsupported)1005 static int tgdb_add_quit_command(struct tgdb *tgdb, bool new_ui_unsupported)
1006 {
1007 struct tgdb_response *response;
1008 response = tgdb_create_response(TGDB_QUIT);
1009 response->choice.quit.new_ui_unsupported = new_ui_unsupported;
1010 tgdb_send_response(tgdb, response);
1011 return 0;
1012 }
1013
1014 /**
1015 * Called to process the sigchld signal, and clean up zombies!
1016 *
1017 * @param tgdb
1018 * The tgdb instance
1019 *
1020 * @return
1021 * 0 on success or -1 on error
1022 */
tgdb_handle_sigchld(struct tgdb * tgdb)1023 static int tgdb_handle_sigchld(struct tgdb *tgdb)
1024 {
1025 int result = 0;
1026 int status;
1027 int waitpid_result;
1028
1029 do {
1030 waitpid_result = waitpid(tgdb->debugger_pid, &status, WNOHANG);
1031 if (waitpid_result == -1) {
1032 result = -1;
1033 clog_error(CLOG_CGDB, "waitpid error %d %s",
1034 errno, strerror(errno));
1035 }
1036 } while (waitpid_result == 0);
1037
1038 return result;
1039 }
1040
1041 /**
1042 * If the user typed control_c at the prompt, clear the queues.
1043 *
1044 * @param tgdb
1045 * The tgdb instance to work on
1046 */
tgdb_handle_control_c(struct tgdb * tgdb)1047 static void tgdb_handle_control_c(struct tgdb *tgdb)
1048 {
1049 if (tgdb->control_c) {
1050 tgdb_request_ptr_list::iterator iter = tgdb->command_requests->begin();
1051 for (; iter != tgdb->command_requests->end(); ++iter) {
1052 tgdb_request_destroy(*iter);
1053 }
1054 tgdb->command_requests->clear();
1055
1056 tgdb->control_c = 0;
1057 }
1058 }
1059
1060 // Search for the string
1061 // Undefined command: "new-ui"
1062 // to determine if this gdb supports the new-ui command or not.
1063 // If the string is found, set tgdb->gdb_supports_new_ui_command to false
tgdb_search_for_unsupported_new_ui_message(struct tgdb * tgdb,const std::string & console_output)1064 static void tgdb_search_for_unsupported_new_ui_message(
1065 struct tgdb *tgdb, const std::string &console_output)
1066 {
1067 static const char *new_ui_text = "Undefined command: \"new-ui\".";
1068
1069 (*tgdb->undefined_new_ui_command) += console_output;
1070
1071 std::istringstream ss(*tgdb->undefined_new_ui_command);
1072 std::string line;
1073 while (getline(ss, line)) {
1074 if (line.find(new_ui_text) == 0) {
1075 tgdb->gdb_supports_new_ui_command = false;
1076 break;
1077 }
1078 }
1079
1080 // Remove everything up to the last newline character so that
1081 // only newly added new lines are searched
1082 size_t pos = tgdb->undefined_new_ui_command->find_last_of("\n");
1083 if (pos != std::string::npos) {
1084 *tgdb->undefined_new_ui_command =
1085 tgdb->undefined_new_ui_command->substr(pos);
1086 }
1087 }
1088
tgdb_process(struct tgdb * tgdb,int fd)1089 int tgdb_process(struct tgdb * tgdb, int fd)
1090 {
1091 const int n = 4096;
1092 static char buf[n];
1093 ssize_t size;
1094 int result = 0;
1095
1096 // If ^c has been typed at the prompt, clear the queues
1097 tgdb_handle_control_c(tgdb);
1098
1099 size = io_read(fd, buf, n);
1100 if (size < 0) {
1101 // Error reading from GDB
1102 clog_error(CLOG_CGDB, "Error reading from gdb's stdout, closing down");
1103 result = -1;
1104 tgdb_add_quit_command(tgdb, false);
1105 } else if (size == 0) {
1106 // Read EOF from GDB
1107 clog_info(CLOG_GDBIO, "read EOF from GDB, closing down");
1108 tgdb_add_quit_command(tgdb, false);
1109 } else {
1110 if (fd == tgdb->debugger_stdout) {
1111 // Read some GDB console output, process it
1112 std::string str = sys_quote_nonprintables(buf, size);
1113 clog_debug(CLOG_GDBIO, "%s", str.c_str());
1114 std::string msg(buf, size);
1115
1116 // Determine if this gdb supports the new-ui command.
1117 // If it does not, send the quit command to alert the user
1118 // that they need a newer gdb.
1119 tgdb_search_for_unsupported_new_ui_message(tgdb, msg);
1120 if (!tgdb->gdb_supports_new_ui_command) {
1121 tgdb_add_quit_command(tgdb, true);
1122 }
1123
1124 tgdb->callbacks.console_output_callback(
1125 tgdb->callbacks.context, msg);
1126 } else if (fd == tgdb->gdb_mi_ui_fd){
1127 // Read some GDB console output, process it
1128 std::string msg(buf, size);
1129 clog_debug(CLOG_GDBMIIO, "%s", msg.c_str());
1130 tgdb_commands_process(tgdb, msg);
1131 } else {
1132 }
1133 }
1134
1135 return result;
1136 }
1137
1138 /* Getting Data out of TGDB {{{*/
1139
tgdb_create_response(enum tgdb_response_type header)1140 struct tgdb_response *tgdb_create_response(enum tgdb_response_type header)
1141 {
1142 struct tgdb_response *response;
1143
1144 response = (struct tgdb_response *)cgdb_calloc(1, sizeof(struct tgdb_response));
1145 response->header = header;
1146
1147 return response;
1148 }
1149
tgdb_delete_response(struct tgdb_response * com)1150 static int tgdb_delete_response(struct tgdb_response *com)
1151 {
1152 if (!com)
1153 return -1;
1154
1155 switch (com->header) {
1156 case TGDB_UPDATE_BREAKPOINTS:
1157 {
1158 int i;
1159 struct tgdb_breakpoint *breakpoints =
1160 com->choice.update_breakpoints.breakpoints;
1161
1162 for (i = 0; i < sbcount(breakpoints); i++) {
1163
1164 struct tgdb_breakpoint *tb = &breakpoints[i];
1165
1166 free(tb->path);
1167 }
1168
1169 sbfree(breakpoints);
1170 com->choice.update_breakpoints.breakpoints = NULL;
1171 break;
1172 }
1173 case TGDB_UPDATE_FILE_POSITION:
1174 {
1175 struct tgdb_file_position *tfp =
1176 com->choice.update_file_position.file_position;
1177
1178 free(tfp->path);
1179 free(tfp->from);
1180 free(tfp->func);
1181
1182 free(tfp);
1183
1184 com->choice.update_file_position.file_position = NULL;
1185 break;
1186 }
1187 case TGDB_UPDATE_SOURCE_FILES:
1188 {
1189 int i;
1190 char **source_files = com->choice.update_source_files.source_files;
1191
1192 for (i = 0; i < sbcount(source_files); i++) {
1193 free(source_files[i]);
1194 }
1195 sbfree(source_files);
1196
1197 com->choice.update_source_files.source_files = NULL;
1198 break;
1199 }
1200 case TGDB_DISASSEMBLE_PC:
1201 case TGDB_DISASSEMBLE_FUNC:
1202 {
1203 int i;
1204 char **disasm = com->choice.disassemble_function.disasm;
1205
1206 for (i = 0; i < sbcount(disasm); i++) {
1207 free(disasm[i]);
1208 }
1209 sbfree(disasm);
1210 break;
1211 }
1212 case TGDB_QUIT:
1213 break;
1214 }
1215
1216 free(com);
1217 com = NULL;
1218 return 0;
1219 }
1220
tgdb_send_response(struct tgdb * tgdb,struct tgdb_response * response)1221 void tgdb_send_response(struct tgdb *tgdb, struct tgdb_response *response)
1222 {
1223 tgdb->callbacks.command_response_callback(
1224 tgdb->callbacks.context, response);
1225 tgdb_delete_response(response);
1226 }
1227
tgdb_resize_console(struct tgdb * tgdb,int rows,int cols)1228 int tgdb_resize_console(struct tgdb *tgdb, int rows, int cols)
1229 {
1230 struct winsize size;
1231 int result;
1232
1233 if (tgdb->debugger_stdin == -1) {
1234 return 0;
1235 }
1236
1237 size.ws_row = rows;
1238 size.ws_col = cols;
1239 size.ws_xpixel = 0;
1240 size.ws_ypixel = 0;
1241
1242 result = ioctl(tgdb->debugger_stdin, TIOCSWINSZ, &size);
1243 if (result == -1) {
1244 clog_error(CLOG_CGDB, "ioctl failed");
1245 }
1246
1247 return 0;
1248 }
1249
1250 /* }}}*/
1251
1252 /* Functional commands {{{ */
1253
1254 /* Request {{{*/
1255
tgdb_request_inferiors_source_files(struct tgdb * tgdb)1256 void tgdb_request_inferiors_source_files(struct tgdb * tgdb)
1257 {
1258 tgdb_request_ptr request_ptr;
1259
1260 request_ptr = (tgdb_request_ptr)cgdb_malloc(sizeof (struct tgdb_request));
1261
1262 request_ptr->header = TGDB_REQUEST_INFO_SOURCES;
1263
1264 tgdb_run_or_queue_request(tgdb, request_ptr, false);
1265 }
1266
tgdb_request_current_location(struct tgdb * tgdb)1267 void tgdb_request_current_location(struct tgdb * tgdb)
1268 {
1269 tgdb_request_ptr request_ptr;
1270
1271 request_ptr = (tgdb_request_ptr)cgdb_malloc(sizeof (struct tgdb_request));
1272
1273 request_ptr->header = TGDB_REQUEST_INFO_FRAME;
1274
1275 tgdb_run_or_queue_request(tgdb, request_ptr, true);
1276 }
1277
tgdb_request_breakpoints(struct tgdb * tgdb)1278 void tgdb_request_breakpoints(struct tgdb * tgdb)
1279 {
1280 tgdb_request_ptr request_ptr;
1281
1282 request_ptr = (tgdb_request_ptr)cgdb_malloc(sizeof (struct tgdb_request));
1283
1284 request_ptr->header = TGDB_REQUEST_BREAKPOINTS;
1285
1286 tgdb_run_or_queue_request(tgdb, request_ptr, false);
1287 }
1288
1289 void
tgdb_request_run_debugger_command(struct tgdb * tgdb,enum tgdb_command_type c)1290 tgdb_request_run_debugger_command(struct tgdb * tgdb, enum tgdb_command_type c)
1291 {
1292 tgdb_request_ptr request_ptr;
1293
1294 request_ptr = (tgdb_request_ptr)cgdb_malloc(sizeof (struct tgdb_request));
1295
1296 request_ptr->header = TGDB_REQUEST_DEBUGGER_COMMAND;
1297 request_ptr->choice.debugger_command.c = c;
1298
1299 tgdb_run_or_queue_request(tgdb, request_ptr, false);
1300 }
1301
1302 void
tgdb_request_modify_breakpoint(struct tgdb * tgdb,const char * file,int line,uint64_t addr,enum tgdb_breakpoint_action b)1303 tgdb_request_modify_breakpoint(struct tgdb *tgdb, const char *file, int line,
1304 uint64_t addr, enum tgdb_breakpoint_action b)
1305 {
1306 tgdb_request_ptr request_ptr;
1307
1308 request_ptr = (tgdb_request_ptr)cgdb_malloc(sizeof (struct tgdb_request));
1309
1310 request_ptr->header = TGDB_REQUEST_MODIFY_BREAKPOINT;
1311 request_ptr->choice.modify_breakpoint.file = file ? cgdb_strdup(file) : NULL;
1312 request_ptr->choice.modify_breakpoint.line = line;
1313 request_ptr->choice.modify_breakpoint.addr = addr;
1314 request_ptr->choice.modify_breakpoint.b = b;
1315
1316 tgdb_run_or_queue_request(tgdb, request_ptr, false);
1317 }
1318
tgdb_request_disassemble_pc(struct tgdb * tgdb,int lines)1319 void tgdb_request_disassemble_pc(struct tgdb *tgdb, int lines)
1320 {
1321 tgdb_request_ptr request_ptr;
1322
1323 request_ptr = (tgdb_request_ptr)cgdb_malloc(sizeof (struct tgdb_request));
1324 request_ptr->header = TGDB_REQUEST_DISASSEMBLE_PC;
1325
1326 request_ptr->choice.disassemble.lines = lines;
1327
1328 tgdb_run_or_queue_request(tgdb, request_ptr, false);
1329 }
1330
tgdb_request_disassemble_func(struct tgdb * tgdb,enum disassemble_func_type type)1331 void tgdb_request_disassemble_func(struct tgdb *tgdb,
1332 enum disassemble_func_type type)
1333 {
1334 tgdb_request_ptr request_ptr;
1335
1336 request_ptr = (tgdb_request_ptr)cgdb_malloc(sizeof (struct tgdb_request));
1337 request_ptr->header = TGDB_REQUEST_DISASSEMBLE_FUNC;
1338
1339 request_ptr->choice.disassemble_func.raw = (type == DISASSEMBLE_FUNC_RAW_INSTRUCTIONS);
1340 request_ptr->choice.disassemble_func.source = (type == DISASSEMBLE_FUNC_SOURCE_LINES);
1341
1342 tgdb_run_or_queue_request(tgdb, request_ptr, false);
1343 }
1344
1345 /* }}}*/
1346
1347 /* Process {{{*/
1348
tgdb_get_gdb_command(struct tgdb * tgdb,tgdb_request_ptr request,std::string & command)1349 int tgdb_get_gdb_command(struct tgdb *tgdb, tgdb_request_ptr request,
1350 std::string &command)
1351 {
1352 char *str;
1353
1354 if (!tgdb || !request) {
1355 return -1;
1356 }
1357
1358 switch (request->header) {
1359 case TGDB_REQUEST_INFO_SOURCES:
1360 command = "-file-list-exec-source-files\n";
1361 break;
1362 case TGDB_REQUEST_INFO_SOURCE_FILE:
1363 command = "-file-list-exec-source-file\n";
1364 break;
1365 case TGDB_REQUEST_BREAKPOINTS:
1366 command = "-break-info\n";
1367 break;
1368 case TGDB_REQUEST_TTY:
1369 str = sys_aprintf("-inferior-tty-set %s\n",
1370 request->choice.tty_command.slavename);
1371 command = str;
1372 free(str);
1373 str = NULL;
1374 break;
1375 case TGDB_REQUEST_INFO_FRAME:
1376 command = "-stack-info-frame\n";
1377 break;
1378 case TGDB_REQUEST_DATA_DISASSEMBLE_MODE_QUERY:
1379 command = "-data-disassemble -s 0 -e 0 -- 4\n";
1380 break;
1381 case TGDB_REQUEST_DEBUGGER_COMMAND:
1382 command = tgdb_get_client_command(tgdb,
1383 request->choice.debugger_command.c);
1384
1385 break;
1386 case TGDB_REQUEST_MODIFY_BREAKPOINT:
1387 str = tgdb_client_modify_breakpoint_call(tgdb,
1388 request->choice.modify_breakpoint.file,
1389 request->choice.modify_breakpoint.line,
1390 request->choice.modify_breakpoint.addr,
1391 request->choice.modify_breakpoint.b);
1392 command = str;
1393 free(str);
1394 str = NULL;
1395 break;
1396 case TGDB_REQUEST_DISASSEMBLE_PC:
1397 str = sys_aprintf("x/%di $pc\n", request->choice.disassemble.lines);
1398 command = str;
1399 free(str);
1400 str = NULL;
1401 break;
1402 case TGDB_REQUEST_DISASSEMBLE_FUNC: {
1403 /* GDB 7.11 adds /s command to disassemble
1404
1405 https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=6ff0ba5f7b8a2b10642bbb233a32043595c55670
1406 The "source centric" /m option to the disassemble command is
1407 often unhelpful, e.g., in the presence of optimized code.
1408 This patch adds a /s modifier that is better.
1409 For one, /m only prints instructions from the originating
1410 source file, leaving out instructions from
1411 e.g., inlined functions from other files.
1412
1413 disassemble
1414 /m: source lines included
1415 /s: source lines included, output in pc order (7.10 and higher)
1416 /r: raw instructions included in hex
1417 single argument: function surrounding is dumped
1418 two arguments: start,end or start,+length
1419 disassemble 'driver.cpp'::main
1420 interp mi "disassemble /s 'driver.cpp'::main,+10"
1421 interp mi "disassemble /r 'driver.cpp'::main,+10"
1422 */
1423 const char *data = NULL;
1424 if (request->choice.disassemble_func.raw) {
1425 data = "/r";
1426 } else if (request->choice.disassemble_func.source &&
1427 tgdb_commands_disassemble_supports_s_mode(tgdb)) {
1428 data = "/s";
1429 }
1430 str = sys_aprintf("disassemble%s%s\n",
1431 data ? " " : "", data ? data : "");
1432 command = str;
1433 free(str);
1434 str = NULL;
1435 break;
1436 }
1437 }
1438
1439 return 0;
1440 }
1441
1442 /* }}}*/
1443
1444 /* }}} */
1445
1446 /* Signal Handling Support {{{*/
1447
tgdb_signal_notification(struct tgdb * tgdb,int signum)1448 int tgdb_signal_notification(struct tgdb *tgdb, int signum)
1449 {
1450 struct termios t;
1451 cc_t *sig_char = NULL;
1452
1453 tcgetattr(tgdb->debugger_stdin, &t);
1454
1455 if (signum == SIGINT) { /* ^c */
1456 tgdb->control_c = 1;
1457 sig_char = &t.c_cc[VINTR];
1458 if (write(tgdb->debugger_stdin, sig_char, 1) < 1)
1459 return -1;
1460 } else if (signum == SIGQUIT) { /* ^\ */
1461 sig_char = &t.c_cc[VQUIT];
1462 if (write(tgdb->debugger_stdin, sig_char, 1) < 1)
1463 return -1;
1464 } else if (signum == SIGCHLD) {
1465 // GDB has died, clean up the zombie and send the quit command
1466 tgdb_handle_sigchld(tgdb);
1467 tgdb_add_quit_command(tgdb, false);
1468 }
1469
1470 return 0;
1471 }
1472
1473 /* }}}*/
1474