mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-25 21:41:47 +08:00
* elf32-spu.c (insert_callee): Reorder call list so most recent
call is always first. (interesting_section): Move. (mark_functions_via_relocs): Fold interesting_section and reloc_count tests in callers to here. Simplify output section owner test. (discover_functions): Set "gaps" when no symbols and some "interesting_section". Run pasted_function loop for no symbol bfds. (for_each_node, transfer_calls): New functions. (mark_non_root): Adjust to suit for_each_node. (call_graph_traverse): Likewise. Fix memory leak. Rename to.. (remove_cycles): ..this. (build_call_tree): Use for_each_node and transfer_calls. (struct _sum_stack_param): New. (sum_stack): Adjust to suit for_each_node. Return error on malloc failure. Move code to print root node cumulative stack from.. (spu_elf_stack_analysis): ..here. Use for_each_node.
This commit is contained in:
@ -1,3 +1,24 @@
|
|||||||
|
2008-04-02 Alan Modra <amodra@bigpond.net.au>
|
||||||
|
|
||||||
|
* elf32-spu.c (insert_callee): Reorder call list so most recent
|
||||||
|
call is always first.
|
||||||
|
(interesting_section): Move.
|
||||||
|
(mark_functions_via_relocs): Fold interesting_section and
|
||||||
|
reloc_count tests in callers to here. Simplify output section
|
||||||
|
owner test.
|
||||||
|
(discover_functions): Set "gaps" when no symbols and some
|
||||||
|
"interesting_section". Run pasted_function loop for no symbol
|
||||||
|
bfds.
|
||||||
|
(for_each_node, transfer_calls): New functions.
|
||||||
|
(mark_non_root): Adjust to suit for_each_node.
|
||||||
|
(call_graph_traverse): Likewise. Fix memory leak. Rename to..
|
||||||
|
(remove_cycles): ..this.
|
||||||
|
(build_call_tree): Use for_each_node and transfer_calls.
|
||||||
|
(struct _sum_stack_param): New.
|
||||||
|
(sum_stack): Adjust to suit for_each_node. Return error on
|
||||||
|
malloc failure. Move code to print root node cumulative stack from..
|
||||||
|
(spu_elf_stack_analysis): ..here. Use for_each_node.
|
||||||
|
|
||||||
2008-03-31 Cary Coutant <ccoutant@google.com>
|
2008-03-31 Cary Coutant <ccoutant@google.com>
|
||||||
|
|
||||||
PR 6006
|
PR 6006
|
||||||
|
352
bfd/elf32-spu.c
352
bfd/elf32-spu.c
@ -1923,8 +1923,9 @@ find_function (asection *sec, bfd_vma offset, struct bfd_link_info *info)
|
|||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
insert_callee (struct function_info *caller, struct call_info *callee)
|
insert_callee (struct function_info *caller, struct call_info *callee)
|
||||||
{
|
{
|
||||||
struct call_info *p;
|
struct call_info **pp, *p;
|
||||||
for (p = caller->call_list; p != NULL; p = p->next)
|
|
||||||
|
for (pp = &caller->call_list; (p = *pp) != NULL; pp = &p->next)
|
||||||
if (p->fun == callee->fun)
|
if (p->fun == callee->fun)
|
||||||
{
|
{
|
||||||
/* Tail calls use less stack than normal calls. Retain entry
|
/* Tail calls use less stack than normal calls. Retain entry
|
||||||
@ -1935,6 +1936,10 @@ insert_callee (struct function_info *caller, struct call_info *callee)
|
|||||||
p->fun->start = NULL;
|
p->fun->start = NULL;
|
||||||
p->fun->is_func = TRUE;
|
p->fun->is_func = TRUE;
|
||||||
}
|
}
|
||||||
|
/* Reorder list so most recent call is first. */
|
||||||
|
*pp = p->next;
|
||||||
|
p->next = caller->call_list;
|
||||||
|
caller->call_list = p;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
callee->next = caller->call_list;
|
callee->next = caller->call_list;
|
||||||
@ -1942,6 +1947,19 @@ insert_callee (struct function_info *caller, struct call_info *callee)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We're only interested in code sections. Testing SEC_IN_MEMORY excludes
|
||||||
|
overlay stub sections. */
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
interesting_section (asection *s, bfd *obfd)
|
||||||
|
{
|
||||||
|
return (s->output_section != NULL
|
||||||
|
&& s->output_section->owner == obfd
|
||||||
|
&& ((s->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_IN_MEMORY))
|
||||||
|
== (SEC_ALLOC | SEC_LOAD | SEC_CODE))
|
||||||
|
&& s->size != 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Rummage through the relocs for SEC, looking for function calls.
|
/* Rummage through the relocs for SEC, looking for function calls.
|
||||||
If CALL_TREE is true, fill in call graph. If CALL_TREE is false,
|
If CALL_TREE is true, fill in call graph. If CALL_TREE is false,
|
||||||
mark destination symbols on calls as being functions. Also
|
mark destination symbols on calls as being functions. Also
|
||||||
@ -1959,6 +1977,10 @@ mark_functions_via_relocs (asection *sec,
|
|||||||
void *psyms;
|
void *psyms;
|
||||||
static bfd_boolean warned;
|
static bfd_boolean warned;
|
||||||
|
|
||||||
|
if (!interesting_section (sec, info->output_bfd)
|
||||||
|
|| sec->reloc_count == 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
internal_relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
|
internal_relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL,
|
||||||
info->keep_memory);
|
info->keep_memory);
|
||||||
if (internal_relocs == NULL)
|
if (internal_relocs == NULL)
|
||||||
@ -1993,7 +2015,7 @@ mark_functions_via_relocs (asection *sec,
|
|||||||
|
|
||||||
if (sym_sec == NULL
|
if (sym_sec == NULL
|
||||||
|| sym_sec->output_section == NULL
|
|| sym_sec->output_section == NULL
|
||||||
|| sym_sec->output_section->owner != sec->output_section->owner)
|
|| sym_sec->output_section->owner != info->output_bfd)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!bfd_get_section_contents (sec->owner, sec, insn,
|
if (!bfd_get_section_contents (sec->owner, sec, insn,
|
||||||
@ -2144,19 +2166,6 @@ pasted_function (asection *sec, struct bfd_link_info *info)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're only interested in code sections. Testing SEC_IN_MEMORY excludes
|
|
||||||
overlay stub sections. */
|
|
||||||
|
|
||||||
static bfd_boolean
|
|
||||||
interesting_section (asection *s, bfd *obfd)
|
|
||||||
{
|
|
||||||
return (s->output_section != NULL
|
|
||||||
&& s->output_section->owner == obfd
|
|
||||||
&& ((s->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_IN_MEMORY))
|
|
||||||
== (SEC_ALLOC | SEC_LOAD | SEC_CODE))
|
|
||||||
&& s->size != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map address ranges in code sections to functions. */
|
/* Map address ranges in code sections to functions. */
|
||||||
|
|
||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
@ -2198,7 +2207,16 @@ discover_functions (struct bfd_link_info *info)
|
|||||||
symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
|
symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
|
||||||
symcount = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
|
symcount = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
|
||||||
if (symcount == 0)
|
if (symcount == 0)
|
||||||
|
{
|
||||||
|
if (!gaps)
|
||||||
|
for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next)
|
||||||
|
if (interesting_section (sec, info->output_bfd))
|
||||||
|
{
|
||||||
|
gaps = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
syms = (Elf_Internal_Sym *) symtab_hdr->contents;
|
syms = (Elf_Internal_Sym *) symtab_hdr->contents;
|
||||||
if (syms == NULL)
|
if (syms == NULL)
|
||||||
@ -2286,13 +2304,9 @@ discover_functions (struct bfd_link_info *info)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
||||||
if (interesting_section (sec, info->output_bfd)
|
|
||||||
&& sec->reloc_count != 0)
|
|
||||||
{
|
|
||||||
if (!mark_functions_via_relocs (sec, info, FALSE))
|
if (!mark_functions_via_relocs (sec, info, FALSE))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (ibfd = info->input_bfds, bfd_idx = 0;
|
for (ibfd = info->input_bfds, bfd_idx = 0;
|
||||||
ibfd != NULL;
|
ibfd != NULL;
|
||||||
@ -2333,6 +2347,15 @@ discover_functions (struct bfd_link_info *info)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
||||||
|
{
|
||||||
|
extern const bfd_target bfd_elf32_spu_vec;
|
||||||
|
asection *sec;
|
||||||
|
|
||||||
|
if (ibfd->xvec != &bfd_elf32_spu_vec)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Some of the symbols we've installed as marking the
|
/* Some of the symbols we've installed as marking the
|
||||||
beginning of functions may have a size of zero. Extend
|
beginning of functions may have a size of zero. Extend
|
||||||
@ -2382,26 +2405,100 @@ discover_functions (struct bfd_link_info *info)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Iterate over all function_info we have collected, calling DOIT on
|
||||||
|
each node if ROOT_ONLY is false. Only call DOIT on root nodes
|
||||||
|
if ROOT_ONLY. */
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
for_each_node (bfd_boolean (*doit) (struct function_info *,
|
||||||
|
struct bfd_link_info *,
|
||||||
|
void *),
|
||||||
|
struct bfd_link_info *info,
|
||||||
|
void *param,
|
||||||
|
int root_only)
|
||||||
|
{
|
||||||
|
bfd *ibfd;
|
||||||
|
|
||||||
|
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
||||||
|
{
|
||||||
|
extern const bfd_target bfd_elf32_spu_vec;
|
||||||
|
asection *sec;
|
||||||
|
|
||||||
|
if (ibfd->xvec != &bfd_elf32_spu_vec)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
||||||
|
{
|
||||||
|
struct _spu_elf_section_data *sec_data;
|
||||||
|
struct spu_elf_stack_info *sinfo;
|
||||||
|
|
||||||
|
if ((sec_data = spu_elf_section_data (sec)) != NULL
|
||||||
|
&& (sinfo = sec_data->u.i.stack_info) != NULL)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < sinfo->num_fun; ++i)
|
||||||
|
if (!root_only || !sinfo->fun[i].non_root)
|
||||||
|
if (!doit (&sinfo->fun[i], info, param))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer call info attached to struct function_info entries for
|
||||||
|
all of a given function's sections to the first entry. */
|
||||||
|
|
||||||
|
static bfd_boolean
|
||||||
|
transfer_calls (struct function_info *fun,
|
||||||
|
struct bfd_link_info *info ATTRIBUTE_UNUSED,
|
||||||
|
void *param ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
struct function_info *start = fun->start;
|
||||||
|
|
||||||
|
if (start != NULL)
|
||||||
|
{
|
||||||
|
struct call_info *call, *call_next;
|
||||||
|
|
||||||
|
while (start->start != NULL)
|
||||||
|
start = start->start;
|
||||||
|
for (call = fun->call_list; call != NULL; call = call_next)
|
||||||
|
{
|
||||||
|
call_next = call->next;
|
||||||
|
if (!insert_callee (start, call))
|
||||||
|
free (call);
|
||||||
|
}
|
||||||
|
fun->call_list = NULL;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mark nodes in the call graph that are called by some other node. */
|
/* Mark nodes in the call graph that are called by some other node. */
|
||||||
|
|
||||||
static void
|
static bfd_boolean
|
||||||
mark_non_root (struct function_info *fun)
|
mark_non_root (struct function_info *fun,
|
||||||
|
struct bfd_link_info *info ATTRIBUTE_UNUSED,
|
||||||
|
void *param ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
struct call_info *call;
|
struct call_info *call;
|
||||||
|
|
||||||
|
if (fun->visit1)
|
||||||
|
return TRUE;
|
||||||
fun->visit1 = TRUE;
|
fun->visit1 = TRUE;
|
||||||
for (call = fun->call_list; call; call = call->next)
|
for (call = fun->call_list; call; call = call->next)
|
||||||
{
|
{
|
||||||
call->fun->non_root = TRUE;
|
call->fun->non_root = TRUE;
|
||||||
if (!call->fun->visit1)
|
mark_non_root (call->fun, 0, 0);
|
||||||
mark_non_root (call->fun);
|
|
||||||
}
|
}
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove cycles from the call graph. */
|
/* Remove cycles from the call graph. */
|
||||||
|
|
||||||
static void
|
static bfd_boolean
|
||||||
call_graph_traverse (struct function_info *fun, struct bfd_link_info *info)
|
remove_cycles (struct function_info *fun,
|
||||||
|
struct bfd_link_info *info,
|
||||||
|
void *param ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
struct call_info **callp, *call;
|
struct call_info **callp, *call;
|
||||||
|
|
||||||
@ -2412,7 +2509,10 @@ call_graph_traverse (struct function_info *fun, struct bfd_link_info *info)
|
|||||||
while ((call = *callp) != NULL)
|
while ((call = *callp) != NULL)
|
||||||
{
|
{
|
||||||
if (!call->fun->visit2)
|
if (!call->fun->visit2)
|
||||||
call_graph_traverse (call->fun, info);
|
{
|
||||||
|
if (!remove_cycles (call->fun, info, 0))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
else if (call->fun->marking)
|
else if (call->fun->marking)
|
||||||
{
|
{
|
||||||
const char *f1 = func_name (fun);
|
const char *f1 = func_name (fun);
|
||||||
@ -2422,11 +2522,13 @@ call_graph_traverse (struct function_info *fun, struct bfd_link_info *info)
|
|||||||
"from %s to %s\n"),
|
"from %s to %s\n"),
|
||||||
f1, f2);
|
f1, f2);
|
||||||
*callp = call->next;
|
*callp = call->next;
|
||||||
|
free (call);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
callp = &call->next;
|
callp = &call->next;
|
||||||
}
|
}
|
||||||
fun->marking = FALSE;
|
fun->marking = FALSE;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Populate call_list for each function. */
|
/* Populate call_list for each function. */
|
||||||
@ -2445,140 +2547,81 @@ build_call_tree (struct bfd_link_info *info)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
||||||
{
|
|
||||||
if (!interesting_section (sec, info->output_bfd)
|
|
||||||
|| sec->reloc_count == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!mark_functions_via_relocs (sec, info, TRUE))
|
if (!mark_functions_via_relocs (sec, info, TRUE))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transfer call info from hot/cold section part of function
|
/* Transfer call info from hot/cold section part of function
|
||||||
to main entry. */
|
to main entry. */
|
||||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
if (!for_each_node (transfer_calls, info, 0, FALSE))
|
||||||
{
|
return FALSE;
|
||||||
struct _spu_elf_section_data *sec_data;
|
|
||||||
struct spu_elf_stack_info *sinfo;
|
|
||||||
|
|
||||||
if ((sec_data = spu_elf_section_data (sec)) != NULL
|
|
||||||
&& (sinfo = sec_data->u.i.stack_info) != NULL)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < sinfo->num_fun; ++i)
|
|
||||||
{
|
|
||||||
struct function_info *start = sinfo->fun[i].start;
|
|
||||||
|
|
||||||
if (start != NULL)
|
|
||||||
{
|
|
||||||
struct call_info *call;
|
|
||||||
|
|
||||||
while (start->start != NULL)
|
|
||||||
start = start->start;
|
|
||||||
call = sinfo->fun[i].call_list;
|
|
||||||
while (call != NULL)
|
|
||||||
{
|
|
||||||
struct call_info *call_next = call->next;
|
|
||||||
if (!insert_callee (start, call))
|
|
||||||
free (call);
|
|
||||||
call = call_next;
|
|
||||||
}
|
|
||||||
sinfo->fun[i].call_list = NULL;
|
|
||||||
sinfo->fun[i].non_root = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the call graph root(s). */
|
/* Find the call graph root(s). */
|
||||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
if (!for_each_node (mark_non_root, info, 0, FALSE))
|
||||||
{
|
return FALSE;
|
||||||
extern const bfd_target bfd_elf32_spu_vec;
|
|
||||||
asection *sec;
|
|
||||||
|
|
||||||
if (ibfd->xvec != &bfd_elf32_spu_vec)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
|
||||||
{
|
|
||||||
struct _spu_elf_section_data *sec_data;
|
|
||||||
struct spu_elf_stack_info *sinfo;
|
|
||||||
|
|
||||||
if ((sec_data = spu_elf_section_data (sec)) != NULL
|
|
||||||
&& (sinfo = sec_data->u.i.stack_info) != NULL)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < sinfo->num_fun; ++i)
|
|
||||||
if (!sinfo->fun[i].visit1)
|
|
||||||
mark_non_root (&sinfo->fun[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove cycles from the call graph. We start from the root node(s)
|
/* Remove cycles from the call graph. We start from the root node(s)
|
||||||
so that we break cycles in a reasonable place. */
|
so that we break cycles in a reasonable place. */
|
||||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
return for_each_node (remove_cycles, info, 0, TRUE);
|
||||||
{
|
|
||||||
extern const bfd_target bfd_elf32_spu_vec;
|
|
||||||
asection *sec;
|
|
||||||
|
|
||||||
if (ibfd->xvec != &bfd_elf32_spu_vec)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
|
||||||
{
|
|
||||||
struct _spu_elf_section_data *sec_data;
|
|
||||||
struct spu_elf_stack_info *sinfo;
|
|
||||||
|
|
||||||
if ((sec_data = spu_elf_section_data (sec)) != NULL
|
|
||||||
&& (sinfo = sec_data->u.i.stack_info) != NULL)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < sinfo->num_fun; ++i)
|
|
||||||
if (!sinfo->fun[i].non_root)
|
|
||||||
call_graph_traverse (&sinfo->fun[i], info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct _sum_stack_param {
|
||||||
|
size_t cum_stack;
|
||||||
|
size_t overall_stack;
|
||||||
|
bfd_boolean emit_stack_syms;
|
||||||
|
};
|
||||||
|
|
||||||
/* Descend the call graph for FUN, accumulating total stack required. */
|
/* Descend the call graph for FUN, accumulating total stack required. */
|
||||||
|
|
||||||
static bfd_vma
|
static bfd_boolean
|
||||||
sum_stack (struct function_info *fun,
|
sum_stack (struct function_info *fun,
|
||||||
struct bfd_link_info *info,
|
struct bfd_link_info *info,
|
||||||
int emit_stack_syms)
|
void *param)
|
||||||
{
|
{
|
||||||
struct call_info *call;
|
struct call_info *call;
|
||||||
struct function_info *max = NULL;
|
struct function_info *max;
|
||||||
bfd_vma max_stack = fun->stack;
|
size_t stack, cum_stack;
|
||||||
bfd_vma stack;
|
|
||||||
const char *f1;
|
const char *f1;
|
||||||
|
struct _sum_stack_param *sum_stack_param = param;
|
||||||
|
|
||||||
|
cum_stack = fun->stack;
|
||||||
|
sum_stack_param->cum_stack = cum_stack;
|
||||||
if (fun->visit3)
|
if (fun->visit3)
|
||||||
return max_stack;
|
return TRUE;
|
||||||
|
|
||||||
|
max = NULL;
|
||||||
for (call = fun->call_list; call; call = call->next)
|
for (call = fun->call_list; call; call = call->next)
|
||||||
{
|
{
|
||||||
stack = sum_stack (call->fun, info, emit_stack_syms);
|
if (!sum_stack (call->fun, info, sum_stack_param))
|
||||||
|
return FALSE;
|
||||||
|
stack = sum_stack_param->cum_stack;
|
||||||
/* Include caller stack for normal calls, don't do so for
|
/* Include caller stack for normal calls, don't do so for
|
||||||
tail calls. fun->stack here is local stack usage for
|
tail calls. fun->stack here is local stack usage for
|
||||||
this function. */
|
this function. */
|
||||||
if (!call->is_tail)
|
if (!call->is_tail)
|
||||||
stack += fun->stack;
|
stack += fun->stack;
|
||||||
if (max_stack < stack)
|
if (cum_stack < stack)
|
||||||
{
|
{
|
||||||
max_stack = stack;
|
cum_stack = stack;
|
||||||
max = call->fun;
|
max = call->fun;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sum_stack_param->cum_stack = cum_stack;
|
||||||
|
stack = fun->stack;
|
||||||
|
/* Now fun->stack holds cumulative stack. */
|
||||||
|
fun->stack = cum_stack;
|
||||||
|
fun->visit3 = TRUE;
|
||||||
|
|
||||||
|
if (!fun->non_root
|
||||||
|
&& sum_stack_param->overall_stack < cum_stack)
|
||||||
|
sum_stack_param->overall_stack = cum_stack;
|
||||||
|
|
||||||
f1 = func_name (fun);
|
f1 = func_name (fun);
|
||||||
|
if (!fun->non_root)
|
||||||
|
info->callbacks->info (_(" %s: 0x%v\n"), f1, (bfd_vma) cum_stack);
|
||||||
info->callbacks->minfo (_("%s: 0x%v 0x%v\n"),
|
info->callbacks->minfo (_("%s: 0x%v 0x%v\n"),
|
||||||
f1, (bfd_vma) fun->stack, max_stack);
|
f1, (bfd_vma) stack, (bfd_vma) cum_stack);
|
||||||
|
|
||||||
if (fun->call_list)
|
if (fun->call_list)
|
||||||
{
|
{
|
||||||
@ -2593,18 +2636,15 @@ sum_stack (struct function_info *fun,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now fun->stack holds cumulative stack. */
|
if (sum_stack_param->emit_stack_syms)
|
||||||
fun->stack = max_stack;
|
|
||||||
fun->visit3 = TRUE;
|
|
||||||
|
|
||||||
if (emit_stack_syms)
|
|
||||||
{
|
{
|
||||||
struct spu_link_hash_table *htab = spu_hash_table (info);
|
struct spu_link_hash_table *htab = spu_hash_table (info);
|
||||||
char *name = bfd_malloc (18 + strlen (f1));
|
char *name = bfd_malloc (18 + strlen (f1));
|
||||||
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
||||||
|
|
||||||
if (name != NULL)
|
if (name == NULL)
|
||||||
{
|
return FALSE;
|
||||||
|
|
||||||
if (fun->global || ELF_ST_BIND (fun->u.sym->st_info) == STB_GLOBAL)
|
if (fun->global || ELF_ST_BIND (fun->u.sym->st_info) == STB_GLOBAL)
|
||||||
sprintf (name, "__stack_%s", f1);
|
sprintf (name, "__stack_%s", f1);
|
||||||
else
|
else
|
||||||
@ -2619,7 +2659,7 @@ sum_stack (struct function_info *fun,
|
|||||||
{
|
{
|
||||||
h->root.type = bfd_link_hash_defined;
|
h->root.type = bfd_link_hash_defined;
|
||||||
h->root.u.def.section = bfd_abs_section_ptr;
|
h->root.u.def.section = bfd_abs_section_ptr;
|
||||||
h->root.u.def.value = max_stack;
|
h->root.u.def.value = cum_stack;
|
||||||
h->size = 0;
|
h->size = 0;
|
||||||
h->type = 0;
|
h->type = 0;
|
||||||
h->ref_regular = 1;
|
h->ref_regular = 1;
|
||||||
@ -2629,9 +2669,8 @@ sum_stack (struct function_info *fun,
|
|||||||
h->non_elf = 0;
|
h->non_elf = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return max_stack;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Provide an estimate of total stack required. */
|
/* Provide an estimate of total stack required. */
|
||||||
@ -2639,8 +2678,7 @@ sum_stack (struct function_info *fun,
|
|||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
spu_elf_stack_analysis (struct bfd_link_info *info, int emit_stack_syms)
|
spu_elf_stack_analysis (struct bfd_link_info *info, int emit_stack_syms)
|
||||||
{
|
{
|
||||||
bfd *ibfd;
|
struct _sum_stack_param sum_stack_param;
|
||||||
bfd_vma max_stack = 0;
|
|
||||||
|
|
||||||
if (!discover_functions (info))
|
if (!discover_functions (info))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -2651,44 +2689,14 @@ spu_elf_stack_analysis (struct bfd_link_info *info, int emit_stack_syms)
|
|||||||
info->callbacks->info (_("Stack size for call graph root nodes.\n"));
|
info->callbacks->info (_("Stack size for call graph root nodes.\n"));
|
||||||
info->callbacks->minfo (_("\nStack size for functions. "
|
info->callbacks->minfo (_("\nStack size for functions. "
|
||||||
"Annotations: '*' max stack, 't' tail call\n"));
|
"Annotations: '*' max stack, 't' tail call\n"));
|
||||||
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
|
|
||||||
{
|
|
||||||
extern const bfd_target bfd_elf32_spu_vec;
|
|
||||||
asection *sec;
|
|
||||||
|
|
||||||
if (ibfd->xvec != &bfd_elf32_spu_vec)
|
sum_stack_param.emit_stack_syms = emit_stack_syms;
|
||||||
continue;
|
sum_stack_param.overall_stack = 0;
|
||||||
|
if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
|
info->callbacks->info (_("Maximum stack required is 0x%v\n"),
|
||||||
{
|
(bfd_vma) sum_stack_param.overall_stack);
|
||||||
struct _spu_elf_section_data *sec_data;
|
|
||||||
struct spu_elf_stack_info *sinfo;
|
|
||||||
|
|
||||||
if ((sec_data = spu_elf_section_data (sec)) != NULL
|
|
||||||
&& (sinfo = sec_data->u.i.stack_info) != NULL)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < sinfo->num_fun; ++i)
|
|
||||||
{
|
|
||||||
if (!sinfo->fun[i].non_root)
|
|
||||||
{
|
|
||||||
bfd_vma stack;
|
|
||||||
const char *f1;
|
|
||||||
|
|
||||||
stack = sum_stack (&sinfo->fun[i], info,
|
|
||||||
emit_stack_syms);
|
|
||||||
f1 = func_name (&sinfo->fun[i]);
|
|
||||||
info->callbacks->info (_(" %s: 0x%v\n"),
|
|
||||||
f1, stack);
|
|
||||||
if (max_stack < stack)
|
|
||||||
max_stack = stack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info->callbacks->info (_("Maximum stack required is 0x%v\n"), max_stack);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user