--- 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