diff options
author | Tom Tromey <tom@tromey.com> | 2025-09-06 11:56:40 -0600 |
---|---|---|
committer | Tom Tromey <tom@tromey.com> | 2025-09-08 18:51:58 -0600 |
commit | 5b17433341939d3f8c18f2fcb5fe270cf9a9f73e (patch) | |
tree | 5bbeab73bbfdc221ca065a0f3e9cfcaae7d337c5 /gdb | |
parent | c4a3646be3ef64e3752f112087b6dc8432ee6fdc (diff) | |
download | binutils-5b17433341939d3f8c18f2fcb5fe270cf9a9f73e.zip binutils-5b17433341939d3f8c18f2fcb5fe270cf9a9f73e.tar.gz binutils-5b17433341939d3f8c18f2fcb5fe270cf9a9f73e.tar.bz2 |
Move lnp_state_machine to new file
This patch moves lnp_state_machine and some supporting code to a new
file, dwarf2/line-program.c. The main benefit of this is shrinking
dwarf2/read.c a bit.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/Makefile.in | 2 | ||||
-rw-r--r-- | gdb/dwarf2/line-program.c | 731 | ||||
-rw-r--r-- | gdb/dwarf2/line-program.h | 47 | ||||
-rw-r--r-- | gdb/dwarf2/read.c | 757 | ||||
-rw-r--r-- | gdb/dwarf2/read.h | 31 |
5 files changed, 815 insertions, 753 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 7654fb1..689f37f 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1344,6 +1344,7 @@ HFILES_NO_SRCDIR = \ dwarf2/expr.h \ dwarf2/index-cache.h \ dwarf2/index-common.h \ + dwarf2/line-program.h \ dwarf2/loc.h \ dwarf2/read.h \ dwarf2/read-debug-names.h \ @@ -1910,6 +1911,7 @@ DWARF2_SRCS = \ dwarf2/index-write.c \ dwarf2/leb.c \ dwarf2/line-header.c \ + dwarf2/line-program.c \ dwarf2/loc.c \ dwarf2/macro.c \ dwarf2/parent-map.c \ diff --git a/gdb/dwarf2/line-program.c b/gdb/dwarf2/line-program.c new file mode 100644 index 0000000..72bdd1f --- /dev/null +++ b/gdb/dwarf2/line-program.c @@ -0,0 +1,731 @@ +/* DWARF 2 debugging format support for GDB. + + Copyright (C) 1994-2025 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "dwarf2/line-program.h" +#include "dwarf2/cu.h" +#include "dwarf2/line-header.h" +#include "dwarf2/read.h" +#include "buildsym.h" +#include "complaints.h" +#include "filenames.h" +#include "gdbarch.h" + +static void +dwarf2_debug_line_missing_file_complaint () +{ + complaint (_(".debug_line section has line data without a file")); +} + +static void +dwarf2_debug_line_missing_end_sequence_complaint () +{ + complaint (_(".debug_line section has line " + "program sequence without an end")); +} + +/* State machine to track the state of the line number program. */ + +class lnp_state_machine +{ +public: + /* Initialize a machine state for the start of a line number + program. */ + lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, line_header *lh); + + file_entry *current_file () + { + /* lh->file_names is 0-based, but the file name numbers in the + statement program are 1-based. */ + return m_line_header->file_name_at (m_file); + } + + /* Record the line in the state machine. END_SEQUENCE is true if + we're processing the end of a sequence. */ + void record_line (bool end_sequence); + + /* Check ADDRESS is -1, -2, or zero and less than UNRELOCATED_LOWPC, and if + true nop-out rest of the lines in this sequence. */ + void check_line_address (struct dwarf2_cu *cu, + const gdb_byte *line_ptr, + unrelocated_addr unrelocated_lowpc, + unrelocated_addr address); + + void handle_set_discriminator (unsigned int discriminator) + { + m_discriminator = discriminator; + m_line_has_non_zero_discriminator |= discriminator != 0; + } + + /* Handle DW_LNE_set_address. */ + void handle_set_address (unrelocated_addr address) + { + m_op_index = 0; + m_address + = (unrelocated_addr) gdbarch_adjust_dwarf2_line (m_gdbarch, + (CORE_ADDR) address, + false); + } + + /* Handle DW_LNS_advance_pc. */ + void handle_advance_pc (CORE_ADDR adjust); + + /* Handle a special opcode. */ + void handle_special_opcode (unsigned char op_code); + + /* Handle DW_LNS_advance_line. */ + void handle_advance_line (int line_delta) + { + advance_line (line_delta); + } + + /* Handle DW_LNS_set_file. */ + void handle_set_file (file_name_index file); + + /* Handle DW_LNS_negate_stmt. */ + void handle_negate_stmt () + { + m_flags ^= LEF_IS_STMT; + } + + /* Handle DW_LNS_const_add_pc. */ + void handle_const_add_pc (); + + /* Handle DW_LNS_fixed_advance_pc. */ + void handle_fixed_advance_pc (CORE_ADDR addr_adj) + { + addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); + m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); + m_op_index = 0; + } + + /* Handle DW_LNS_copy. */ + void handle_copy () + { + record_line (false); + m_discriminator = 0; + m_flags &= ~LEF_PROLOGUE_END; + m_flags &= ~LEF_EPILOGUE_BEGIN; + } + + /* Handle DW_LNE_end_sequence. */ + void handle_end_sequence () + { + m_currently_recording_lines = true; + } + + /* Handle DW_LNS_set_prologue_end. */ + void handle_set_prologue_end () + { + m_flags |= LEF_PROLOGUE_END; + } + + void handle_set_epilogue_begin () + { + m_flags |= LEF_EPILOGUE_BEGIN; + } + +private: + /* Advance the line by LINE_DELTA. */ + void advance_line (int line_delta) + { + m_line += line_delta; + + if (line_delta != 0) + m_line_has_non_zero_discriminator = m_discriminator != 0; + } + + struct dwarf2_cu *m_cu; + + gdbarch *m_gdbarch; + + /* The line number header. */ + line_header *m_line_header; + + /* These are part of the standard DWARF line number state machine, + and initialized according to the DWARF spec. */ + + unsigned char m_op_index = 0; + /* The line table index of the current file. */ + file_name_index m_file = 1; + unsigned int m_line = 1; + + /* These are initialized in the constructor. */ + + unrelocated_addr m_address; + linetable_entry_flags m_flags; + unsigned int m_discriminator = 0; + + /* Additional bits of state we need to track. */ + + /* The last file a line number was recorded for. */ + struct subfile *m_last_subfile = NULL; + + /* The address of the last line entry. */ + unrelocated_addr m_last_address; + + /* Set to true when a previous line at the same address (using + m_last_address) had LEF_IS_STMT set in m_flags. This is reset to false + when a line entry at a new address (m_address different to + m_last_address) is processed. */ + bool m_stmt_at_address = false; + + /* When true, record the lines we decode. */ + bool m_currently_recording_lines = true; + + /* The last line number that was recorded, used to coalesce + consecutive entries for the same line. This can happen, for + example, when discriminators are present. PR 17276. */ + unsigned int m_last_line = 0; + bool m_line_has_non_zero_discriminator = false; +}; + +void +lnp_state_machine::handle_advance_pc (CORE_ADDR adjust) +{ + CORE_ADDR addr_adj = (((m_op_index + adjust) + / m_line_header->maximum_ops_per_instruction) + * m_line_header->minimum_instruction_length); + addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); + m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); + m_op_index = ((m_op_index + adjust) + % m_line_header->maximum_ops_per_instruction); +} + +void +lnp_state_machine::handle_special_opcode (unsigned char op_code) +{ + unsigned char adj_opcode = op_code - m_line_header->opcode_base; + unsigned char adj_opcode_d = adj_opcode / m_line_header->line_range; + unsigned char adj_opcode_r = adj_opcode % m_line_header->line_range; + CORE_ADDR addr_adj = (((m_op_index + adj_opcode_d) + / m_line_header->maximum_ops_per_instruction) + * m_line_header->minimum_instruction_length); + addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); + m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); + m_op_index = ((m_op_index + adj_opcode_d) + % m_line_header->maximum_ops_per_instruction); + + int line_delta = m_line_header->line_base + adj_opcode_r; + advance_line (line_delta); + record_line (false); + m_discriminator = 0; + m_flags &= ~LEF_PROLOGUE_END; + m_flags &= ~LEF_EPILOGUE_BEGIN; +} + +void +lnp_state_machine::handle_set_file (file_name_index file) +{ + m_file = file; + + const file_entry *fe = current_file (); + if (fe == NULL) + dwarf2_debug_line_missing_file_complaint (); + else + { + m_line_has_non_zero_discriminator = m_discriminator != 0; + dwarf2_start_subfile (m_cu, *fe, *m_line_header); + } +} + +void +lnp_state_machine::handle_const_add_pc () +{ + CORE_ADDR adjust + = (255 - m_line_header->opcode_base) / m_line_header->line_range; + + CORE_ADDR addr_adj + = (((m_op_index + adjust) + / m_line_header->maximum_ops_per_instruction) + * m_line_header->minimum_instruction_length); + + addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); + m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); + m_op_index = ((m_op_index + adjust) + % m_line_header->maximum_ops_per_instruction); +} + +/* Return non-zero if we should add LINE to the line number table. + LINE is the line to add, LAST_LINE is the last line that was added, + LAST_SUBFILE is the subfile for LAST_LINE. + LINE_HAS_NON_ZERO_DISCRIMINATOR is non-zero if LINE has ever + had a non-zero discriminator. + + We have to be careful in the presence of discriminators. + E.g., for this line: + + for (i = 0; i < 100000; i++); + + clang can emit four line number entries for that one line, + each with a different discriminator. + See gdb.dwarf2/dw2-single-line-discriminators.exp for an example. + + However, we want gdb to coalesce all four entries into one. + Otherwise the user could stepi into the middle of the line and + gdb would get confused about whether the pc really was in the + middle of the line. + + Things are further complicated by the fact that two consecutive + line number entries for the same line is a heuristic used by gcc + to denote the end of the prologue. So we can't just discard duplicate + entries, we have to be selective about it. The heuristic we use is + that we only collapse consecutive entries for the same line if at least + one of those entries has a non-zero discriminator. PR 17276. + + Note: Addresses in the line number state machine can never go backwards + within one sequence, thus this coalescing is ok. */ + +static int +dwarf_record_line_p (struct dwarf2_cu *cu, + unsigned int line, unsigned int last_line, + int line_has_non_zero_discriminator, + struct subfile *last_subfile) +{ + if (cu->get_builder ()->get_current_subfile () != last_subfile) + return 1; + if (line != last_line) + return 1; + /* Same line for the same file that we've seen already. + As a last check, for pr 17276, only record the line if the line + has never had a non-zero discriminator. */ + if (!line_has_non_zero_discriminator) + return 1; + return 0; +} + +/* Use the CU's builder to record line number LINE beginning at + address ADDRESS in the line table of subfile SUBFILE. */ + +static void +dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile, + unsigned int line, unrelocated_addr address, + linetable_entry_flags flags, + struct dwarf2_cu *cu) +{ + unrelocated_addr addr + = unrelocated_addr (gdbarch_addr_bits_remove (gdbarch, + (CORE_ADDR) address)); + + if (cu != nullptr) + { + if (dwarf_line_debug) + gdb_printf (gdb_stdlog, "Recording line %u, file %s, address %s\n", + line, lbasename (subfile->name.c_str ()), + paddress (gdbarch, (CORE_ADDR) address)); + + cu->get_builder ()->record_line (subfile, line, addr, flags); + } +} + +/* Subroutine of dwarf_decode_lines_1 to simplify it. + Mark the end of a set of line number records. + The arguments are the same as for dwarf_record_line_1. + If SUBFILE is NULL the request is ignored. */ + +static void +dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile, + unrelocated_addr address, struct dwarf2_cu *cu) +{ + if (subfile == NULL) + return; + + if (dwarf_line_debug) + { + gdb_printf (gdb_stdlog, + "Finishing current line, file %s, address %s\n", + lbasename (subfile->name.c_str ()), + paddress (gdbarch, (CORE_ADDR) address)); + } + + dwarf_record_line_1 (gdbarch, subfile, 0, address, LEF_IS_STMT, cu); +} + +void +lnp_state_machine::record_line (bool end_sequence) +{ + if (dwarf_line_debug) + { + gdb_printf (gdb_stdlog, + "Processing actual line %u: file %u," + " address %s, is_stmt %u, prologue_end %u," + " epilogue_begin %u, discrim %u%s\n", + m_line, m_file, + paddress (m_gdbarch, (CORE_ADDR) m_address), + (m_flags & LEF_IS_STMT) != 0, + (m_flags & LEF_PROLOGUE_END) != 0, + (m_flags & LEF_EPILOGUE_BEGIN) != 0, + m_discriminator, + (end_sequence ? "\t(end sequence)" : "")); + } + + file_entry *fe = current_file (); + + if (fe == NULL) + dwarf2_debug_line_missing_file_complaint (); + /* For now we ignore lines not starting on an instruction boundary. + But not when processing end_sequence for compatibility with the + previous version of the code. */ + else if (m_op_index == 0 || end_sequence) + { + /* When we switch files we insert an end maker in the first file, + switch to the second file and add a new line entry. The + problem is that the end marker inserted in the first file will + discard any previous line entries at the same address. If the + line entries in the first file are marked as is-stmt, while + the new line in the second file is non-stmt, then this means + the end marker will discard is-stmt lines so we can have a + non-stmt line. This means that there are less addresses at + which the user can insert a breakpoint. + + To improve this we track the last address in m_last_address, + and whether we have seen an is-stmt at this address. Then + when switching files, if we have seen a stmt at the current + address, and we are switching to create a non-stmt line, then + discard the new line. */ + bool file_changed + = m_last_subfile != m_cu->get_builder ()->get_current_subfile (); + bool ignore_this_line + = ((file_changed && !end_sequence && m_last_address == m_address + && ((m_flags & LEF_IS_STMT) == 0) + && m_stmt_at_address) + || (!end_sequence && m_line == 0)); + + if ((file_changed && !ignore_this_line) || end_sequence) + { + dwarf_finish_line (m_gdbarch, m_last_subfile, m_address, + m_currently_recording_lines ? m_cu : nullptr); + } + + if (!end_sequence && !ignore_this_line) + { + linetable_entry_flags lte_flags = m_flags; + if (m_cu->producer_is_codewarrior ()) + lte_flags |= LEF_IS_STMT; + + if (dwarf_record_line_p (m_cu, m_line, m_last_line, + m_line_has_non_zero_discriminator, + m_last_subfile)) + { + buildsym_compunit *builder = m_cu->get_builder (); + dwarf_record_line_1 (m_gdbarch, + builder->get_current_subfile (), + m_line, m_address, lte_flags, + m_currently_recording_lines ? m_cu : nullptr); + + m_last_subfile = m_cu->get_builder ()->get_current_subfile (); + m_last_line = m_line; + } + } + } + + /* Track whether we have seen any IS_STMT true at m_address in case we + have multiple line table entries all at m_address. */ + if (m_last_address != m_address) + { + m_stmt_at_address = false; + m_last_address = m_address; + } + m_stmt_at_address |= (m_flags & LEF_IS_STMT) != 0; +} + +lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, + line_header *lh) + : m_cu (cu), + m_gdbarch (arch), + m_line_header (lh), + /* Call `gdbarch_adjust_dwarf2_line' on the initial 0 address as + if there was a line entry for it so that the backend has a + chance to adjust it and also record it in case it needs it. + This is currently used by MIPS code, + cf. `mips_adjust_dwarf2_line'. */ + m_address ((unrelocated_addr) gdbarch_adjust_dwarf2_line (arch, 0, 0)), + m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0), + m_last_address (m_address) +{ +} + +void +lnp_state_machine::check_line_address (struct dwarf2_cu *cu, + const gdb_byte *line_ptr, + unrelocated_addr unrelocated_lowpc, + unrelocated_addr address) +{ + /* Linkers resolve a symbolic relocation referencing a GC'd function to 0, + -1 or -2 (-2 is used by certain lld versions, see + https://github.com/llvm/llvm-project/commit/e618ccbf431f6730edb6d1467a127c3a52fd57f7). + If ADDRESS is 0, ignoring the opcode will err if the text section is + located at 0x0. In this case, additionally check that if + ADDRESS < UNRELOCATED_LOWPC. */ + + if ((address == (unrelocated_addr) 0 && address < unrelocated_lowpc) + || address == (unrelocated_addr) -1 + || address == (unrelocated_addr) -2) + { + /* This line table is for a function which has been + GCd by the linker. Ignore it. PR gdb/12528 */ + + struct objfile *objfile = cu->per_objfile->objfile; + long line_offset = line_ptr - get_debug_line_section (cu)->buffer; + + complaint (_(".debug_line address at offset 0x%lx is 0 [in module %s]"), + line_offset, objfile_name (objfile)); + m_currently_recording_lines = false; + /* Note: m_currently_recording_lines is left as false until we see + DW_LNE_end_sequence. */ + } +} + +/* Subroutine of dwarf_decode_lines to simplify it. + Process the line number information in LH. */ + +static void +dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, + unrelocated_addr lowpc) +{ + const gdb_byte *line_ptr, *extended_end; + const gdb_byte *line_end; + unsigned int bytes_read, extended_len; + unsigned char op_code, extended_op; + struct objfile *objfile = cu->per_objfile->objfile; + bfd *abfd = objfile->obfd.get (); + struct gdbarch *gdbarch = objfile->arch (); + + 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) + { + /* The DWARF line number program state machine. Reset the state + machine at the start of each sequence. */ + lnp_state_machine state_machine (cu, gdbarch, lh); + bool end_sequence = false; + + /* Start a subfile for the current file of the state + machine. */ + const file_entry *fe = state_machine.current_file (); + + if (fe != NULL) + dwarf2_start_subfile (cu, *fe, *lh); + + /* Decode the table. */ + while (line_ptr < line_end && !end_sequence) + { + op_code = read_1_byte (abfd, line_ptr); + line_ptr += 1; + + if (op_code >= lh->opcode_base) + { + /* Special opcode. */ + state_machine.handle_special_opcode (op_code); + } + else switch (op_code) + { + case DW_LNS_extended_op: + extended_len = read_unsigned_leb128 (abfd, line_ptr, + &bytes_read); + line_ptr += bytes_read; + extended_end = line_ptr + extended_len; + extended_op = read_1_byte (abfd, line_ptr); + line_ptr += 1; + if (DW_LNE_lo_user <= extended_op + && extended_op <= DW_LNE_hi_user) + { + /* Vendor extension, ignore. */ + line_ptr = extended_end; + break; + } + switch (extended_op) + { + case DW_LNE_end_sequence: + state_machine.handle_end_sequence (); + end_sequence = true; + break; + case DW_LNE_set_address: + { + unrelocated_addr address + = cu->header.read_address (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + state_machine.check_line_address (cu, line_ptr, lowpc, + address); + state_machine.handle_set_address (address); + } + break; + case DW_LNE_define_file: + { + const char *cur_file; + unsigned int mod_time, length; + dir_index dindex; + + cur_file = read_direct_string (abfd, line_ptr, + &bytes_read); + line_ptr += bytes_read; + dindex = (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; + lh->add_file_name (cur_file, dindex, mod_time, length); + } + break; + case DW_LNE_set_discriminator: + { + /* The discriminator is not interesting to the + debugger; just ignore it. We still need to + check its value though: + if there are consecutive entries for the same + (non-prologue) line we want to coalesce them. + PR 17276. */ + unsigned int discr + = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + state_machine.handle_set_discriminator (discr); + } + break; + default: + complaint (_("mangled .debug_line section")); + return; + } + /* Make sure that we parsed the extended op correctly. If e.g. + we expected a different address size than the producer used, + we may have read the wrong number of bytes. */ + if (line_ptr != extended_end) + { + complaint (_("mangled .debug_line section")); + return; + } + break; + case DW_LNS_copy: + state_machine.handle_copy (); + break; + case DW_LNS_advance_pc: + { + CORE_ADDR adjust + = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + state_machine.handle_advance_pc (adjust); + } + break; + case DW_LNS_advance_line: + { + int line_delta + = read_signed_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + + state_machine.handle_advance_line (line_delta); + } + break; + case DW_LNS_set_file: + { + file_name_index file + = (file_name_index) read_unsigned_leb128 (abfd, line_ptr, + &bytes_read); + line_ptr += bytes_read; + + state_machine.handle_set_file (file); + } + break; + case DW_LNS_set_column: + (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + break; + case DW_LNS_negate_stmt: + state_machine.handle_negate_stmt (); + break; + case DW_LNS_set_basic_block: + break; + /* Add to the address register of the state machine the + address increment value corresponding to special opcode + 255. I.e., this value is scaled by the minimum + instruction length since special opcode 255 would have + scaled the increment. */ + case DW_LNS_const_add_pc: + state_machine.handle_const_add_pc (); + break; + case DW_LNS_fixed_advance_pc: + { + CORE_ADDR addr_adj = read_2_bytes (abfd, line_ptr); + line_ptr += 2; + + state_machine.handle_fixed_advance_pc (addr_adj); + } + break; + case DW_LNS_set_prologue_end: + state_machine.handle_set_prologue_end (); + break; + case DW_LNS_set_epilogue_begin: + state_machine.handle_set_epilogue_begin (); + break; + default: + { + /* Unknown standard opcode, ignore it. */ + int 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; + } + } + } + } + + if (!end_sequence) + dwarf2_debug_line_missing_end_sequence_complaint (); + + /* We got a DW_LNE_end_sequence (or we ran off the end of the buffer, + in which case we still finish recording the last line). */ + state_machine.record_line (true); + } +} + +/* See dwarf2/line-program.h. */ + +void +dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu, + unrelocated_addr lowpc, int decode_mapping) +{ + if (decode_mapping) + dwarf_decode_lines_1 (lh, cu, lowpc); + + /* Make sure a symtab is created for every file, even files + which contain only variables (i.e. no code with associated + line numbers). */ + buildsym_compunit *builder = cu->get_builder (); + struct compunit_symtab *cust = builder->get_compunit_symtab (); + + for (auto &fe : lh->file_names ()) + { + dwarf2_start_subfile (cu, fe, *lh); + subfile *sf = builder->get_current_subfile (); + + if (sf->symtab == nullptr) + sf->symtab = allocate_symtab (cust, sf->name.c_str (), + sf->name_for_id.c_str ()); + + fe.symtab = sf->symtab; + } +} diff --git a/gdb/dwarf2/line-program.h b/gdb/dwarf2/line-program.h new file mode 100644 index 0000000..c844032 --- /dev/null +++ b/gdb/dwarf2/line-program.h @@ -0,0 +1,47 @@ +/* DWARF 2 debugging format support for GDB. + + Copyright (C) 1994-2025 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef GDB_DWARF2_LINE_PROGRAM_H +#define GDB_DWARF2_LINE_PROGRAM_H + +/* Decode the Line Number Program (LNP) for the given line_header + structure and CU. The actual information extracted and the type + of structures created from the LNP depends on the value of PST. + + FND holds the CU file name and directory, if known. + It is used for relative paths in the line table. + + NOTE: It is important that psymtabs have the same file name (via + strcmp) as the corresponding symtab. Since the directory is not + used in the name of the symtab we don't use it in the name of the + psymtabs we create. E.g. expand_line_sal requires this when + finding psymtabs to expand. A good testcase for this is + mb-inline.exp. + + LOWPC is the lowest address in CU (or 0 if not known). + + Boolean DECODE_MAPPING specifies we need to fully decode .debug_line + for its PC<->lines mapping information. Otherwise only the filename + table is read in. */ + +extern void dwarf_decode_lines (struct line_header *lh, + struct dwarf2_cu *cu, + unrelocated_addr lowpc, int decode_mapping); + +#endif /* GDB_DWARF2_LINE_PROGRAM_H */ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 29650c5..efff522 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -38,6 +38,7 @@ #include "dwarf2/index-cache.h" #include "dwarf2/leb.h" #include "dwarf2/line-header.h" +#include "dwarf2/line-program.h" #include "dwarf2/dwz.h" #include "dwarf2/macro.h" #include "dwarf2/die.h" @@ -787,13 +788,6 @@ static line_header_up dwarf_decode_line_header (sect_offset sect_off, struct dwarf2_cu *cu, const char *comp_dir); -static void dwarf_decode_lines (struct line_header *, - struct dwarf2_cu *, - unrelocated_addr, int decode_mapping); - -static void dwarf2_start_subfile (dwarf2_cu *cu, const file_entry &fe, - const line_header &lh); - static struct symbol *new_symbol (struct die_info *, struct type *, struct dwarf2_cu *, struct symbol * = NULL); @@ -1063,19 +1057,6 @@ static void process_cu_includes (dwarf2_per_objfile *per_objfile); /* Various complaints about symbol reading that don't abort the process. */ static void -dwarf2_debug_line_missing_file_complaint (void) -{ - complaint (_(".debug_line section has line data without a file")); -} - -static void -dwarf2_debug_line_missing_end_sequence_complaint (void) -{ - complaint (_(".debug_line section has line " - "program sequence without an end")); -} - -static void dwarf2_complex_location_expr_complaint (void) { complaint (_("location expression too complex")); @@ -15759,9 +15740,9 @@ die_specification (struct die_info *die, struct dwarf2_cu **spec_cu) return follow_die_ref (die, spec_attr, spec_cu); } -/* A convenience function to find the proper .debug_line section for a CU. */ +/* See dwarf2/read.h. */ -static struct dwarf2_section_info * +struct dwarf2_section_info * get_debug_line_section (struct dwarf2_cu *cu) { struct dwarf2_section_info *section; @@ -15881,739 +15862,9 @@ compute_include_file_name (const struct line_header *lh, const file_entry &fe, return include_name; } -/* State machine to track the state of the line number program. */ - -class lnp_state_machine -{ -public: - /* Initialize a machine state for the start of a line number - program. */ - lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, line_header *lh); - - file_entry *current_file () - { - /* lh->file_names is 0-based, but the file name numbers in the - statement program are 1-based. */ - return m_line_header->file_name_at (m_file); - } - - /* Record the line in the state machine. END_SEQUENCE is true if - we're processing the end of a sequence. */ - void record_line (bool end_sequence); - - /* Check ADDRESS is -1, -2, or zero and less than UNRELOCATED_LOWPC, and if - true nop-out rest of the lines in this sequence. */ - void check_line_address (struct dwarf2_cu *cu, - const gdb_byte *line_ptr, - unrelocated_addr unrelocated_lowpc, - unrelocated_addr address); - - void handle_set_discriminator (unsigned int discriminator) - { - m_discriminator = discriminator; - m_line_has_non_zero_discriminator |= discriminator != 0; - } - - /* Handle DW_LNE_set_address. */ - void handle_set_address (unrelocated_addr address) - { - m_op_index = 0; - m_address - = (unrelocated_addr) gdbarch_adjust_dwarf2_line (m_gdbarch, - (CORE_ADDR) address, - false); - } - - /* Handle DW_LNS_advance_pc. */ - void handle_advance_pc (CORE_ADDR adjust); - - /* Handle a special opcode. */ - void handle_special_opcode (unsigned char op_code); - - /* Handle DW_LNS_advance_line. */ - void handle_advance_line (int line_delta) - { - advance_line (line_delta); - } - - /* Handle DW_LNS_set_file. */ - void handle_set_file (file_name_index file); - - /* Handle DW_LNS_negate_stmt. */ - void handle_negate_stmt () - { - m_flags ^= LEF_IS_STMT; - } - - /* Handle DW_LNS_const_add_pc. */ - void handle_const_add_pc (); - - /* Handle DW_LNS_fixed_advance_pc. */ - void handle_fixed_advance_pc (CORE_ADDR addr_adj) - { - addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); - m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); - m_op_index = 0; - } - - /* Handle DW_LNS_copy. */ - void handle_copy () - { - record_line (false); - m_discriminator = 0; - m_flags &= ~LEF_PROLOGUE_END; - m_flags &= ~LEF_EPILOGUE_BEGIN; - } - - /* Handle DW_LNE_end_sequence. */ - void handle_end_sequence () - { - m_currently_recording_lines = true; - } - - /* Handle DW_LNS_set_prologue_end. */ - void handle_set_prologue_end () - { - m_flags |= LEF_PROLOGUE_END; - } - - void handle_set_epilogue_begin () - { - m_flags |= LEF_EPILOGUE_BEGIN; - } - -private: - /* Advance the line by LINE_DELTA. */ - void advance_line (int line_delta) - { - m_line += line_delta; - - if (line_delta != 0) - m_line_has_non_zero_discriminator = m_discriminator != 0; - } - - struct dwarf2_cu *m_cu; - - gdbarch *m_gdbarch; - - /* The line number header. */ - line_header *m_line_header; - - /* These are part of the standard DWARF line number state machine, - and initialized according to the DWARF spec. */ - - unsigned char m_op_index = 0; - /* The line table index of the current file. */ - file_name_index m_file = 1; - unsigned int m_line = 1; - - /* These are initialized in the constructor. */ - - unrelocated_addr m_address; - linetable_entry_flags m_flags; - unsigned int m_discriminator = 0; - - /* Additional bits of state we need to track. */ - - /* The last file a line number was recorded for. */ - struct subfile *m_last_subfile = NULL; - - /* The address of the last line entry. */ - unrelocated_addr m_last_address; - - /* Set to true when a previous line at the same address (using - m_last_address) had LEF_IS_STMT set in m_flags. This is reset to false - when a line entry at a new address (m_address different to - m_last_address) is processed. */ - bool m_stmt_at_address = false; - - /* When true, record the lines we decode. */ - bool m_currently_recording_lines = true; - - /* The last line number that was recorded, used to coalesce - consecutive entries for the same line. This can happen, for - example, when discriminators are present. PR 17276. */ - unsigned int m_last_line = 0; - bool m_line_has_non_zero_discriminator = false; -}; - -void -lnp_state_machine::handle_advance_pc (CORE_ADDR adjust) -{ - CORE_ADDR addr_adj = (((m_op_index + adjust) - / m_line_header->maximum_ops_per_instruction) - * m_line_header->minimum_instruction_length); - addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); - m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); - m_op_index = ((m_op_index + adjust) - % m_line_header->maximum_ops_per_instruction); -} - -void -lnp_state_machine::handle_special_opcode (unsigned char op_code) -{ - unsigned char adj_opcode = op_code - m_line_header->opcode_base; - unsigned char adj_opcode_d = adj_opcode / m_line_header->line_range; - unsigned char adj_opcode_r = adj_opcode % m_line_header->line_range; - CORE_ADDR addr_adj = (((m_op_index + adj_opcode_d) - / m_line_header->maximum_ops_per_instruction) - * m_line_header->minimum_instruction_length); - addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); - m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); - m_op_index = ((m_op_index + adj_opcode_d) - % m_line_header->maximum_ops_per_instruction); - - int line_delta = m_line_header->line_base + adj_opcode_r; - advance_line (line_delta); - record_line (false); - m_discriminator = 0; - m_flags &= ~LEF_PROLOGUE_END; - m_flags &= ~LEF_EPILOGUE_BEGIN; -} - -void -lnp_state_machine::handle_set_file (file_name_index file) -{ - m_file = file; - - const file_entry *fe = current_file (); - if (fe == NULL) - dwarf2_debug_line_missing_file_complaint (); - else - { - m_line_has_non_zero_discriminator = m_discriminator != 0; - dwarf2_start_subfile (m_cu, *fe, *m_line_header); - } -} - -void -lnp_state_machine::handle_const_add_pc () -{ - CORE_ADDR adjust - = (255 - m_line_header->opcode_base) / m_line_header->line_range; - - CORE_ADDR addr_adj - = (((m_op_index + adjust) - / m_line_header->maximum_ops_per_instruction) - * m_line_header->minimum_instruction_length); - - addr_adj = gdbarch_adjust_dwarf2_line (m_gdbarch, addr_adj, true); - m_address = (unrelocated_addr) ((CORE_ADDR) m_address + addr_adj); - m_op_index = ((m_op_index + adjust) - % m_line_header->maximum_ops_per_instruction); -} - -/* Return non-zero if we should add LINE to the line number table. - LINE is the line to add, LAST_LINE is the last line that was added, - LAST_SUBFILE is the subfile for LAST_LINE. - LINE_HAS_NON_ZERO_DISCRIMINATOR is non-zero if LINE has ever - had a non-zero discriminator. - - We have to be careful in the presence of discriminators. - E.g., for this line: - - for (i = 0; i < 100000; i++); - - clang can emit four line number entries for that one line, - each with a different discriminator. - See gdb.dwarf2/dw2-single-line-discriminators.exp for an example. - - However, we want gdb to coalesce all four entries into one. - Otherwise the user could stepi into the middle of the line and - gdb would get confused about whether the pc really was in the - middle of the line. - - Things are further complicated by the fact that two consecutive - line number entries for the same line is a heuristic used by gcc - to denote the end of the prologue. So we can't just discard duplicate - entries, we have to be selective about it. The heuristic we use is - that we only collapse consecutive entries for the same line if at least - one of those entries has a non-zero discriminator. PR 17276. - - Note: Addresses in the line number state machine can never go backwards - within one sequence, thus this coalescing is ok. */ - -static int -dwarf_record_line_p (struct dwarf2_cu *cu, - unsigned int line, unsigned int last_line, - int line_has_non_zero_discriminator, - struct subfile *last_subfile) -{ - if (cu->get_builder ()->get_current_subfile () != last_subfile) - return 1; - if (line != last_line) - return 1; - /* Same line for the same file that we've seen already. - As a last check, for pr 17276, only record the line if the line - has never had a non-zero discriminator. */ - if (!line_has_non_zero_discriminator) - return 1; - return 0; -} - -/* Use the CU's builder to record line number LINE beginning at - address ADDRESS in the line table of subfile SUBFILE. */ - -static void -dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile, - unsigned int line, unrelocated_addr address, - linetable_entry_flags flags, - struct dwarf2_cu *cu) -{ - unrelocated_addr addr - = unrelocated_addr (gdbarch_addr_bits_remove (gdbarch, - (CORE_ADDR) address)); - - if (cu != nullptr) - { - if (dwarf_line_debug) - gdb_printf (gdb_stdlog, "Recording line %u, file %s, address %s\n", - line, lbasename (subfile->name.c_str ()), - paddress (gdbarch, (CORE_ADDR) address)); - - cu->get_builder ()->record_line (subfile, line, addr, flags); - } -} - -/* Subroutine of dwarf_decode_lines_1 to simplify it. - Mark the end of a set of line number records. - The arguments are the same as for dwarf_record_line_1. - If SUBFILE is NULL the request is ignored. */ - -static void -dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile, - unrelocated_addr address, struct dwarf2_cu *cu) -{ - if (subfile == NULL) - return; - - if (dwarf_line_debug) - { - gdb_printf (gdb_stdlog, - "Finishing current line, file %s, address %s\n", - lbasename (subfile->name.c_str ()), - paddress (gdbarch, (CORE_ADDR) address)); - } - - dwarf_record_line_1 (gdbarch, subfile, 0, address, LEF_IS_STMT, cu); -} - -void -lnp_state_machine::record_line (bool end_sequence) -{ - if (dwarf_line_debug) - { - gdb_printf (gdb_stdlog, - "Processing actual line %u: file %u," - " address %s, is_stmt %u, prologue_end %u," - " epilogue_begin %u, discrim %u%s\n", - m_line, m_file, - paddress (m_gdbarch, (CORE_ADDR) m_address), - (m_flags & LEF_IS_STMT) != 0, - (m_flags & LEF_PROLOGUE_END) != 0, - (m_flags & LEF_EPILOGUE_BEGIN) != 0, - m_discriminator, - (end_sequence ? "\t(end sequence)" : "")); - } - - file_entry *fe = current_file (); - - if (fe == NULL) - dwarf2_debug_line_missing_file_complaint (); - /* For now we ignore lines not starting on an instruction boundary. - But not when processing end_sequence for compatibility with the - previous version of the code. */ - else if (m_op_index == 0 || end_sequence) - { - /* When we switch files we insert an end maker in the first file, - switch to the second file and add a new line entry. The - problem is that the end marker inserted in the first file will - discard any previous line entries at the same address. If the - line entries in the first file are marked as is-stmt, while - the new line in the second file is non-stmt, then this means - the end marker will discard is-stmt lines so we can have a - non-stmt line. This means that there are less addresses at - which the user can insert a breakpoint. - - To improve this we track the last address in m_last_address, - and whether we have seen an is-stmt at this address. Then - when switching files, if we have seen a stmt at the current - address, and we are switching to create a non-stmt line, then - discard the new line. */ - bool file_changed - = m_last_subfile != m_cu->get_builder ()->get_current_subfile (); - bool ignore_this_line - = ((file_changed && !end_sequence && m_last_address == m_address - && ((m_flags & LEF_IS_STMT) == 0) - && m_stmt_at_address) - || (!end_sequence && m_line == 0)); - - if ((file_changed && !ignore_this_line) || end_sequence) - { - dwarf_finish_line (m_gdbarch, m_last_subfile, m_address, - m_currently_recording_lines ? m_cu : nullptr); - } - - if (!end_sequence && !ignore_this_line) - { - linetable_entry_flags lte_flags = m_flags; - if (m_cu->producer_is_codewarrior ()) - lte_flags |= LEF_IS_STMT; - - if (dwarf_record_line_p (m_cu, m_line, m_last_line, - m_line_has_non_zero_discriminator, - m_last_subfile)) - { - buildsym_compunit *builder = m_cu->get_builder (); - dwarf_record_line_1 (m_gdbarch, - builder->get_current_subfile (), - m_line, m_address, lte_flags, - m_currently_recording_lines ? m_cu : nullptr); - - m_last_subfile = m_cu->get_builder ()->get_current_subfile (); - m_last_line = m_line; - } - } - } - - /* Track whether we have seen any IS_STMT true at m_address in case we - have multiple line table entries all at m_address. */ - if (m_last_address != m_address) - { - m_stmt_at_address = false; - m_last_address = m_address; - } - m_stmt_at_address |= (m_flags & LEF_IS_STMT) != 0; -} - -lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, - line_header *lh) - : m_cu (cu), - m_gdbarch (arch), - m_line_header (lh), - /* Call `gdbarch_adjust_dwarf2_line' on the initial 0 address as - if there was a line entry for it so that the backend has a - chance to adjust it and also record it in case it needs it. - This is currently used by MIPS code, - cf. `mips_adjust_dwarf2_line'. */ - m_address ((unrelocated_addr) gdbarch_adjust_dwarf2_line (arch, 0, 0)), - m_flags (lh->default_is_stmt ? LEF_IS_STMT : (linetable_entry_flags) 0), - m_last_address (m_address) -{ -} +/* See dwarf2/read.h. */ void -lnp_state_machine::check_line_address (struct dwarf2_cu *cu, - const gdb_byte *line_ptr, - unrelocated_addr unrelocated_lowpc, - unrelocated_addr address) -{ - /* Linkers resolve a symbolic relocation referencing a GC'd function to 0, - -1 or -2 (-2 is used by certain lld versions, see - https://github.com/llvm/llvm-project/commit/e618ccbf431f6730edb6d1467a127c3a52fd57f7). - If ADDRESS is 0, ignoring the opcode will err if the text section is - located at 0x0. In this case, additionally check that if - ADDRESS < UNRELOCATED_LOWPC. */ - - if ((address == (unrelocated_addr) 0 && address < unrelocated_lowpc) - || address == (unrelocated_addr) -1 - || address == (unrelocated_addr) -2) - { - /* This line table is for a function which has been - GCd by the linker. Ignore it. PR gdb/12528 */ - - struct objfile *objfile = cu->per_objfile->objfile; - long line_offset = line_ptr - get_debug_line_section (cu)->buffer; - - complaint (_(".debug_line address at offset 0x%lx is 0 [in module %s]"), - line_offset, objfile_name (objfile)); - m_currently_recording_lines = false; - /* Note: m_currently_recording_lines is left as false until we see - DW_LNE_end_sequence. */ - } -} - -/* Subroutine of dwarf_decode_lines to simplify it. - Process the line number information in LH. */ - -static void -dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, - unrelocated_addr lowpc) -{ - const gdb_byte *line_ptr, *extended_end; - const gdb_byte *line_end; - unsigned int bytes_read, extended_len; - unsigned char op_code, extended_op; - struct objfile *objfile = cu->per_objfile->objfile; - bfd *abfd = objfile->obfd.get (); - struct gdbarch *gdbarch = objfile->arch (); - - 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) - { - /* The DWARF line number program state machine. Reset the state - machine at the start of each sequence. */ - lnp_state_machine state_machine (cu, gdbarch, lh); - bool end_sequence = false; - - /* Start a subfile for the current file of the state - machine. */ - const file_entry *fe = state_machine.current_file (); - - if (fe != NULL) - dwarf2_start_subfile (cu, *fe, *lh); - - /* Decode the table. */ - while (line_ptr < line_end && !end_sequence) - { - op_code = read_1_byte (abfd, line_ptr); - line_ptr += 1; - - if (op_code >= lh->opcode_base) - { - /* Special opcode. */ - state_machine.handle_special_opcode (op_code); - } - else switch (op_code) - { - case DW_LNS_extended_op: - extended_len = read_unsigned_leb128 (abfd, line_ptr, - &bytes_read); - line_ptr += bytes_read; - extended_end = line_ptr + extended_len; - extended_op = read_1_byte (abfd, line_ptr); - line_ptr += 1; - if (DW_LNE_lo_user <= extended_op - && extended_op <= DW_LNE_hi_user) - { - /* Vendor extension, ignore. */ - line_ptr = extended_end; - break; - } - switch (extended_op) - { - case DW_LNE_end_sequence: - state_machine.handle_end_sequence (); - end_sequence = true; - break; - case DW_LNE_set_address: - { - unrelocated_addr address - = cu->header.read_address (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - - state_machine.check_line_address (cu, line_ptr, lowpc, - address); - state_machine.handle_set_address (address); - } - break; - case DW_LNE_define_file: - { - const char *cur_file; - unsigned int mod_time, length; - dir_index dindex; - - cur_file = read_direct_string (abfd, line_ptr, - &bytes_read); - line_ptr += bytes_read; - dindex = (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; - lh->add_file_name (cur_file, dindex, mod_time, length); - } - break; - case DW_LNE_set_discriminator: - { - /* The discriminator is not interesting to the - debugger; just ignore it. We still need to - check its value though: - if there are consecutive entries for the same - (non-prologue) line we want to coalesce them. - PR 17276. */ - unsigned int discr - = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - - state_machine.handle_set_discriminator (discr); - } - break; - default: - complaint (_("mangled .debug_line section")); - return; - } - /* Make sure that we parsed the extended op correctly. If e.g. - we expected a different address size than the producer used, - we may have read the wrong number of bytes. */ - if (line_ptr != extended_end) - { - complaint (_("mangled .debug_line section")); - return; - } - break; - case DW_LNS_copy: - state_machine.handle_copy (); - break; - case DW_LNS_advance_pc: - { - CORE_ADDR adjust - = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - - state_machine.handle_advance_pc (adjust); - } - break; - case DW_LNS_advance_line: - { - int line_delta - = read_signed_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - - state_machine.handle_advance_line (line_delta); - } - break; - case DW_LNS_set_file: - { - file_name_index file - = (file_name_index) read_unsigned_leb128 (abfd, line_ptr, - &bytes_read); - line_ptr += bytes_read; - - state_machine.handle_set_file (file); - } - break; - case DW_LNS_set_column: - (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; - break; - case DW_LNS_negate_stmt: - state_machine.handle_negate_stmt (); - break; - case DW_LNS_set_basic_block: - break; - /* Add to the address register of the state machine the - address increment value corresponding to special opcode - 255. I.e., this value is scaled by the minimum - instruction length since special opcode 255 would have - scaled the increment. */ - case DW_LNS_const_add_pc: - state_machine.handle_const_add_pc (); - break; - case DW_LNS_fixed_advance_pc: - { - CORE_ADDR addr_adj = read_2_bytes (abfd, line_ptr); - line_ptr += 2; - - state_machine.handle_fixed_advance_pc (addr_adj); - } - break; - case DW_LNS_set_prologue_end: - state_machine.handle_set_prologue_end (); - break; - case DW_LNS_set_epilogue_begin: - state_machine.handle_set_epilogue_begin (); - break; - default: - { - /* Unknown standard opcode, ignore it. */ - int 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; - } - } - } - } - - if (!end_sequence) - dwarf2_debug_line_missing_end_sequence_complaint (); - - /* We got a DW_LNE_end_sequence (or we ran off the end of the buffer, - in which case we still finish recording the last line). */ - state_machine.record_line (true); - } -} - -/* Decode the Line Number Program (LNP) for the given line_header - structure and CU. The actual information extracted and the type - of structures created from the LNP depends on the value of PST. - - FND holds the CU file name and directory, if known. - It is used for relative paths in the line table. - - NOTE: It is important that psymtabs have the same file name (via - strcmp) as the corresponding symtab. Since the directory is not - used in the name of the symtab we don't use it in the name of the - psymtabs we create. E.g. expand_line_sal requires this when - finding psymtabs to expand. A good testcase for this is - mb-inline.exp. - - LOWPC is the lowest address in CU (or 0 if not known). - - Boolean DECODE_MAPPING specifies we need to fully decode .debug_line - for its PC<->lines mapping information. Otherwise only the filename - table is read in. */ - -static void -dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu, - unrelocated_addr lowpc, int decode_mapping) -{ - if (decode_mapping) - dwarf_decode_lines_1 (lh, cu, lowpc); - - /* Make sure a symtab is created for every file, even files - which contain only variables (i.e. no code with associated - line numbers). */ - buildsym_compunit *builder = cu->get_builder (); - struct compunit_symtab *cust = builder->get_compunit_symtab (); - - for (auto &fe : lh->file_names ()) - { - dwarf2_start_subfile (cu, fe, *lh); - subfile *sf = builder->get_current_subfile (); - - if (sf->symtab == nullptr) - sf->symtab = allocate_symtab (cust, sf->name.c_str (), - sf->name_for_id.c_str ()); - - fe.symtab = sf->symtab; - } -} - -/* Start a subfile for DWARF. FILENAME is the name of the file and - DIRNAME the name of the source directory which contains FILENAME - or NULL if not known. - This routine tries to keep line numbers from identical absolute and - relative file names in a common subfile. - - Using the `list' example from the GDB testsuite, which resides in - /srcdir and compiling it with Irix6.2 cc in /compdir using a filename - of /srcdir/list0.c yields the following debugging information for list0.c: - - DW_AT_name: /srcdir/list0.c - DW_AT_comp_dir: /compdir - files.files[0].name: list0.h - files.files[0].dir: /srcdir - files.files[1].name: list0.c - files.files[1].dir: /srcdir - - The line number information for list0.c has to end up in a single - subfile, so that `break /srcdir/list0.c:1' works as expected. - start_subfile will ensure that this happens provided that we pass the - concatenation of files.files[1].dir and files.files[1].name as the - subfile's name. */ - -static void dwarf2_start_subfile (dwarf2_cu *cu, const file_entry &fe, const line_header &lh) { diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 74ec420..b9be541 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -54,6 +54,7 @@ struct dwarf2_cu; struct dwarf2_debug_sections; struct dwarf2_per_bfd; struct dwarf2_per_cu; +struct file_entry; struct mapped_index; struct mapped_debug_names; struct signatured_type; @@ -1351,4 +1352,34 @@ extern file_and_directory &find_file_and_directory (die_info *die, extern const dwarf2_section_info &get_section_for_ref (const attribute &attr, dwarf2_cu *cu); +/* A convenience function to find the proper .debug_line section for a CU. */ + +extern struct dwarf2_section_info *get_debug_line_section + (struct dwarf2_cu *cu); + +/* Start a subfile for DWARF. FILENAME is the name of the file and + DIRNAME the name of the source directory which contains FILENAME + or NULL if not known. + This routine tries to keep line numbers from identical absolute and + relative file names in a common subfile. + + Using the `list' example from the GDB testsuite, which resides in + /srcdir and compiling it with Irix6.2 cc in /compdir using a filename + of /srcdir/list0.c yields the following debugging information for list0.c: + + DW_AT_name: /srcdir/list0.c + DW_AT_comp_dir: /compdir + files.files[0].name: list0.h + files.files[0].dir: /srcdir + files.files[1].name: list0.c + files.files[1].dir: /srcdir + + The line number information for list0.c has to end up in a single + subfile, so that `break /srcdir/list0.c:1' works as expected. + start_subfile will ensure that this happens provided that we pass the + concatenation of files.files[1].dir and files.files[1].name as the + subfile's name. */ +extern void dwarf2_start_subfile (dwarf2_cu *cu, const file_entry &fe, + const line_header &lh); + #endif /* GDB_DWARF2_READ_H */ |