From debd256d71bf60d1285d31c5742909f535ccfab3 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 6 May 2002 21:00:21 +0000 Subject: [PATCH] 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. --- gdb/ChangeLog | 26 +++ gdb/dwarf2read.c | 489 ++++++++++++++++++++++++++++++----------------- 2 files changed, 336 insertions(+), 179 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4002c809627..93a2353ba3c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,29 @@ +2002-05-06 Jim Blandy + + 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 * gdbtypes.c (init_vector_type): New function. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 0f05c0922fc..5c06e9af75f 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -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) +{ + if (lh->standard_opcode_lengths) + free (lh->standard_opcode_lengths); + + /* 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) { - unsigned int num_files; - struct fileinfo + /* Grow the array if necessary. */ + if (lh->include_dirs_size == 0) { - char *name; - unsigned int dir; - unsigned int time; - unsigned int size; + 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))); } - *files; -}; -struct directories - { - unsigned int num_dirs; - char **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 -- 2.30.2