#include "defs.h"
#include "symtab.h"
#include "frame.h"
#include "breakpoint.h"
#include "symfile.h"
#include "source.h"
#include "demangle.h"
#include "inferior.h"
#include "gdb_assert.h"
#include "frame-unwind.h"
#include "annotate.h"
#include "ui-out.h"
#include "inlining.h"
#include "objfiles.h"
#include "gdbthread.h"
extern int addressprint;
int stepping_into_inlined_subroutine = 0;
struct rb_tree_node_list
{
struct rb_tree_node *node;
struct rb_tree_node_list *next;
};
struct record_list
{
struct inlined_call_stack_record *record;
struct record_list *next;
};
struct pending_node {
struct linetable_entry *entry;
struct symtab *s;
struct pending_node *next;
};
struct inlined_function_data global_inlined_call_stack;
static struct inlined_function_data temp_frame_stack;
static struct inlined_function_data saved_call_stack;
static int call_stack_initialized = 0;
static void verify_stack (void);
static void find_function_names_and_address_ranges (struct objfile *,
struct inlined_call_stack_record *);
static void add_item_to_inlined_subroutine_stack (struct linetable_entry *,
struct symtab *,
struct bfd_section *);
static int find_correct_current_position (void);
int inlined_frame_sniffer (const struct frame_unwind *, struct frame_info *,
void **);
void inlined_frame_this_id (struct frame_info *, void **, struct frame_id *);
static void reset_temp_frame_stack (void);
static void insert_pending_node (struct pending_node *, struct pending_node **);
static CORE_ADDR
address_range_ending_pc (struct address_range_list *ranges)
{
struct symtab_and_line sal;
int j;
int max_line = 0;
int max_idx = 0;
if (!ranges)
return 0;
for (j = 0; j < ranges->nelts; j++)
{
sal = find_pc_line (ranges->ranges[j].endaddr, 0);
if (sal.line > max_line)
{
max_line = sal.line;
max_idx = j;
}
}
return ranges->ranges[max_idx].endaddr;
}
static CORE_ADDR
record_end_pc (struct inlined_call_stack_record record)
{
if (record.ranges)
return address_range_ending_pc (record.ranges);
else
return record.end_pc;
}
static int
record_ranges_contains_pc (int i, CORE_ADDR pc)
{
int retval;
int j;
if (i < 1 || i > global_inlined_call_stack.nelts)
return 0;
if (!global_inlined_call_stack.records[i].ranges)
return 0;
retval = 0;
for (j = 0; j < global_inlined_call_stack.records[i].ranges->nelts; j++)
if (global_inlined_call_stack.records[i].ranges->ranges[j].startaddr <= pc
&& global_inlined_call_stack.records[i].ranges->ranges[j].endaddr > pc)
retval = 1;
return retval;
}
static void
copy_temp_frame_stack_record (int from, int to)
{
gdb_assert (from < temp_frame_stack.max_array_size);
gdb_assert (to < temp_frame_stack.max_array_size);
gdb_assert (from > 0);
gdb_assert (to > 0);
temp_frame_stack.records[to].start_pc =
temp_frame_stack.records[from].start_pc;
temp_frame_stack.records[to].end_pc = temp_frame_stack.records[from].end_pc;
temp_frame_stack.records[to].ranges = temp_frame_stack.records[from].ranges;
temp_frame_stack.records[to].call_site_line =
temp_frame_stack.records[from].call_site_line;
temp_frame_stack.records[to].call_site_column =
temp_frame_stack.records[from].call_site_column;
temp_frame_stack.records[to].s = temp_frame_stack.records[from].s;
temp_frame_stack.records[to].fn_name =
temp_frame_stack.records[from].fn_name;
temp_frame_stack.records[to].calling_fn_name =
temp_frame_stack.records[from].calling_fn_name;
temp_frame_stack.records[to].call_site_filename =
temp_frame_stack.records[from].call_site_filename;
temp_frame_stack.records[to].stack_frame_created =
temp_frame_stack.records[from].stack_frame_created;
temp_frame_stack.records[to].stack_frame_printed =
temp_frame_stack.records[from].stack_frame_printed;
temp_frame_stack.records[to].stepped_into = 1;
memset (&(temp_frame_stack.records[from]), 0,
sizeof (struct inlined_call_stack_record));
}
static void
add_item_to_temp_frame_stack (struct linetable_entry *item,
struct symtab *s,
struct bfd_section *section)
{
int i;
int j;
int k;
int new_pos;
int nelts = temp_frame_stack.nelts;
int max_size = temp_frame_stack.max_array_size;
for (i = 1; i <= nelts; i++)
if (temp_frame_stack.records[i].start_pc == item->pc
&& temp_frame_stack.records[i].end_pc == item->end_pc
&& (item->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| temp_frame_stack.records[i].call_site_line == 0
|| temp_frame_stack.records[i].call_site_line == item->line))
break;
if (i > nelts)
{
if (nelts >= max_size - 1)
{
if (max_size == 0)
{
max_size = 10;
temp_frame_stack.records =
(struct inlined_call_stack_record *) xmalloc
(max_size * sizeof (struct inlined_call_stack_record));
memset (temp_frame_stack.records, 0,
max_size * sizeof (struct inlined_call_stack_record));
}
else
{
int old_size = max_size;
max_size = 2 * max_size;
temp_frame_stack.records = (struct inlined_call_stack_record *)
xrealloc (temp_frame_stack.records,
max_size * sizeof (struct inlined_call_stack_record));
for (j = old_size; j < max_size; j++)
memset (&(temp_frame_stack.records[j]), 0,
sizeof (struct inlined_call_stack_record));
}
}
temp_frame_stack.max_array_size = max_size;
new_pos = 0;
if (item->pc < temp_frame_stack.records[1].start_pc
|| (item->pc == temp_frame_stack.records[1].start_pc
&& item->end_pc > temp_frame_stack.records[1].end_pc))
new_pos = 1;
else
{
for (j = 1; j < nelts && !new_pos; j++)
{
k = j + 1;
if (temp_frame_stack.records[j].start_pc <= item->pc
&& item->pc <= temp_frame_stack.records[k].start_pc
&& temp_frame_stack.records[j].end_pc >= item->end_pc
&& item->end_pc >= temp_frame_stack.records[k].end_pc)
new_pos = k;
}
}
if (new_pos)
{
for (j = nelts; j >= new_pos; j--)
copy_temp_frame_stack_record (j, j + 1);
i = new_pos;
}
nelts++;
}
if (!s)
s = find_pc_symtab (item->pc);
gdb_assert (s != NULL);
if (item->entry_type == INLINED_SUBROUTINE_LT_ENTRY)
{
temp_frame_stack.records[i].start_pc = item->pc;
temp_frame_stack.records[i].end_pc = item->end_pc;
temp_frame_stack.records[i].s = s;
}
else if (item->entry_type == INLINED_CALL_SITE_LT_ENTRY)
{
temp_frame_stack.records[i].start_pc = item->pc;
temp_frame_stack.records[i].end_pc = item->end_pc;
temp_frame_stack.records[i].call_site_filename = s->filename;
temp_frame_stack.records[i].call_site_line = item->line;
temp_frame_stack.records[i].call_site_column = 0;
}
temp_frame_stack.records[i].stepped_into = 1;
find_function_names_and_address_ranges (s->objfile,
&(temp_frame_stack.records[i]));
temp_frame_stack.nelts = nelts;
}
static void
update_tmp_frame_stack (CORE_ADDR pc)
{
struct symtab *s;
struct symtab *orig_s;
struct symtab *alt_symtab = 0;
struct linetable *l;
int len;
struct linetable_entry *alt = NULL;
struct linetable_entry *item;
struct linetable_entry *prev;
struct blockvector *bv;
asection *section_tmp;
struct bfd_section *section;
int i;
struct linetable_entry *best = NULL;
CORE_ADDR best_end = 0;
struct symtab *best_symtab = 0;
struct pending_node *pending_list;
struct pending_node *temp;
struct pending_node *cur_pend;
if (!dwarf2_allow_inlined_stepping
|| temp_frame_stack.last_pc == pc)
return;
reset_temp_frame_stack ();
section_tmp = find_pc_overlay (pc);
if (pc_in_unmapped_range (pc, section_tmp))
pc = overlay_mapped_address (pc, section_tmp);
section = (struct bfd_section *) section_tmp;
s = find_pc_sect_symtab (pc, section);
orig_s = s;
if (s)
{
bv = BLOCKVECTOR (s);
for ( ; s && BLOCKVECTOR (s) == bv; s = s->next)
{
l = LINETABLE (s);
if (!l)
continue;
len = l->nitems;
if (len <= 0)
continue;
pending_list = NULL;
prev = NULL;
item = l->item;
if (item->pc > pc && (!alt || item->pc < alt->pc))
{
alt = item;
alt_symtab = s;
}
for (i = 0; i < len; i++, item++)
{
if ((item->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| item->entry_type == INLINED_CALL_SITE_LT_ENTRY)
&& item->pc <= pc
&& item->end_pc > pc)
{
temp = (struct pending_node *)
xmalloc (sizeof (struct pending_node));
temp->entry = item;
temp->s = s;
temp->next = NULL;
insert_pending_node (temp, &pending_list);
}
if (item->pc > pc
|| (item->pc == pc
&& prev
&& item->pc == prev->pc))
break;
prev = item;
}
if (prev && prev->line && (!best || prev->pc > best->pc))
{
best = prev;
best_symtab = s;
if (best_end <= best->pc)
best_end = 0;
}
if (best_symtab
&& best->line != 0
&& prev
&& prev->pc == item->pc)
{
while (prev->pc == item->pc)
{
prev = item;
item++;
if ((item->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| item->entry_type == INLINED_CALL_SITE_LT_ENTRY)
&& item->pc <= pc
&& item->end_pc > pc)
{
temp = (struct pending_node *)
xmalloc (sizeof (struct pending_node));
temp->entry = item;
temp->s = s;
temp->next = NULL;
insert_pending_node (temp, &pending_list);
}
}
best = prev;
}
for (cur_pend = pending_list; cur_pend; cur_pend = cur_pend->next)
add_item_to_temp_frame_stack (cur_pend->entry, cur_pend->s,
section);
}
}
temp_frame_stack.current_pos = temp_frame_stack.nelts;
if (temp_frame_stack.nelts > 0)
temp_frame_stack.last_inlined_pc = pc;
temp_frame_stack.last_pc = pc;
}
static int
tmp_frame_record_ranges_contains_pc (int i, CORE_ADDR cur_pc)
{
int retval;
int j;
if (i < 1 || i > temp_frame_stack.nelts)
return 0;
if (!temp_frame_stack.records[i].ranges)
return 0;
retval = 0;
for (j = 0; j < temp_frame_stack.records[i].ranges->nelts; j++)
if (temp_frame_stack.records[i].ranges->ranges[j].startaddr <= cur_pc
&& temp_frame_stack.records[i].ranges->ranges[j].endaddr > cur_pc)
retval = 1;
return retval;
}
static int
current_tmp_frame_stack_position (void)
{
return temp_frame_stack.current_pos;
}
static int
tmp_frame_in_inlined_function_call_p (CORE_ADDR cur_pc,
CORE_ADDR *inline_end_pc)
{
int ret_val = 0;
int i;
int low = 0;
int high = 0;
*inline_end_pc = (CORE_ADDR) 0;
for (i = 1; i <= temp_frame_stack.nelts; i++)
if ((temp_frame_stack.records[i].ranges
&& tmp_frame_record_ranges_contains_pc (i, cur_pc))
|| (!temp_frame_stack.records[i].ranges
&& (temp_frame_stack.records[i].start_pc <= cur_pc
&& cur_pc < temp_frame_stack.records[i].end_pc)))
{
if (!low)
low = i;
high = i;
}
if (low > 0)
{
if (low <= current_tmp_frame_stack_position ()
&& current_tmp_frame_stack_position () <= high)
i = current_tmp_frame_stack_position ();
else
i = high;
if (!temp_frame_stack.records[i].ranges)
*inline_end_pc = temp_frame_stack.records[i].end_pc;
else
*inline_end_pc = address_range_ending_pc (temp_frame_stack.records[i].ranges);
ret_val = i;
}
return ret_val;
}
static int
find_correct_current_position (void)
{
int i;
int ret_val = 0;
if (global_inlined_call_stack.records[1].start_pc == stop_pc)
ret_val = 1;
else
for (i = 1; i <= global_inlined_call_stack.nelts; i++)
{
if (global_inlined_call_stack.records[i].ranges)
{
if (record_ranges_contains_pc (i, stop_pc))
{
global_inlined_call_stack.records[i].stepped_into = 1;
ret_val = i;
}
}
else if (global_inlined_call_stack.records[i].start_pc <= stop_pc
&& stop_pc < record_end_pc (global_inlined_call_stack.records[i]))
{
global_inlined_call_stack.records[i].stepped_into = 1;
ret_val = i;
}
}
return ret_val;
}
void
inlined_function_initialize_call_stack (void)
{
global_inlined_call_stack.last_pc = (CORE_ADDR) 0;
global_inlined_call_stack.last_inlined_pc = (CORE_ADDR) 0;
global_inlined_call_stack.max_array_size = 10;
global_inlined_call_stack.nelts = 0;
global_inlined_call_stack.current_pos = 0;
global_inlined_call_stack.records =
(struct inlined_call_stack_record *) xmalloc
(10 * sizeof (struct inlined_call_stack_record));
memset (global_inlined_call_stack.records, 0,
10 * sizeof (struct inlined_call_stack_record));
saved_call_stack.last_pc = (CORE_ADDR) 0;
saved_call_stack.last_inlined_pc = (CORE_ADDR) 0;
saved_call_stack.max_array_size = 10;
saved_call_stack.nelts = 0;
saved_call_stack.current_pos = 0;
saved_call_stack.records =
(struct inlined_call_stack_record *) xmalloc
(10 * sizeof (struct inlined_call_stack_record));
memset (saved_call_stack.records, 0,
10 * sizeof (struct inlined_call_stack_record));
temp_frame_stack.last_pc = (CORE_ADDR) 0;
temp_frame_stack.last_inlined_pc = (CORE_ADDR) 0;
temp_frame_stack.max_array_size = 10;
temp_frame_stack.nelts = 0;
temp_frame_stack.current_pos = 0;
temp_frame_stack.records =
(struct inlined_call_stack_record *) xmalloc
(10 * sizeof (struct inlined_call_stack_record));
memset (saved_call_stack.records, 0,
10 * sizeof (struct inlined_call_stack_record));
call_stack_initialized = 1;
}
static void
reset_saved_call_stack (void)
{
saved_call_stack.last_pc = (CORE_ADDR) 0;
saved_call_stack.last_inlined_pc = (CORE_ADDR) 0;
saved_call_stack.nelts = 0;
saved_call_stack.current_pos = 0;
memset (saved_call_stack.records, 0,
saved_call_stack.max_array_size * sizeof (struct inlined_call_stack_record));
}
static void
reset_temp_frame_stack (void)
{
temp_frame_stack.last_pc = (CORE_ADDR) 0;
temp_frame_stack.last_inlined_pc = (CORE_ADDR) 0;
temp_frame_stack.nelts = 0;
temp_frame_stack.current_pos = 0;
memset (temp_frame_stack.records, 0,
temp_frame_stack.max_array_size * sizeof(struct inlined_call_stack_record));
}
void
inlined_function_reinitialize_call_stack (void)
{
global_inlined_call_stack.last_pc = (CORE_ADDR) 0;
global_inlined_call_stack.last_inlined_pc = (CORE_ADDR) 0;
global_inlined_call_stack.nelts = 0;
global_inlined_call_stack.current_pos = 0;
memset (global_inlined_call_stack.records, 0,
global_inlined_call_stack.max_array_size
* sizeof (struct inlined_call_stack_record));
reset_saved_call_stack ();
}
int
inlined_function_call_stack_initialized_p (void)
{
return call_stack_initialized;
}
CORE_ADDR
inlined_function_call_stack_pc (void)
{
return global_inlined_call_stack.last_pc;
}
void
inlined_function_update_call_stack_pc (CORE_ADDR new_pc)
{
global_inlined_call_stack.last_pc = new_pc;
}
static int
inlined_function_address_ranges_properly_contained (int outer, int inner)
{
struct inlined_call_stack_record *outer_record;
struct inlined_call_stack_record *inner_record;
int okay = 1;
int fits_some;
int i;
int j;
CORE_ADDR inner_start;
CORE_ADDR inner_end;
CORE_ADDR outer_start;
CORE_ADDR outer_end;
if (outer < 1 || inner <= outer
|| inner > global_inlined_call_stack.nelts)
okay = 0;
if (okay)
{
outer_record = &(global_inlined_call_stack.records[outer]);
inner_record = &(global_inlined_call_stack.records[inner]);
if (inner_record->ranges && outer_record->ranges)
{
fits_some = 0;
for (i = 0; i < inner_record->ranges->nelts; i++)
{
inner_start = inner_record->ranges->ranges[i].startaddr;
inner_end = inner_record->ranges->ranges[i].endaddr;
for (j = 0; j < outer_record->ranges->nelts && !fits_some; j++)
{
outer_start = outer_record->ranges->ranges[i].startaddr;
outer_end = outer_record->ranges->ranges[i].endaddr;
if (outer_start <= inner_start
&& inner_start < outer_end)
{
if (inner_end <= outer_end)
fits_some = 1;
else
okay = 0;
}
else if (outer_start < inner_end
&& inner_end <= outer_end)
okay = 0;
}
}
if (!fits_some)
okay = 0;
}
else if (inner_record->ranges)
{
outer_start = outer_record->start_pc;
outer_end = outer_record->end_pc;
fits_some = 0;
for (i = 0; i < inner_record->ranges->nelts && okay; i++)
{
inner_start = inner_record->ranges->ranges[i].startaddr;
inner_end = inner_record->ranges->ranges[i].endaddr;
if (outer_start <= inner_start
&& inner_start < outer_end)
{
if (inner_end <= outer_end)
fits_some = 1;
else
okay = 0;
}
else if (outer_start < inner_end
&& inner_end <= outer_end)
okay = 0;
}
if (!fits_some)
okay = 0;
}
else if (outer_record->ranges)
{
fits_some = 0;
for (i = 0; i < outer_record->ranges->nelts && !fits_some; i++)
if (inner_record->start_pc >= outer_record->ranges->ranges[i].startaddr
&& inner_record->end_pc <= outer_record->ranges->ranges[i].endaddr)
fits_some = 1;
okay = fits_some;
}
else
{
if (inner_record->start_pc < outer_record->start_pc
|| inner_record->end_pc > outer_record->end_pc)
okay = 0;
}
}
return okay;
}
static void
verify_stack (void)
{
int i;
if (global_inlined_call_stack.current_pos > global_inlined_call_stack.nelts)
internal_error (__FILE__, __LINE__,
_("Illegal position in inlined call stack."));
if (global_inlined_call_stack.nelts > 1)
{
for (i = 2; i <= global_inlined_call_stack.nelts; i++)
if (!inlined_function_address_ranges_properly_contained (i-1, i))
internal_error (__FILE__, __LINE__,
_("Inconsistent inlined call stack."));
}
}
static void
rb_tree_find_all_matching_nodes (struct rb_tree_node *root, CORE_ADDR key,
int secondary_key, CORE_ADDR third_key,
struct rb_tree_node_list **matches)
{
struct rb_tree_node_list *tmp_node;
if (!root)
return;
if (key == root->key)
{
if (secondary_key == root->secondary_key)
{
if (third_key == root->third_key)
{
tmp_node = (struct rb_tree_node_list *) xmalloc (sizeof (struct rb_tree_node_list));
tmp_node->node = root;
tmp_node->next = *matches;
*matches = tmp_node;
rb_tree_find_all_matching_nodes (root->left, key, secondary_key,
third_key, matches);
rb_tree_find_all_matching_nodes (root->right, key, secondary_key,
third_key, matches);
}
else if (third_key < root->third_key)
rb_tree_find_all_matching_nodes (root->left, key, secondary_key,
third_key, matches);
else
rb_tree_find_all_matching_nodes (root->right, key, secondary_key,
third_key, matches);
}
else if (secondary_key < root->secondary_key)
rb_tree_find_all_matching_nodes (root->left, key, secondary_key,
third_key, matches);
else
rb_tree_find_all_matching_nodes (root->right, key, secondary_key,
third_key, matches);
}
else if (key < root->key)
rb_tree_find_all_matching_nodes (root->left, key, secondary_key, third_key,
matches);
else
rb_tree_find_all_matching_nodes (root->right, key, secondary_key, third_key,
matches);
}
static struct rb_tree_node *
rb_tree_find_next_node (struct rb_tree_node *root, long long key, int secondary_key,
long long third_key)
{
if (root->parent
&& root == root->parent->left
&& root->parent->key == key
&& root->parent->third_key == third_key
&& root->parent->right)
{
if (root->parent->right->key == key
&& root->parent->right->third_key == third_key)
return root->parent->right;
}
else if (root->left
&& root->left->key == key
&& root->left->third_key == third_key)
return root->left;
else if (root->right
&& root->right->key == key
&& root->right->third_key == third_key)
return root->right;
else
return NULL;
return NULL;
}
static void
add_to_list (struct inlined_call_stack_record *new_record,
struct record_list **found_records)
{
struct record_list *tmp_node;
tmp_node = (struct record_list *) xmalloc (sizeof (struct record_list));
tmp_node->record = new_record;
tmp_node->next = *found_records;
*found_records = tmp_node;
}
static void
search_tree_for_name (struct rb_tree_node *root, char *name,
struct record_list **found_records)
{
struct inlined_call_stack_record *tmp_record;
if (root)
{
tmp_record = (struct inlined_call_stack_record *) root->data;
if (tmp_record->fn_name
&& strcmp (tmp_record->fn_name, name) == 0)
add_to_list (tmp_record, found_records);
search_tree_for_name (root->left, name, found_records);
search_tree_for_name (root->right, name, found_records);
}
}
static void
find_function_names_and_address_ranges (struct objfile *objfile,
struct inlined_call_stack_record *record)
{
struct rb_tree_node *tmp_node;
struct inlined_call_stack_record *tmp_record;
struct rb_tree_node_list *matches = NULL;
struct rb_tree_node_list *next;
struct rb_tree_node_list *current;
int match_found = 0;
rb_tree_find_all_matching_nodes (objfile->inlined_subroutine_data,
record->start_pc, 0, record->end_pc,
&matches);
for (current = matches; current && !match_found; current = current->next)
{
tmp_node = current->node;
if (tmp_node != NULL)
{
tmp_record = (struct inlined_call_stack_record *) tmp_node->data;
if (!record->call_site_line
|| tmp_record->call_site_line == record->call_site_line)
{
record->fn_name = tmp_record->fn_name;
record->calling_fn_name = tmp_record->calling_fn_name;
record->ranges = tmp_record->ranges;
match_found = 1;
}
}
}
current = matches;
while (current)
{
next = current->next;
xfree (current);
current = next;
}
}
static void
copy_inlined_call_stack_record (int from, int to)
{
gdb_assert (from < global_inlined_call_stack.max_array_size);
gdb_assert (to < global_inlined_call_stack.max_array_size);
gdb_assert (from > 0);
gdb_assert (to > 0);
global_inlined_call_stack.records[to].start_pc =
global_inlined_call_stack.records[from].start_pc;
global_inlined_call_stack.records[to].end_pc =
global_inlined_call_stack.records[from].end_pc;
global_inlined_call_stack.records[to].ranges =
global_inlined_call_stack.records[from].ranges;
global_inlined_call_stack.records[to].call_site_line =
global_inlined_call_stack.records[from].call_site_line;
global_inlined_call_stack.records[to].call_site_column =
global_inlined_call_stack.records[from].call_site_column;
global_inlined_call_stack.records[to].s =
global_inlined_call_stack.records[from].s;
global_inlined_call_stack.records[to].fn_name =
global_inlined_call_stack.records[from].fn_name;
global_inlined_call_stack.records[to].calling_fn_name =
global_inlined_call_stack.records[from].calling_fn_name;
global_inlined_call_stack.records[to].call_site_filename =
global_inlined_call_stack.records[from].call_site_filename;
global_inlined_call_stack.records[to].stack_frame_created =
global_inlined_call_stack.records[from].stack_frame_created;
global_inlined_call_stack.records[to].stack_frame_printed =
global_inlined_call_stack.records[from].stack_frame_printed;
global_inlined_call_stack.records[to].stepped_into =
global_inlined_call_stack.records[from].stepped_into;
memset (&(global_inlined_call_stack.records[from]), 0,
sizeof (struct inlined_call_stack_record));
}
static void
add_item_to_inlined_subroutine_stack (struct linetable_entry *item,
struct symtab *s,
struct bfd_section *section)
{
int i;
int j;
int k;
int new_pos;
int nelts = global_inlined_call_stack.nelts;
int max_size = global_inlined_call_stack.max_array_size;
for (i = 1; i <= nelts; i++)
{
if (global_inlined_call_stack.records[i].start_pc == item->pc
&& global_inlined_call_stack.records[i].end_pc == item->end_pc
&& (item->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| global_inlined_call_stack.records[i].call_site_line == 0
|| global_inlined_call_stack.records[i].call_site_line == item->line))
break;
}
if (i > nelts)
{
if (nelts >= max_size - 1)
{
if (max_size == 0)
{
max_size = 10;
global_inlined_call_stack.records =
(struct inlined_call_stack_record *) xmalloc
(max_size * sizeof (struct inlined_call_stack_record));
memset (global_inlined_call_stack.records, 0,
max_size * sizeof (struct inlined_call_stack_record));
saved_call_stack.records =
(struct inlined_call_stack_record *) xmalloc
(max_size * sizeof (struct inlined_call_stack_record));
memset (saved_call_stack.records, 0,
max_size * sizeof (struct inlined_call_stack_record));
}
else
{
int old_size = max_size;
max_size = 2 * max_size;
global_inlined_call_stack.records =
(struct inlined_call_stack_record *) xrealloc
(global_inlined_call_stack.records,
max_size * sizeof (struct inlined_call_stack_record));
saved_call_stack.records =
(struct inlined_call_stack_record *) xrealloc
(saved_call_stack.records,
max_size * sizeof (struct inlined_call_stack_record));
for (j = old_size; j < max_size; j++)
{
memset (&(global_inlined_call_stack.records[j]), 0,
sizeof (struct inlined_call_stack_record));
memset (&(saved_call_stack.records[j]), 0,
sizeof (struct inlined_call_stack_record));
}
}
}
global_inlined_call_stack.max_array_size = max_size;
saved_call_stack.max_array_size = max_size;
new_pos = 0;
if (item->pc < global_inlined_call_stack.records[1].start_pc
|| (item->pc == global_inlined_call_stack.records[1].start_pc
&& item->end_pc > global_inlined_call_stack.records[1].end_pc))
new_pos = 1;
else
{
for (j = 1; j < nelts && !new_pos; j++)
{
k = j + 1;
if (global_inlined_call_stack.records[j].start_pc <= item->pc
&& item->pc <= global_inlined_call_stack.records[k].start_pc
&& global_inlined_call_stack.records[j].end_pc >= item->end_pc
&& item->end_pc >= global_inlined_call_stack.records[k].end_pc)
new_pos = k;
}
}
if (new_pos)
{
for (j = nelts; j >= new_pos; j--)
copy_inlined_call_stack_record (j, j + 1);
i = new_pos;
}
nelts++;
}
if (!s)
s = find_pc_symtab (item->pc);
gdb_assert (s != NULL);
if (item->entry_type == INLINED_SUBROUTINE_LT_ENTRY)
{
global_inlined_call_stack.records[i].start_pc = item->pc;
global_inlined_call_stack.records[i].end_pc = item->end_pc;
global_inlined_call_stack.records[i].s = s;
}
else if (item->entry_type == INLINED_CALL_SITE_LT_ENTRY)
{
global_inlined_call_stack.records[i].start_pc = item->pc;
global_inlined_call_stack.records[i].end_pc = item->end_pc;
global_inlined_call_stack.records[i].call_site_filename =
s->filename;
global_inlined_call_stack.records[i].call_site_line = item->line;
global_inlined_call_stack.records[i].call_site_column = 0;
}
find_function_names_and_address_ranges (s->objfile,
&(global_inlined_call_stack.records[i]));
global_inlined_call_stack.nelts = nelts;
verify_stack ();
}
int
current_inlined_subroutine_stack_position (void)
{
return global_inlined_call_stack.current_pos;
}
int
current_inlined_subroutine_stack_size (void)
{
return global_inlined_call_stack.nelts;
}
void
adjust_current_inlined_subroutine_stack_position (int i)
{
global_inlined_call_stack.current_pos += i;
}
static void
insert_pending_node (struct pending_node *node, struct pending_node **list)
{
struct pending_node *prev;
struct pending_node *cur;
if (*list == NULL)
*list = node;
else
{
int done = 0;
prev = NULL;
cur = *list;
while (cur && !done)
{
if (node->entry->pc < cur->entry->pc)
{
if (!prev)
*list = node;
else
prev->next = node;
node->next = cur;
done = 1;
}
else if (node->entry->pc > cur->entry->pc)
{
prev = cur;
cur = cur->next;
}
else if (node->entry->pc == cur->entry->pc)
{
if (cur->entry->end_pc > node->entry->end_pc)
{
prev = cur;
cur = cur->next;
}
else
{
if (!prev)
*list = node;
else
prev->next = node;
node->next = cur;
done = 1;
}
}
}
if (prev && !done)
prev->next = node;
}
}
void
inlined_function_update_call_stack (CORE_ADDR pc)
{
struct symtab *s;
struct symtab *orig_s;
struct symtab *alt_symtab = 0;
struct linetable *l;
int len;
struct linetable_entry *alt = NULL;
struct linetable_entry *item;
struct linetable_entry *prev;
struct blockvector *bv;
asection *section_tmp;
struct bfd_section *section;
int i;
int done;
struct linetable_entry *best = NULL;
CORE_ADDR best_end = 0;
struct symtab *best_symtab = 0;
struct pending_node *pending_list;
struct pending_node *temp;
struct pending_node *cur_pend;
if (!dwarf2_allow_inlined_stepping)
{
if (global_inlined_call_stack.nelts > 0)
inlined_function_reinitialize_call_stack ();
return;
}
if (stepping_over_inlined_subroutine
&& stop_pc > step_range_end
&& frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id))
stepping_over_inlined_subroutine = 0;
for (i = 1; i <= global_inlined_call_stack.nelts; i++)
global_inlined_call_stack.records[i].stack_frame_created = 0;
done = 0;
while (!done)
{
i = global_inlined_call_stack.nelts;
if (i == 0)
done = 1;
else if ((global_inlined_call_stack.records[i].ranges
&& !record_ranges_contains_pc (i, pc))
|| (!global_inlined_call_stack.records[i].ranges
&& (global_inlined_call_stack.records[i].start_pc > pc
|| global_inlined_call_stack.records[i].end_pc <= pc)))
{
memset (&global_inlined_call_stack.records[i], 0,
sizeof (struct inlined_call_stack_record));
global_inlined_call_stack.nelts--;
}
else
done = 1;
}
if (global_inlined_call_stack.current_pos > global_inlined_call_stack.nelts)
global_inlined_call_stack.current_pos = global_inlined_call_stack.nelts;
section_tmp = find_pc_overlay (pc);
if (pc_in_unmapped_range (pc, section_tmp))
pc = overlay_mapped_address (pc, section_tmp);
section = (struct bfd_section *) section_tmp;
s = find_pc_sect_symtab (pc, section);
orig_s = s;
if (s)
{
bv = BLOCKVECTOR (s);
for ( ; s && BLOCKVECTOR (s) == bv; s = s->next)
{
l = LINETABLE (s);
if (!l)
continue;
len = l->nitems;
if (len <= 0)
continue;
pending_list = NULL;
prev = NULL;
item = l->item;
if (item->pc > pc && (!alt || item->pc < alt->pc))
{
alt = item;
alt_symtab = s;
}
for (i = 0; i < len; i++, item++)
{
if ((item->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| item->entry_type == INLINED_CALL_SITE_LT_ENTRY)
&& item->pc <= pc
&& item->end_pc > pc)
{
temp = (struct pending_node *) xmalloc (sizeof (struct pending_node));
temp->entry = item;
temp->s = s;
temp->next = NULL;
insert_pending_node (temp, &pending_list);
}
if (item->pc > pc
|| (item->pc == pc
&& prev
&& item->pc == prev->pc))
break;
prev = item;
}
if (prev && prev->line && (!best || prev->pc > best->pc))
{
best = prev;
best_symtab = s;
if (best_end <= best->pc)
best_end = 0;
}
if (best_symtab
&& best->line != 0
&& prev
&& prev->pc == item->pc)
{
while (prev->pc == item->pc)
{
prev = item;
item++;
if ((item->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| item->entry_type == INLINED_CALL_SITE_LT_ENTRY)
&& item->pc <= pc
&& item->end_pc > pc)
{
temp = (struct pending_node *) xmalloc (sizeof (struct pending_node));
temp->entry = item;
temp->s = s;
temp->next = NULL;
insert_pending_node (temp, &pending_list);
}
}
best = prev;
}
for (cur_pend = pending_list; cur_pend; cur_pend = cur_pend->next)
add_item_to_inlined_subroutine_stack (cur_pend->entry, cur_pend->s,
section);
}
}
if (current_inlined_subroutine_stack_position () == 0
&& current_inlined_subroutine_stack_size () > 0)
{
int i = find_correct_current_position ();
adjust_current_inlined_subroutine_stack_position (i);
if (stepping_into_inlined_subroutine)
{
step_into_current_inlined_subroutine ();
stepping_into_inlined_subroutine = 0;
}
else if (step_range_start && step_range_end
&& step_range_start != step_range_end
&& ((global_inlined_call_stack.last_inlined_pc <
global_inlined_call_stack.records[i].start_pc)
|| (global_inlined_call_stack.last_inlined_pc >=
global_inlined_call_stack.records[i].end_pc)))
{
global_inlined_call_stack.records[i].stepped_into = 0;
}
}
if (global_inlined_call_stack.nelts > 0)
global_inlined_call_stack.last_inlined_pc = pc;
inlined_function_update_call_stack_pc (pc);
}
void
inlined_function_add_function_names (struct objfile *objfile,
CORE_ADDR low_pc, CORE_ADDR high_pc,
int line, int column, char *fn_name,
char *calling_fn_name,
struct address_range_list *ranges)
{
struct rb_tree_node *tmp_rb_node;
struct inlined_call_stack_record *tmp_record;
struct rb_tree_node_list *matches = NULL;
struct rb_tree_node_list *current;
struct rb_tree_node_list *next;
int found = 0;
rb_tree_find_all_matching_nodes (objfile->inlined_subroutine_data,
low_pc, 0, high_pc,
&matches);
for (current = matches; current && !found; current = current->next)
{
tmp_rb_node = current->node;
if (tmp_rb_node && !found)
{
tmp_record = (struct inlined_call_stack_record *) tmp_rb_node->data;
if (tmp_record->call_site_line == line)
{
found = 1;
if (! tmp_record->fn_name)
tmp_record->fn_name = xstrdup (fn_name);
if (! tmp_record->calling_fn_name)
tmp_record->fn_name = xstrdup (calling_fn_name);
}
}
}
if (!found)
{
tmp_record = (struct inlined_call_stack_record *) xmalloc
(sizeof (struct inlined_call_stack_record));
tmp_record->start_pc = low_pc;
tmp_record->end_pc = high_pc;
if (ranges != NULL)
{
int i;
tmp_record->ranges
= (struct address_range_list *) xmalloc (sizeof (struct address_range_list));
tmp_record->ranges->ranges
= (struct address_range *) xmalloc (ranges->nelts * sizeof (struct address_range));
tmp_record->ranges->nelts = ranges->nelts;
for (i = 0; i < ranges->nelts; i++)
tmp_record->ranges->ranges[i] = ranges->ranges[i];
}
else
tmp_record->ranges = NULL;
tmp_record->fn_name = xstrdup (fn_name);
tmp_record->calling_fn_name = xstrdup (calling_fn_name);
tmp_record->call_site_filename = NULL;
tmp_record->call_site_line = line;
tmp_record->call_site_column = column;
tmp_rb_node = (struct rb_tree_node *) xmalloc
(sizeof (struct rb_tree_node));
tmp_rb_node->key = low_pc;
tmp_rb_node->secondary_key = 0;
tmp_rb_node->third_key = high_pc;
tmp_rb_node->data = (void *) tmp_record;
tmp_rb_node->left = NULL;
tmp_rb_node->right = NULL;
tmp_rb_node->parent = NULL;
tmp_rb_node->color = UNINIT;
rb_tree_insert (&(objfile->inlined_subroutine_data),
objfile->inlined_subroutine_data, tmp_rb_node);
}
current = matches;
while (current)
{
next = current->next;
xfree (current);
current = next;
}
}
struct symtab *
current_inlined_subroutine_stack_symtab (void)
{
int i;
struct inlined_function_data *stack_ptr;
if (global_inlined_call_stack.nelts > 0)
stack_ptr = &(global_inlined_call_stack);
else
stack_ptr = &(temp_frame_stack);
i = stack_ptr->current_pos;
return stack_ptr->records[i].s;
}
CORE_ADDR
current_inlined_subroutine_call_stack_start_pc (void)
{
int i;
struct inlined_function_data *stack_ptr;
if (global_inlined_call_stack.nelts > 0)
stack_ptr = &(global_inlined_call_stack);
else
stack_ptr = &(temp_frame_stack);
i = stack_ptr->current_pos;
return stack_ptr->records[i].start_pc;
}
CORE_ADDR
current_inlined_subroutine_call_stack_eof_pc (void)
{
int i;
struct inlined_function_data *stack_ptr;
if (global_inlined_call_stack.nelts > 0)
stack_ptr = &(global_inlined_call_stack);
else
stack_ptr = &(temp_frame_stack);
i = stack_ptr->current_pos;
return record_end_pc (stack_ptr->records[i]);
}
CORE_ADDR
current_inlined_subroutine_call_stack_end_pc (void)
{
int i;
struct inlined_function_data *stack_ptr;
if (global_inlined_call_stack.nelts > 0)
stack_ptr = &(global_inlined_call_stack);
else
stack_ptr = &(temp_frame_stack);
i = stack_ptr->current_pos;
return stack_ptr->records[i].end_pc;
}
char *
current_inlined_subroutine_function_name (void)
{
int i;
struct inlined_function_data *stack_ptr;
if (global_inlined_call_stack.nelts > 0)
stack_ptr = &(global_inlined_call_stack);
else
stack_ptr = &(temp_frame_stack);
i = stack_ptr->current_pos;
return stack_ptr->records[i].fn_name;
}
char *
current_inlined_subroutine_calling_function_name (void)
{
int i;
struct inlined_function_data *stack_ptr;
if (global_inlined_call_stack.nelts > 0)
stack_ptr = &(global_inlined_call_stack);
else
stack_ptr = &(temp_frame_stack);
i = stack_ptr->current_pos;
return stack_ptr->records[i].calling_fn_name;
}
int
current_inlined_subroutine_call_site_line (void)
{
int i;
struct inlined_function_data *stack_ptr;
if (global_inlined_call_stack.nelts > 0)
stack_ptr = &(global_inlined_call_stack);
else
stack_ptr = &(temp_frame_stack);
i = stack_ptr->current_pos;
return stack_ptr->records[i].call_site_line;
}
int
at_inlined_call_site_p (char **file_name, int *line_num, int *column)
{
int ret_val = 0;
int i;
int low = 0;
int high = 0;
for (i = 1; i <= global_inlined_call_stack.nelts; i++)
if (global_inlined_call_stack.records[i].start_pc == stop_pc
&& !global_inlined_call_stack.records[i].stepped_into)
{
if (!low)
low = i;
high = i;
}
if (low > 0)
{
i = 0;
if (low == high
&& !global_inlined_call_stack.records[low].stepped_into)
i = low;
else if (low <= current_inlined_subroutine_stack_position ()
&& current_inlined_subroutine_stack_position() <= high)
i = current_inlined_subroutine_stack_position ();
if (i > 0)
{
*file_name = global_inlined_call_stack.records[i].call_site_filename;
*line_num = global_inlined_call_stack.records[i].call_site_line;
*column = global_inlined_call_stack.records[i].call_site_column;
ret_val = i;
}
}
return ret_val;
}
int
in_inlined_function_call_p (CORE_ADDR *inline_end_pc)
{
int ret_val = 0;
int i;
int low = 0;
int high = 0;
*inline_end_pc = (CORE_ADDR) 0;
for (i = 1; i <= global_inlined_call_stack.nelts; i++)
if (global_inlined_call_stack.records[i].stepped_into)
if ((global_inlined_call_stack.records[i].ranges
&& record_ranges_contains_pc (i, stop_pc))
|| (!global_inlined_call_stack.records[i].ranges
&& (global_inlined_call_stack.records[i].start_pc <= stop_pc
&& stop_pc < global_inlined_call_stack.records[i].end_pc)))
{
if (!low)
low = i;
high = i;
}
if (low > 0)
{
if (low <= current_inlined_subroutine_stack_position ()
&& current_inlined_subroutine_stack_position() <= high)
i = current_inlined_subroutine_stack_position ();
else
i = high;
if (!global_inlined_call_stack.records[i].ranges)
*inline_end_pc = global_inlined_call_stack.records[i].end_pc;
else
*inline_end_pc = address_range_ending_pc
(global_inlined_call_stack.records[i].ranges);
ret_val = i;
}
return ret_val;
}
int
inlined_function_end_of_inlined_code_p (CORE_ADDR pc)
{
int i;
int ret_val = 0;
for (i = 1; i <= current_inlined_subroutine_stack_size (); i++)
if (record_end_pc (global_inlined_call_stack.records[i]) == pc
&& global_inlined_call_stack.records[i].stepped_into)
{
ret_val = 1;
if (i != current_inlined_subroutine_stack_position())
internal_error (__FILE__, __LINE__,
_("Inlined stack position is inconsistent."));
break;
}
return ret_val;
}
static const struct frame_unwind inlined_frame_unwinder =
{
INLINED_FRAME,
inlined_frame_this_id,
inlined_frame_prev_register,
NULL,
inlined_frame_sniffer,
};
const struct frame_unwind *const inlined_frame_unwind = {
&inlined_frame_unwinder
};
static int
inlined_frame_sniffer_helper (struct frame_info *next_frame, CORE_ADDR pc)
{
CORE_ADDR inline_end_pc;
int inside_inlined_code;
int cur_pos;
int i;
update_tmp_frame_stack (pc);
inside_inlined_code = tmp_frame_in_inlined_function_call_p (pc,
&inline_end_pc);
if (!inside_inlined_code)
return 0;
cur_pos = current_tmp_frame_stack_position ();
if (cur_pos == 0)
return 0;
for (i = cur_pos; i > 0; i--)
if (!temp_frame_stack.records[i].stack_frame_created)
{
temp_frame_stack.records[i].stack_frame_created = 1;
return 1;
}
return 0;
}
int
inlined_frame_sniffer (const struct frame_unwind *self,
struct frame_info *next_frame,
void **this_prologue_cache)
{
CORE_ADDR inline_end_pc;
CORE_ADDR pc = 0;
int inside_inlined_code;
int cur_pos;
int i;
if (!gdbarch_unwind_pc_p (current_gdbarch))
return 0;
pc = gdbarch_unwind_pc (current_gdbarch, next_frame);
if (step_range_start && step_range_end
&& step_range_start < pc
&& pc <= step_range_end
&& pc != stop_pc)
return 0;
if (global_inlined_call_stack.nelts == 0
|| global_inlined_call_stack.last_pc != pc)
return inlined_frame_sniffer_helper (next_frame, pc);
inside_inlined_code = in_inlined_function_call_p (&inline_end_pc);
if (!inside_inlined_code)
return 0;
cur_pos = current_inlined_subroutine_stack_position ();
if (!global_inlined_call_stack.records[cur_pos].stepped_into)
cur_pos--;
if (cur_pos == 0)
return 0;
for (i = 1; i <= cur_pos; i++)
{
if (!global_inlined_call_stack.records[i].stack_frame_created)
{
global_inlined_call_stack.records[i].stack_frame_created = 1;
return 1;
}
}
return 0;
}
void
inlined_frame_this_id (struct frame_info *next_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct frame_id tmp_id;
int i;
int this_level = frame_relative_level (next_frame) + 1;
int cur_pos = 0;
if (global_inlined_call_stack.nelts > 0)
cur_pos = global_inlined_call_stack.current_pos;
else
cur_pos = temp_frame_stack.current_pos;
gdb_assert (cur_pos > 0);
tmp_id = gdbarch_unwind_dummy_id (get_frame_arch (next_frame),
next_frame);
if (global_inlined_call_stack.nelts > 0)
{
if (cur_pos > 1
&& !global_inlined_call_stack.records[cur_pos].stepped_into)
cur_pos--;
i = cur_pos - this_level;
if (i < 1)
i = 1;
}
else
{
for (cur_pos = 1;
cur_pos <= temp_frame_stack.nelts
&& !temp_frame_stack.records[cur_pos].stack_frame_created;
cur_pos++);
i = cur_pos;
}
if (global_inlined_call_stack.nelts > 0)
{
tmp_id.code_addr = global_inlined_call_stack.records[i].start_pc;
tmp_id.special_addr = record_end_pc (global_inlined_call_stack.records[i]);
}
else
{
tmp_id.code_addr = temp_frame_stack.records[i].start_pc;
tmp_id.special_addr = record_end_pc (temp_frame_stack.records[i]);
}
tmp_id.code_addr_p = 1;
tmp_id.special_addr_p = 1;
(*this_id) = tmp_id;
}
void
print_inlined_frame (struct frame_info *fi, int print_level,
enum print_what print_what,
int print_args,
struct symtab_and_line sal, int call_site_line)
{
struct ui_stream *stb;
struct cleanup *old_chain;
struct cleanup *list_chain;
char *funname;
char *buffer;
char *tmp_name;
enum language funlang = language_unknown;
int i;
int buffer_len;
int line;
struct inlined_function_data *stack_ptr;
if (global_inlined_call_stack.nelts > 0)
stack_ptr = &global_inlined_call_stack;
else
stack_ptr = &temp_frame_stack;
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
annotate_frame_begin (print_level ? frame_relative_level (fi) : 0,
get_frame_pc (fi));
list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
if (print_level)
{
ui_out_text (uiout, "#");
ui_out_field_fmt_int (uiout, 2, ui_left, "level",
frame_relative_level (fi));
}
if (addressprint)
if (get_frame_pc (fi) != sal.pc
|| !sal.symtab
|| print_what == LOC_AND_ADDRESS)
{
annotate_frame_address ();
ui_out_field_core_addr (uiout, "addr", get_frame_pc (fi));
annotate_frame_address_end ();
ui_out_text (uiout, " in ");
if (ui_out_is_mi_like_p (uiout))
{
ui_out_field_core_addr (uiout, "fp", get_frame_base (fi));
}
}
annotate_frame_function_name ();
if (call_site_line)
{
for (i = 1; i < stack_ptr->current_pos; i++)
if (stack_ptr->records[i].call_site_line == call_site_line)
break;
}
else
{
i = stack_ptr->current_pos;
if (!stack_ptr->records[i].stepped_into
&& i > 1)
i--;
while (i > 1
&& stack_ptr->records[i].stack_frame_printed)
i--;
}
while (i > 1
&& (stack_ptr->records[i].stack_frame_printed
|| !stack_ptr->records[i].stepped_into))
i--;
if (stack_ptr->records[i].stepped_into)
tmp_name = stack_ptr->records[i].fn_name;
else
tmp_name = stack_ptr->records[i].calling_fn_name;
if (tmp_name)
{
buffer_len = strlen (tmp_name) + strlen (" [inlined]") + 1;
buffer = (char *) xmalloc (buffer_len);
sprintf (buffer, "%s [inlined]", tmp_name);
}
else
{
buffer_len = strlen ("<unknown function> [inlined]") + 1;
buffer = (char *) xmalloc (buffer_len);
sprintf (buffer, "<unknown function> [inlined]");
}
funname = buffer;
if (stack_ptr->records[i].s)
funlang = stack_ptr->records[i].s->language;
else
funlang = sal.symtab->language;
annotate_frame_function_name ();
fprintf_symbol_filtered (stb->stream, funname, funlang, DMGL_ANSI);
ui_out_field_stream (uiout, "func", stb);
ui_out_wrap_hint (uiout, " ");
annotate_frame_args ();
ui_out_text (uiout, " (");
ui_out_text (uiout, ")");
annotate_frame_source_begin ();
ui_out_wrap_hint (uiout, " ");
ui_out_text (uiout, " at " );
annotate_frame_source_file ();
if (!stack_ptr->records[i].stepped_into)
ui_out_field_string (uiout, "file",
stack_ptr->records[i].call_site_filename);
else
{
if (stack_ptr->records[i].s)
ui_out_field_string (uiout, "file",
stack_ptr->records[i].s->filename);
else if (sal.symtab)
ui_out_field_string (uiout, "file", sal.symtab->filename);
else
ui_out_field_string (uiout, "file", "<unknown>");
}
if (ui_out_is_mi_like_p (uiout))
{
const char *fullname = symtab_to_fullname
(stack_ptr->records[i].s);
if (fullname != NULL)
ui_out_field_string (uiout, "fullname", fullname);
}
annotate_frame_source_file_end ();
ui_out_text (uiout, ":");
annotate_frame_source_line ();
if (!stack_ptr->records[i].stepped_into)
line = stack_ptr->records[i].call_site_line;
else
{
if (i < stack_ptr->current_pos)
line = stack_ptr->records[i+1].call_site_line;
else
line = sal.line;
}
ui_out_field_int (uiout, "line", line);
annotate_frame_source_end ();
if (print_frame_more_info_hook)
print_frame_more_info_hook (uiout, &sal, fi);
stack_ptr->records[i].stack_frame_printed = 1;
do_cleanups (list_chain);
ui_out_text (uiout, "\n");
do_cleanups (old_chain);
}
void
flush_inlined_subroutine_frames (void)
{
int cur_pos = current_inlined_subroutine_stack_position ();
int i;
for (i = 1; i <= cur_pos; i++)
{
global_inlined_call_stack.records[i].stack_frame_created = 0;
global_inlined_call_stack.records[i].stack_frame_printed = 0;
}
for (i = 1; i < temp_frame_stack.nelts; i++)
{
temp_frame_stack.records[i].stack_frame_created = 0;
temp_frame_stack.records[i].stack_frame_printed = 0;
}
}
void
clear_inlined_subroutine_print_frames (void)
{
int cur_pos = current_inlined_subroutine_stack_position ();
int i;
for (i = 1; i <= cur_pos; i++)
global_inlined_call_stack.records[i].stack_frame_printed = 0;
}
void
step_into_current_inlined_subroutine (void)
{
int cur_pos = current_inlined_subroutine_stack_position ();
while (cur_pos <= global_inlined_call_stack.nelts
&& global_inlined_call_stack.records[cur_pos].start_pc < stop_pc)
{
global_inlined_call_stack.records[cur_pos].stepped_into = 1;
if (cur_pos < global_inlined_call_stack.nelts)
adjust_current_inlined_subroutine_stack_position (1);
cur_pos++;
}
if (cur_pos <= global_inlined_call_stack.nelts
&& global_inlined_call_stack.records[cur_pos].start_pc == stop_pc
&& !global_inlined_call_stack.records[cur_pos].stepped_into)
{
global_inlined_call_stack.records[cur_pos].stepped_into = 1;
if (cur_pos < global_inlined_call_stack.nelts)
adjust_current_inlined_subroutine_stack_position (1);
}
gdb_assert (current_inlined_subroutine_call_stack_start_pc() == stop_pc);
}
int
current_inlined_bottom_call_site_line (void)
{
if (global_inlined_call_stack.nelts > 0)
return global_inlined_call_stack.records[1].call_site_line;
else
return temp_frame_stack.records[1].call_site_line;
}
struct symtabs_and_lines
check_for_additional_inlined_breakpoint_locations (struct symtabs_and_lines sals,
char **addr_string,
struct expression **cond,
char **cond_string,
char ***new_addr_string,
struct expression ***new_cond,
char ***new_cond_string)
{
int i;
int j;
int *indices;
int max_size = sals.nelts * 2;
struct objfile *obj;
struct symtabs_and_lines new_sals;
struct rb_tree_node *function_name_records;
new_sals.sals = (struct symtab_and_line *)
xmalloc (max_size *
sizeof (struct symtab_and_line));
new_sals.nelts = 0;
indices = (int *) xmalloc (sals.nelts * sizeof (int));
for (i = 0; i < sals.nelts; i++)
indices[i] = 0;
ALL_OBJFILES (obj)
{
function_name_records = obj->inlined_subroutine_data;
if (!function_name_records)
continue;
for (i = 0; i < sals.nelts; i++)
{
if (addr_string[i])
{
int already_found = 0;
for (j = i - 1; j > 0 && !already_found; j--)
if (addr_string[j]
&& strcmp (addr_string[i], addr_string[j]) == 0)
already_found = 1;
if (!already_found)
{
struct record_list *found_records = NULL;
struct record_list *cur;
search_tree_for_name (function_name_records,
addr_string[i], &found_records);
for (cur = found_records; cur; cur = cur->next)
{
indices[i] = 1;
if (new_sals.nelts >= max_size)
{
max_size = max_size * 2;
new_sals.sals = xrealloc (new_sals.sals,
max_size *
sizeof (struct symtab_and_line));
}
new_sals.sals[new_sals.nelts] = find_pc_line
(cur->record->start_pc,
0);
new_sals.sals[new_sals.nelts].end = cur->record->end_pc;
new_sals.sals[new_sals.nelts].entry_type =
INLINED_SUBROUTINE_LT_ENTRY;
new_sals.sals[new_sals.nelts].next = NULL;
new_sals.nelts++;
}
}
}
}
}
if (new_sals.nelts > 0)
{
*new_addr_string = (char **) xmalloc (new_sals.nelts * sizeof (char *));
*new_cond = (struct expression **) xmalloc (new_sals.nelts *
sizeof (struct expression *));
*new_cond_string = (char **) xmalloc (new_sals.nelts * sizeof (char *));
i = 0;
j = 0;
while (j < new_sals.nelts)
{
while (i < sals.nelts && indices[i] == 0)
i++;
if (i < sals.nelts)
{
(*new_addr_string)[j] = xstrdup (addr_string[i]);
if (cond_string[i])
(*new_cond_string)[j] = xstrdup (cond_string[i]);
else
(*new_cond_string)[j] = NULL;
if (cond[i])
(*new_cond)[j] = cond[i];
else
(*new_cond)[j] = NULL;
}
else
{
(*new_addr_string)[j] = NULL;
(*new_cond_string)[j] = NULL;
(*new_cond)[j] = NULL;
}
j++;
}
}
return new_sals;
}
void
inlined_subroutine_adjust_position_for_breakpoint (struct breakpoint *b)
{
int i;
int j;
int cur_pos;
gdb_assert (b->addr_string != NULL);
for (i = 1; i <= global_inlined_call_stack.nelts; i++)
{
if ((strcmp (global_inlined_call_stack.records[i].fn_name, b->addr_string)
== 0)
&& (global_inlined_call_stack.records[i].start_pc == b->loc->address))
{
global_inlined_call_stack.current_pos = i;
cur_pos = i;
global_inlined_call_stack.records[i].stepped_into = 1;
for (j = i; j > 0; j--)
global_inlined_call_stack.records[j].stepped_into = 1;
break;
}
}
gdb_assert ( 1 <= i
&& i <= global_inlined_call_stack.nelts);
if (cur_pos < global_inlined_call_stack.nelts
&& (global_inlined_call_stack.records[cur_pos].start_pc ==
global_inlined_call_stack.records[cur_pos + 1].start_pc))
global_inlined_call_stack.current_pos++;
}
void
inlined_subroutine_restore_after_dummy_call (void)
{
int stack_size;
int i;
if (saved_call_stack.nelts > 0)
{
stack_size = global_inlined_call_stack.max_array_size *
sizeof (struct inlined_call_stack_record);
memset (global_inlined_call_stack.records, 0, stack_size);
gdb_assert (global_inlined_call_stack.max_array_size ==
saved_call_stack.max_array_size);
global_inlined_call_stack.last_pc = saved_call_stack.last_pc;
global_inlined_call_stack.last_inlined_pc = saved_call_stack.last_inlined_pc;
global_inlined_call_stack.nelts = saved_call_stack.nelts;
global_inlined_call_stack.current_pos = saved_call_stack.current_pos;
for (i = 1; i <= saved_call_stack.nelts; i++)
{
global_inlined_call_stack.records[i].start_pc =
saved_call_stack.records[i].start_pc;
global_inlined_call_stack.records[i].end_pc =
saved_call_stack.records[i].end_pc;
global_inlined_call_stack.records[i].ranges =
saved_call_stack.records[i].ranges;
global_inlined_call_stack.records[i].call_site_line =
saved_call_stack.records[i].call_site_line;
global_inlined_call_stack.records[i].call_site_column =
saved_call_stack.records[i].call_site_column;
global_inlined_call_stack.records[i].s = saved_call_stack.records[i].s;
global_inlined_call_stack.records[i].fn_name =
xstrdup (saved_call_stack.records[i].fn_name);
global_inlined_call_stack.records[i].calling_fn_name =
xstrdup (saved_call_stack.records[i].calling_fn_name);
global_inlined_call_stack.records[i].call_site_filename =
xstrdup (saved_call_stack.records[i].call_site_filename);
global_inlined_call_stack.records[i].stack_frame_created =
saved_call_stack.records[i].stack_frame_created;
global_inlined_call_stack.records[i].stack_frame_printed =
saved_call_stack.records[i].stack_frame_printed;
global_inlined_call_stack.records[i].stepped_into =
saved_call_stack.records[i].stepped_into;
}
reset_saved_call_stack ();
}
}
void
inlined_subroutine_save_before_dummy_call (void)
{
if (saved_call_stack.nelts == 0)
{
int i;
saved_call_stack.last_pc = global_inlined_call_stack.last_pc;
saved_call_stack.last_inlined_pc = global_inlined_call_stack.last_inlined_pc;
saved_call_stack.nelts = global_inlined_call_stack.nelts;
saved_call_stack.current_pos = global_inlined_call_stack.current_pos;
for (i = 1; i <= global_inlined_call_stack.nelts; i++)
{
saved_call_stack.records[i].start_pc =
global_inlined_call_stack.records[i].start_pc;
saved_call_stack.records[i].end_pc =
global_inlined_call_stack.records[i].end_pc;
saved_call_stack.records[i].ranges =
global_inlined_call_stack.records[i].ranges;
saved_call_stack.records[i].call_site_line =
global_inlined_call_stack.records[i].call_site_line;
saved_call_stack.records[i].call_site_column =
global_inlined_call_stack.records[i].call_site_column;
saved_call_stack.records[i].s = global_inlined_call_stack.records[i].s;
saved_call_stack.records[i].fn_name =
xstrdup (global_inlined_call_stack.records[i].fn_name);
saved_call_stack.records[i].calling_fn_name =
xstrdup (global_inlined_call_stack.records[i].calling_fn_name);
saved_call_stack.records[i].call_site_filename =
xstrdup (global_inlined_call_stack.records[i].call_site_filename);
saved_call_stack.records[i].stack_frame_created =
global_inlined_call_stack.records[i].stack_frame_created;
saved_call_stack.records[i].stack_frame_printed =
global_inlined_call_stack.records[i].stack_frame_printed;
saved_call_stack.records[i].stepped_into =
global_inlined_call_stack.records[i].stepped_into;
}
}
}
int
rest_of_line_contains_inlined_subroutine (CORE_ADDR *end_of_line)
{
struct symtab_and_line sal;
struct symtab_and_line *cur;
int current_line;
int cur_pos;
CORE_ADDR current_end;
CORE_ADDR line_start_pc = 0;
CORE_ADDR inline_start_pc = 0;
int inlined_subroutine_found = 0;
if (!dwarf2_allow_inlined_stepping)
return 0;
sal = find_pc_line (stop_pc, 0);
if (sal.line == 0)
{
inlined_subroutine_found = 0;
current_end = 0;
*end_of_line = 0;
return inlined_subroutine_found;
}
cur_pos = current_inlined_subroutine_stack_position ();
if (cur_pos > 0
&& !global_inlined_call_stack.records[cur_pos].stepped_into)
cur_pos--;
if (cur_pos > 0
&& sal.next)
{
for (cur = &sal; cur; cur = cur->next)
{
if (cur->entry_type == INLINED_SUBROUTINE_LT_ENTRY
&& cur->pc == global_inlined_call_stack.records[cur_pos].start_pc
&& cur->end == record_end_pc
(global_inlined_call_stack.records[cur_pos]))
{
sal.symtab = cur->symtab;
sal.line = cur->line;
sal.pc = cur->pc;
sal.end = cur->end;
break;
}
}
}
if (sal.next
&& (sal.next->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| sal.next->entry_type == INLINED_CALL_SITE_LT_ENTRY))
{
inlined_subroutine_found = 1;
inline_start_pc = sal.pc;
}
else if (find_line_pc (sal.symtab, sal.line, &line_start_pc))
if (line_start_pc != sal.pc)
sal = find_pc_line (line_start_pc, 0);
current_line = sal.line;
current_end = sal.end;
if (current_end < stop_pc)
current_end = stop_pc;
while (sal.line == current_line)
{
sal = find_pc_line (current_end, 0);
if (sal.line == current_line)
current_end = sal.end;
cur = &sal;
while (cur)
{
if (cur->line == current_line
&& (cur->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| cur->entry_type == INLINED_CALL_SITE_LT_ENTRY))
{
inlined_subroutine_found = 1;
inline_start_pc = cur->pc;
current_end = cur->end;
break;
}
cur = cur->next;
}
}
if ((inline_start_pc != 0
&& inline_start_pc == stop_pc)
|| (current_end <= stop_pc))
{
inlined_subroutine_found = 0;
current_end = 0;
}
*end_of_line = current_end;
return inlined_subroutine_found;
}
void
find_next_inlined_subroutine (CORE_ADDR pc, CORE_ADDR *inline_start_pc)
{
struct symtab_and_line sal;
int current_line;
CORE_ADDR current_end;
*inline_start_pc = 0;
sal = find_pc_line (pc, 0);
current_line = sal.line;
current_end = sal.end;
while (sal.line == current_line
&& !sal.next)
{
sal = find_pc_line (current_end, 0);
if (sal.line == current_line)
current_end = sal.end;
if (sal.next
&& (sal.next->entry_type == INLINED_SUBROUTINE_LT_ENTRY
|| sal.next->entry_type == INLINED_CALL_SITE_LT_ENTRY))
*inline_start_pc = sal.pc;
}
}
int
is_within_stepping_ranges (CORE_ADDR pc)
{
int i;
int range_found = 0;
if (!stepping_ranges)
return 0;
for (i = 0; i < stepping_ranges->nelts && !range_found; i++)
{
if (pc >= stepping_ranges->ranges[i].startaddr
&& pc < stepping_ranges->ranges[i].endaddr)
range_found = 1;
}
return range_found;
}
int
is_at_stepping_ranges_end (CORE_ADDR pc)
{
int i;
int end_found = 0;
if (!stepping_ranges)
return 0;
for (i = 0; i < stepping_ranges->nelts && !end_found; i++)
if (pc == stepping_ranges->ranges[i].endaddr)
end_found = 1;
return end_found;
}
void
inlined_subroutine_free_objfile_data (struct rb_tree_node *root)
{
struct inlined_call_stack_record *data;
if (root->left)
inlined_subroutine_free_objfile_data (root->left);
if (root->right)
inlined_subroutine_free_objfile_data (root->right);
data = (struct inlined_call_stack_record *) root->data;
if (data->ranges)
xfree (data->ranges);
xfree (root->data);
xfree (root);
}
static void
update_inlined_data_addresses (CORE_ADDR offset,
struct rb_tree_node *tree)
{
struct inlined_call_stack_record *data;
int i;
tree->key += offset;
tree->third_key += offset;
data = (struct inlined_call_stack_record *) tree->data;
data->start_pc += offset;
data->end_pc += offset;
if (data->ranges)
for (i = 0; i < data->ranges->nelts; i++)
{
data->ranges->ranges[i].startaddr += offset;
data->ranges->ranges[i].endaddr += offset;
}
if (tree->left)
update_inlined_data_addresses (offset, tree->left);
if (tree->right)
update_inlined_data_addresses (offset, tree->right);
}
void
inlined_subroutine_objfile_relocate (struct objfile *objfile,
struct rb_tree_node *tree_node,
struct section_offsets *deltas)
{
struct obj_section *sect = NULL;
CORE_ADDR offset = 0;
if (!tree_node)
return;
offset = ANOFFSET (deltas, SECT_OFF_TEXT (objfile));
ALL_OBJFILE_OSECTIONS (objfile, sect)
if (objfile->separate_debug_objfile_backlink == NULL
&& sect->addr <= tree_node->key && tree_node->key < sect->endaddr)
{
offset = ANOFFSET (deltas, sect->the_bfd_section->index);
break;
}
if (offset)
update_inlined_data_addresses (offset, tree_node);
}
int
inlined_function_find_first_line (struct symtab_and_line sal)
{
int first_line = sal.line;
int len;
int i;
struct linetable *l;
struct linetable_entry *item;
struct linetable_entry *prev;
l = LINETABLE (sal.symtab);
if (l)
{
len = l->nitems;
if (len)
{
prev = NULL;
item = l->item;
for (i = 0; i < len; i++, item++)
if (item->line >= sal.line
&& item->pc >= sal.pc
&& item->entry_type == NORMAL_LT_ENTRY)
{
first_line = item->line;
break;
}
}
}
return first_line;
}
void
save_thread_inlined_call_stack (ptid_t ptid)
{
struct thread_info *tp;
int num_bytes;
tp = find_thread_id (pid_to_thread_id (ptid));
if (tp == NULL)
return;
if (current_inlined_subroutine_stack_size() == 0)
{
tp->thread_inlined_call_stack = NULL;
return;
}
tp->thread_inlined_call_stack = (struct inlined_function_data *)
xmalloc (sizeof (struct inlined_function_data));
tp->thread_inlined_call_stack->last_pc = global_inlined_call_stack.last_pc;
tp->thread_inlined_call_stack->last_inlined_pc =
global_inlined_call_stack.last_inlined_pc;
tp->thread_inlined_call_stack->max_array_size =
global_inlined_call_stack.max_array_size;
tp->thread_inlined_call_stack->nelts = global_inlined_call_stack.nelts;
tp->thread_inlined_call_stack->current_pos =
global_inlined_call_stack.current_pos;
num_bytes = global_inlined_call_stack.max_array_size *
sizeof (struct inlined_call_stack_record);
tp->thread_inlined_call_stack->records = (struct inlined_call_stack_record *)
xmalloc (num_bytes);
memcpy (tp->thread_inlined_call_stack->records,
global_inlined_call_stack.records, num_bytes);
}
void
restore_thread_inlined_call_stack (ptid_t ptid)
{
struct thread_info *tp;
int num_bytes;
int i;
tp = find_thread_id (pid_to_thread_id (ptid));
if (tp == NULL)
return;
if (tp->thread_inlined_call_stack == NULL
|| tp->thread_inlined_call_stack->nelts == 0)
{
inlined_function_reinitialize_call_stack ();
return;
}
global_inlined_call_stack.last_pc = tp->thread_inlined_call_stack->last_pc;
global_inlined_call_stack.last_inlined_pc =
tp->thread_inlined_call_stack->last_inlined_pc;
gdb_assert (global_inlined_call_stack.max_array_size >=
tp->thread_inlined_call_stack->max_array_size);
global_inlined_call_stack.nelts = tp->thread_inlined_call_stack->nelts;
global_inlined_call_stack.current_pos =
tp->thread_inlined_call_stack->current_pos;
num_bytes = global_inlined_call_stack.max_array_size *
sizeof (struct inlined_call_stack_record);
memset (global_inlined_call_stack.records, 0, num_bytes);
for (i = 1;
i <= global_inlined_call_stack.nelts
&& i < global_inlined_call_stack.max_array_size; i++)
memcpy (&(global_inlined_call_stack.records[i]),
&(tp->thread_inlined_call_stack->records[i]),
sizeof (struct inlined_call_stack_record));
flush_inlined_subroutine_frames ();
}
void
inlined_function_reset_frame_stack (void)
{
int i;
flush_inlined_subroutine_frames ();
if (temp_frame_stack.last_pc == global_inlined_call_stack.last_pc
&& temp_frame_stack.last_inlined_pc ==
global_inlined_call_stack.last_inlined_pc
&& temp_frame_stack.nelts == global_inlined_call_stack.nelts
&& temp_frame_stack.current_pos == global_inlined_call_stack.current_pos)
{
for (i = 1; i <= temp_frame_stack.nelts; i++)
global_inlined_call_stack.records[i].stack_frame_created =
temp_frame_stack.records[i].stack_frame_created;
}
}