| /* 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; |
| } |
| |
| bool record_line_p (); |
| void finish_line (); |
| void record_line_1 (unsigned int line, linetable_entry_flags flags); |
| |
| struct dwarf2_cu *m_cu; |
| |
| /* The builder associated with the CU. */ |
| buildsym_compunit *m_builder; |
| |
| 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 true 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. */ |
| |
| bool |
| lnp_state_machine::record_line_p () |
| { |
| if (m_builder->get_current_subfile () != m_last_subfile) |
| return true; |
| if (m_line != m_last_line) |
| return true; |
| /* 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 (!m_line_has_non_zero_discriminator) |
| return true; |
| return false; |
| } |
| |
| /* Use the CU's builder to record line number LINE with the given |
| flags. */ |
| |
| void |
| lnp_state_machine::record_line_1 (unsigned int line, |
| linetable_entry_flags flags) |
| { |
| if (m_currently_recording_lines) |
| { |
| unrelocated_addr addr |
| = unrelocated_addr (gdbarch_addr_bits_remove (m_gdbarch, |
| (CORE_ADDR) m_address)); |
| |
| if (dwarf_line_debug) |
| gdb_printf (gdb_stdlog, "Recording line %u, file %s, address %s\n", |
| m_line, lbasename (m_last_subfile->name.c_str ()), |
| paddress (m_gdbarch, (CORE_ADDR) addr)); |
| |
| m_builder->record_line (m_last_subfile, line, addr, flags); |
| } |
| } |
| |
| /* Subroutine of dwarf_decode_lines_1 to simplify it. |
| Mark the end of a set of line number records. */ |
| |
| void |
| lnp_state_machine::finish_line () |
| { |
| if (m_last_subfile == nullptr) |
| return; |
| |
| if (dwarf_line_debug) |
| { |
| gdb_printf (gdb_stdlog, |
| "Finishing current line, file %s, address %s\n", |
| lbasename (m_last_subfile->name.c_str ()), |
| paddress (m_gdbarch, (CORE_ADDR) m_address)); |
| } |
| |
| record_line_1 (0, LEF_IS_STMT); |
| } |
| |
| 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_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) |
| finish_line (); |
| |
| 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 (record_line_p ()) |
| { |
| m_last_subfile = m_builder->get_current_subfile (); |
| record_line_1 (m_line, lte_flags); |
| 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_builder (cu->get_builder ()), |
| 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, bool 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; |
| } |
| } |