diff options
author | Daniel Jacobowitz <dan@debian.org> | 2002-06-13 19:16:25 +0000 |
---|---|---|
committer | Daniel Jacobowitz <dan@debian.org> | 2002-06-13 19:16:25 +0000 |
commit | eeb9f70d2d9b67b7369932670aea6e701551ca40 (patch) | |
tree | 07645ad8b9a04c8eb746869b76e1f0299b7779b9 /gdb/mips-tdep.c | |
parent | b9412fd5fdc0e089aee4560841023c6c651d1d93 (diff) | |
download | gdb-eeb9f70d2d9b67b7369932670aea6e701551ca40.tar.gz |
2002-06-13 Daniel Jacobowitz <drow@mvista.com>
* mips-tdep.c (PROC_SYMBOL): Add warning comment.
(struct mips_objfile_private, compare_pdr_entries): New.
(non_heuristic_proc_desc): Read the ".pdr" section if it
is present.
Diffstat (limited to 'gdb/mips-tdep.c')
-rw-r--r-- | gdb/mips-tdep.c | 168 |
1 files changed, 158 insertions, 10 deletions
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 0c42caf618c..d7f6d855ea0 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -381,6 +381,8 @@ static unsigned int heuristic_fence_post = 0; #define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset) #define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset) #define PROC_PC_REG(proc) ((proc)->pdr.pcreg) +/* FIXME drow/2002-06-10: If a pointer on the host is bigger than a long, + this will corrupt pdr.iline. Fortunately we don't use it. */ #define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym) #define _PROC_MAGIC_ 0x0F0F0F0F #define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_) @@ -1888,6 +1890,30 @@ heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc, return &temp_proc_desc; } +struct mips_objfile_private +{ + bfd_size_type size; + char *contents; +}; + +/* Global used to communicate between non_heuristic_proc_desc and + compare_pdr_entries within qsort (). */ +static bfd *the_bfd; + +static int +compare_pdr_entries (const void *a, const void *b) +{ + CORE_ADDR lhs = bfd_get_32 (the_bfd, (bfd_byte *) a); + CORE_ADDR rhs = bfd_get_32 (the_bfd, (bfd_byte *) b); + + if (lhs < rhs) + return -1; + else if (lhs == rhs) + return 0; + else + return 1; +} + static mips_extra_func_info_t non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr) { @@ -1895,23 +1921,145 @@ non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr) mips_extra_func_info_t proc_desc; struct block *b = block_for_pc (pc); struct symbol *sym; + struct obj_section *sec; + struct mips_objfile_private *priv; + + if (PC_IN_CALL_DUMMY (pc, 0, 0)) + return NULL; find_pc_partial_function (pc, NULL, &startaddr, NULL); if (addrptr) *addrptr = startaddr; - if (b == NULL || PC_IN_CALL_DUMMY (pc, 0, 0)) - sym = NULL; - else + + priv = NULL; + + sec = find_pc_section (pc); + if (sec != NULL) { - if (startaddr > BLOCK_START (b)) - /* This is the "pathological" case referred to in a comment in - print_frame_info. It might be better to move this check into - symbol reading. */ - sym = NULL; - else - sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL); + priv = (struct mips_objfile_private *) sec->objfile->obj_private; + + /* Search the ".pdr" section generated by GAS. This includes most of + the information normally found in ECOFF PDRs. */ + + the_bfd = sec->objfile->obfd; + if (priv == NULL + && (the_bfd->format == bfd_object + && bfd_get_flavour (the_bfd) == bfd_target_elf_flavour + && elf_elfheader (the_bfd)->e_ident[EI_CLASS] == ELFCLASS64)) + { + /* Right now GAS only outputs the address as a four-byte sequence. + This means that we should not bother with this method on 64-bit + targets (until that is fixed). */ + + priv = obstack_alloc (& sec->objfile->psymbol_obstack, + sizeof (struct mips_objfile_private)); + priv->size = 0; + sec->objfile->obj_private = priv; + } + else if (priv == NULL) + { + asection *bfdsec; + + priv = obstack_alloc (& sec->objfile->psymbol_obstack, + sizeof (struct mips_objfile_private)); + + bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr"); + if (bfdsec != NULL) + { + priv->size = bfd_section_size (sec->objfile->obfd, bfdsec); + priv->contents = obstack_alloc (& sec->objfile->psymbol_obstack, + priv->size); + bfd_get_section_contents (sec->objfile->obfd, bfdsec, + priv->contents, 0, priv->size); + + /* In general, the .pdr section is sorted. However, in the + presence of multiple code sections (and other corner cases) + it can become unsorted. Sort it so that we can use a faster + binary search. */ + qsort (priv->contents, priv->size / 32, 32, compare_pdr_entries); + } + else + priv->size = 0; + + sec->objfile->obj_private = priv; + } + the_bfd = NULL; + + if (priv->size != 0) + { + int low, mid, high; + char *ptr; + + low = 0; + high = priv->size / 32; + + do + { + CORE_ADDR pdr_pc; + + mid = (low + high) / 2; + + ptr = priv->contents + mid * 32; + pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr); + pdr_pc += ANOFFSET (sec->objfile->section_offsets, + SECT_OFF_TEXT (sec->objfile)); + if (pdr_pc == startaddr) + break; + if (pdr_pc > startaddr) + high = mid; + else + low = mid + 1; + } + while (low != high); + + if (low != high) + { + struct symbol *sym = find_pc_function (pc); + + /* Fill in what we need of the proc_desc. */ + proc_desc = (mips_extra_func_info_t) + obstack_alloc (&sec->objfile->psymbol_obstack, + sizeof (struct mips_extra_func_info)); + PROC_LOW_ADDR (proc_desc) = startaddr; + + /* Only used for dummy frames. */ + PROC_HIGH_ADDR (proc_desc) = 0; + + PROC_FRAME_OFFSET (proc_desc) + = bfd_get_32 (sec->objfile->obfd, ptr + 20); + PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd, + ptr + 24); + PROC_FRAME_ADJUST (proc_desc) = 0; + PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd, + ptr + 4); + PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd, + ptr + 12); + PROC_REG_OFFSET (proc_desc) = bfd_get_32 (sec->objfile->obfd, + ptr + 8); + PROC_FREG_OFFSET (proc_desc) + = bfd_get_32 (sec->objfile->obfd, ptr + 16); + PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd, + ptr + 28); + proc_desc->pdr.isym = (long) sym; + + return proc_desc; + } + } } + if (b == NULL) + return NULL; + + if (startaddr > BLOCK_START (b)) + { + /* This is the "pathological" case referred to in a comment in + print_frame_info. It might be better to move this check into + symbol reading. */ + return NULL; + } + + sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL); + /* If we never found a PDR for this function in symbol reading, then examine prologues to find the information. */ if (sym) |