---
gcc/pdbout.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++-
gcc/pdbout.h | 16 +++++
2 files changed, 209 insertions(+), 2 deletions(-)
diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 29b0d1c131f..a4424fa470d 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -32,6 +32,7 @@
#include "function.h"
#include "output.h"
#include "target.h"
+#include "md5.h"
#include "rtl.h"
#include "insn-config.h"
#include "reload.h"
@@ -47,9 +48,12 @@ static void pdbout_begin_prologue (unsigned int line
ATTRIBUTE_UNUSED,
const char *file ATTRIBUTE_UNUSED);
static void pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
const char *file ATTRIBUTE_UNUSED);
+static void pdbout_init (const char *filename);
static void pdbout_finish (const char *filename);
static void pdbout_begin_function (tree func);
static void pdbout_late_global_decl (tree var);
+static void pdbout_start_source_file (unsigned int line ATTRIBUTE_UNUSED,
+ const char *file);
static void pdbout_function_decl (tree decl);
static void pdbout_var_location (rtx_insn * loc_note);
static void pdbout_begin_block (unsigned int line ATTRIBUTE_UNUSED,
@@ -63,6 +67,9 @@ static struct pdb_func *funcs = NULL, *cur_func = NULL;
static struct pdb_block *cur_block = NULL;
static struct pdb_global_var *global_vars = NULL;
static struct pdb_type *types = NULL, *last_type = NULL;
+static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
+static uint32_t source_file_string_offset = 1;
+static unsigned int num_source_files = 0;
static unsigned int var_loc_number = 1;
static hash_table <pdb_type_tree_hasher> tree_hash_table (31);
static struct pdb_type *byte_type, *signed_byte_type, *wchar_type,
@@ -79,13 +86,13 @@ static struct pdb_type *void_type, *nullptr_type;
static bool builtins_initialized = false;
const struct gcc_debug_hooks pdb_debug_hooks = {
- debug_nothing_charstar, /* init */
+ pdbout_init,
pdbout_finish,
debug_nothing_charstar, /* early_finish */
debug_nothing_void, /* assembly_start */
debug_nothing_int_charstar, /* define */
debug_nothing_int_charstar, /* undef */
- debug_nothing_int_charstar, /* start_source_file */
+ pdbout_start_source_file,
debug_nothing_int, /* end_source_file */
pdbout_begin_block,
pdbout_end_block,
@@ -576,6 +583,40 @@ pdbout_data32 (struct pdb_global_var *v)
fprintf (asm_out_file, "\t.balign\t4\n");
}
+/* Output names of the files which make up this translation unit,
+ * along with their MD5 checksums. */
+static void
+write_file_checksums ()
+{
+ fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_FILECHKSMS);
+ fprintf (asm_out_file, "\t.long\t[.Lchksumsend]-[.Lchksumsstart]\n");
+ fprintf (asm_out_file, ".Lchksumsstart:\n");
+
+ while (source_files)
+ {
+ struct pdb_source_file *n;
+
+ fprintf (asm_out_file, "\t.long\t0x%x\n", source_files->str_offset);
+ fprintf (asm_out_file, "\t.byte\t0x%x\n", 16); // length of MD5 hash
+ fprintf (asm_out_file, "\t.byte\t0x%x\n", CHKSUM_TYPE_MD5);
+
+ for (unsigned int i = 0; i < 16; i++)
+ {
+ fprintf (asm_out_file, "\t.byte\t0x%x\n", source_files->hash[i]);
+ }
+
+ fprintf (asm_out_file, "\t.short\t0\n");
+
+ n = source_files->next;
+
+ free (source_files);
+
+ source_files = n;
+ }
+
+ fprintf (asm_out_file, ".Lchksumsend:\n");
+}
+
/* Output the .debug$S section, which has everything except the
* type definitions (global variables, functions, string table,
* file checksums, line numbers).
@@ -587,6 +628,7 @@ pdbout_data32 (struct pdb_global_var *v)
static void
write_pdb_section (void)
{
+ struct pdb_source_file *psf;
struct pdb_func *func;
fprintf (asm_out_file, "\t.section\t.debug$S, \"ndr\"\n");
@@ -625,6 +667,27 @@ write_pdb_section (void)
fprintf (asm_out_file, ".Lsymend:\n");
+ fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_STRINGTABLE);
+ fprintf (asm_out_file, "\t.long\t[.Lstrtableend]-[.Lstrtablestart]\n");
+ fprintf (asm_out_file, ".Lstrtablestart:\n");
+ fprintf (asm_out_file, "\t.byte\t0\n");
+
+ psf = source_files;
+ while (psf)
+ {
+ size_t name_len = strlen (psf->name);
+
+ ASM_OUTPUT_ASCII (asm_out_file, psf->name + name_len + 1,
+ strlen (psf->name + name_len + 1) + 1);
+
+ psf = psf->next;
+ }
+
+ fprintf (asm_out_file, "\t.balign\t4\n");
+ fprintf (asm_out_file, ".Lstrtableend:\n");
+
+ write_file_checksums ();
+
while (funcs)
{
struct pdb_func *n = funcs->next;
@@ -993,6 +1056,134 @@ find_type (tree t)
return NULL;
}
+#ifndef _WIN32
+/* Given a Unix-style path, construct a fake Windows path, which is what windbg
+ * and Visual Studio are expecting. This maps / to Z:\, which is the default
+ * behaviour on Wine. */
+static char *
+make_windows_path (char *src)
+{
+ size_t len = strlen (src);
+ char *dest = (char *) xmalloc (len + 3);
+ char *in, *ptr;
+
+ ptr = dest;
+ *ptr = 'Z';
+ ptr++;
+ *ptr = ':';
+ ptr++;
+
+ in = src;
+
+ for (unsigned int i = 0; i < len; i++)
+ {
+ if (*in == '/')
+ *ptr = '\\';
+ else
+ *ptr = *in;
+
+ in++;
+ ptr++;
+ }
+
+ *ptr = 0;
+
+ free (src);
+
+ return dest;
+}
+#endif
+
+/* Add a source file to the list of files making up this translation unit.
+ * Non-Windows systems will see the filename being given a fake Windows-style
+ * path, so as not to confuse Microsoft's debuggers.
+ * This also includes a MD5 checksum, which MSVC uses to tell if a file has
+ * been modified since compilation. Recent versions of MSVC seem to use SHA1
+ * instead. */
+static void
+add_source_file (const char *file)
+{
+ struct pdb_source_file *psf;
+ char *path;
+ size_t file_len, path_len;
+ FILE *f;
+
+ // check not already added
+ psf = source_files;
+ while (psf)
+ {
+ if (!strcmp (psf->name, file))
+ return;
+
+ psf = psf->next;
+ }
+
+ path = lrealpath (file);
+ if (!path)
+ return;
+
+#ifndef _WIN32
+ path = make_windows_path (path);
+#endif
+
+ file_len = strlen (file);
+ path_len = strlen (path);
+
+ f = fopen (file, "r");
+
+ if (!f)
+ {
+ free (path);
+ return;
+ }
+
+ psf =
+ (struct pdb_source_file *)
+ xmalloc (offsetof (struct pdb_source_file, name) + file_len + 1 +
+ path_len + 1);
+
+ md5_stream (f, psf->hash);
+
+ fclose (f);
+
+ psf->next = NULL;
+ psf->str_offset = source_file_string_offset;
+ memcpy (psf->name, file, file_len + 1);
+ memcpy (psf->name + file_len + 1, path, path_len + 1);
+
+ free (path);
+
+ source_file_string_offset += path_len + 1;
+
+ if (last_source_file)
+ last_source_file->next = psf;
+
+ last_source_file = psf;
+
+ if (!source_files)
+ source_files = psf;
+
+ psf->num = num_source_files;
+
+ num_source_files++;
+}
+
+/* We've encountered an #include - add the header file to the
+ * list of source files. */
+static void
+pdbout_start_source_file (unsigned int line ATTRIBUTE_UNUSED,
+ const char *file)
+{
+ add_source_file (file);
+}
+
+/* Start of compilation - add the main source file to the list. */
+static void
+pdbout_init (const char *file)
+{
+ add_source_file (file);
+}
+
/* Given an x86 gcc register no., return the CodeView equivalent. */
static enum pdb_x86_register
map_register_no_x86 (unsigned int regno, machine_mode mode)
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index 9a92a4f9972..bd0a29635e7 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -37,6 +37,13 @@
#define CV_SIGNATURE_C13 4
#define DEBUG_S_SYMBOLS 0xf1
+#define DEBUG_S_STRINGTABLE 0xf3
+#define DEBUG_S_FILECHKSMS 0xf4
+
+#define CHKSUM_TYPE_NONE 0
+#define CHKSUM_TYPE_MD5 1
+#define CHKSUM_TYPE_SHA1 2
+#define CHKSUM_TYPE_SHA_256 3
enum pdb_local_var_type
{
@@ -177,6 +184,15 @@ struct pdb_type_tree_hasher : nofree_ptr_hash <struct
pdb_type>
static inline bool equal (const value_type, compare_type);
};
+struct pdb_source_file
+{
+ struct pdb_source_file *next;
+ uint8_t hash[16];
+ uint32_t str_offset;
+ unsigned int num;
+ char name[1];
+};
+
enum pdb_x86_register
{
CV_X86_NONE = 0,
--
2.26.2