@@ -45,6 +45,7 @@ line_header::add_include_dir (const char *include_dir)
void
line_header::add_file_name (const char *name,
dir_index d_index,
+ const char *source,
unsigned int mod_time,
unsigned int length)
{
@@ -54,7 +55,7 @@ line_header::add_file_name (const char *name,
if (dwarf_line_debug >= 2)
gdb_printf (gdb_stdlog, "Adding file %d: %s\n", index, name);
- m_file_names.emplace_back (name, index, d_index, mod_time, length);
+ m_file_names.emplace_back (name, index, d_index, source, mod_time, length);
}
std::string
@@ -125,6 +126,7 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
void (*callback) (struct line_header *lh,
const char *name,
dir_index d_index,
+ const char *source,
unsigned int mod_time,
unsigned int length))
{
@@ -239,13 +241,17 @@ read_formatted_entries (dwarf2_per_objfile *per_objfile, bfd *abfd,
break;
case DW_LNCT_MD5:
break;
+ case DW_LNCT_llvm_SOURCE:
+ case DW_LNCT_SOURCE:
+ fe.source = *string;
+ break;
default:
complaint (_("Unknown format content type %s"),
pulongest (content_type));
}
}
- callback (lh, fe.name, fe.d_index, fe.mod_time, fe.length);
+ callback (lh, fe.name, fe.d_index, fe.source, fe.mod_time, fe.length);
}
*bufp = buf;
@@ -368,8 +374,8 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (),
offset_size,
[] (struct line_header *header, const char *name,
- dir_index d_index, unsigned int mod_time,
- unsigned int length)
+ dir_index d_index, const char *source,
+ unsigned int mod_time, unsigned int length)
{
header->add_include_dir (name);
});
@@ -378,10 +384,10 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
read_formatted_entries (per_objfile, abfd, &line_ptr, lh.get (),
offset_size,
[] (struct line_header *header, const char *name,
- dir_index d_index, unsigned int mod_time,
- unsigned int length)
+ dir_index d_index, const char *source,
+ unsigned int mod_time, unsigned int length)
{
- header->add_file_name (name, d_index, mod_time, length);
+ header->add_file_name (name, d_index, source, mod_time, length);
});
}
else
@@ -408,7 +414,7 @@ dwarf_decode_line_header (sect_offset sect_off, bool is_dwz,
length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
- lh->add_file_name (cur_file, d_index, mod_time, length);
+ lh->add_file_name (cur_file, d_index, nullptr, mod_time, length);
}
line_ptr += bytes_read;
}
@@ -35,9 +35,10 @@ struct file_entry
file_entry () = default;
file_entry (const char *name_, file_name_index index_, dir_index d_index_,
- unsigned int mod_time_, unsigned int length_)
+ const char *source_, unsigned int mod_time_, unsigned int length_)
: name (name_),
index (index_),
+ source (source_),
d_index (d_index_),
mod_time (mod_time_),
length (length_)
@@ -54,6 +55,10 @@ struct file_entry
/* The index of this file in the file table. */
file_name_index index {};
+ /* The file's contents (if not null). Note this is an observing pointer.
+ The memory is owned by debug_line_buffer. */
+ const char *source {};
+
/* The directory index (1-based). */
dir_index d_index {};
@@ -88,7 +93,7 @@ struct line_header
void add_include_dir (const char *include_dir);
/* Add an entry to the file name table. */
- void add_file_name (const char *name, dir_index d_index,
+ void add_file_name (const char *name, dir_index d_index, const char *source,
unsigned int mod_time, unsigned int length);
/* Return the include dir at INDEX (0-based in DWARF 5 and 1-based before).
@@ -18426,7 +18426,7 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
length =
read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
line_ptr += bytes_read;
- lh->add_file_name (cur_file, dindex, mod_time, length);
+ lh->add_file_name (cur_file, dindex, nullptr, mod_time, length);
}
break;
case DW_LNE_set_discriminator:
@@ -18581,9 +18581,12 @@ dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu,
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 ());
-
+ {
+ sf->symtab = allocate_symtab (cust, sf->name.c_str (),
+ sf->name_for_id.c_str ());
+ if (fe.source)
+ sf->symtab->source = cu->per_objfile->objfile->intern (fe.source);
+ }
fe.symtab = sf->symtab;
}
}
@@ -29,9 +29,11 @@
#include "gdbsupport/filestuff.h"
#include <sys/types.h>
+#include <sys/time.h>
#include <fcntl.h>
#include "gdbcore.h"
#include "gdbsupport/gdb_regex.h"
+#include "gdbsupport/gdb_unlinker.h"
#include "symfile.h"
#include "objfiles.h"
#include "annotate.h"
@@ -1135,6 +1137,67 @@ find_and_open_source (const char *filename,
return scoped_fd (result);
}
+/* Open an embedded source file given a symtab S. Returns a file descriptor
+ or negative errno for error. */
+
+scoped_fd
+open_embedded_source(struct symtab *s,
+ gdb::unique_xmalloc_ptr<char> *fullname)
+{
+ if (!s->source || !strlen (s->source))
+ return scoped_fd (-1);
+
+ /* Make a temporary file in the same directory as the object file. */
+ std::string dirname = ldirname (objfile_name (s->compunit ()-> objfile
+ ()));
+ std::string filename = lbasename (s->filename);
+ gdb::char_vector temp_name = make_temp_filename (dirname +
+ SLASH_STRING +
+ filename);
+ scoped_fd fd = gdb_mkostemp_cloexec (temp_name.data (),
+ O_TEXT);
+ if (fd.get () < 0)
+ return fd;
+
+ /* Always unlink. Noone else needs the file by name. */
+ gdb::unlinker unlink (temp_name.data ());
+
+ /* Write the source contents into it. */
+ size_t source_len = strlen (s->source);
+ if (source_len != write(fd.get (), s->source, source_len))
+ {
+ close (fd.get ());
+ return scoped_fd (-1);
+ }
+
+ if (lseek(fd.get (), 0, SEEK_SET))
+ {
+ close (fd.get ());
+ return scoped_fd (-1);
+ }
+
+ /* Adjust its time(s) so that gdb doesn't print an awkward
+ message about it being more recent than the exe. */
+ time_t mtime = 0;
+ if (s->compunit ()->objfile () != NULL
+ && s->compunit ()->objfile ()->obfd != NULL)
+ mtime = s->compunit ()->objfile ()->mtime;
+ else if (current_program_space->exec_bfd ())
+ mtime = current_program_space->ebfd_mtime;
+
+ struct timeval tvs[2] = {};
+ tvs[0].tv_sec = mtime;
+ tvs[1].tv_sec = mtime;
+ if (futimes (fd.get (), tvs) < 0)
+ {
+ close (fd.get ());
+ return scoped_fd (-1);
+ }
+
+ *fullname = make_unique_xstrdup (temp_name.data ());
+ return fd;
+}
+
/* Open a source file given a symtab S. Returns a file descriptor or
negative errno for error.
@@ -1148,7 +1211,15 @@ open_source_file (struct symtab *s)
gdb::unique_xmalloc_ptr<char> fullname (s->fullname);
s->fullname = NULL;
- scoped_fd fd = find_and_open_source (s->filename, s->compunit ()->dirname (),
+
+ scoped_fd fd = open_embedded_source(s, &fullname);
+ if (fd.get () >= 0)
+ {
+ s->fullname = fullname.release ();
+ return fd;
+ }
+
+ fd = find_and_open_source (s->filename, s->compunit ()->dirname (),
&fullname);
if (fd.get () < 0)
@@ -85,6 +85,10 @@ extern gdb::unique_xmalloc_ptr<char> find_source_or_rewrite
negative errno indicating the reason for the failure. */
extern scoped_fd open_source_file (struct symtab *s);
+extern scoped_fd
+open_embedded_source(struct symtab *s,
+ gdb::unique_xmalloc_ptr<char> *fullname);
+
extern gdb::unique_xmalloc_ptr<char> rewrite_source_path (const char *path);
extern const char *symtab_to_fullname (struct symtab *s);
@@ -1755,6 +1755,8 @@ struct symtab
const char *filename;
+ const char *source;
+
/* Filename for this source file, used as an identifier to link with
related objects such as associated macro_source_file objects. It must
therefore match the name of any macro_source_file object created for this
new file mode 100644
@@ -0,0 +1,24 @@
+/* Copyright 2022-2024 Free Software Foundation, Inc.
+
+ 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/>. */
+
+
+int
+main (void)
+{ /* main prologue */
+ asm ("main_label: .global main_label");
+ int m = 42; /* main assign m */
+ asm ("main_end: .global main_end"); /* main end */
+ return m;
+}
new file mode 100644
@@ -0,0 +1,85 @@
+# Copyright 2022-2024 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Check that GDB can honor LNCT_llvm_SOURCE.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+require dwarf2_support
+
+standard_testfile .c .S
+
+set asm_file [standard_output_file $srcfile2]
+
+set fp [open "${srcdir}/${subdir}/${srcfile}" r]
+set srcfile_data [read $fp]
+close $fp
+
+Dwarf::assemble $asm_file {
+ global srcdir subdir srcfile srcfile2 srcfile_data
+ declare_labels lines_label
+
+ get_func_info main
+
+ cu {} {
+ compile_unit {
+ {language @DW_LANG_C}
+ {name missing-file.c}
+ {stmt_list ${lines_label} DW_FORM_sec_offset}
+ } {
+ subprogram {
+ {external 1 flag}
+ {name main}
+ {low_pc $main_start addr}
+ {high_pc "$main_start + $main_len" addr}
+ }
+ }
+ }
+
+ lines {version 5} lines_label {
+ set diridx [include_dir "${srcdir}/${subdir}"]
+ file_name "missing-file.c" $diridx "${srcfile_data}"
+
+ program {
+ DW_LNS_set_file $diridx
+ DW_LNE_set_address $main_start
+ line [gdb_get_line_number "main prologue"]
+ DW_LNS_copy
+
+ DW_LNE_set_address main_label
+ line [gdb_get_line_number "main assign m"]
+ DW_LNS_copy
+
+ DW_LNE_set_address main_end
+ line [gdb_get_line_number "main end"]
+ DW_LNS_copy
+
+ DW_LNE_end_sequence
+ }
+ }
+}
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+ [list $srcfile $asm_file] {nodebug}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+set assign_m_line [gdb_get_line_number "main assign m"]
+gdb_test "frame" ".*main \\\(\\\) at \[^\r\n\]*:$assign_m_line\r\n.*"
@@ -2423,9 +2423,9 @@ namespace eval Dwarf {
# Add a file name entry to the line table header's file names table.
#
# Return the index by which this entry can be referred to.
- proc file_name {filename diridx} {
+ proc file_name {filename diridx { source "" }} {
variable _line_file_names
- lappend _line_file_names $filename $diridx
+ lappend _line_file_names $filename $diridx $source
if { $Dwarf::_line_unit_version >= 5 } {
return [expr [llength $_line_file_names] - 1]
@@ -2481,7 +2481,7 @@ namespace eval Dwarf {
}
}
- _op .byte 2 "file_name_entry_format_count"
+ _op .byte 3 "file_name_entry_format_count"
_op .uleb128 1 \
"file_name_entry_format (content type code: DW_LNCT_path)"
switch $_line_string_form {
@@ -2494,6 +2494,11 @@ namespace eval Dwarf {
"directory_entry_format (form: DW_FORM_line_strp)"
}
}
+ _op .uleb128 0x2001 \
+ "file_name_entry_format (content type code:
+ DW_LNCT_llvm_source)"
+ _op .uleb128 0x08 \
+ "directory_entry_format (form: DW_FORM_string)"
_op .uleb128 2 \
"file_name_entry_format (content type code: DW_LNCT_directory_index)"
_op .uleb128 0x0f \
@@ -2502,7 +2507,7 @@ namespace eval Dwarf {
set nr_files [expr [llength $_line_file_names] / 2]
_op .byte $nr_files "file_names_count"
- foreach { filename diridx } $_line_file_names {
+ foreach { filename diridx source } $_line_file_names {
switch $_line_string_form {
string {
_op .ascii [_quote $filename]
@@ -2516,6 +2521,7 @@ namespace eval Dwarf {
_op_offset [expr $_line_is_64 ? 8 : 4] $string_ptr
}
}
+ _op .ascii [_quote [string map { "\"" "\\\"" "\n" "\\n" } "$source"]]
_op .uleb128 $diridx
}
} else {
@@ -288,7 +288,9 @@ enum dwarf_line_number_content_type
DW_LNCT_timestamp = 0x3,
DW_LNCT_size = 0x4,
DW_LNCT_MD5 = 0x5,
+ DW_LNCT_SOURCE = 0x6,
DW_LNCT_lo_user = 0x2000,
+ DW_LNCT_llvm_SOURCE = 0x2001,
DW_LNCT_hi_user = 0x3fff
};