xcoff.c (struct xcoff_line, [...]): Remove.

* xcoff.c (struct xcoff_line, struct xcoff_line_vector): Remove.
	(struct xcoff_func, struct xcoff_func_vector): New structs.
	(xcoff_syminfo): Drop leading dot from symbol name.
	(xcoff_line_compare, xcoff_line_search): Remove.
	(xcoff_func_compare, xcoff_func_search): New static functions.
	(xcoff_lookup_pc): Search function table.
	(xcoff_add_line, xcoff_process_linenos): Remove.
	(xcoff_initialize_fileline): Build function table.

From-SVN: r263238
This commit is contained in:
Tony Reix 2018-08-01 21:55:05 +00:00 committed by Ian Lance Taylor
parent 701d080a4b
commit ca9a1314ec
2 changed files with 212 additions and 232 deletions

View file

@ -1,3 +1,14 @@
2018-08-01 Tony Reix <tony.reix@atos.net>
* xcoff.c (struct xcoff_line, struct xcoff_line_vector): Remove.
(struct xcoff_func, struct xcoff_func_vector): New structs.
(xcoff_syminfo): Drop leading dot from symbol name.
(xcoff_line_compare, xcoff_line_search): Remove.
(xcoff_func_compare, xcoff_func_search): New static functions.
(xcoff_lookup_pc): Search function table.
(xcoff_add_line, xcoff_process_linenos): Remove.
(xcoff_initialize_fileline): Build function table.
2018-06-21 Denis Khalikov <d.khalikov@partner.samsung.com> 2018-06-21 Denis Khalikov <d.khalikov@partner.samsung.com>
PR other/86198 PR other/86198

View file

@ -338,27 +338,32 @@ struct xcoff_incl_vector
size_t count; size_t count;
}; };
/* Map a single PC value to a file/function/line. */ /* A growable vector of functions information. */
struct xcoff_line struct xcoff_func
{ {
/* PC. */ /* PC. */
uintptr_t pc; uintptr_t pc;
/* File name. Many entries in the array are expected to point to /* The size of the function. */
the same file name. */ size_t size;
const char *filename;
/* Function name. */ /* Function name. */
const char *function; const char *name;
/* Line number. */ /* File name. */
int lineno; const char *filename;
/* Pointer to first lnno entry. */
uintptr_t lnnoptr;
/* Base address of containing section. */
uintptr_t sect_base;
/* Starting source line number. */
int lnno;
}; };
/* A growable vector of line number information. This is used while /* A growable vector of function information. This is used while
reading the line numbers. */ reading the function symbols. */
struct xcoff_line_vector struct xcoff_func_vector
{ {
/* Memory. This is an array of struct xcoff_line. */ /* Memory. This is an array of struct xcoff_func. */
struct backtrace_vector vec; struct backtrace_vector vec;
/* Number of valid mappings. */ /* Number of valid mappings. */
size_t count; size_t count;
@ -370,8 +375,16 @@ struct xcoff_fileline_data
{ {
/* The data for the next file we know about. */ /* The data for the next file we know about. */
struct xcoff_fileline_data *next; struct xcoff_fileline_data *next;
/* Line number information. */ /* Functions information. */
struct xcoff_line_vector vec; struct xcoff_func_vector func_vec;
/* Include files information. */
struct xcoff_incl_vector incl_vec;
/* Line numbers information. */
const unsigned char *linenos;
size_t linenos_size;
uint64_t lnnoptr0;
/* Loader address. */
uintptr_t base_address;
}; };
/* An index of DWARF sections we care about. */ /* An index of DWARF sections we care about. */
@ -509,6 +522,7 @@ xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
{ {
struct xcoff_syminfo_data *edata; struct xcoff_syminfo_data *edata;
struct xcoff_symbol *sym = NULL; struct xcoff_symbol *sym = NULL;
const char *name;
if (!state->threaded) if (!state->threaded)
{ {
@ -547,7 +561,13 @@ xcoff_syminfo (struct backtrace_state *state ATTRIBUTE_UNUSED, uintptr_t addr,
if (sym == NULL) if (sym == NULL)
callback (data, addr, NULL, 0, 0); callback (data, addr, NULL, 0, 0);
else else
callback (data, addr, sym->name, sym->address, sym->size); {
name = sym->name;
/* AIX prepends a '.' to function entry points, remove it. */
if (name && *name == '.')
++name;
callback (data, addr, name, sym->address, sym->size);
}
} }
/* Return the name of an XCOFF symbol. */ /* Return the name of an XCOFF symbol. */
@ -640,43 +660,76 @@ xcoff_initialize_syminfo (struct backtrace_state *state,
return 1; return 1;
} }
/* Compare struct xcoff_line for qsort. */ /* Compare struct xcoff_func for qsort. */
static int static int
xcoff_line_compare (const void *v1, const void *v2) xcoff_func_compare (const void *v1, const void *v2)
{ {
const struct xcoff_line *ln1 = (const struct xcoff_line *) v1; const struct xcoff_func *fn1 = (const struct xcoff_func *) v1;
const struct xcoff_line *ln2 = (const struct xcoff_line *) v2; const struct xcoff_func *fn2 = (const struct xcoff_func *) v2;
if (ln1->pc < ln2->pc) if (fn1->pc < fn2->pc)
return -1; return -1;
else if (ln1->pc > ln2->pc) else if (fn1->pc > fn2->pc)
return 1; return 1;
else else
return 0; return 0;
} }
/* Find a PC in a line vector. We always allocate an extra entry at /* Compare a PC against an xcoff_func for bsearch. */
the end of the lines vector, so that this routine can safely look
at the next entry. */
static int static int
xcoff_line_search (const void *vkey, const void *ventry) xcoff_func_search (const void *vkey, const void *ventry)
{ {
const uintptr_t *key = (const uintptr_t *) vkey; const uintptr_t *key = (const uintptr_t *) vkey;
const struct xcoff_line *entry = (const struct xcoff_line *) ventry; const struct xcoff_func *entry = (const struct xcoff_func *) ventry;
uintptr_t pc; uintptr_t pc;
pc = *key; pc = *key;
if (pc < entry->pc) if (pc < entry->pc)
return -1; return -1;
else if ((entry + 1)->pc == (uintptr_t) -1 || pc >= (entry + 1)->pc) else if ((entry->size == 0 && pc > entry->pc)
|| (entry->size > 0 && pc >= entry->pc + entry->size))
return 1; return 1;
else else
return 0; return 0;
} }
/* Look for a PC in the line vector for one module. On success, /* Compare struct xcoff_incl for qsort. */
static int
xcoff_incl_compare (const void *v1, const void *v2)
{
const struct xcoff_incl *in1 = (const struct xcoff_incl *) v1;
const struct xcoff_incl *in2 = (const struct xcoff_incl *) v2;
if (in1->begin < in2->begin)
return -1;
else if (in1->begin > in2->begin)
return 1;
else
return 0;
}
/* Find a lnnoptr in an include file. */
static int
xcoff_incl_search (const void *vkey, const void *ventry)
{
const uintptr_t *key = (const uintptr_t *) vkey;
const struct xcoff_incl *entry = (const struct xcoff_incl *) ventry;
uintptr_t lnno;
lnno = *key;
if (lnno < entry->begin)
return -1;
else if (lnno > entry->end)
return 1;
else
return 0;
}
/* Look for a PC in the function vector for one module. On success,
call CALLBACK and return whatever it returns. On error, call call CALLBACK and return whatever it returns. On error, call
ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found, ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found,
0 if not. */ 0 if not. */
@ -688,26 +741,82 @@ xcoff_lookup_pc (struct backtrace_state *state ATTRIBUTE_UNUSED,
backtrace_error_callback error_callback ATTRIBUTE_UNUSED, backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
void *data, int *found) void *data, int *found)
{ {
const struct xcoff_line *ln; const struct xcoff_incl *incl, *bincl;
const struct xcoff_func *fn;
const b_xcoff_lineno *lineno;
const unsigned char *lineptr;
const char *function; const char *function;
const char *filename;
uintptr_t lnnoptr, match;
uint32_t lnno = 0;
*found = 1; *found = 1;
ln = (struct xcoff_line *) bsearch (&pc, fdata->vec.vec.base, if ((pc & 3) != 0)
fdata->vec.count, ++pc;
sizeof (struct xcoff_line),
xcoff_line_search); /* Find the function first. */
if (ln == NULL) fn = ((struct xcoff_func *)
bsearch (&pc, fdata->func_vec.vec.base, fdata->func_vec.count,
sizeof (struct xcoff_func), xcoff_func_search));
if (fn == NULL)
{ {
*found = 0; *found = 0;
return 0; return 0;
} }
function = ln->function; filename = fn->filename;
/* Find the line number next. */
/* Skip first entry that points to symtab. */
lnnoptr = fn->lnnoptr + LINESZ;
match = lnnoptr;
lineptr = fdata->linenos + (lnnoptr - fdata->lnnoptr0);
while (lineptr + LINESZ <= fdata->linenos + fdata->linenos_size)
{
lineno = (const b_xcoff_lineno *) lineptr;
if (lineno->l_lnno == 0)
break;
if (pc <= fdata->base_address + lineno->l_addr.l_paddr - fn->sect_base)
break;
match = lnnoptr;
lnno = lineno->l_lnno;
lnnoptr += LINESZ;
lineptr += LINESZ;
}
/* If part of a function other than the beginning comes from an
include file, the line numbers are absolute, rather than
relative to the beginning of the function. */
incl = ((struct xcoff_incl *)
bsearch (&match, fdata->incl_vec.vec.base,
fdata->incl_vec.count, sizeof (struct xcoff_incl),
xcoff_incl_search));
if (incl != NULL)
{
bincl = ((struct xcoff_incl *)
bsearch (&fn->lnnoptr, fdata->incl_vec.vec.base,
fdata->incl_vec.count, sizeof (struct xcoff_incl),
xcoff_incl_search));
if (bincl != NULL && strcmp (incl->filename, bincl->filename) == 0)
{
lnno += fn->lnno - 1;
}
filename = incl->filename;
}
else
{
lnno += fn->lnno - 1;
}
function = fn->name;
/* AIX prepends a '.' to function entry points, remove it. */ /* AIX prepends a '.' to function entry points, remove it. */
if (*function == '.') if (function != NULL && *function == '.')
++function; ++function;
return callback (data, pc, ln->filename, ln->lineno, function); return callback (data, pc, filename, lnno, function);
} }
/* Return the file/line information for a PC using the XCOFF lineno /* Return the file/line information for a PC using the XCOFF lineno
@ -760,146 +869,7 @@ xcoff_fileline (struct backtrace_state *state, uintptr_t pc,
return callback (data, pc, NULL, 0, NULL); return callback (data, pc, NULL, 0, NULL);
} }
/* Compare struct xcoff_incl for qsort. */ /* Initialize the function vector info for xcoff_fileline. */
static int
xcoff_incl_compare (const void *v1, const void *v2)
{
const struct xcoff_incl *in1 = (const struct xcoff_incl *) v1;
const struct xcoff_incl *in2 = (const struct xcoff_incl *) v2;
if (in1->begin < in2->begin)
return -1;
else if (in1->begin > in2->begin)
return 1;
else
return 0;
}
/* Find a lnnoptr in an include file. */
static int
xcoff_incl_search (const void *vkey, const void *ventry)
{
const uintptr_t *key = (const uintptr_t *) vkey;
const struct xcoff_incl *entry = (const struct xcoff_incl *) ventry;
uintptr_t lnno;
lnno = *key;
if (lnno < entry->begin)
return -1;
else if (lnno > entry->end)
return 1;
else
return 0;
}
/* Add a new mapping to the vector of line mappings that we are
building. Returns 1 on success, 0 on failure. */
static int
xcoff_add_line (struct backtrace_state *state, uintptr_t pc,
const char *filename, const char *function, uint32_t lnno,
backtrace_error_callback error_callback, void *data,
struct xcoff_line_vector *vec)
{
struct xcoff_line *ln;
ln = ((struct xcoff_line *)
backtrace_vector_grow (state, sizeof (struct xcoff_line),
error_callback, data, &vec->vec));
if (ln == NULL)
return 0;
ln->pc = pc;
ln->filename = filename;
ln->function = function;
ln->lineno = lnno;
++vec->count;
return 1;
}
/* Add the line number entries for a function to the line vector. */
static int
xcoff_process_linenos (struct backtrace_state *state, uintptr_t base_address,
const b_xcoff_syment *fsym, const char *filename,
const b_xcoff_scnhdr *sects,
const unsigned char *strtab, size_t strtab_size,
uint32_t fcn_lnno, struct xcoff_incl_vector *vec,
struct xcoff_line_vector *lvec,
const unsigned char *linenos, size_t linenos_size,
uintptr_t lnnoptr0,
backtrace_error_callback error_callback, void *data)
{
const b_xcoff_auxent *aux;
const b_xcoff_lineno *lineno;
const unsigned char *lineptr;
const char *function;
struct xcoff_incl *incl = NULL;
uintptr_t lnnoptr;
uintptr_t pc;
uint32_t lnno;
int begincl;
aux = (const b_xcoff_auxent *) (fsym + 1);
lnnoptr = aux->x_fcn.x_lnnoptr;
if (lnnoptr < lnnoptr0 || lnnoptr + LINESZ > lnnoptr0 + linenos_size)
return 0;
function = xcoff_symname (fsym, strtab, strtab_size);
if (function == NULL)
return 0;
/* Skip first entry that points to symtab. */
lnnoptr += LINESZ;
lineptr = linenos + (lnnoptr - lnnoptr0);
begincl = -1;
while (lineptr + LINESZ <= linenos + linenos_size)
{
lineno = (const b_xcoff_lineno *) lineptr;
lnno = lineno->l_lnno;
if (lnno == 0)
break;
/* If part of a function other than the beginning comes from an
include file, the line numbers are absolute, rather than
relative to the beginning of the function. */
incl = (struct xcoff_incl *) bsearch (&lnnoptr, vec->vec.base,
vec->count,
sizeof (struct xcoff_incl),
xcoff_incl_search);
if (begincl == -1)
begincl = incl != NULL;
if (incl != NULL)
{
filename = incl->filename;
if (begincl == 1)
lnno += fcn_lnno - 1;
}
else
lnno += fcn_lnno - 1;
pc = base_address + lineno->l_addr.l_paddr
- sects[fsym->n_scnum - 1].s_paddr;
xcoff_add_line (state, pc, filename, function, lnno, error_callback,
data, lvec);
lnnoptr += LINESZ;
lineptr += LINESZ;
}
return 1;
}
/* Initialize the line vector info for xcoff_fileline. */
static int static int
xcoff_initialize_fileline (struct backtrace_state *state, xcoff_initialize_fileline (struct backtrace_state *state,
@ -912,15 +882,15 @@ xcoff_initialize_fileline (struct backtrace_state *state,
backtrace_error_callback error_callback, void *data) backtrace_error_callback error_callback, void *data)
{ {
struct xcoff_fileline_data *fdata; struct xcoff_fileline_data *fdata;
struct xcoff_incl_vector vec; struct xcoff_func *fn;
struct xcoff_line *ln;
const b_xcoff_syment *fsym; const b_xcoff_syment *fsym;
const b_xcoff_auxent *aux; const b_xcoff_auxent *aux;
const char *filename; const char *filename;
const char *name; const char *name;
struct xcoff_incl *incl; struct xcoff_incl *incl;
uintptr_t begin, end; uintptr_t begin, end;
uintptr_t lnno; uintptr_t lnno, lnnoptr;
uint32_t fsize;
size_t i; size_t i;
fdata = ((struct xcoff_fileline_data *) fdata = ((struct xcoff_fileline_data *)
@ -928,13 +898,17 @@ xcoff_initialize_fileline (struct backtrace_state *state,
error_callback, data)); error_callback, data));
if (fdata == NULL) if (fdata == NULL)
return 0; return 0;
memset (fdata, 0, sizeof *fdata); memset (fdata, 0, sizeof *fdata);
memset (&vec, 0, sizeof vec); fdata->base_address = base_address;
fdata->linenos = linenos;
/* Process include files first. */ fdata->linenos_size = linenos_size;
fdata->lnnoptr0 = lnnoptr0;
begin = 0; begin = 0;
filename = NULL;
fsym = NULL;
lnnoptr = 0;
fsize = 0;
for (i = 0; i < nsyms; ++i) for (i = 0; i < nsyms; ++i)
{ {
const b_xcoff_syment *asym = &syms[i]; const b_xcoff_syment *asym = &syms[i];
@ -951,32 +925,18 @@ xcoff_initialize_fileline (struct backtrace_state *state,
end = asym->n_value; end = asym->n_value;
incl = ((struct xcoff_incl *) incl = ((struct xcoff_incl *)
backtrace_vector_grow (state, sizeof (struct xcoff_incl), backtrace_vector_grow (state, sizeof (struct xcoff_incl),
error_callback, data, &vec.vec)); error_callback, data,
&fdata->incl_vec.vec));
if (incl != NULL) if (incl != NULL)
{ {
incl->filename = xcoff_symname (asym, strtab, strtab_size); incl->filename = xcoff_symname (asym, strtab, strtab_size);
incl->begin = begin; incl->begin = begin;
incl->end = end; incl->end = end;
++vec.count; ++fdata->incl_vec.count;
} }
begin = 0; begin = 0;
break; break;
}
i += asym->n_numaux;
}
backtrace_qsort (vec.vec.base, vec.count,
sizeof (struct xcoff_incl), xcoff_incl_compare);
filename = NULL;
fsym = NULL;
for (i = 0; i < nsyms; ++i)
{
const b_xcoff_syment *asym = &syms[i];
switch (asym->n_sclass)
{
case C_FILE: case C_FILE:
filename = xcoff_symname (asym, strtab, strtab_size); filename = xcoff_symname (asym, strtab, strtab_size);
if (filename == NULL) if (filename == NULL)
@ -988,7 +948,7 @@ xcoff_initialize_fileline (struct backtrace_state *state,
file auxiliary entry (by convention) contains the source file auxiliary entry (by convention) contains the source
file name. */ file name. */
if (asym->n_numaux > 0 && !strcmp (filename, ".file")) if (asym->n_numaux > 0 && strcmp (filename, ".file") == 0)
{ {
aux = (const b_xcoff_auxent *) (asym + 1); aux = (const b_xcoff_auxent *) (asym + 1);
if (aux->x_file._x.x_zeroes != 0) if (aux->x_file._x.x_zeroes != 0)
@ -1010,10 +970,20 @@ xcoff_initialize_fileline (struct backtrace_state *state,
case C_HIDEXT: case C_HIDEXT:
case C_WEAKEXT: case C_WEAKEXT:
fsym = NULL; fsym = NULL;
if (!ISFCN (asym->n_type) || asym->n_numaux == 0) lnnoptr = 0;
fsize = 0;
if (!ISFCN (asym->n_type) || asym->n_numaux == 0
|| asym->n_scnum <= 0)
break; break;
if (filename == NULL) if (filename == NULL)
break; break;
aux = (const b_xcoff_auxent *) (asym + 1);
lnnoptr = aux->x_fcn.x_lnnoptr;
if (lnnoptr < lnnoptr0
|| lnnoptr + LINESZ > lnnoptr0 + linenos_size)
break;
/* x_fsize will be 0 if there is no debug information. */
fsize = aux->x_fcn.x_fsize;
fsym = asym; fsym = asym;
break; break;
@ -1023,8 +993,11 @@ xcoff_initialize_fileline (struct backtrace_state *state,
if (fsym == NULL) if (fsym == NULL)
break; break;
name = xcoff_symname (asym, strtab, strtab_size); name = xcoff_symname (asym, strtab, strtab_size);
if (name == NULL) if (name == NULL || strcmp (name, ".bf") != 0)
break; {
fsym = NULL;
break;
}
aux = (const b_xcoff_auxent *) (asym + 1); aux = (const b_xcoff_auxent *) (asym + 1);
#if BACKTRACE_XCOFF_SIZE == 32 #if BACKTRACE_XCOFF_SIZE == 32
lnno = (uint32_t) aux->x_block.x_lnnohi << 16 lnno = (uint32_t) aux->x_block.x_lnnohi << 16
@ -1032,39 +1005,37 @@ xcoff_initialize_fileline (struct backtrace_state *state,
#else #else
lnno = aux->x_block.x_lnno; lnno = aux->x_block.x_lnno;
#endif #endif
if (!strcmp (name, ".bf")) fn = ((struct xcoff_func *)
{ backtrace_vector_grow (state, sizeof (struct xcoff_func),
xcoff_process_linenos (state, base_address, fsym, filename, error_callback, data,
sects, strtab, strtab_size, lnno, &vec, &fdata->func_vec.vec));
&fdata->vec, linenos, linenos_size, if (fn == NULL)
lnnoptr0, error_callback, data); break;
} fn->name = xcoff_symname (fsym, strtab, strtab_size);
else if (!strcmp (name, ".ef")) fn->filename = filename;
{ fn->sect_base = sects[fsym->n_scnum - 1].s_paddr;
fsym = NULL; fn->pc = base_address + fsym->n_value - fn->sect_base;
} fn->size = fsize;
fn->lnno = lnno;
fn->lnnoptr = lnnoptr;
++fdata->func_vec.count;
break; break;
} }
i += asym->n_numaux; i += asym->n_numaux;
} }
/* Allocate one extra entry at the end. */ if (!backtrace_vector_release (state, &fdata->func_vec.vec, error_callback,
ln = ((struct xcoff_line *) data))
backtrace_vector_grow (state, sizeof (struct xcoff_line),
error_callback, data, &fdata->vec.vec));
if (ln == NULL)
goto fail; goto fail;
ln->pc = (uintptr_t) -1; backtrace_qsort (fdata->func_vec.vec.base, fdata->func_vec.count,
ln->filename = NULL; sizeof (struct xcoff_func), xcoff_func_compare);
ln->function = NULL;
ln->lineno = 0;
if (!backtrace_vector_release (state, &fdata->vec.vec, error_callback, data)) if (!backtrace_vector_release (state, &fdata->incl_vec.vec, error_callback,
data))
goto fail; goto fail;
backtrace_qsort (fdata->incl_vec.vec.base, fdata->incl_vec.count,
backtrace_qsort (fdata->vec.vec.base, fdata->vec.count, sizeof (struct xcoff_incl), xcoff_incl_compare);
sizeof (struct xcoff_line), xcoff_line_compare);
if (!state->threaded) if (!state->threaded)
{ {
@ -1354,6 +1325,7 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
{ {
size_t linenos_size = (size_t) nlnno * LINESZ; size_t linenos_size = (size_t) nlnno * LINESZ;
/* We never release this view. */
if (!backtrace_get_view (state, descriptor, offset + lnnoptr, if (!backtrace_get_view (state, descriptor, offset + lnnoptr,
linenos_size, linenos_size,
error_callback, data, &linenos_view)) error_callback, data, &linenos_view))
@ -1366,9 +1338,6 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
linenos_view.data, linenos_size, linenos_view.data, linenos_size,
lnnoptr, error_callback, data)) lnnoptr, error_callback, data))
*fileline_fn = xcoff_fileline; *fileline_fn = xcoff_fileline;
backtrace_release_view (state, &linenos_view, error_callback, data);
linenos_view_valid = 0;
} }
backtrace_release_view (state, &sects_view, error_callback, data); backtrace_release_view (state, &sects_view, error_callback, data);