mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-05 23:23:09 +00:00
This changes dwarf_record_line_1 to be a method of lnp_state_machine, simplifying it a bit. Approved-By: Simon Marchi <simon.marchi@efficios.com>
721 lines
22 KiB
C
721 lines
22 KiB
C
/* 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;
|
|
}
|
|
}
|