Separate the job of reading the line number info statement program

header (...expialidocious) out into its own function.
* dwarf2read.c (struct line_head, struct filenames, struct
directories): Replace with...
(struct line_header): New structure, containing the full
contents of the statement program header, including the
include directory and file name tables.
(read_file_scope): If we have line number info, instead of just
calling dwarf_decode_lines to do all the work, call
dwarf_decode_line_header first to get a `struct line_header'
containing the data in the statement program header, and then
pass that to dwarf_decode_lines, which will pick up where that
left off.  Be sure to clean up the `struct line_header' object.
(dwarf_decode_line_header, free_line_header, add_include_dir,
add_file_name): New functions.
(dwarf_decode_lines): Move all the code to read the statement
program header into dwarf_decode_line_header.  Take the line
header it built as the first argument, instead of the offset to
the compilation unit's line number info.  Use the new `struct
line_header' type instead of the old structures.  No need to do
cleanups here now, since we don't allocate anything.
(dwarf2_statement_list_fits_in_line_number_section,
dwarf2_line_header_too_long): New complaints.
This commit is contained in:
Jim Blandy 2002-05-06 21:00:21 +00:00
parent ac3aafc7a6
commit debd256d71
2 changed files with 338 additions and 181 deletions

View File

@ -1,3 +1,29 @@
2002-05-06 Jim Blandy <jimb@redhat.com>
Separate the job of reading the line number info statement program
header (...expialidocious) out into its own function.
* dwarf2read.c (struct line_head, struct filenames, struct
directories): Replace with...
(struct line_header): New structure, containing the full
contents of the statement program header, including the
include directory and file name tables.
(read_file_scope): If we have line number info, instead of just
calling dwarf_decode_lines to do all the work, call
dwarf_decode_line_header first to get a `struct line_header'
containing the data in the statement program header, and then
pass that to dwarf_decode_lines, which will pick up where that
left off. Be sure to clean up the `struct line_header' object.
(dwarf_decode_line_header, free_line_header, add_include_dir,
add_file_name): New functions.
(dwarf_decode_lines): Move all the code to read the statement
program header into dwarf_decode_line_header. Take the line
header it built as the first argument, instead of the offset to
the compilation unit's line number info. Use the new `struct
line_header' type instead of the old structures. No need to do
cleanups here now, since we don't allocate anything.
(dwarf2_statement_list_fits_in_line_number_section,
dwarf2_line_header_too_long): New complaints.
2002-05-06 Elena Zannoni <ezannoni@redhat.com>
* gdbtypes.c (init_vector_type): New function.

View File

@ -175,19 +175,49 @@ struct comp_unit_head
4 or 12 */
};
/* The data in the .debug_line statement prologue looks like this. */
struct line_head
/* The line number information for a compilation unit (found in the
.debug_line section) begins with a "statement program header",
which contains the following information. */
struct line_header
{
unsigned int total_length;
unsigned short version;
unsigned int header_length;
unsigned char minimum_instruction_length;
unsigned char default_is_stmt;
int line_base;
unsigned char line_range;
unsigned char opcode_base;
/* standard_opcode_lengths[i] is the number of operands for the
standard opcode whose value is i. This means that
standard_opcode_lengths[0] is unused, and the last meaningful
element is standard_opcode_lengths[opcode_base - 1]. */
unsigned char *standard_opcode_lengths;
/* The include_directories table. NOTE! These strings are not
allocated with xmalloc; instead, they are pointers into
debug_line_buffer. If you try to free them, `free' will get
indigestion. */
unsigned int num_include_dirs, include_dirs_size;
char **include_dirs;
/* The file_names table. NOTE! These strings are not allocated
with xmalloc; instead, they are pointers into debug_line_buffer.
Don't try to free them directly. */
unsigned int num_file_names, file_names_size;
struct file_entry
{
unsigned int total_length;
unsigned short version;
unsigned int prologue_length;
unsigned char minimum_instruction_length;
unsigned char default_is_stmt;
int line_base;
unsigned char line_range;
unsigned char opcode_base;
unsigned char *standard_opcode_lengths;
};
char *name;
unsigned int dir_index;
unsigned int mod_time;
unsigned int length;
} *file_names;
/* The start and end of the statement program following this
header. These point into dwarf_line_buffer. */
char *statement_program_start, *statement_program_end;
};
/* When we construct a partial symbol table entry we only
need this much information. */
@ -502,6 +532,10 @@ static struct complaint dwarf2_missing_line_number_section =
{
"missing .debug_line section", 0, 0
};
static struct complaint dwarf2_statement_list_fits_in_line_number_section =
{
"statement list doesn't fit in .debug_line section", 0, 0
};
static struct complaint dwarf2_mangled_line_number_section =
{
"mangled .debug_line section", 0, 0
@ -574,6 +608,10 @@ static struct complaint dwarf2_misplaced_line_number =
{
"misplaced first line number at 0x%lx for '%s'", 0, 0
};
static struct complaint dwarf2_line_header_too_long =
{
"line number info header doesn't fit in `.debug_line' section", 0, 0
};
/* local function prototypes */
@ -653,7 +691,14 @@ static struct attribute *dwarf_attr (struct die_info *, unsigned int);
static int die_is_declaration (struct die_info *);
static void dwarf_decode_lines (unsigned int, char *, bfd *,
static void free_line_header (struct line_header *lh);
static struct line_header *(dwarf_decode_line_header
(unsigned int offset,
bfd *abfd,
const struct comp_unit_head *cu_header));
static void dwarf_decode_lines (struct line_header *, char *, bfd *,
const struct comp_unit_head *);
static void dwarf2_start_subfile (char *, char *);
@ -1569,7 +1614,7 @@ static void
read_file_scope (struct die_info *die, struct objfile *objfile,
const struct comp_unit_head *cu_header)
{
unsigned int line_offset = 0;
struct cleanup *back_to = make_cleanup (null_cleanup, 0);
CORE_ADDR lowpc = ((CORE_ADDR) -1);
CORE_ADDR highpc = ((CORE_ADDR) 0);
struct attribute *attr;
@ -1577,6 +1622,7 @@ read_file_scope (struct die_info *die, struct objfile *objfile,
char *comp_dir = NULL;
struct die_info *child_die;
bfd *abfd = objfile->obfd;
struct line_header *line_header = 0;
if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, objfile))
{
@ -1674,9 +1720,18 @@ read_file_scope (struct die_info *die, struct objfile *objfile,
attr = dwarf_attr (die, DW_AT_stmt_list);
if (attr)
{
line_offset = DW_UNSND (attr);
dwarf_decode_lines (line_offset, comp_dir, abfd, cu_header);
unsigned int line_offset = DW_UNSND (attr);
line_header = dwarf_decode_line_header (line_offset,
abfd, cu_header);
if (line_header)
{
make_cleanup ((make_cleanup_ftype *) free_line_header,
(void *) line_header);
dwarf_decode_lines (line_header, comp_dir, abfd, cu_header);
}
}
do_cleanups (back_to);
}
static void
@ -3945,28 +4000,188 @@ die_is_declaration (struct die_info *die)
&& ! dwarf_attr (die, DW_AT_specification));
}
/* Decode the line number information for the compilation unit whose
line number info is at OFFSET in the .debug_line section.
The compilation directory of the file is passed in COMP_DIR. */
struct filenames
/* Free the line_header structure *LH, and any arrays and strings it
refers to. */
static void
free_line_header (struct line_header *lh)
{
unsigned int num_files;
struct fileinfo
{
char *name;
unsigned int dir;
unsigned int time;
unsigned int size;
}
*files;
};
if (lh->standard_opcode_lengths)
free (lh->standard_opcode_lengths);
struct directories
{
unsigned int num_dirs;
char **dirs;
};
/* Remember that all the lh->file_names[i].name pointers are
pointers into debug_line_buffer, and don't need to be freed. */
if (lh->file_names)
free (lh->file_names);
/* Similarly for the include directory names. */
if (lh->include_dirs)
free (lh->include_dirs);
free (lh);
}
/* Add an entry to LH's include directory table. */
static void
add_include_dir (struct line_header *lh, char *include_dir)
{
/* Grow the array if necessary. */
if (lh->include_dirs_size == 0)
{
lh->include_dirs_size = 1; /* for testing */
lh->include_dirs = xmalloc (lh->include_dirs_size
* sizeof (*lh->include_dirs));
}
else if (lh->num_include_dirs >= lh->include_dirs_size)
{
lh->include_dirs_size *= 2;
lh->include_dirs = xrealloc (lh->include_dirs,
(lh->include_dirs_size
* sizeof (*lh->include_dirs)));
}
lh->include_dirs[lh->num_include_dirs++] = include_dir;
}
/* Add an entry to LH's file name table. */
static void
add_file_name (struct line_header *lh,
char *name,
unsigned int dir_index,
unsigned int mod_time,
unsigned int length)
{
struct file_entry *fe;
/* Grow the array if necessary. */
if (lh->file_names_size == 0)
{
lh->file_names_size = 1; /* for testing */
lh->file_names = xmalloc (lh->file_names_size
* sizeof (*lh->file_names));
}
else if (lh->num_file_names >= lh->file_names_size)
{
lh->file_names_size *= 2;
lh->file_names = xrealloc (lh->file_names,
(lh->file_names_size
* sizeof (*lh->file_names)));
}
fe = &lh->file_names[lh->num_file_names++];
fe->name = name;
fe->dir_index = dir_index;
fe->mod_time = mod_time;
fe->length = length;
}
/* Read the statement program header starting at OFFSET in
dwarf_line_buffer, according to the endianness of ABFD. Return a
pointer to a struct line_header, allocated using xmalloc.
NOTE: the strings in the include directory and file name tables of
the returned object point into debug_line_buffer, and must not be
freed. */
static struct line_header *
dwarf_decode_line_header (unsigned int offset, bfd *abfd,
const struct comp_unit_head *cu_header)
{
struct cleanup *back_to;
struct line_header *lh;
char *line_ptr;
int bytes_read;
int i;
char *cur_dir, *cur_file;
if (dwarf_line_buffer == NULL)
{
complain (&dwarf2_missing_line_number_section);
return 0;
}
/* Make sure that at least there's room for the total_length field. That
could be 12 bytes long, but we're just going to fudge that. */
if (offset + 4 >= dwarf_line_size)
{
complain (&dwarf2_statement_list_fits_in_line_number_section);
return 0;
}
lh = xmalloc (sizeof (*lh));
memset (lh, 0, sizeof (*lh));
back_to = make_cleanup ((make_cleanup_ftype *) free_line_header,
(void *) lh);
line_ptr = dwarf_line_buffer + offset;
/* read in the header */
lh->total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
line_ptr += bytes_read;
if (line_ptr + lh->total_length > dwarf_line_buffer + dwarf_line_size)
{
complain (&dwarf2_statement_list_fits_in_line_number_section);
return 0;
}
lh->statement_program_end = line_ptr + lh->total_length;
lh->version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
lh->header_length = read_offset (abfd, line_ptr, cu_header, &bytes_read);
line_ptr += bytes_read;
lh->minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh->default_is_stmt = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh->line_base = read_1_signed_byte (abfd, line_ptr);
line_ptr += 1;
lh->line_range = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh->opcode_base = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh->standard_opcode_lengths
= (unsigned char *) xmalloc (lh->opcode_base * sizeof (unsigned char));
lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
for (i = 1; i < lh->opcode_base; ++i)
{
lh->standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
/* Read directory table */
while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
add_include_dir (lh, cur_dir);
}
line_ptr += bytes_read;
/* Read file name table */
while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
unsigned int dir_index, mod_time, length;
line_ptr += bytes_read;
dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
add_file_name (lh, cur_file, dir_index, mod_time, length);
}
line_ptr += bytes_read;
lh->statement_program_start = line_ptr;
if (line_ptr > dwarf_line_buffer + dwarf_line_size)
complain (&dwarf2_line_header_too_long);
discard_cleanups (back_to);
return lh;
}
/* This function exists to work around a bug in certain compilers
(particularly GCC 2.95), in which the first line number marker of a
@ -4013,109 +4228,22 @@ check_cu_functions (CORE_ADDR address)
return fn->lowpc;
}
/* Decode the line number information for the compilation unit whose
line number info is at OFFSET in the .debug_line section.
The compilation directory of the file is passed in COMP_DIR. */
static void
dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd,
const struct comp_unit_head *cu_header)
{
char *line_ptr;
char *line_end;
struct line_head lh;
struct cleanup *back_to;
unsigned int i, bytes_read;
char *cur_file, *cur_dir;
char *cur_dir;
unsigned char op_code, extended_op, adj_opcode;
#define FILE_ALLOC_CHUNK 5
#define DIR_ALLOC_CHUNK 5
struct filenames files;
struct directories dirs;
if (dwarf_line_buffer == NULL)
{
complain (&dwarf2_missing_line_number_section);
return;
}
files.num_files = 0;
files.files = NULL;
dirs.num_dirs = 0;
dirs.dirs = NULL;
line_ptr = dwarf_line_buffer + offset;
/* read in the prologue */
lh.total_length = read_initial_length (abfd, line_ptr, NULL, &bytes_read);
line_ptr += bytes_read;
line_end = line_ptr + lh.total_length;
lh.version = read_2_bytes (abfd, line_ptr);
line_ptr += 2;
lh.prologue_length = read_offset (abfd, line_ptr, cu_header, &bytes_read);
line_ptr += bytes_read;
lh.minimum_instruction_length = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh.default_is_stmt = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh.line_base = read_1_signed_byte (abfd, line_ptr);
line_ptr += 1;
lh.line_range = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh.opcode_base = read_1_byte (abfd, line_ptr);
line_ptr += 1;
lh.standard_opcode_lengths = (unsigned char *)
xmalloc (lh.opcode_base * sizeof (unsigned char));
back_to = make_cleanup (free_current_contents, &lh.standard_opcode_lengths);
lh.standard_opcode_lengths[0] = 1;
for (i = 1; i < lh.opcode_base; ++i)
{
lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr);
line_ptr += 1;
}
/* Read directory table */
while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
if ((dirs.num_dirs % DIR_ALLOC_CHUNK) == 0)
{
dirs.dirs = (char **)
xrealloc (dirs.dirs,
(dirs.num_dirs + DIR_ALLOC_CHUNK) * sizeof (char *));
if (dirs.num_dirs == 0)
make_cleanup (free_current_contents, &dirs.dirs);
}
dirs.dirs[dirs.num_dirs++] = cur_dir;
}
line_ptr += bytes_read;
/* Read file name table */
while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
if ((files.num_files % FILE_ALLOC_CHUNK) == 0)
{
files.files = (struct fileinfo *)
xrealloc (files.files,
(files.num_files + FILE_ALLOC_CHUNK)
* sizeof (struct fileinfo));
if (files.num_files == 0)
make_cleanup (free_current_contents, &files.files);
}
files.files[files.num_files].name = cur_file;
files.files[files.num_files].dir =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
files.files[files.num_files].time =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
files.files[files.num_files].size =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
files.num_files++;
}
line_ptr += bytes_read;
line_ptr = lh->statement_program_start;
line_end = lh->statement_program_end;
/* Read the statement sequences until there's nothing left. */
while (line_ptr < line_end)
@ -4125,19 +4253,23 @@ dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
unsigned int file = 1;
unsigned int line = 1;
unsigned int column = 0;
int is_stmt = lh.default_is_stmt;
int is_stmt = lh->default_is_stmt;
int basic_block = 0;
int end_sequence = 0;
/* Start a subfile for the current file of the state machine. */
if (files.num_files >= file)
if (lh->num_file_names >= file)
{
/* The file and directory tables are 0 based, the references
are 1 based. */
dwarf2_start_subfile (files.files[file - 1].name,
(files.files[file - 1].dir
? dirs.dirs[files.files[file - 1].dir - 1]
: comp_dir));
/* lh->include_dirs and lh->file_names are 0-based, but the
directory and file name numbers in the statement program
are 1-based. */
struct file_entry *fe = &lh->file_names[file - 1];
char *dir;
if (fe->dir_index)
dir = lh->include_dirs[fe->dir_index - 1];
else
dir = comp_dir;
dwarf2_start_subfile (fe->name, dir);
}
/* Decode the table. */
@ -4146,12 +4278,12 @@ dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
op_code = read_1_byte (abfd, line_ptr);
line_ptr += 1;
if (op_code >= lh.opcode_base)
if (op_code >= lh->opcode_base)
{ /* Special operand. */
adj_opcode = op_code - lh.opcode_base;
address += (adj_opcode / lh.line_range)
* lh.minimum_instruction_length;
line += lh.line_base + (adj_opcode % lh.line_range);
adj_opcode = op_code - lh->opcode_base;
address += (adj_opcode / lh->line_range)
* lh->minimum_instruction_length;
line += lh->line_base + (adj_opcode % lh->line_range);
/* append row to matrix using current values */
address = check_cu_functions (address);
record_line (current_subfile, line, address);
@ -4175,32 +4307,27 @@ dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
address += baseaddr;
break;
case DW_LNE_define_file:
cur_file = read_string (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
if ((files.num_files % FILE_ALLOC_CHUNK) == 0)
{
files.files = (struct fileinfo *)
xrealloc (files.files,
(files.num_files + FILE_ALLOC_CHUNK)
* sizeof (struct fileinfo));
if (files.num_files == 0)
make_cleanup (free_current_contents, &files.files);
}
files.files[files.num_files].name = cur_file;
files.files[files.num_files].dir =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
files.files[files.num_files].time =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
files.files[files.num_files].size =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
files.num_files++;
{
char *cur_file;
unsigned int dir_index, mod_time, length;
cur_file = read_string (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
dir_index =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
mod_time =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
length =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
add_file_name (lh, cur_file, dir_index, mod_time, length);
}
break;
default:
complain (&dwarf2_mangled_line_number_section);
goto done;
return;
}
break;
case DW_LNS_copy:
@ -4209,7 +4336,7 @@ dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
basic_block = 0;
break;
case DW_LNS_advance_pc:
address += lh.minimum_instruction_length
address += lh->minimum_instruction_length
* read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
break;
@ -4218,15 +4345,21 @@ dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
line_ptr += bytes_read;
break;
case DW_LNS_set_file:
/* The file and directory tables are 0 based, the references
are 1 based. */
file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
dwarf2_start_subfile
(files.files[file - 1].name,
(files.files[file - 1].dir
? dirs.dirs[files.files[file - 1].dir - 1]
: comp_dir));
{
/* lh->include_dirs and lh->file_names are 0-based,
but the directory and file name numbers in the
statement program are 1-based. */
struct file_entry *fe;
char *dir;
file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
fe = &lh->file_names[file - 1];
if (fe->dir_index)
dir = lh->include_dirs[fe->dir_index - 1];
else
dir = comp_dir;
dwarf2_start_subfile (fe->name, dir);
}
break;
case DW_LNS_set_column:
column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
@ -4244,8 +4377,8 @@ dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
length since special opcode 255 would have scaled the
the increment. */
case DW_LNS_const_add_pc:
address += (lh.minimum_instruction_length
* ((255 - lh.opcode_base) / lh.line_range));
address += (lh->minimum_instruction_length
* ((255 - lh->opcode_base) / lh->line_range));
break;
case DW_LNS_fixed_advance_pc:
address += read_2_bytes (abfd, line_ptr);
@ -4254,7 +4387,7 @@ dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
default:
{ /* Unknown standard opcode, ignore it. */
int i;
for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++)
for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++)
{
(void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
@ -4263,8 +4396,6 @@ dwarf_decode_lines (unsigned int offset, char *comp_dir, bfd *abfd,
}
}
}
done:
do_cleanups (back_to);
}
/* Start a subfile for DWARF. FILENAME is the name of the file and