--- breakpoint.c | 454 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ breakpoint.h | 49 ++++++ remote.c | 133 +++++++++++++++++ 3 files changed, 635 insertions(+), 1 deletion(-) --- a/breakpoint.c +++ b/breakpoint.c @@ -82,6 +82,9 @@ #include "mi/mi-common.h" #include "python/python.h" +extern int hex2bin (const char *hex, gdb_byte *bin, int count); +extern char *unpack_varlen_hex (char *buff, ULONGEST *result); + /* Prototypes for local functions. */ static void enable_delete_command (char *, int); @@ -510,6 +513,19 @@ gdb_evaluates_breakpoint_condition_p (vo return (mode == condition_evaluation_host); } +const char autoload_breakpoints_query[] = "query"; +const char autoload_breakpoints_merge[] = "merge"; +const char autoload_breakpoints_gdb[] = "gdb"; +const char autoload_breakpoints_stub[] = "stub"; +const char *const autoload_breakpoints_enums[] = { + autoload_breakpoints_query, + autoload_breakpoints_merge, + autoload_breakpoints_gdb, + autoload_breakpoints_stub, + NULL +}; +const char *autoload_breakpoints_mode = autoload_breakpoints_query; + void _initialize_breakpoint (void); /* Are we executing breakpoint commands? */ @@ -1216,6 +1232,15 @@ breakpoint_set_commands (struct breakpoi observer_notify_breakpoint_modified (b); } +struct command_line * +breakpoint_get_commands (struct breakpoint *b) +{ + if (b->commands && b->commands->commands) + return b->commands->commands; + + return NULL; +} + /* Set the internal `silent' flag on the breakpoint. Note that this is not the same as the "silent" that may appear in the breakpoint's commands. */ @@ -6149,6 +6174,14 @@ print_one_breakpoint (struct breakpoint } } } + + if (b->autoload_id) + { + annotate_field (7); + ui_out_text (uiout, "\tautoload-breakpoint "); + ui_out_field_int (uiout, "id", b->autoload_id); + ui_out_text (uiout, "\n"); + } } static int @@ -6868,6 +6901,8 @@ init_raw_breakpoint_without_location (st b->condition_not_parsed = 0; b->py_bp_object = NULL; b->related_breakpoint = b; + b->autoload_id = 0; + b->autoload_inserted = 0; } /* Helper to set_raw_breakpoint below. Creates a breakpoint @@ -15660,6 +15695,407 @@ pc_at_non_inline_function (struct addres return 0; } +static int +autoload_breakpoints_get_id (void) +{ + struct breakpoint *b; + int id = 1; + + while (1) + { + ALL_BREAKPOINTS (b) + { + if (b->autoload_id == id) + break; + } + if (b) + id ++; + else + break; + } + + return id; +} + +static void +uploaded_bp_commands_clean (struct uploaded_bp *ubp) +{ + struct uploaded_bpcmd *cmd, *cmd_tmp; + + for (cmd = ubp->commands; cmd ? (cmd_tmp = cmd->next, 1): 0; cmd = cmd_tmp) + xfree (cmd); + ubp->commands = NULL; +} + +static void +uploaded_bp_commands_add (struct uploaded_bp *ubp, char *buf) +{ + struct uploaded_bpcmd *new_cmd, *cmd; + + new_cmd = xzalloc (sizeof (struct uploaded_bpcmd)); + new_cmd->str = xstrdup (buf); + + for (cmd = ubp->commands; cmd && cmd->next; cmd = cmd->next) + ; + if (cmd) + cmd->next = new_cmd; + else + ubp->commands = new_cmd; +} + +static void +handle_autoload_breakpoint_cmd (char cmd, struct uploaded_bp *ubp) +{ + switch (cmd) + { + case 'E': + ubp->enable = 1; + break; + case 'D': + ubp->enable = 0; + break; + case 'R': + ubp->removed = 1; + break; + } +} + +int +parse_autoload_breakpoint_definition (char *line, struct uploaded_bp **ubpp) +{ + ULONGEST id; + char cmd; + struct uploaded_bp *ubp, *ubp_tmp; + + /* Get id. */ + line = unpack_varlen_hex (line, &id); + if (line[0] != ':') + return -1; + if (strlen (line) < 2) + return -1; + line += 1; + + cmd = line[0]; + if (line[1] == ':') + line += 2; + else + line += 1; + + if ((cmd == 'C' || cmd == 'O') && id == 0) + return -1; + + for (ubp = *ubpp; ubp ? (ubp_tmp = ubp->next, 1): 0; ubp = ubp_tmp) + { + int loop_stop = 0; + + if (ubp->removed) + continue; + + switch (cmd) + { + case 'E': + case 'D': + case 'R': + if (id == 0) + handle_autoload_breakpoint_cmd (cmd, ubp); + else if (ubp->id == (int)id) + { + if (line[0] != '\0' && cmd != 'R') + { + /* Get the ubp that same with the id, + change it to new value. */ + loop_stop = 1; + } + else + { + handle_autoload_breakpoint_cmd (cmd, ubp); + return 0; + } + } + break; + case 'C': + case 'O': + if (ubp->id == (int)id) + loop_stop = 1; + break; + default: + return -1; + break; + } + + if (loop_stop) + break; + } + + if (id == 0) + return 0; + + switch (cmd) + { + case 'E': + case 'D': + { + char *b_addr_hex; + char *b_addr; + enum bptype b_type; + ULONGEST ignore_num; + int end; + + b_addr_hex = line; + line = strchr (line, ':'); + if (!line) + return -1; + line[0] = '\0'; + line += 1; + b_addr = alloca (strlen (b_addr_hex) / 2); + end = hex2bin (b_addr_hex, (gdb_byte *) b_addr, + strlen (b_addr_hex) / 2); + b_addr[end] = '\0'; + + if (line[0] == 'S') + b_type = bp_breakpoint; + else if (line[0] == 'H') + b_type = bp_hardware_breakpoint; + else + return -1; + if (line[1] != ':' || line[2] == '\0') + return -1; + line += 2; + + unpack_varlen_hex (line, &ignore_num); + + if (ubp) + ubp->removed = 1; + ubp = xzalloc (sizeof (struct uploaded_bp)); + + ubp->id = (int) id; + ubp->enable = (cmd == 'E') ? 1 : 0; + ubp->addr_string = xstrdup (b_addr); + ubp->type = b_type; + ubp->ignore_count = (int) ignore_num; + + for (ubp_tmp = *ubpp; ubp_tmp && ubp_tmp->next; + ubp_tmp = ubp_tmp->next) + ; + if (ubp_tmp) + ubp_tmp->next = ubp; + else + *ubpp = ubp; + } + break; + case 'R': + return -1; + break; + case 'C': + case 'O': + if (!ubp) + return -1; + { + char buf[strlen(line)/2 + 1]; + int end; + + end = hex2bin (line, (gdb_byte *) buf, strlen (line) / 2); + buf[end] = '\0'; + if (cmd == 'O') + { + if (ubp->condition) + { + xfree (ubp->condition); + ubp->condition = NULL; + } + if (end) + ubp->condition = xstrdup (buf); + } + else + { + if (end == 0) + uploaded_bp_commands_clean (ubp); + else + uploaded_bp_commands_add (ubp, buf); + } + } + break; + } + + return 0; +} + +void +clean_upload_autoload_breakpoints (void *p) +{ + struct uploaded_bp **ubpp = p; + struct uploaded_bp *ubp, *ubp_tmp; + + for (ubp = *ubpp; ubp ? (ubp_tmp = ubp->next, 1): 0; ubp = ubp_tmp) + { + uploaded_bp_commands_clean (ubp); + xfree (ubp); + } + *ubpp = NULL; +} + +void +show_upload_autoload_breakpoints (struct uploaded_bp *ubp) +{ + struct uploaded_bp *tmp; + int number = 0; + + for (tmp = ubp; tmp; tmp = tmp->next) + { + if (!tmp->removed) + number ++; + } + if (number) + printf_filtered (_("Got %d autoload-breakpoints from target\n"), number); + else + return; + + for (tmp = ubp; tmp; tmp = tmp->next) + { + if (tmp->removed) + continue; + printf_filtered (_("Id %d in %s"), tmp->id, tmp->addr_string); + if (tmp->condition) + printf_filtered (_(" stop only if %s"), tmp->condition); + if (tmp->ignore_count) + printf_filtered (_(" ignore next %d hits"), tmp->ignore_count); + printf_filtered (_("\n")); + if (tmp->commands) + { + struct uploaded_bpcmd *cmd; + + for (cmd = ubp->commands; cmd; cmd = cmd->next) + printf_filtered (_(" %s\n"), cmd->str); + } + } +} + +struct uploaded_bpcmd *this_ubpcmd = NULL; + +static char * +read_autoload_breakpoints_action (void) +{ + char *ret = NULL; + + if (this_ubpcmd) + { + ret = this_ubpcmd->str; + this_ubpcmd = this_ubpcmd->next; + } + + return ret; +} + +void +merge_uploaded_autoload_breakpoints (struct uploaded_bp *ubp) +{ + for (; ubp; ubp = ubp->next) + { + struct breakpoint *b; + + if (ubp->removed) + continue; + + ALL_BREAKPOINTS(b) + { + if (b->autoload_inserted) + continue; + + if (b->autoload_id == ubp->id) + { + if (strcmp (b->addr_string, ubp->addr_string) == 0) + { + printf_filtered (_("\ +Assuming autoload-breakpoints %d in GDB is same as target's\n\ +autoload-breakpoints %d at %s.\n"), + b->number, ubp->id, ubp->addr_string); + b->autoload_inserted = 1; + break; + } + else + { + b->autoload_id = autoload_breakpoints_get_id (); + printf_filtered (_("\ +Change breakpoint %d's autoload-breakpoints id to %d.\n"), + b->number, b->autoload_id); + } + } + } + + if (!b) + { + /* Create new breakpoint. */ + if (!create_breakpoint (get_current_arch (), + ubp->addr_string, + ubp->condition, -1, 0, 0, 0, + ubp->type, + ubp->ignore_count, + pending_break_support, + &bkpt_breakpoint_ops, + 0, + ubp->enable, + 0, CREATE_BREAKPOINT_FLAGS_INSERTED)) + { + printf_filtered (_("\ +Create breakpoint for autoload-breakpoint %d got error.\n"), + ubp->id); + continue; + } + b = get_breakpoint (breakpoint_count); + b->autoload_id = ubp->id; + b->autoload_inserted = 1; + if (ubp->commands) + { + struct command_line *cmd_list; + + this_ubpcmd = ubp->commands; + cmd_list = read_command_lines_1 (read_autoload_breakpoints_action, + 1, NULL, NULL); + breakpoint_set_commands (b, cmd_list); + } + printf_filtered (_("\ +Create breakpoint %d for autoload-breakpoint %d.\n"), + b->number, b->autoload_id); + } + } +} + +void +autoload_breakpoints_reset (void) +{ + struct breakpoint *b; + + ALL_BREAKPOINTS(b) + b->autoload_inserted = 0; +} + +void +autoload_breakpoints_clean (void) +{ + struct breakpoint *b, *btmp; + + ALL_BREAKPOINTS_SAFE (b, btmp) + { + if (b->autoload_id) + delete_breakpoint (b); + } +} + +int +autoload_breakpoints_number (void) +{ + int ret = 0; + struct breakpoint *b; + + ALL_BREAKPOINTS(b) + { + if (b->autoload_id) + ret ++; + } + + return ret; +} + void initialize_breakpoint_ops (void) { @@ -16426,6 +16862,24 @@ be set to \"gdb\""), &breakpoint_set_cmdlist, &breakpoint_show_cmdlist); + add_setshow_enum_cmd ("autoload", class_support, + autoload_breakpoints_enums, &autoload_breakpoints_mode, + _("\ +Set mode for autoload-breakpoints."), _("\ +Show mode for autoload-breakpoints."), _("\ +When this mode is \"query\" (the default mode), will query when got the\n\ +autoload-breakpoints.\n\ +When this mode is \"merge\", the autoload-breakpoints\n\ +of GDB and stub will merge together when GDB connect to stub.\n\ +When this mode is \"gdb\", the autoload-breakpoints of stub will be removed\n\ +when GDB connect to stub.\n\ +When this mode is \"stub\", the autoload-breakpoints of GDB will be removed\n\ +when GDB connect to stub."), + NULL, + NULL, + &breakpoint_set_cmdlist, + &breakpoint_show_cmdlist); + add_com ("break-range", class_breakpoint, break_range_command, _("\ Set a breakpoint for an address range.\n\ break-range START-LOCATION, END-LOCATION\n\ --- a/breakpoint.h +++ b/breakpoint.h @@ -735,6 +735,9 @@ struct breakpoint can sometimes be NULL for enabled GDBs as not all breakpoint types are tracked by the Python scripting API. */ struct breakpoint_object *py_bp_object; + + int autoload_id; + int autoload_inserted; }; /* An instance of this type is used to represent a watchpoint. It @@ -1085,6 +1088,25 @@ struct bpstats enum bp_print_how print_it; }; +struct uploaded_bpcmd + { + struct uploaded_bpcmd *next; + char *str; + }; + +struct uploaded_bp + { + int removed; + struct uploaded_bp *next; + int id; + int enable; + char *addr_string; + enum bptype type; + int ignore_count; + char *condition; + struct uploaded_bpcmd *commands; + }; + enum inf_context { inf_starting, @@ -1101,8 +1123,14 @@ enum breakpoint_here ordinary_breakpoint_here, permanent_breakpoint_here }; - +extern const char autoload_breakpoints_query[]; +extern const char autoload_breakpoints_merge[]; +extern const char autoload_breakpoints_gdb[]; +extern const char autoload_breakpoints_stub[]; +extern const char *autoload_breakpoints_mode; + + /* Prototypes for breakpoint-related functions. */ extern enum breakpoint_here breakpoint_here_p (struct address_space *, @@ -1373,6 +1401,8 @@ extern void enable_breakpoint (struct br extern void breakpoint_set_commands (struct breakpoint *b, struct command_line *commands); +extern struct command_line * breakpoint_get_commands (struct breakpoint *b); + extern void breakpoint_set_silent (struct breakpoint *b, int silent); extern void breakpoint_set_thread (struct breakpoint *b, int thread); @@ -1517,4 +1547,21 @@ extern struct gdbarch *get_sal_arch (str extern void handle_solib_event (void); +extern void autoload_breakpoints_reset (void); + +extern void autoload_breakpoints_clean (void); + +extern int autoload_breakpoints_number (void); + +extern int parse_autoload_breakpoint_definition (char *line, + struct uploaded_bp **ubpp); + +extern int parse_autoload_breakpoint_definition_to_breakpoints (char *line); + +extern void clean_upload_autoload_breakpoints (void *p); + +extern void show_upload_autoload_breakpoints (struct uploaded_bp *ubp); + +extern void merge_uploaded_autoload_breakpoints (struct uploaded_bp *ubp); + #endif /* !defined (BREAKPOINT_H) */ --- a/remote.c +++ b/remote.c @@ -215,6 +215,10 @@ static int remote_get_trace_status (stru static int remote_upload_tracepoints (struct uploaded_tp **utpp); static int remote_upload_trace_state_variables (struct uploaded_tsv **utsvp); + +static int remote_upload_autoload_breakpoints (struct uploaded_bp **ubpp); + +static void remote_download_autoload_breakpoints (void); static void remote_query_supported (void); @@ -1292,6 +1296,7 @@ enum { PACKET_qXfer_fdpic, PACKET_QDisableRandomization, PACKET_QAgent, + PACKET_AutoloadBreakpoints, PACKET_MAX }; @@ -3537,6 +3542,52 @@ remote_start_remote (int from_tty, struc up. */ rs->starting_up = 0; + /* Get autoload-breakpoints from stub. */ + if (remote_protocol_packets[PACKET_AutoloadBreakpoints].support + != PACKET_DISABLE) + { + static struct uploaded_bp *uploaded_bps = NULL; + struct cleanup *old_chain = make_cleanup + (clean_upload_autoload_breakpoints, + &uploaded_bps); + int num; + + if ((autoload_breakpoints_mode == autoload_breakpoints_stub) + || (autoload_breakpoints_mode == autoload_breakpoints_query + && (num = autoload_breakpoints_number ()) + && query (_("Remove %d autoload-breakpoints in GDB?"), num))) + autoload_breakpoints_clean (); + else + autoload_breakpoints_reset (); + + if (autoload_breakpoints_mode != autoload_breakpoints_gdb) + { + remote_upload_autoload_breakpoints (&uploaded_bps); + show_upload_autoload_breakpoints (uploaded_bps); + } + else + { + /* Remove all the autoload-breakpoints in stub part. */ + snprintf (rs->buf, rs->buf_size, "QBDP:0:R"); + remote_send (&rs->buf, &rs->buf_size); + } + + if (autoload_breakpoints_mode == autoload_breakpoints_query) + { + if (uploaded_bps) + { + if (!query (_("Add to GDB?"))) + clean_upload_autoload_breakpoints (&uploaded_bps); + } + } + + merge_uploaded_autoload_breakpoints (uploaded_bps); + + do_cleanups (old_chain); + + remote_download_autoload_breakpoints (); + } + /* If breakpoints are global, insert them now. */ if (gdbarch_has_global_breakpoints (target_gdbarch) && breakpoints_always_inserted_mode ()) @@ -3945,6 +3996,8 @@ static struct protocol_feature remote_pr { "QAgent", PACKET_DISABLE, remote_supported_packet, PACKET_QAgent}, { "tracenz", PACKET_DISABLE, remote_string_tracing_feature, -1 }, + { "AutoloadBreakpoints", PACKET_DISABLE, remote_supported_packet, + PACKET_AutoloadBreakpoints }, }; static char *remote_support_xml; @@ -11299,6 +11352,83 @@ remote_upload_trace_state_variables (str return 0; } +static int +remote_upload_autoload_breakpoints (struct uploaded_bp **ubpp) +{ + struct remote_state *rs = get_remote_state (); + char *p; + + /* Ask for a first packet of autoload-breakpoints definition. */ + putpkt ("qBfP"); + getpkt (&rs->buf, &rs->buf_size, 0); + p = rs->buf; + while (*p && *p != 'l') + { + parse_autoload_breakpoint_definition (p, ubpp); + /* Ask for another packet of autoload-breakpoints definition. */ + putpkt ("qBsP"); + getpkt (&rs->buf, &rs->buf_size, 0); + p = rs->buf; + } + return 0; +} + +static void +remote_download_autoload_breakpoints (void) +{ + struct remote_state *rs = get_remote_state (); + struct breakpoint *b; + extern struct breakpoint *breakpoint_chain; + + for (b = breakpoint_chain; b; b = b->next) + { + if (b->autoload_id && !b->autoload_inserted) + { + struct command_line *cmd; + char *hex = alloca (strlen (b->addr_string) * 2); + int end = bin2hex (b->addr_string, hex, 0); + + hex[end * 2] = '\0'; + snprintf (rs->buf, rs->buf_size, "QBDP:%x:%c:%s:%c:%x", + b->autoload_id, (b->enable_state == bp_enabled) ? 'E' : 'D', + hex, + (b->type == bp_hardware_breakpoint) ? 'H' : 'S', + b->ignore_count); + remote_send (&rs->buf, &rs->buf_size); + + if (b->cond_string) + { + char *p = rs->buf; + int end; + + snprintf (rs->buf, rs->buf_size, "QBDP:%x:O:", b->autoload_id); + p += strlen (p); + end = bin2hex (b->cond_string, p, strlen (b->cond_string)); + p[end] = '\0'; + remote_send (&rs->buf, &rs->buf_size); + } + + for (cmd = breakpoint_get_commands (b); cmd; cmd = cmd->next) + { + char *p = rs->buf; + int end; + + snprintf (rs->buf, rs->buf_size, "QBDP:%x:C:", b->autoload_id); + p += strlen (p); + end = bin2hex (cmd->line, p, strlen (cmd->line)); + p[end] = '\0'; + remote_send (&rs->buf, &rs->buf_size); + } + + b->autoload_inserted = 1; + + printf_filtered (_("\ +Download breakpoint %d to target as autoload-breakpoint %d.\n"), + b->number, b->autoload_id); + } + } +} + void _initialize_remote (void) { @@ -11636,6 +11766,9 @@ Show the maximum size of the address (in add_packet_config_cmd (&remote_protocol_packets[PACKET_QAgent], "QAgent", "agent", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_AutoloadBreakpoints], + "AutoloadBreakpoints", "autoload-breakpoints", 0); + /* Keep the old ``set remote Z-packet ...'' working. Each individual Z sub-packet has its own set and show commands, but users may have sets to this variable in their .gdbinit files (or in their