Files
binutils-gdb/binutils/rddbg.c
Alan Modra 19cacf6729 Use bfd_alloc memory for read_debugging_info storage
Trying to free malloc'd memory used by the stabs and coff debug info
parsers is complicated, and traversing the trees generated requires a
lot of code.  It's better to bfd_alloc the memory which allows it all
to be freed without fuss when the bfd is closed.  In the process of
doing this I reverted most of commit a633691333.

Some of the stabs handling code grows arrays of pointers with realloc,
to deal with arbitrary numbers of fields, function args, etc.  The
code still does that but copies over to bfd_alloc memory when
finished.  The alternative is to parse twice, once to size, then again
to populate the arrays.  I think that complication is unwarranted.

Note that there is a greater than zero chance this patch breaks
something, eg. that I missed an attempt to free obj_alloc memory.
Also it seems there are no tests in the binutils testsuite aimed at
exercising objdump --debugging.

	* budbg.h (finish_stab, parse_stab): Update prototypes
	* debug.c: Include bucomm.h.
	(struct debug_handle): Add "abfd" field.
	(debug_init): Add "abfd" param.  bfd_alloc handle.
	(debug_xalloc, debug_xzalloc): New functions.  Use throughout
	in place of xmalloc and memset.
	(debug_start_source): Remove "name_used" param.
	* debug.h (debug_init, debug_start_source): Update prototypes.
	(debug_xalloc, debug_xzalloc): Declare.
	* objcopy.c (copy_object): Don't free dhandle.
	* objdump.c (dump_bfd): Likewise.
	* rdcoff.c (coff_get_slot): Add dhandle arg.  debug_xzalloc
	memory in place of xcalloc.  Update callers.
	(parse_coff_struct_type): Don't leak on error return.  Copy
	fields over to debug_xalloc memory.
	(parse_coff_enum_type): Copy names and vals over the
	debug_xalloc memory.
	* rddbg.c (read_debugging_info): Adjust debug_init call.
	Don't free dhandle.
	(read_section_stabs_debugging_info): Don't free shandle.
	Adjust parse_stab call.  Call finish_stab on error return.
	(read_symbol_stabs_debugging_info): Similarly.
	* stabs.c (savestring): Delete unnecessary forward declaration.
	Add dhandle param.  debug_xalloc memory.  Update callers.
	(start_stab): Delete unnecessary casts.
	(finish_stab): Add "emit" param.  Free file_types, so_string,
	and stabs handle.
	(parse_stab): Delete string_used param.  Revert code dealing
	with string_used.  Copy so_string passed to debug_set_filename
	and stored as main_filename to debug_xalloc memory.  Similarly
	for string passed to debug_start_source and push_bincl.  Copy
	args to debug_xalloc memory.  Don't leak args.
	(parse_stab_enum_type): Copy names and values to debug_xalloc
	memory.  Don't free name.
	(parse_stab_struct_type): Don't free fields.
	(parse_stab_baseclasses): Delete unnecessary cast.
	(parse_stab_struct_fields): Return debug_xalloc fields.
	(parse_stab_cpp_abbrev): Use debug_xalloc for _vb$ type name.
	(parse_stab_one_struct_field): Don't free name.
	(parse_stab_members): Copy variants and methods to
	debug_xalloc memory.  Don't free name or argtypes.
	(parse_stab_argtypes): Use debug_xalloc memory for physname
	and args.
	(push_bincl): Add dhandle param.  Use debug_xalloc memory.
	(stab_record_variable): Use debug_xalloc memory.
	(stab_emit_pending_vars): Don't free var list.
	(stab_find_slot): Add dhandle param.  Use debug_xzalloc
	memory.  Update all callers.
	(stab_find_tagged_type): Don't free name.  Use debug_xzalloc.
	(stab_demangle_qualified): Don't free name.
	(stab_demangle_template): Don't free s1.
	(stab_demangle_args): Tidy pvarargs refs.  Copy *pargs on
	success to debug_xalloc memory, free on failure.
	(stab_demangle_fund_type): Don't free name.
	(stab_demangle_v3_arglist): Copy args to debug_xalloc memory.
	Don't free dt.
2023-04-04 12:47:56 +09:30

432 lines
9.9 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* rddbg.c -- Read debugging information into a generic form.
Copyright (C) 1995-2023 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
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, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* This file reads debugging information into a generic form. This
file knows how to dig the debugging information out of an object
file. */
#include "sysdep.h"
#include "bfd.h"
#include "libiberty.h"
#include "bucomm.h"
#include "debug.h"
#include "budbg.h"
static bool read_section_stabs_debugging_info
(bfd *, asymbol **, long, void *, bool *);
static bool read_symbol_stabs_debugging_info
(bfd *, asymbol **, long, void *, bool *);
static void save_stab (int, int, bfd_vma, const char *);
static void stab_context (void);
static void free_saved_stabs (void);
/* Read debugging information from a BFD. Returns a generic debugging
pointer. */
void *
read_debugging_info (bfd *abfd, asymbol **syms, long symcount,
bool no_messages)
{
void *dhandle;
bool found;
dhandle = debug_init (abfd);
if (dhandle == NULL)
return NULL;
if (! read_section_stabs_debugging_info (abfd, syms, symcount, dhandle,
&found))
goto err_exit;
if (bfd_get_flavour (abfd) == bfd_target_aout_flavour)
{
if (! read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle,
&found))
goto err_exit;
}
/* Try reading the COFF symbols if we didn't find any stabs in COFF
sections. */
if (! found
&& bfd_get_flavour (abfd) == bfd_target_coff_flavour
&& symcount > 0)
{
if (! parse_coff (abfd, syms, symcount, dhandle))
goto err_exit;
found = true;
}
if (! found)
{
if (! no_messages)
non_fatal (_("%s: no recognized debugging information"),
bfd_get_filename (abfd));
err_exit:
return NULL;
}
return dhandle;
}
/* Read stabs in sections debugging information from a BFD. */
static bool
read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
void *dhandle, bool *pfound)
{
static struct
{
const char *secname;
const char *strsecname;
}
names[] =
{
{ ".stab", ".stabstr" },
{ "LC_SYMTAB.stabs", "LC_SYMTAB.stabstr" },
{ "$GDB_SYMBOLS$", "$GDB_STRINGS$" }
};
unsigned int i;
void *shandle;
bool ret = false;
*pfound = false;
shandle = NULL;
for (i = 0; i < sizeof names / sizeof names[0]; i++)
{
asection *sec, *strsec;
sec = bfd_get_section_by_name (abfd, names[i].secname);
strsec = bfd_get_section_by_name (abfd, names[i].strsecname);
if (sec != NULL
&& (bfd_section_flags (sec) & SEC_HAS_CONTENTS) != 0
&& bfd_section_size (sec) >= 12
&& strsec != NULL
&& (bfd_section_flags (strsec) & SEC_HAS_CONTENTS) != 0)
{
bfd_size_type stabsize, strsize;
bfd_byte *stabs, *strings;
bfd_byte *stab;
bfd_size_type stroff, next_stroff;
if (!bfd_malloc_and_get_section (abfd, sec, &stabs))
{
fprintf (stderr, "%s: %s: %s\n",
bfd_get_filename (abfd), names[i].secname,
bfd_errmsg (bfd_get_error ()));
goto out;
}
if (!bfd_malloc_and_get_section (abfd, strsec, &strings))
{
fprintf (stderr, "%s: %s: %s\n",
bfd_get_filename (abfd), names[i].strsecname,
bfd_errmsg (bfd_get_error ()));
free (stabs);
goto out;
}
/* Zero terminate the strings table, just in case. */
strsize = bfd_section_size (strsec);
if (strsize != 0)
strings [strsize - 1] = 0;
if (shandle == NULL)
{
shandle = start_stab (dhandle, abfd, true, syms, symcount);
if (shandle == NULL)
{
free (strings);
free (stabs);
goto out;
}
}
*pfound = true;
stroff = 0;
next_stroff = 0;
stabsize = bfd_section_size (sec);
/* PR 17512: file: 078-60391-0.001:0.1. */
for (stab = stabs; stab <= (stabs + stabsize) - 12; stab += 12)
{
unsigned int strx;
int type;
int other ATTRIBUTE_UNUSED;
int desc;
bfd_vma value;
/* This code presumes 32 bit values. */
strx = bfd_get_32 (abfd, stab);
type = bfd_get_8 (abfd, stab + 4);
other = bfd_get_8 (abfd, stab + 5);
desc = bfd_get_16 (abfd, stab + 6);
value = bfd_get_32 (abfd, stab + 8);
if (type == 0)
{
/* Special type 0 stabs indicate the offset to the
next string table. */
stroff = next_stroff;
next_stroff += value;
}
else
{
size_t len;
char *f, *s;
if (stroff + strx >= strsize)
{
fprintf (stderr, _("%s: %s: stab entry %ld is corrupt, strx = 0x%x, type = %d\n"),
bfd_get_filename (abfd), names[i].secname,
(long) (stab - stabs) / 12, strx, type);
continue;
}
s = (char *) strings + stroff + strx;
f = NULL;
/* PR 17512: file: 002-87578-0.001:0.1.
It is possible to craft a file where, without the 'strlen (s) > 0',
an attempt to read the byte before 'strings' would occur. */
while ((len = strlen (s)) > 0
&& s[len - 1] == '\\'
&& stab + 16 <= stabs + stabsize)
{
char *p;
stab += 12;
p = s + len - 1;
*p = '\0';
strx = stroff + bfd_get_32 (abfd, stab);
if (strx >= strsize)
{
fprintf (stderr, _("%s: %s: stab entry %ld is corrupt\n"),
bfd_get_filename (abfd), names[i].secname,
(long) (stab - stabs) / 12);
break;
}
s = concat (s, (char *) strings + strx,
(const char *) NULL);
/* We have to restore the backslash, because, if
the linker is hashing stabs strings, we may
see the same string more than once. */
*p = '\\';
free (f);
f = s;
}
save_stab (type, desc, value, s);
if (!parse_stab (dhandle, shandle, type, desc, value, s))
{
stab_context ();
free_saved_stabs ();
free (f);
free (stabs);
free (strings);
goto out;
}
free (f);
}
}
free_saved_stabs ();
free (stabs);
free (strings);
}
}
ret = true;
out:
if (shandle != NULL)
{
if (! finish_stab (dhandle, shandle, ret))
return false;
}
return ret;
}
/* Read stabs in the symbol table. */
static bool
read_symbol_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
void *dhandle, bool *pfound)
{
void *shandle;
asymbol **ps, **symend;
shandle = NULL;
symend = syms + symcount;
for (ps = syms; ps < symend; ps++)
{
symbol_info i;
bfd_get_symbol_info (abfd, *ps, &i);
if (i.type == '-')
{
const char *s;
char *f;
if (shandle == NULL)
{
shandle = start_stab (dhandle, abfd, false, syms, symcount);
if (shandle == NULL)
return false;
}
*pfound = true;
s = i.name;
if (s == NULL || strlen (s) < 1)
break;
f = NULL;
while (strlen (s) > 0
&& s[strlen (s) - 1] == '\\'
&& ps + 1 < symend)
{
char *sc, *n;
++ps;
sc = xstrdup (s);
sc[strlen (sc) - 1] = '\0';
n = concat (sc, bfd_asymbol_name (*ps), (const char *) NULL);
free (sc);
free (f);
f = n;
s = n;
}
save_stab (i.stab_type, i.stab_desc, i.value, s);
if (!parse_stab (dhandle, shandle, i.stab_type, i.stab_desc,
i.value, s))
{
stab_context ();
free (f);
break;
}
free (f);
}
}
bool ret = ps >= symend;
free_saved_stabs ();
if (shandle != NULL)
{
if (! finish_stab (dhandle, shandle, ret))
return false;
}
return ret;
}
/* Record stabs strings, so that we can give some context for errors. */
#define SAVE_STABS_COUNT (16)
struct saved_stab
{
int type;
int desc;
bfd_vma value;
char *string;
};
static struct saved_stab saved_stabs[SAVE_STABS_COUNT];
static int saved_stabs_index;
/* Save a stabs string. */
static void
save_stab (int type, int desc, bfd_vma value, const char *string)
{
free (saved_stabs[saved_stabs_index].string);
saved_stabs[saved_stabs_index].type = type;
saved_stabs[saved_stabs_index].desc = desc;
saved_stabs[saved_stabs_index].value = value;
saved_stabs[saved_stabs_index].string = xstrdup (string);
saved_stabs_index = (saved_stabs_index + 1) % SAVE_STABS_COUNT;
}
/* Provide context for an error. */
static void
stab_context (void)
{
int i;
fprintf (stderr, _("Last stabs entries before error:\n"));
fprintf (stderr, "n_type n_desc n_value string\n");
i = saved_stabs_index;
do
{
struct saved_stab *stabp;
stabp = saved_stabs + i;
if (stabp->string != NULL)
{
const char *s;
s = bfd_get_stab_name (stabp->type);
if (s != NULL)
fprintf (stderr, "%-6s", s);
else if (stabp->type == 0)
fprintf (stderr, "HdrSym");
else
fprintf (stderr, "%-6d", stabp->type);
fprintf (stderr, " %-6d ", stabp->desc);
fprintf (stderr, "%08" PRIx64, (uint64_t) stabp->value);
if (stabp->type != 0)
fprintf (stderr, " %s", stabp->string);
fprintf (stderr, "\n");
}
i = (i + 1) % SAVE_STABS_COUNT;
}
while (i != saved_stabs_index);
}
/* Free the saved stab strings. */
static void
free_saved_stabs (void)
{
int i;
for (i = 0; i < SAVE_STABS_COUNT; i++)
{
free (saved_stabs[i].string);
saved_stabs[i].string = NULL;
}
saved_stabs_index = 0;
}