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