2005-01-20 Jeff Johnston * symtab.h (find_line_pc): Change prototype to new api which returns a list of pc values and the number of list elements. * symtab.c (find_line_pc): Change function to new api which returns a list of pc values. Support recognizing a base ctor or dtor and finding an additional pc value for the in-charge ctor or dtor accordingly. (find_line_common): Change api to accept a start_index argument which determines where to start searching from in the line table. (find_line_by_pc): New function. * breakpoint.c (resolve_sal_pc_list): New function. (breakpoint_sals_to_pc): Support multiple pc values for a line in a ctor/dtor. (gdb_breakpoint): Change call to find_line_pc to use new api. (break_command_1): Move resolve_sals_to_pc earlier due to the fact it now can extend the sal list. * mi/mi-cmd-disas.c (mi_cmd_disassemble): Change call to find_line_pc to new api. * tui/tui-layout.c (extract_display_start_addr): Ditto. * tui/tui-win.c (make_visible_with_new_height): Ditto. * tui/tui-winsource.c (tui_update_source_windows_with_addr): Ditto. 2007-09-22 Jan Kratochvil * symtab.c (find_line_pc): Support also the `$allocate' and `$delete' variants. Support searching for the `$base' name even if the bare name was found first. * breakpoint.c (breakpoint_sals_to_pc): Support more than two returned PC values. 2007-09-25 Jan Kratochvil * breakpoint.c (breakpoint_sals_to_pc): New parameter ADDR_STRING_P. Expand also *ADDR_STRING_P if multiple PCs were found. (break_command_1, do_captured_breakpoint): Pass also the ADDR_STRING variable to be updated. 2007-10-05 Jan Kratochvil * breakpoint.c (breakpoint_sals_to_pc): Provide "%42" suffix to the multiple-PC breakpoints' ADDR_STRINGs. (breakpoint_re_set_one): New variables ID_S, ID, PC_LIST, NUM_PC_VALUES. Parse the "%42" suffix of the multiple-PC breakpoints's ADDR_STRINGs. 2007-10-14 Jan Kratochvil Port to GDB-6.7. Index: gdb-6.7/gdb/mi/mi-cmd-disas.c =================================================================== --- gdb-6.7.orig/gdb/mi/mi-cmd-disas.c 2007-08-23 20:08:48.000000000 +0200 +++ gdb-6.7/gdb/mi/mi-cmd-disas.c 2007-10-14 23:26:23.000000000 +0200 @@ -143,11 +143,18 @@ mi_cmd_disassemble (char *command, char if (line_seen && file_seen) { + CORE_ADDR *pc_list; + int num_pc_values; + s = lookup_symtab (file_string); if (s == NULL) error (_("mi_cmd_disassemble: Invalid filename.")); - if (!find_line_pc (s, line_num, &start)) + if (!find_line_pc (s, line_num, &pc_list, &num_pc_values)) error (_("mi_cmd_disassemble: Invalid line number")); + /* FIXME: What do we do with multiple pc values for ctors/dtors + under mi? */ + start = pc_list[0]; + xfree (pc_list); if (find_pc_partial_function (start, NULL, &low, &high) == 0) error (_("mi_cmd_disassemble: No function contains specified address")); } Index: gdb-6.7/gdb/tui/tui-layout.c =================================================================== --- gdb-6.7.orig/gdb/tui/tui-layout.c 2007-08-23 20:08:50.000000000 +0200 +++ gdb-6.7/gdb/tui/tui-layout.c 2007-10-14 23:26:23.000000000 +0200 @@ -516,7 +516,8 @@ extract_display_start_addr (void) { enum tui_layout_type cur_layout = tui_current_layout (); CORE_ADDR addr; - CORE_ADDR pc; + CORE_ADDR *pc_list; + int num_pc_values; struct symtab_and_line cursal = get_current_source_symtab_and_line (); switch (cur_layout) @@ -525,8 +526,11 @@ extract_display_start_addr (void) case SRC_DATA_COMMAND: find_line_pc (cursal.symtab, TUI_SRC_WIN->detail.source_info.start_line_or_addr.u.line_no, - &pc); - addr = pc; + &pc_list, &num_pc_values); + /* FIXME: What do we do with multiple pc values for ctors/dtors or + inlined functions? */ + addr = pc_list[0]; + xfree (pc_list); break; case DISASSEM_COMMAND: case SRC_DISASSEM_COMMAND: Index: gdb-6.7/gdb/tui/tui-win.c =================================================================== --- gdb-6.7.orig/gdb/tui/tui-win.c 2007-08-23 20:08:50.000000000 +0200 +++ gdb-6.7/gdb/tui/tui-win.c 2007-10-14 23:26:23.000000000 +0200 @@ -1359,8 +1359,16 @@ make_visible_with_new_height (struct tui } else { + CORE_ADDR *pc_list; + int num_pc_values; line.loa = LOA_ADDRESS; - find_line_pc (s, cursal.line, &line.u.addr); + if (find_line_pc (s, cursal.line, &pc_list, &num_pc_values)) + { + /* FIXME: What do we do with multiple pc values for + ctors/dtors and inlined functions? */ + line.u.addr = pc_list[0]; + xfree (pc_list); + } } tui_update_source_window (win_info, s, line, TRUE); } Index: gdb-6.7/gdb/tui/tui-winsource.c =================================================================== --- gdb-6.7.orig/gdb/tui/tui-winsource.c 2007-08-23 20:08:50.000000000 +0200 +++ gdb-6.7/gdb/tui/tui-winsource.c 2007-10-14 23:26:23.000000000 +0200 @@ -173,14 +173,21 @@ tui_update_source_windows_with_addr (COR void tui_update_source_windows_with_line (struct symtab *s, int line) { - CORE_ADDR pc; + CORE_ADDR pc = 0; + CORE_ADDR *pc_list; + int num_pc_values; struct tui_line_or_address l; switch (tui_current_layout ()) { case DISASSEM_COMMAND: case DISASSEM_DATA_COMMAND: - find_line_pc (s, line, &pc); + /* FIXME: What do we do with multiple pc values for ctors/dtors? */ + if (find_line_pc (s, line, &pc_list, &num_pc_values)) + { + pc = pc_list[0]; + xfree (pc_list); + } tui_update_source_windows_with_addr (pc); break; default: @@ -189,7 +196,12 @@ tui_update_source_windows_with_line (str tui_show_symtab_source (s, l, FALSE); if (tui_current_layout () == SRC_DISASSEM_COMMAND) { - find_line_pc (s, line, &pc); + /* FIXME: What do we do with multiple pc values for ctors/dtors? */ + if (find_line_pc (s, line, &pc_list, &num_pc_values)) + { + pc = pc_list[0]; + xfree (pc_list); + } tui_show_disassem (pc); } break; Index: gdb-6.7/gdb/symtab.c =================================================================== --- gdb-6.7.orig/gdb/symtab.c 2007-10-12 22:35:58.000000000 +0200 +++ gdb-6.7/gdb/symtab.c 2007-10-14 23:26:23.000000000 +0200 @@ -73,7 +73,9 @@ static void sources_info (char *, int); static void output_source_filename (const char *, int *); -static int find_line_common (struct linetable *, int, int *); +static int find_line_common (struct linetable *, int, int, int *); + +static int find_line_by_pc (struct linetable *, CORE_ADDR, int *); /* This one is used by linespec.c */ @@ -2252,6 +2254,9 @@ find_pc_line (CORE_ADDR pc, int notcurre /* Find line number LINE in any symtab whose name is the same as SYMTAB. + If INDEX is non-NULL, use the value as the starting index in the + linetable to start at. + If found, return the symtab that contains the linetable in which it was found, set *INDEX to the index in the linetable of the best entry found, and set *EXACT_MATCH nonzero if the value returned is an @@ -2268,13 +2273,19 @@ find_line_symtab (struct symtab *symtab, so far seen. */ int best_index; + int start_index; struct linetable *best_linetable; struct symtab *best_symtab; + if (index) + start_index = *index; + else + start_index = 0; + /* First try looking it up in the given symtab. */ best_linetable = LINETABLE (symtab); best_symtab = symtab; - best_index = find_line_common (best_linetable, line, &exact); + best_index = find_line_common (best_linetable, line, start_index, &exact); if (best_index < 0 || !exact) { /* Didn't find an exact match. So we better keep looking for @@ -2305,7 +2316,7 @@ find_line_symtab (struct symtab *symtab, if (strcmp (symtab->filename, s->filename) != 0) continue; l = LINETABLE (s); - ind = find_line_common (l, line, &exact); + ind = find_line_common (l, line, start_index, &exact); if (ind >= 0) { if (exact) @@ -2341,13 +2352,23 @@ done: Returns zero for invalid line number (and sets the PC to 0). The source file is specified with a struct symtab. */ +static CORE_ADDR empty_pc_list = (CORE_ADDR)0; + int -find_line_pc (struct symtab *symtab, int line, CORE_ADDR *pc) +find_line_pc (struct symtab *symtab, int line, CORE_ADDR **pc_array, + int *num_elements) { struct linetable *l; - int ind; + int ind = 0; + char *name; + CORE_ADDR main_pc; + struct minimal_symbol *minsym; + struct minimal_symbol *minsym2; + + + *pc_array = &empty_pc_list; + *num_elements = 0; - *pc = 0; if (symtab == 0) return 0; @@ -2355,7 +2376,73 @@ find_line_pc (struct symtab *symtab, int if (symtab != NULL) { l = LINETABLE (symtab); - *pc = l->item[ind].pc; + main_pc = l->item[ind].pc; + *pc_array = xmalloc (sizeof (CORE_ADDR) * 3); + *num_elements = 0; + (*pc_array)[(*num_elements)++] = main_pc; + minsym = lookup_minimal_symbol_by_pc (main_pc); + if (minsym != NULL && minsym->ginfo.language == language_cplus) + { + char *src = minsym->ginfo.language_specific.cplus_specific.demangled_name; + char *src_point = strchr (src, '('); + char *s, *point; + /* Keep "" last as the trimming part always matches it. */ + const char *variants[] = {"$base","$allocate","$delete",""}; + int i; + + if (src_point != NULL) + { + char *dst = xmalloc (strlen (src) + strlen ("$allocate") + 1); + char *dst_point = dst + (src_point - src); + + memcpy (dst, src, src_point - src); + + /* Trim out any variant markers there first. */ + for (i = 0; i < ARRAY_SIZE (variants); i++) + { + size_t len = strlen (variants[i]); + + if (dst_point - dst >= len + && memcmp (dst_point - len, variants[i], len) == 0) + { + dst_point -= len; + /* In fact it should not be needed here. */ + break; + } + } + + /* And now try to append all of them. */ + for (i = 0; i < ARRAY_SIZE (variants); i++) + { + size_t len = strlen (variants[i]); + struct minimal_symbol *minsym2; + + memcpy (dst_point, variants[i], len); + strcpy (dst_point + len, src_point); + + minsym2 = lookup_minimal_symbol (dst, NULL, NULL); + if (minsym2 != NULL) + { + /* We have recognized we have a ctor or dtor and have + located our line in the not-in-charge version. We + also have located the in-charge version's minsym. + From this, we can find the index for the first line + line in the in-charge ctor/dtor and then search forward + for the specified line, thereby finding the 2nd match. */ + int exact; + int ind = find_line_by_pc (l, minsym2->ginfo.value.address, + &exact); + if (ind >= 0) + { + ind = find_line_common (l, line, ind, &exact); + if (ind >= 0 && l->item[ind].pc != main_pc) + (*pc_array)[(*num_elements)++] = l->item[ind].pc; + } + } + } + xfree (dst); + } + } return 1; } else @@ -2373,12 +2460,22 @@ find_line_pc_range (struct symtab_and_li CORE_ADDR *endptr) { CORE_ADDR startaddr; + CORE_ADDR *pc_list; + int num_pc_values; struct symtab_and_line found_sal; startaddr = sal.pc; - if (startaddr == 0 && !find_line_pc (sal.symtab, sal.line, &startaddr)) + if (startaddr == 0 + && !find_line_pc (sal.symtab, sal.line, &pc_list, &num_pc_values)) return 0; + /* FIXME: have to handle ctors/dtors where line equates to multiple + pc ranges. */ + if (startaddr == 0) + startaddr = pc_list[0]; + + xfree (pc_list); + /* This whole function is based on address. For example, if line 10 has two parts, one from 0x100 to 0x200 and one from 0x300 to 0x400, then "info line *0x123" should say the line goes from 0x100 to 0x200 @@ -2408,7 +2505,7 @@ find_line_pc_range (struct symtab_and_li Set *EXACT_MATCH nonzero if the value returned is an exact match. */ static int -find_line_common (struct linetable *l, int lineno, +find_line_common (struct linetable *l, int lineno, int start_index, int *exact_match) { int i; @@ -2427,7 +2524,7 @@ find_line_common (struct linetable *l, i return -1; len = l->nitems; - for (i = 0; i < len; i++) + for (i = start_index; i < len; i++) { struct linetable_entry *item = &(l->item[i]); @@ -2451,6 +2548,52 @@ find_line_common (struct linetable *l, i return best_index; } +/* Given a line table and a pc value, return the index into the line + table for the line with pc >= specified pc value. + Return -1 if none is found. The value is >= 0 if it is an index. + + Set *EXACT_MATCH nonzero if the value returned is an exact match. */ + +static int +find_line_by_pc (struct linetable *l, CORE_ADDR pc, + int *exact_match) +{ + int i; + int len; + + /* BEST is the smallest linenumber > LINENO so far seen, + or 0 if none has been seen so far. + BEST_INDEX identifies the item for it. */ + + if (l == 0) + return -1; + + len = l->nitems; + for (i = 0; i < len; i++) + { + struct linetable_entry *item = &(l->item[i]); + + /* Return the first (lowest address) entry which matches or + exceeds the given pc value. */ + if (item->pc == pc) + { + *exact_match = 1; + return i; + } + + if (item->pc > pc) + { + *exact_match = 0; + return i; + } + } + + /* If we got here, we didn't get a match. */ + + *exact_match = 0; + return -1; +} + int find_pc_line_pc_range (CORE_ADDR pc, CORE_ADDR *startptr, CORE_ADDR *endptr) { Index: gdb-6.7/gdb/symtab.h =================================================================== --- gdb-6.7.orig/gdb/symtab.h 2007-08-23 20:08:45.000000000 +0200 +++ gdb-6.7/gdb/symtab.h 2007-10-14 23:26:23.000000000 +0200 @@ -1271,13 +1271,16 @@ extern struct symtab_and_line find_pc_se /* Given a symtab and line number, return the pc there. */ -extern int find_line_pc (struct symtab *, int, CORE_ADDR *); +extern int find_line_pc (struct symtab *, int, CORE_ADDR **, int *); extern int find_line_pc_range (struct symtab_and_line, CORE_ADDR *, CORE_ADDR *); extern void resolve_sal_pc (struct symtab_and_line *); +extern void resolve_sal_pc_list (struct symtab_and_line *, CORE_ADDR **, + int *); + /* Given a string, return the line specified by it. For commands like "list" and "breakpoint". */ Index: gdb-6.7/gdb/breakpoint.c =================================================================== --- gdb-6.7.orig/gdb/breakpoint.c 2007-10-13 05:29:58.000000000 +0200 +++ gdb-6.7/gdb/breakpoint.c 2007-10-14 23:26:23.000000000 +0200 @@ -5325,12 +5325,70 @@ parse_breakpoint_sals (char **address, static void breakpoint_sals_to_pc (struct symtabs_and_lines *sals, - char *address) + char *address, char ***addr_string_p) { - int i; - for (i = 0; i < sals->nelts; i++) - { - resolve_sal_pc (&sals->sals[i]); + int i, j, incr; + int num_pc_values = 1; + + /* If a line has multiple pc values, we want to create an sal for + each pc value so we will end up creating n breakpoints. */ + for (i = 0; i < sals->nelts; i+=incr) + { + CORE_ADDR *pc_list; + incr = 1; + + resolve_sal_pc_list (&sals->sals[i], &pc_list, &num_pc_values); + if (num_pc_values != 0) + sals->sals[i].pc = pc_list[0]; + if (num_pc_values > 1) + { + struct symtab_and_line *new_sals = + xmalloc ((sals->nelts + num_pc_values - 1) + * sizeof (struct symtab_and_line)); + char **new_addr_string; + char *addr_string_base; + + /* Expand the SALS array. */ + memcpy (new_sals, sals->sals, (i + 1) + * sizeof (struct symtab_and_line)); + /* The one returned SALS entry is copied for all the PCs. */ + for (j = 1; j < num_pc_values; ++j) + { + memcpy (&(new_sals[i + j]), &sals->sals[i], + sizeof (struct symtab_and_line)); + } + xfree (sals->sals); + sals->sals = new_sals; + sals->nelts += num_pc_values - 1; + for (j = 1; j < num_pc_values; ++j) + { + sals->sals[i + j].pc = pc_list[j]; + } + + /* Expand the *ADDR_STRING_P array. */ + new_addr_string = xmalloc ((sals->nelts + num_pc_values - 1) + * sizeof *new_addr_string); + memcpy (new_addr_string, *addr_string_p, + (i + 1) * sizeof *new_addr_string); + /* The existing *ADDR_STRING_P entry must be copied for all the + multiple PCs. BREAKPOINT_RE_SET will follow the new trailing "%id" + syntax so it will get resolved right even later. Do not use the + unambiguous NULL values (resolved to "0x%x" by CREATE_BREAKPOINTS) + as the address may change for the shared libraries. */ + addr_string_base = (*addr_string_p)[i]; + for (j = 0; j < num_pc_values; ++j) + new_addr_string[i + j] = xstrprintf ("%s%%%d", addr_string_base, j); + xfree (addr_string_base); + memcpy (&new_addr_string[i + num_pc_values], &(*addr_string_p)[i + 1], + (sals->nelts - (i + num_pc_values)) * sizeof *new_addr_string); + xfree (*addr_string_p); + *addr_string_p = new_addr_string; + + incr = num_pc_values; + } + + if (num_pc_values != 0) + xfree (pc_list); /* It's possible for the PC to be nonzero, but still an illegal value on some targets. @@ -5465,6 +5523,10 @@ break_command_1 (char *arg, int flag, in if (!pending) { + /* Resolve all line numbers to PC's and verify that the addresses + are ok for the target. */ + breakpoint_sals_to_pc (&sals, addr_start, &addr_string); + /* Make sure that all storage allocated to SALS gets freed. */ make_cleanup (xfree, sals.sals); @@ -5495,11 +5557,6 @@ break_command_1 (char *arg, int flag, in make_cleanup (xfree, addr_string[i]); } - /* Resolve all line numbers to PC's and verify that the addresses - are ok for the target. */ - if (!pending) - breakpoint_sals_to_pc (&sals, addr_start); - /* Verify that condition can be parsed, before setting any breakpoints. Allocate a separate condition expression for each breakpoint. */ @@ -5675,7 +5732,7 @@ do_captured_breakpoint (struct ui_out *u error (_("Garbage %s following breakpoint address"), address_end); /* Resolve all line numbers to PC's. */ - breakpoint_sals_to_pc (&sals, args->address); + breakpoint_sals_to_pc (&sals, args->address, &addr_string); /* Verify that conditions can be parsed, before setting any breakpoints. */ @@ -5732,14 +5789,16 @@ gdb_breakpoint (char *address, char *con void resolve_sal_pc (struct symtab_and_line *sal) { - CORE_ADDR pc; + CORE_ADDR *pc_list; + int num_pc_values; if (sal->pc == 0 && sal->symtab != NULL) { - if (!find_line_pc (sal->symtab, sal->line, &pc)) + if (!find_line_pc (sal->symtab, sal->line, &pc_list, &num_pc_values)) error (_("No line %d in file \"%s\"."), sal->line, sal->symtab->filename); - sal->pc = pc; + sal->pc = pc_list[0]; + xfree (pc_list); } if (sal->section == 0 && sal->symtab != NULL) @@ -5776,6 +5835,54 @@ resolve_sal_pc (struct symtab_and_line * } } +/* Helper function for break_command_1 and disassemble_command. */ + +void +resolve_sal_pc_list (struct symtab_and_line *sal, CORE_ADDR **pc_list, + int *num_pc_values) +{ + *num_pc_values = 0; + if (sal->pc == 0 && sal->symtab != NULL) + { + if (!find_line_pc (sal->symtab, sal->line, pc_list, num_pc_values)) + error ("No line %d in file \"%s\".", + sal->line, sal->symtab->filename); + sal->pc = (*pc_list)[0]; + } + + if (sal->section == 0 && sal->symtab != NULL) + { + struct blockvector *bv; + struct block *b; + struct symbol *sym; + int index; + + bv = blockvector_for_pc_sect (sal->pc, 0, &index, sal->symtab); + if (bv != NULL) + { + b = BLOCKVECTOR_BLOCK (bv, index); + sym = block_function (b); + if (sym != NULL) + { + fixup_symbol_section (sym, sal->symtab->objfile); + sal->section = SYMBOL_BFD_SECTION (sym); + } + else + { + /* It really is worthwhile to have the section, so we'll just + have to look harder. This case can be executed if we have + line numbers but no functions (as can happen in assembly + source). */ + + struct minimal_symbol *msym; + + msym = lookup_minimal_symbol_by_pc (sal->pc); + if (msym) + sal->section = SYMBOL_BFD_SECTION (msym); + } + } + } +} void break_command (char *arg, int from_tty) { @@ -7320,6 +7427,8 @@ breakpoint_re_set_one (void *bint) int *not_found_ptr = NULL; struct symtabs_and_lines sals; char *s; + char *id_s; + int id = -1; enum enable_state save_enable; switch (b->type) @@ -7380,11 +7489,44 @@ breakpoint_re_set_one (void *bint) set_language (b->language); input_radix = b->input_radix; s = b->addr_string; + for (id_s = s + strlen (s) - 1; id_s >= s; id_s--) + { + if (isdigit (*id_s)) + continue; + if (*id_s == '%') + break; + id_s = NULL; + break; + } + if (id_s >= s) + { + s = alloca (id_s - b->addr_string + 1); + memcpy (s, b->addr_string, id_s - b->addr_string); + s[id_s - b->addr_string] = 0; + id = atoi (id_s + 1); + } sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL, not_found_ptr); for (i = 0; i < sals.nelts; i++) { - resolve_sal_pc (&sals.sals[i]); + CORE_ADDR *pc_list; + int num_pc_values; + + resolve_sal_pc_list (&sals.sals[i], &pc_list, &num_pc_values); + if (num_pc_values > 0) + { + if (id != -1) + { + /* The number of PC values should not usually change. */ + if (id >= num_pc_values) + { + delete_breakpoint (b); + return 0; + } + sals.sals[i].pc = pc_list[id]; + } + xfree (pc_list); + } /* Reparse conditions, they might contain references to the old symtab. */