diff --git a/gdb/ChangeLog b/gdb/ChangeLog index bf1f80b58b..1dc180a6f9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,68 @@ +2014-12-12 Maciej W. Rozycki + Maciej W. Rozycki + Pedro Alves + + * gdbarch.sh (elf_make_msymbol_special): Change type to `F', + remove `predefault' and `invalid_p' initializers. + (make_symbol_special): New architecture method. + (adjust_dwarf2_addr, adjust_dwarf2_line): Likewise. + (objfile, symbol): New declarations. + * arch-utils.h (default_elf_make_msymbol_special): Remove + prototype. + (default_make_symbol_special): New prototype. + (default_adjust_dwarf2_addr): Likewise. + (default_adjust_dwarf2_line): Likewise. + * mips-tdep.h (mips_unmake_compact_addr): New prototype. + * arch-utils.c (default_elf_make_msymbol_special): Remove + function. + (default_make_symbol_special): New function. + (default_adjust_dwarf2_addr): Likewise. + (default_adjust_dwarf2_line): Likewise. + * dwarf2-frame.c (decode_frame_entry_1): Call + `gdbarch_adjust_dwarf2_addr'. + * dwarf2loc.c (dwarf2_find_location_expression): Likewise. + * dwarf2read.c (create_addrmap_from_index): Likewise. + (process_psymtab_comp_unit_reader): Likewise. + (add_partial_symbol): Likewise. + (add_partial_subprogram): Likewise. + (process_full_comp_unit): Likewise. + (read_file_scope): Likewise. + (read_func_scope): Likewise. Call `gdbarch_make_symbol_special'. + (read_lexical_block_scope): Call `gdbarch_adjust_dwarf2_addr'. + (read_call_site_scope): Likewise. + (dwarf2_ranges_read): Likewise. + (dwarf2_record_block_ranges): Likewise. + (read_attribute_value): Likewise. + (dwarf_decode_lines_1): Call `gdbarch_adjust_dwarf2_line'. + (new_symbol_full): Call `gdbarch_adjust_dwarf2_addr'. + * elfread.c (elf_symtab_read): Don't call + `gdbarch_elf_make_msymbol_special' if unset. + * mips-linux-tdep.c (micromips_linux_sigframe_validate): Strip + the ISA bit from the PC. + * mips-tdep.c (mips_unmake_compact_addr): New function. + (mips_elf_make_msymbol_special): Set the ISA bit in the symbol's + address appropriately. + (mips_make_symbol_special): New function. + (mips_pc_is_mips): Set the ISA bit before symbol lookup. + (mips_pc_is_mips16): Likewise. + (mips_pc_is_micromips): Likewise. + (mips_pc_isa): Likewise. + (mips_adjust_dwarf2_addr): New function. + (mips_adjust_dwarf2_line): Likewise. + (mips_read_pc, mips_unwind_pc): Keep the ISA bit. + (mips_addr_bits_remove): Likewise. + (mips_skip_trampoline_code): Likewise. + (mips_write_pc): Don't set the ISA bit. + (mips_eabi_push_dummy_call): Likewise. + (mips_o64_push_dummy_call): Likewise. + (mips_gdbarch_init): Install `mips_make_symbol_special', + `mips_adjust_dwarf2_addr' and `mips_adjust_dwarf2_line' gdbarch + handlers. + * solib.c (gdb_bfd_lookup_symbol_from_symtab): Get + target-specific symbol address adjustments. + * gdbarch.h: Regenerate. + * gdbarch.c: Regenerate. + 2014-12-12 Yao Qi PR tdep/14261 diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index a2e76deb87..33d5543101 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -31,6 +31,7 @@ #include "target-descriptions.h" #include "objfiles.h" #include "language.h" +#include "symtab.h" #include "version.h" @@ -167,17 +168,35 @@ no_op_reg_to_regnum (struct gdbarch *gdbarch, int reg) } void -default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym) +default_coff_make_msymbol_special (int val, struct minimal_symbol *msym) { return; } +/* See arch-utils.h. */ + void -default_coff_make_msymbol_special (int val, struct minimal_symbol *msym) +default_make_symbol_special (struct symbol *sym, struct objfile *objfile) { return; } +/* See arch-utils.h. */ + +CORE_ADDR +default_adjust_dwarf2_addr (CORE_ADDR pc) +{ + return pc; +} + +/* See arch-utils.h. */ + +CORE_ADDR +default_adjust_dwarf2_line (CORE_ADDR addr, int rel) +{ + return addr; +} + int cannot_register_not (struct gdbarch *gdbarch, int regnum) { diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index 1f5dd55f46..11e68e2787 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -68,15 +68,22 @@ extern gdbarch_convert_from_func_ptr_addr_ftype convert_from_func_ptr_addr_ident extern int no_op_reg_to_regnum (struct gdbarch *gdbarch, int reg); -/* Do nothing version of elf_make_msymbol_special. */ - -void default_elf_make_msymbol_special (asymbol *sym, - struct minimal_symbol *msym); - /* Do nothing version of coff_make_msymbol_special. */ void default_coff_make_msymbol_special (int val, struct minimal_symbol *msym); +/* Do nothing default implementation of gdbarch_make_symbol_special. */ + +void default_make_symbol_special (struct symbol *sym, struct objfile *objfile); + +/* Do nothing default implementation of gdbarch_adjust_dwarf2_addr. */ + +CORE_ADDR default_adjust_dwarf2_addr (CORE_ADDR pc); + +/* Do nothing default implementation of gdbarch_adjust_dwarf2_line. */ + +CORE_ADDR default_adjust_dwarf2_line (CORE_ADDR addr, int rel); + /* Version of cannot_fetch_register() / cannot_store_register() that always fails. */ diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 586f1345c1..8747f4cc6b 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -2066,6 +2066,7 @@ decode_frame_entry_1 (struct comp_unit *unit, const gdb_byte *start, { /* This is a FDE. */ struct dwarf2_fde *fde; + CORE_ADDR addr; /* Check that an FDE was expected. */ if ((entry_type & EH_FDE_TYPE_ID) == 0) @@ -2099,14 +2100,16 @@ decode_frame_entry_1 (struct comp_unit *unit, const gdb_byte *start, gdb_assert (fde->cie != NULL); - fde->initial_location = - read_encoded_value (unit, fde->cie->encoding, fde->cie->ptr_size, - buf, &bytes_read, 0); + addr = read_encoded_value (unit, fde->cie->encoding, fde->cie->ptr_size, + buf, &bytes_read, 0); + fde->initial_location = gdbarch_adjust_dwarf2_addr (gdbarch, addr); buf += bytes_read; fde->address_range = read_encoded_value (unit, fde->cie->encoding & 0x0f, fde->cie->ptr_size, buf, &bytes_read, 0); + addr = gdbarch_adjust_dwarf2_addr (gdbarch, addr + fde->address_range); + fde->address_range = addr - fde->initial_location; buf += bytes_read; /* A 'z' augmentation in the CIE implies the presence of an diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 6e461bcdcc..fbaa7d30aa 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -4296,6 +4296,9 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr, low += base_address; high += base_address; + low = gdbarch_adjust_dwarf2_addr (gdbarch, low); + high = gdbarch_adjust_dwarf2_addr (gdbarch, high); + length = extract_unsigned_integer (loc_ptr, 2, byte_order); loc_ptr += 2; diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 829611dfe9..e36af5ab43 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -2824,6 +2824,7 @@ create_signatured_type_table_from_index (struct objfile *objfile, static void create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index) { + struct gdbarch *gdbarch = get_objfile_arch (objfile); const gdb_byte *iter, *end; struct obstack temp_obstack; struct addrmap *mutable_map; @@ -2865,8 +2866,9 @@ create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index) continue; } - addrmap_set_empty (mutable_map, lo + baseaddr, hi + baseaddr - 1, - dw2_get_cutu (cu_index)); + lo = gdbarch_adjust_dwarf2_addr (gdbarch, lo + baseaddr); + hi = gdbarch_adjust_dwarf2_addr (gdbarch, hi + baseaddr); + addrmap_set_empty (mutable_map, lo, hi - 1, dw2_get_cutu (cu_index)); } objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map, @@ -5849,6 +5851,7 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader, { struct dwarf2_cu *cu = reader->cu; struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); struct dwarf2_per_cu_data *per_cu = cu->per_cu; struct attribute *attr; CORE_ADDR baseaddr; @@ -5893,8 +5896,11 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader, /* Store the contiguous range if it is not empty; it can be empty for CUs with no code. */ addrmap_set_empty (objfile->psymtabs_addrmap, - best_lowpc + baseaddr, - best_highpc + baseaddr - 1, pst); + gdbarch_adjust_dwarf2_addr (gdbarch, + best_lowpc + baseaddr), + gdbarch_adjust_dwarf2_addr (gdbarch, + best_highpc + baseaddr) - 1, + pst); /* Check if comp unit has_children. If so, read the rest of the partial symbols from this comp unit. @@ -5925,8 +5931,8 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader, best_highpc = highpc; } } - pst->textlow = best_lowpc + baseaddr; - pst->texthigh = best_highpc + baseaddr; + pst->textlow = gdbarch_adjust_dwarf2_addr (gdbarch, best_lowpc + baseaddr); + pst->texthigh = gdbarch_adjust_dwarf2_addr (gdbarch, best_highpc + baseaddr); pst->n_global_syms = objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset); @@ -6789,6 +6795,7 @@ static void add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); CORE_ADDR addr = 0; const char *actual_name = NULL; CORE_ADDR baseaddr; @@ -6806,31 +6813,30 @@ add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu) switch (pdi->tag) { case DW_TAG_subprogram: + addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr); if (pdi->is_external || cu->language == language_ada) { /* brobecker/2007-12-26: Normally, only "external" DIEs are part of the global scope. But in Ada, we want to be able to access nested procedures globally. So all Ada subprograms are stored in the global scope. */ - /* prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr, - mst_text, objfile); */ + /* prim_record_minimal_symbol (actual_name, addr, mst_text, + objfile); */ add_psymbol_to_list (actual_name, strlen (actual_name), built_actual_name != NULL, VAR_DOMAIN, LOC_BLOCK, &objfile->global_psymbols, - 0, pdi->lowpc + baseaddr, - cu->language, objfile); + 0, addr, cu->language, objfile); } else { - /* prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr, - mst_file_text, objfile); */ + /* prim_record_minimal_symbol (actual_name, addr, mst_file_text, + objfile); */ add_psymbol_to_list (actual_name, strlen (actual_name), built_actual_name != NULL, VAR_DOMAIN, LOC_BLOCK, &objfile->static_psymbols, - 0, pdi->lowpc + baseaddr, - cu->language, objfile); + 0, addr, cu->language, objfile); } break; case DW_TAG_constant: @@ -7031,14 +7037,19 @@ add_partial_subprogram (struct partial_die_info *pdi, *highpc = pdi->highpc; if (set_addrmap) { - CORE_ADDR baseaddr; struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); + CORE_ADDR baseaddr; + CORE_ADDR highpc; + CORE_ADDR lowpc; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); - addrmap_set_empty (objfile->psymtabs_addrmap, - pdi->lowpc + baseaddr, - pdi->highpc - 1 + baseaddr, + lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, + pdi->lowpc + baseaddr); + highpc = gdbarch_adjust_dwarf2_addr (gdbarch, + pdi->highpc + baseaddr); + addrmap_set_empty (objfile->psymtabs_addrmap, lowpc, highpc - 1, cu->per_cu->v.psymtab); } } @@ -7925,11 +7936,13 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu, { struct dwarf2_cu *cu = per_cu->cu; struct objfile *objfile = per_cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); CORE_ADDR lowpc, highpc; struct compunit_symtab *cust; struct cleanup *back_to, *delayed_list_cleanup; CORE_ADDR baseaddr; struct block *static_block; + CORE_ADDR addr; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); @@ -7960,8 +7973,8 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu, it, by scanning the DIE's below the compilation unit. */ get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu); - static_block - = end_symtab_get_static_block (highpc + baseaddr, 0, 1); + addr = gdbarch_adjust_dwarf2_addr (gdbarch, highpc + baseaddr); + static_block = end_symtab_get_static_block (addr, 0, 1); /* If the comp unit has DW_AT_ranges, it may have discontiguous ranges. Also, DW_AT_ranges may record ranges not belonging to any child DIEs @@ -9006,6 +9019,7 @@ static void read_file_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = dwarf2_per_objfile->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); struct cleanup *back_to = make_cleanup (null_cleanup, 0); CORE_ADDR lowpc = ((CORE_ADDR) -1); CORE_ADDR highpc = ((CORE_ADDR) 0); @@ -9024,8 +9038,7 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu) from finish_block. */ if (lowpc == ((CORE_ADDR) -1)) lowpc = highpc; - lowpc += baseaddr; - highpc += baseaddr; + lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr); find_file_and_directory (die, cu, &name, &comp_dir); @@ -11133,6 +11146,7 @@ static void read_func_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); struct context_stack *new; CORE_ADDR lowpc; CORE_ADDR highpc; @@ -11185,8 +11199,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) return; } - lowpc += baseaddr; - highpc += baseaddr; + lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr); + highpc = gdbarch_adjust_dwarf2_addr (gdbarch, highpc + baseaddr); /* If we have any template arguments, then we must allocate a different sort of symbol. */ @@ -11273,6 +11287,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu) /* If we have address ranges, record them. */ dwarf2_record_block_ranges (die, block, baseaddr, cu); + gdbarch_make_symbol_special (gdbarch, new->name, objfile); + /* Attach template arguments to function. */ if (! VEC_empty (symbolp, template_args)) { @@ -11309,6 +11325,7 @@ static void read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); struct context_stack *new; CORE_ADDR lowpc, highpc; struct die_info *child_die; @@ -11323,8 +11340,8 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) describe ranges. */ if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)) return; - lowpc += baseaddr; - highpc += baseaddr; + lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr); + highpc = gdbarch_adjust_dwarf2_addr (gdbarch, highpc + baseaddr); push_context (0, lowpc); if (die->child != NULL) @@ -11386,6 +11403,7 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) return; } pc = attr_value_as_address (attr) + baseaddr; + pc = gdbarch_adjust_dwarf2_addr (gdbarch, pc); if (cu->call_site_htab == NULL) cu->call_site_htab = htab_create_alloc_ex (16, core_addr_hash, core_addr_eq, @@ -11534,7 +11552,10 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu) "low pc, for referencing DIE 0x%x [in module %s]"), die->offset.sect_off, objfile_name (objfile)); else - SET_FIELD_PHYSADDR (call_site->target, lowpc + baseaddr); + { + lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr); + SET_FIELD_PHYSADDR (call_site->target, lowpc); + } } } else @@ -11662,6 +11683,7 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return, struct partial_symtab *ranges_pst) { struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); struct comp_unit_head *cu_header = &cu->header; bfd *obfd = objfile->obfd; unsigned int addr_size = cu_header->addr_size; @@ -11769,10 +11791,17 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return, } if (ranges_pst != NULL) - addrmap_set_empty (objfile->psymtabs_addrmap, - range_beginning + baseaddr, - range_end - 1 + baseaddr, - ranges_pst); + { + CORE_ADDR lowpc; + CORE_ADDR highpc; + + lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, + range_beginning + baseaddr); + highpc = gdbarch_adjust_dwarf2_addr (gdbarch, + range_end + baseaddr); + addrmap_set_empty (objfile->psymtabs_addrmap, lowpc, highpc - 1, + ranges_pst); + } /* FIXME: This is recording everything as a low-high segment of consecutive addresses. We should have a @@ -11986,6 +12015,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block, CORE_ADDR baseaddr, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); struct attribute *attr; struct attribute *attr_high; @@ -12001,7 +12031,9 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block, if (cu->header.version >= 4 && attr_form_is_constant (attr_high)) high += low; - record_block_range (block, baseaddr + low, baseaddr + high - 1); + low = gdbarch_adjust_dwarf2_addr (gdbarch, low + baseaddr); + high = gdbarch_adjust_dwarf2_addr (gdbarch, high + baseaddr); + record_block_range (block, low, high - 1); } } @@ -12105,6 +12137,8 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block, continue; } + start = gdbarch_adjust_dwarf2_addr (gdbarch, start); + end = gdbarch_adjust_dwarf2_addr (gdbarch, end); record_block_range (block, start, end - 1); } } @@ -15931,6 +15965,8 @@ read_attribute_value (const struct die_reader_specs *reader, const gdb_byte *info_ptr) { struct dwarf2_cu *cu = reader->cu; + struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); bfd *abfd = reader->abfd; struct comp_unit_head *cu_header = &cu->header; unsigned int bytes_read; @@ -15953,6 +15989,7 @@ read_attribute_value (const struct die_reader_specs *reader, break; case DW_FORM_addr: DW_ADDR (attr) = read_address (abfd, info_ptr, cu, &bytes_read); + DW_ADDR (attr) = gdbarch_adjust_dwarf2_addr (gdbarch, DW_ADDR (attr)); info_ptr += bytes_read; break; case DW_FORM_block2: @@ -17284,8 +17321,12 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, /* Read the statement sequences until there's nothing left. */ while (line_ptr < line_end) { - /* state machine registers */ - CORE_ADDR address = 0; + /* State machine registers. Call `gdbarch_adjust_dwarf2_line' + on the initial 0 address as if there was a line entry for it + so that the backend has a chance to adjust it and also record + it in case it needs it. This is currently used by MIPS code, + cf. `mips_adjust_dwarf2_line'. */ + CORE_ADDR address = gdbarch_adjust_dwarf2_line (gdbarch, 0, 0); unsigned int file = 1; unsigned int line = 1; int is_stmt = lh->default_is_stmt; @@ -17328,12 +17369,14 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, { /* Special opcode. */ unsigned char adj_opcode; + CORE_ADDR addr_adj; int line_delta; adj_opcode = op_code - lh->opcode_base; - address += (((op_index + (adj_opcode / lh->line_range)) + addr_adj = (((op_index + (adj_opcode / lh->line_range)) / lh->maximum_ops_per_instruction) * lh->minimum_instruction_length); + address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); op_index = ((op_index + (adj_opcode / lh->line_range)) % lh->maximum_ops_per_instruction); line_delta = lh->line_base + (adj_opcode % lh->line_range); @@ -17410,6 +17453,7 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, op_index = 0; line_ptr += bytes_read; address += baseaddr; + address = gdbarch_adjust_dwarf2_line (gdbarch, address, 0); break; case DW_LNE_define_file: { @@ -17487,10 +17531,12 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, { CORE_ADDR adjust = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + CORE_ADDR addr_adj; - address += (((op_index + adjust) + addr_adj = (((op_index + adjust) / lh->maximum_ops_per_instruction) * lh->minimum_instruction_length); + address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); op_index = ((op_index + adjust) % lh->maximum_ops_per_instruction); line_ptr += bytes_read; @@ -17550,18 +17596,25 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, case DW_LNS_const_add_pc: { CORE_ADDR adjust = (255 - lh->opcode_base) / lh->line_range; + CORE_ADDR addr_adj; - address += (((op_index + adjust) + addr_adj = (((op_index + adjust) / lh->maximum_ops_per_instruction) * lh->minimum_instruction_length); + address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); op_index = ((op_index + adjust) % lh->maximum_ops_per_instruction); } break; case DW_LNS_fixed_advance_pc: - address += read_2_bytes (abfd, line_ptr); - op_index = 0; - line_ptr += 2; + { + CORE_ADDR addr_adj; + + addr_adj = read_2_bytes (abfd, line_ptr); + address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); + op_index = 0; + line_ptr += 2; + } break; default: { @@ -17813,6 +17866,7 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, struct symbol *space) { struct objfile *objfile = cu->objfile; + struct gdbarch *gdbarch = get_objfile_arch (objfile); struct symbol *sym = NULL; const char *name; struct attribute *attr = NULL; @@ -17890,8 +17944,13 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu, case DW_TAG_label: attr = dwarf2_attr (die, DW_AT_low_pc, cu); if (attr) - SYMBOL_VALUE_ADDRESS (sym) - = attr_value_as_address (attr) + baseaddr; + { + CORE_ADDR addr; + + addr = attr_value_as_address (attr); + addr = gdbarch_adjust_dwarf2_addr (gdbarch, addr + baseaddr); + SYMBOL_VALUE_ADDRESS (sym) = addr; + } SYMBOL_TYPE (sym) = objfile_type (objfile)->builtin_core_addr; SYMBOL_DOMAIN (sym) = LABEL_DOMAIN; SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL; diff --git a/gdb/elfread.c b/gdb/elfread.c index 19aaed35dc..b4ec067777 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -247,6 +247,8 @@ elf_symtab_read (struct objfile *objfile, int type, const char *filesymname = ""; struct dbx_symfile_info *dbx = DBX_SYMFILE_INFO (objfile); int stripped = (bfd_get_symcount (objfile->obfd) == 0); + int elf_make_msymbol_special_p + = gdbarch_elf_make_msymbol_special_p (gdbarch); for (i = 0; i < number_of_symbols; i++) { @@ -330,7 +332,8 @@ elf_symtab_read (struct objfile *objfile, int type, if (msym != NULL) { msym->filename = filesymname; - gdbarch_elf_make_msymbol_special (gdbarch, sym, msym); + if (elf_make_msymbol_special_p) + gdbarch_elf_make_msymbol_special (gdbarch, sym, msym); } continue; } @@ -558,7 +561,8 @@ elf_symtab_read (struct objfile *objfile, int type, } msym->filename = filesymname; - gdbarch_elf_make_msymbol_special (gdbarch, sym, msym); + if (elf_make_msymbol_special_p) + gdbarch_elf_make_msymbol_special (gdbarch, sym, msym); } /* If we see a default versioned symbol, install it under @@ -597,7 +601,9 @@ elf_symtab_read (struct objfile *objfile, int type, SET_MSYMBOL_SIZE (mtramp, MSYMBOL_SIZE (msym)); mtramp->created_by_gdb = 1; mtramp->filename = filesymname; - gdbarch_elf_make_msymbol_special (gdbarch, sym, mtramp); + if (elf_make_msymbol_special_p) + gdbarch_elf_make_msymbol_special (gdbarch, + sym, mtramp); } } } diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index f89a6d2e0b..132fff3528 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -252,6 +252,9 @@ struct gdbarch gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p; gdbarch_elf_make_msymbol_special_ftype *elf_make_msymbol_special; gdbarch_coff_make_msymbol_special_ftype *coff_make_msymbol_special; + gdbarch_make_symbol_special_ftype *make_symbol_special; + gdbarch_adjust_dwarf2_addr_ftype *adjust_dwarf2_addr; + gdbarch_adjust_dwarf2_line_ftype *adjust_dwarf2_line; int cannot_step_breakpoint; int have_nonsteppable_watchpoint; gdbarch_address_class_type_flags_ftype *address_class_type_flags; @@ -392,8 +395,10 @@ gdbarch_alloc (const struct gdbarch_info *info, gdbarch->skip_solib_resolver = generic_skip_solib_resolver; gdbarch->in_solib_return_trampoline = generic_in_solib_return_trampoline; gdbarch->in_function_epilogue_p = generic_in_function_epilogue_p; - gdbarch->elf_make_msymbol_special = default_elf_make_msymbol_special; gdbarch->coff_make_msymbol_special = default_coff_make_msymbol_special; + gdbarch->make_symbol_special = default_make_symbol_special; + gdbarch->adjust_dwarf2_addr = default_adjust_dwarf2_addr; + gdbarch->adjust_dwarf2_line = default_adjust_dwarf2_line; gdbarch->register_reggroup_p = default_register_reggroup_p; gdbarch->skip_permanent_breakpoint = default_skip_permanent_breakpoint; gdbarch->displaced_step_hw_singlestep = default_displaced_step_hw_singlestep; @@ -565,8 +570,11 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of skip_solib_resolver, invalid_p == 0 */ /* Skip verify of in_solib_return_trampoline, invalid_p == 0 */ /* Skip verify of in_function_epilogue_p, invalid_p == 0 */ - /* Skip verify of elf_make_msymbol_special, invalid_p == 0 */ + /* Skip verify of elf_make_msymbol_special, has predicate. */ /* Skip verify of coff_make_msymbol_special, invalid_p == 0 */ + /* Skip verify of make_symbol_special, invalid_p == 0 */ + /* Skip verify of adjust_dwarf2_addr, invalid_p == 0 */ + /* Skip verify of adjust_dwarf2_line, invalid_p == 0 */ /* Skip verify of cannot_step_breakpoint, invalid_p == 0 */ /* Skip verify of have_nonsteppable_watchpoint, invalid_p == 0 */ /* Skip verify of address_class_type_flags, has predicate. */ @@ -690,6 +698,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: adjust_breakpoint_address = <%s>\n", host_address_to_string (gdbarch->adjust_breakpoint_address)); + fprintf_unfiltered (file, + "gdbarch_dump: adjust_dwarf2_addr = <%s>\n", + host_address_to_string (gdbarch->adjust_dwarf2_addr)); + fprintf_unfiltered (file, + "gdbarch_dump: adjust_dwarf2_line = <%s>\n", + host_address_to_string (gdbarch->adjust_dwarf2_line)); fprintf_unfiltered (file, "gdbarch_dump: auto_charset = <%s>\n", host_address_to_string (gdbarch->auto_charset)); @@ -837,6 +851,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: ecoff_reg_to_regnum = <%s>\n", host_address_to_string (gdbarch->ecoff_reg_to_regnum)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_elf_make_msymbol_special_p() = %d\n", + gdbarch_elf_make_msymbol_special_p (gdbarch)); fprintf_unfiltered (file, "gdbarch_dump: elf_make_msymbol_special = <%s>\n", host_address_to_string (gdbarch->elf_make_msymbol_special)); @@ -1017,6 +1034,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: make_corefile_notes = <%s>\n", host_address_to_string (gdbarch->make_corefile_notes)); + fprintf_unfiltered (file, + "gdbarch_dump: make_symbol_special = <%s>\n", + host_address_to_string (gdbarch->make_symbol_special)); fprintf_unfiltered (file, "gdbarch_dump: gdbarch_max_insn_length_p() = %d\n", gdbarch_max_insn_length_p (gdbarch)); @@ -3065,6 +3085,13 @@ set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, gdbarch->in_function_epilogue_p = in_function_epilogue_p; } +int +gdbarch_elf_make_msymbol_special_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->elf_make_msymbol_special != NULL; +} + void gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, asymbol *sym, struct minimal_symbol *msym) { @@ -3099,6 +3126,57 @@ set_gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch, gdbarch->coff_make_msymbol_special = coff_make_msymbol_special; } +void +gdbarch_make_symbol_special (struct gdbarch *gdbarch, struct symbol *sym, struct objfile *objfile) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->make_symbol_special != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_make_symbol_special called\n"); + gdbarch->make_symbol_special (sym, objfile); +} + +void +set_gdbarch_make_symbol_special (struct gdbarch *gdbarch, + gdbarch_make_symbol_special_ftype make_symbol_special) +{ + gdbarch->make_symbol_special = make_symbol_special; +} + +CORE_ADDR +gdbarch_adjust_dwarf2_addr (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->adjust_dwarf2_addr != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_adjust_dwarf2_addr called\n"); + return gdbarch->adjust_dwarf2_addr (pc); +} + +void +set_gdbarch_adjust_dwarf2_addr (struct gdbarch *gdbarch, + gdbarch_adjust_dwarf2_addr_ftype adjust_dwarf2_addr) +{ + gdbarch->adjust_dwarf2_addr = adjust_dwarf2_addr; +} + +CORE_ADDR +gdbarch_adjust_dwarf2_line (struct gdbarch *gdbarch, CORE_ADDR addr, int rel) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->adjust_dwarf2_line != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_adjust_dwarf2_line called\n"); + return gdbarch->adjust_dwarf2_line (addr, rel); +} + +void +set_gdbarch_adjust_dwarf2_line (struct gdbarch *gdbarch, + gdbarch_adjust_dwarf2_line_ftype adjust_dwarf2_line) +{ + gdbarch->adjust_dwarf2_line = adjust_dwarf2_line; +} + int gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 0bd1d5662d..ba4fe62ae9 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -51,6 +51,8 @@ struct target_ops; struct obstack; struct bp_target_info; struct target_desc; +struct objfile; +struct symbol; struct displaced_step_closure; struct core_regset_section; struct syscall; @@ -688,6 +690,16 @@ typedef int (gdbarch_in_function_epilogue_p_ftype) (struct gdbarch *gdbarch, COR extern int gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr); extern void set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p); +/* Process an ELF symbol in the minimal symbol table in a backend-specific + way. Normally this hook is supposed to do nothing, however if required, + then this hook can be used to apply tranformations to symbols that are + considered special in some way. For example the MIPS backend uses it + to interpret `st_other' information to mark compressed code symbols so + that they can be treated in the appropriate manner in the processing of + the main symbol table and DWARF-2 records. */ + +extern int gdbarch_elf_make_msymbol_special_p (struct gdbarch *gdbarch); + typedef void (gdbarch_elf_make_msymbol_special_ftype) (asymbol *sym, struct minimal_symbol *msym); extern void gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, asymbol *sym, struct minimal_symbol *msym); extern void set_gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, gdbarch_elf_make_msymbol_special_ftype *elf_make_msymbol_special); @@ -696,6 +708,45 @@ typedef void (gdbarch_coff_make_msymbol_special_ftype) (int val, struct minimal_ extern void gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch, int val, struct minimal_symbol *msym); extern void set_gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch, gdbarch_coff_make_msymbol_special_ftype *coff_make_msymbol_special); +/* Process a symbol in the main symbol table in a backend-specific way. + Normally this hook is supposed to do nothing, however if required, + then this hook can be used to apply tranformations to symbols that + are considered special in some way. This is currently used by the + MIPS backend to make sure compressed code symbols have the ISA bit + set. This in turn is needed for symbol values seen in GDB to match + the values used at the runtime by the program itself, for function + and label references. */ + +typedef void (gdbarch_make_symbol_special_ftype) (struct symbol *sym, struct objfile *objfile); +extern void gdbarch_make_symbol_special (struct gdbarch *gdbarch, struct symbol *sym, struct objfile *objfile); +extern void set_gdbarch_make_symbol_special (struct gdbarch *gdbarch, gdbarch_make_symbol_special_ftype *make_symbol_special); + +/* Adjust the address retrieved from a DWARF-2 record other than a line + entry in a backend-specific way. Normally this hook is supposed to + return the address passed unchanged, however if that is incorrect for + any reason, then this hook can be used to fix the address up in the + required manner. This is currently used by the MIPS backend to make + sure addresses in FDE, range records, etc. referring to compressed + code have the ISA bit set, matching line information and the symbol + table. */ + +typedef CORE_ADDR (gdbarch_adjust_dwarf2_addr_ftype) (CORE_ADDR pc); +extern CORE_ADDR gdbarch_adjust_dwarf2_addr (struct gdbarch *gdbarch, CORE_ADDR pc); +extern void set_gdbarch_adjust_dwarf2_addr (struct gdbarch *gdbarch, gdbarch_adjust_dwarf2_addr_ftype *adjust_dwarf2_addr); + +/* Adjust the address updated by a line entry in a backend-specific way. + Normally this hook is supposed to return the address passed unchanged, + however in the case of inconsistencies in these records, this hook can + be used to fix them up in the required manner. This is currently used + by the MIPS backend to make sure all line addresses in compressed code + are presented with the ISA bit set, which is not always the case. This + in turn ensures breakpoint addresses are correctly matched against the + stop PC. */ + +typedef CORE_ADDR (gdbarch_adjust_dwarf2_line_ftype) (CORE_ADDR addr, int rel); +extern CORE_ADDR gdbarch_adjust_dwarf2_line (struct gdbarch *gdbarch, CORE_ADDR addr, int rel); +extern void set_gdbarch_adjust_dwarf2_line (struct gdbarch *gdbarch, gdbarch_adjust_dwarf2_line_ftype *adjust_dwarf2_line); + extern int gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch); extern void set_gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch, int cannot_step_breakpoint); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 8aeb394cbe..25544e3d8d 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -635,8 +635,42 @@ m:int:in_solib_return_trampoline:CORE_ADDR pc, const char *name:pc, name::generi # which don't suffer from that problem could just let this functionality # untouched. m:int:in_function_epilogue_p:CORE_ADDR addr:addr:0:generic_in_function_epilogue_p::0 -f:void:elf_make_msymbol_special:asymbol *sym, struct minimal_symbol *msym:sym, msym::default_elf_make_msymbol_special::0 +# Process an ELF symbol in the minimal symbol table in a backend-specific +# way. Normally this hook is supposed to do nothing, however if required, +# then this hook can be used to apply tranformations to symbols that are +# considered special in some way. For example the MIPS backend uses it +# to interpret \`st_other' information to mark compressed code symbols so +# that they can be treated in the appropriate manner in the processing of +# the main symbol table and DWARF-2 records. +F:void:elf_make_msymbol_special:asymbol *sym, struct minimal_symbol *msym:sym, msym f:void:coff_make_msymbol_special:int val, struct minimal_symbol *msym:val, msym::default_coff_make_msymbol_special::0 +# Process a symbol in the main symbol table in a backend-specific way. +# Normally this hook is supposed to do nothing, however if required, +# then this hook can be used to apply tranformations to symbols that +# are considered special in some way. This is currently used by the +# MIPS backend to make sure compressed code symbols have the ISA bit +# set. This in turn is needed for symbol values seen in GDB to match +# the values used at the runtime by the program itself, for function +# and label references. +f:void:make_symbol_special:struct symbol *sym, struct objfile *objfile:sym, objfile::default_make_symbol_special::0 +# Adjust the address retrieved from a DWARF-2 record other than a line +# entry in a backend-specific way. Normally this hook is supposed to +# return the address passed unchanged, however if that is incorrect for +# any reason, then this hook can be used to fix the address up in the +# required manner. This is currently used by the MIPS backend to make +# sure addresses in FDE, range records, etc. referring to compressed +# code have the ISA bit set, matching line information and the symbol +# table. +f:CORE_ADDR:adjust_dwarf2_addr:CORE_ADDR pc:pc::default_adjust_dwarf2_addr::0 +# Adjust the address updated by a line entry in a backend-specific way. +# Normally this hook is supposed to return the address passed unchanged, +# however in the case of inconsistencies in these records, this hook can +# be used to fix them up in the required manner. This is currently used +# by the MIPS backend to make sure all line addresses in compressed code +# are presented with the ISA bit set, which is not always the case. This +# in turn ensures breakpoint addresses are correctly matched against the +# stop PC. +f:CORE_ADDR:adjust_dwarf2_line:CORE_ADDR addr, int rel:addr, rel::default_adjust_dwarf2_line::0 v:int:cannot_step_breakpoint:::0:0::0 v:int:have_nonsteppable_watchpoint:::0:0::0 F:int:address_class_type_flags:int byte_size, int dwarf2_addr_class:byte_size, dwarf2_addr_class @@ -1153,6 +1187,8 @@ struct target_ops; struct obstack; struct bp_target_info; struct target_desc; +struct objfile; +struct symbol; struct displaced_step_closure; struct core_regset_section; struct syscall; diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 41602ba736..243a671212 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -1364,7 +1364,13 @@ micromips_linux_sigframe_validate (const struct tramp_frame *self, struct frame_info *this_frame, CORE_ADDR *pc) { - return mips_pc_is_micromips (get_frame_arch (this_frame), *pc); + if (mips_pc_is_micromips (get_frame_arch (this_frame), *pc)) + { + *pc = mips_unmake_compact_addr (*pc); + return 1; + } + else + return 0; } /* Implement the "write_pc" gdbarch method. */ diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index c072bf0be6..5a5a716433 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -340,6 +340,15 @@ make_compact_addr (CORE_ADDR addr) return ((addr) | (CORE_ADDR) 1); } +/* Extern version of unmake_compact_addr; we use a separate function + so that unmake_compact_addr can be inlined throughout this file. */ + +CORE_ADDR +mips_unmake_compact_addr (CORE_ADDR addr) +{ + return unmake_compact_addr (addr); +} + /* Functions for setting and testing a bit in a minimal symbol that marks it as MIPS16 or microMIPS function. The MSB of the minimal symbol's "info" field is used for this purpose. @@ -369,9 +378,15 @@ mips_elf_make_msymbol_special (asymbol * sym, struct minimal_symbol *msym) return; if (ELF_ST_IS_MICROMIPS (st_other)) - MSYMBOL_TARGET_FLAG_2 (msym) = 1; + { + MSYMBOL_TARGET_FLAG_2 (msym) = 1; + SET_MSYMBOL_VALUE_ADDRESS (msym, MSYMBOL_VALUE_RAW_ADDRESS (msym) | 1); + } else if (ELF_ST_IS_MIPS16 (st_other)) - MSYMBOL_TARGET_FLAG_1 (msym) = 1; + { + MSYMBOL_TARGET_FLAG_1 (msym) = 1; + SET_MSYMBOL_VALUE_ADDRESS (msym, MSYMBOL_VALUE_RAW_ADDRESS (msym) | 1); + } } /* Return one iff MSYM refers to standard ISA code. */ @@ -398,6 +413,35 @@ msymbol_is_micromips (struct minimal_symbol *msym) return MSYMBOL_TARGET_FLAG_2 (msym); } +/* Set the ISA bit in the main symbol too, complementing the corresponding + minimal symbol setting and reflecting the run-time value of the symbol. + The need for comes from the ISA bit having been cleared as code in + `_bfd_mips_elf_symbol_processing' separated it into the ELF symbol's + `st_other' STO_MIPS16 or STO_MICROMIPS annotation, making the values + of symbols referring to compressed code different in GDB to the values + used by actual code. That in turn makes them evaluate incorrectly in + expressions, producing results different to what the same expressions + yield when compiled into the program being debugged. */ + +static void +mips_make_symbol_special (struct symbol *sym, struct objfile *objfile) +{ + if (SYMBOL_CLASS (sym) == LOC_BLOCK) + { + /* We are in symbol reading so it is OK to cast away constness. */ + struct block *block = (struct block *) SYMBOL_BLOCK_VALUE (sym); + CORE_ADDR compact_block_start; + struct bound_minimal_symbol msym; + + compact_block_start = BLOCK_START (block) | 1; + msym = lookup_minimal_symbol_by_pc (compact_block_start); + if (msym.minsym && !msymbol_is_mips (msym.minsym)) + { + BLOCK_START (block) = compact_block_start; + } + } +} + /* XFER a value from the big/little/left end of the register. Depending on the size of the value it might occupy the entire register or just part of it. Make an allowance for this, aligning @@ -1132,7 +1176,7 @@ mips_pc_is_mips (CORE_ADDR memaddr) stored by elfread.c in the high bit of the info field. Use this to decide if the function is standard MIPS. Otherwise if bit 0 of the address is clear, then this is a standard MIPS function. */ - sym = lookup_minimal_symbol_by_pc (memaddr); + sym = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr)); if (sym.minsym) return msymbol_is_mips (sym.minsym); else @@ -1150,7 +1194,7 @@ mips_pc_is_mips16 (struct gdbarch *gdbarch, CORE_ADDR memaddr) elfread.c in the high bit of the info field. Use this to decide if the function is MIPS16. Otherwise if bit 0 of the address is set, then ELF file flags will tell if this is a MIPS16 function. */ - sym = lookup_minimal_symbol_by_pc (memaddr); + sym = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr)); if (sym.minsym) return msymbol_is_mips16 (sym.minsym); else @@ -1169,7 +1213,7 @@ mips_pc_is_micromips (struct gdbarch *gdbarch, CORE_ADDR memaddr) if the function is microMIPS. Otherwise if bit 0 of the address is set, then ELF file flags will tell if this is a microMIPS function. */ - sym = lookup_minimal_symbol_by_pc (memaddr); + sym = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr)); if (sym.minsym) return msymbol_is_micromips (sym.minsym); else @@ -1189,7 +1233,7 @@ mips_pc_isa (struct gdbarch *gdbarch, CORE_ADDR memaddr) this to decide if the function is MIPS16 or microMIPS or normal MIPS. Otherwise if bit 0 of the address is set, then ELF file flags will tell if this is a MIPS16 or a microMIPS function. */ - sym = lookup_minimal_symbol_by_pc (memaddr); + sym = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr)); if (sym.minsym) { if (msymbol_is_micromips (sym.minsym)) @@ -1210,6 +1254,67 @@ mips_pc_isa (struct gdbarch *gdbarch, CORE_ADDR memaddr) } } +/* Set the ISA bit correctly in the PC, used by DWARF-2 machinery. + The need for comes from the ISA bit having been cleared, making + addresses in FDE, range records, etc. referring to compressed code + different to those in line information, the symbol table and finally + the PC register. That in turn confuses many operations. */ + +static CORE_ADDR +mips_adjust_dwarf2_addr (CORE_ADDR pc) +{ + pc = unmake_compact_addr (pc); + return mips_pc_is_mips (pc) ? pc : make_compact_addr (pc); +} + +/* Recalculate the line record requested so that the resulting PC has + the ISA bit set correctly, used by DWARF-2 machinery. The need for + this adjustment comes from some records associated with compressed + code having the ISA bit cleared, most notably at function prologue + ends. The ISA bit is in this context retrieved from the minimal + symbol covering the address requested, which in turn has been + constructed from the binary's symbol table rather than DWARF-2 + information. The correct setting of the ISA bit is required for + breakpoint addresses to correctly match against the stop PC. + + As line entries can specify relative address adjustments we need to + keep track of the absolute value of the last line address recorded + in line information, so that we can calculate the actual address to + apply the ISA bit adjustment to. We use PC for this tracking and + keep the original address there. + + As such relative address adjustments can be odd within compressed + code we need to keep track of the last line address with the ISA + bit adjustment applied too, as the original address may or may not + have had the ISA bit set. We use ADJ_PC for this tracking and keep + the adjusted address there. + + For relative address adjustments we then use these variables to + calculate the address intended by line information, which will be + PC-relative, and return an updated adjustment carrying ISA bit + information, which will be ADJ_PC-relative. For absolute address + adjustments we just return the same address that we store in ADJ_PC + too. + + As the first line entry can be relative to an implied address value + of 0 we need to have the initial address set up that we store in PC + and ADJ_PC. This is arranged with a call from `dwarf_decode_lines_1' + that sets PC to 0 and ADJ_PC accordingly, usually 0 as well. */ + +static CORE_ADDR +mips_adjust_dwarf2_line (CORE_ADDR addr, int rel) +{ + static CORE_ADDR adj_pc; + static CORE_ADDR pc; + CORE_ADDR isa_pc; + + pc = rel ? pc + addr : addr; + isa_pc = mips_adjust_dwarf2_addr (pc); + addr = rel ? isa_pc - adj_pc : isa_pc; + adj_pc = isa_pc; + return addr; +} + /* Various MIPS16 thunk (aka stub or trampoline) names. */ static const char mips_str_mips16_call_stub[] = "__mips16_call_stub_"; @@ -1259,8 +1364,6 @@ mips_read_pc (struct regcache *regcache) LONGEST pc; regcache_cooked_read_signed (regcache, regnum, &pc); - if (is_compact_addr (pc)) - pc = unmake_compact_addr (pc); return pc; } @@ -1270,8 +1373,6 @@ mips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) CORE_ADDR pc; pc = frame_unwind_register_signed (next_frame, gdbarch_pc_regnum (gdbarch)); - if (is_compact_addr (pc)) - pc = unmake_compact_addr (pc); /* macro/2012-04-20: This hack skips over MIPS16 call thunks as intermediate frames. In this case we can get the caller's address from $ra, or if $ra contains an address within a thunk as well, then @@ -1281,15 +1382,9 @@ mips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { pc = frame_unwind_register_signed (next_frame, gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM); - if (is_compact_addr (pc)) - pc = unmake_compact_addr (pc); if (mips_in_frame_stub (pc)) - { - pc = frame_unwind_register_signed - (next_frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM); - if (is_compact_addr (pc)) - pc = unmake_compact_addr (pc); - } + pc = frame_unwind_register_signed + (next_frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM); } return pc; } @@ -1323,10 +1418,7 @@ mips_write_pc (struct regcache *regcache, CORE_ADDR pc) { int regnum = gdbarch_pc_regnum (get_regcache_arch (regcache)); - if (mips_pc_is_mips (pc)) - regcache_cooked_write_unsigned (regcache, regnum, pc); - else - regcache_cooked_write_unsigned (regcache, regnum, make_compact_addr (pc)); + regcache_cooked_write_unsigned (regcache, regnum, pc); } /* Fetch and return instruction from the specified location. Handle @@ -3765,9 +3857,6 @@ mips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - if (is_compact_addr (addr)) - addr = unmake_compact_addr (addr); - if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL)) /* This hack is a work-around for existing boards using PMON, the simulator, and any other 64-bit targets that doesn't have true @@ -4466,25 +4555,9 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, "mips_eabi_push_dummy_call: %d len=%d type=%d", argnum + 1, len, (int) typecode); - /* Function pointer arguments to mips16 code need to be made into - mips16 pointers. */ - if (typecode == TYPE_CODE_PTR - && TYPE_CODE (TYPE_TARGET_TYPE (arg_type)) == TYPE_CODE_FUNC) - { - CORE_ADDR addr = extract_signed_integer (value_contents (arg), - len, byte_order); - if (mips_pc_is_mips (addr)) - val = value_contents (arg); - else - { - store_signed_integer (valbuf, len, byte_order, - make_compact_addr (addr)); - val = valbuf; - } - } /* The EABI passes structures that do not fit in a register by reference. */ - else if (len > regsize + if (len > regsize && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) { store_unsigned_integer (valbuf, regsize, byte_order, @@ -5849,7 +5922,6 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, for (argnum = 0; argnum < nargs; argnum++) { const gdb_byte *val; - gdb_byte valbuf[MAX_REGISTER_SIZE]; struct value *arg = args[argnum]; struct type *arg_type = check_typedef (value_type (arg)); int len = TYPE_LENGTH (arg_type); @@ -5862,21 +5934,6 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, val = value_contents (arg); - /* Function pointer arguments to mips16 code need to be made into - mips16 pointers. */ - if (typecode == TYPE_CODE_PTR - && TYPE_CODE (TYPE_TARGET_TYPE (arg_type)) == TYPE_CODE_FUNC) - { - CORE_ADDR addr = extract_signed_integer (value_contents (arg), - len, byte_order); - if (!mips_pc_is_mips (addr)) - { - store_signed_integer (valbuf, len, byte_order, - make_compact_addr (addr)); - val = valbuf; - } - } - /* Floating point arguments passed in registers have to be treated specially. On 32-bit architectures, doubles are passed in register pairs; the even FP register gets the @@ -7833,27 +7890,15 @@ mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) new_pc = mips_skip_mips16_trampoline_code (frame, pc); if (new_pc) - { - pc = new_pc; - if (is_compact_addr (pc)) - pc = unmake_compact_addr (pc); - } + pc = new_pc; new_pc = find_solib_trampoline_target (frame, pc); if (new_pc) - { - pc = new_pc; - if (is_compact_addr (pc)) - pc = unmake_compact_addr (pc); - } + pc = new_pc; new_pc = mips_skip_pic_trampoline_code (frame, pc); if (new_pc) - { - pc = new_pc; - if (is_compact_addr (pc)) - pc = unmake_compact_addr (pc); - } + pc = new_pc; } while (pc != target_pc); @@ -8509,6 +8554,9 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_elf_make_msymbol_special (gdbarch, mips_elf_make_msymbol_special); + set_gdbarch_make_symbol_special (gdbarch, mips_make_symbol_special); + set_gdbarch_adjust_dwarf2_addr (gdbarch, mips_adjust_dwarf2_addr); + set_gdbarch_adjust_dwarf2_line (gdbarch, mips_adjust_dwarf2_line); regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct mips_regnum); *regnum = mips_regnum; diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h index ba299528ed..b42f2d66df 100644 --- a/gdb/mips-tdep.h +++ b/gdb/mips-tdep.h @@ -155,6 +155,9 @@ enum /* Single step based on where the current instruction will take us. */ extern int mips_software_single_step (struct frame_info *frame); +/* Strip the ISA (compression) bit off from ADDR. */ +extern CORE_ADDR mips_unmake_compact_addr (CORE_ADDR addr); + /* Tell if the program counter value in MEMADDR is in a standard MIPS function. */ extern int mips_pc_is_mips (bfd_vma memaddr); diff --git a/gdb/solib.c b/gdb/solib.c index ce9dc05f9a..4b4386ccf2 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1443,8 +1443,28 @@ gdb_bfd_lookup_symbol_from_symtab (bfd *abfd, if (match_sym (sym, data)) { + struct gdbarch *gdbarch = target_gdbarch (); + symaddr = sym->value; + + /* Some ELF targets fiddle with addresses of symbols they + consider special. They use minimal symbols to do that + and this is needed for correct breakpoint placement, + but we do not have full data here to build a complete + minimal symbol, so just set the address and let the + targets cope with that. */ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && gdbarch_elf_make_msymbol_special_p (gdbarch)) + { + struct minimal_symbol msym; + + memset (&msym, 0, sizeof (msym)); + SET_MSYMBOL_VALUE_ADDRESS (&msym, symaddr); + gdbarch_elf_make_msymbol_special (gdbarch, sym, &msym); + symaddr = MSYMBOL_VALUE_RAW_ADDRESS (&msym); + } + /* BFD symbols are section relative. */ - symaddr = sym->value + sym->section->vma; + symaddr += sym->section->vma; break; } } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 5ce30296a7..6e17360842 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-12-12 Maciej W. Rozycki + + * gdb.base/func-ptrs.c: New file. + * gdb.base/func-ptrs.exp: New file. + 2014-12-10 Simon Marchi PR breakpoints/17012 diff --git a/gdb/testsuite/gdb.base/func-ptrs.c b/gdb/testsuite/gdb.base/func-ptrs.c new file mode 100644 index 0000000000..ce36074c62 --- /dev/null +++ b/gdb/testsuite/gdb.base/func-ptrs.c @@ -0,0 +1,50 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +void +sentinel (void) +{ + return; +} + +int +incr (int i) +{ + sentinel (); + return i + 1; +} + +int +decr (int i) +{ + sentinel (); + return i - 1; +} + +int (*calc) (int) = incr; + +int +main (void) +{ + int i = -1; + + i = calc (i); + i = calc (i); + i = calc (i); + + return i; +} diff --git a/gdb/testsuite/gdb.base/func-ptrs.exp b/gdb/testsuite/gdb.base/func-ptrs.exp new file mode 100644 index 0000000000..c26eb9df5c --- /dev/null +++ b/gdb/testsuite/gdb.base/func-ptrs.exp @@ -0,0 +1,95 @@ +# Copyright 2014 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set testname func-ptrs +set srcfile ${testname}.c +if { [prepare_for_testing ${testname}.exp ${testname} ${srcfile}] } { + return -1 +} + +if { ![runto_main] } { + untested ${testname}.exp + return -1 +} + + +# First set our breakpoints. + +set fp_breakpoint_re \ + "Breakpoint $decimal at $hex: file .*${srcfile}, line $decimal\\." +gdb_test "break sentinel if calc == decr" \ + "${fp_breakpoint_re}" \ + "breakpoint at sentinel" +gdb_test "break incr" \ + "${fp_breakpoint_re}" \ + "breakpoint at incr" +gdb_test "break decr" \ + "${fp_breakpoint_re}" \ + "breakpoint at decr" + + +# Check if we run through to the breakpoint in incr. + +gdb_test "continue" \ + "Breakpoint $decimal, incr \\(i=-1\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*" \ + "continue to incr, first time" + + +# Go back up, make sure the return value is 0. + +gdb_test "finish" \ + "Run till exit from #0 +incr \\(i=-1\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+($hex in )?main \\(\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*Value returned is \\$$decimal = 0" \ + "go back to main from incr, first time" + + +# Redirect calc and see if we run to the breakpoint in decr instead. + +gdb_test_no_output "set calc = decr" "set calc to decr" +gdb_test "continue" \ + "Breakpoint $decimal, decr \\(i=0\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*" \ + "continue to decr" + + +# Go back up, check if we stop in sentinel instead. + +gdb_test "finish" \ + "Run till exit from #0 +decr \\(i=0\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+Breakpoint $decimal, sentinel \\(\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*" \ + "stop in sentinel" + + +# Go back all the way up to main, make sure the return value is -1. + +gdb_test_no_output "up-silently" "move up to decr" +gdb_test "finish" \ + "Run till exit from #1 +($hex in )?decr \\(i=0\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+($hex in )?main \\(\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*Value returned is \\$$decimal = -1" \ + "go back to main from decr" + + +# Reset calc and see if we run to the breakpoint in incr again. + +gdb_test_no_output "set calc = incr" "set calc to incr" +gdb_test "continue" \ + "Breakpoint $decimal, incr \\(i=-1\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*" \ + "continue to incr, second time" + + +# Go back up again, make sure the return value is 0. + +gdb_test "finish" \ + "Run till exit from #0 +incr \\(i=-1\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+($hex in )?main \\(\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*Value returned is \\$$decimal = 0" \ + "go back to main from incr, second time" + + +# All done!