@@ -29,14 +29,25 @@
#include "tree.h"
#include "debug.h"
#include "pdbout.h"
+#include "function.h"
#include "output.h"
#include "target.h"
+#define FUNC_BEGIN_LABEL ".Lstartfunc"
+#define FUNC_END_LABEL ".Lendfunc"
+
+static void pdbout_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
+ unsigned int column 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_finish (const char *filename);
+static void pdbout_begin_function (tree func);
static void pdbout_late_global_decl (tree var);
static struct pdb_type *find_type (tree t);
+static struct pdb_func *funcs = NULL, *cur_func = NULL;
static struct pdb_global_var *global_vars = NULL;
static struct pdb_type *types = NULL, *last_type = NULL;
static hash_table <pdb_type_tree_hasher> tree_hash_table (31);
@@ -66,11 +77,11 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
debug_nothing_int_int, /* end_block */
debug_true_const_tree, /* ignore_block */
debug_nothing_int_int_charstar_int_bool, /* source_line */
- debug_nothing_int_int_charstar, /* begin_prologue */
+ pdbout_begin_prologue,
debug_nothing_int_charstar, /* end_prologue */
debug_nothing_int_charstar, /* begin_epilogue */
- debug_nothing_int_charstar, /* end_epilogue */
- debug_nothing_tree, /* begin_function */
+ pdbout_end_epilogue,
+ pdbout_begin_function,
debug_nothing_int, /* end_function */
debug_nothing_tree, /* register_main_translation_unit */
debug_nothing_tree, /* function_decl */
@@ -93,6 +104,84 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
TYPE_SYMTAB_IS_ADDRESS /* tree_type_symtab_field */
};
+/* Add label before function start */
+static void
+pdbout_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
+ unsigned int column ATTRIBUTE_UNUSED,
+ const char *file ATTRIBUTE_UNUSED)
+{
+ fprintf (asm_out_file, FUNC_BEGIN_LABEL "%u:\n",
+ current_function_funcdef_no);
+}
+
+/* Add label after function end */
+static void
+pdbout_end_epilogue (unsigned int line ATTRIBUTE_UNUSED,
+ const char *file ATTRIBUTE_UNUSED)
+{
+ fprintf (asm_out_file, FUNC_END_LABEL "%u:\n", current_function_funcdef_no);
+}
+
+/* Output PROCSYM32 structure, which describes a global function (S_GPROC32)
+ * or a local (i.e. static) one (S_LPROC32). */
+static void
+pdbout_proc32 (struct pdb_func *func)
+{
+ size_t name_len = func->name ? strlen (func->name) : 0;
+ uint16_t len = 40 + name_len, align;
+
+ // start procedure
+
+ if (len % 4 != 0)
+ {
+ align = 4 - (len % 4);
+ len += 4 - (len % 4);
+ }
+ else
+ align = 0;
+
+ fprintf (asm_out_file, ".Lcvprocstart%u:\n", func->num);
+ fprintf (asm_out_file, "\t.short\t0x%x\n",
+ (uint16_t) (len - sizeof (uint16_t))); // reclen
+ fprintf (asm_out_file, "\t.short\t0x%x\n",
+ func->public_flag ? S_GPROC32 : S_LPROC32);
+ fprintf (asm_out_file, "\t.long\t0\n"); // pParent
+ fprintf (asm_out_file, "\t.long\t[.Lcvprocend%u]-[.debug$S]\n",
+ func->num); // pEnd
+ fprintf (asm_out_file, "\t.long\t0\n"); // pNext
+ fprintf (asm_out_file,
+ "\t.long\t[" FUNC_END_LABEL "%u]-[" FUNC_BEGIN_LABEL "%u]\n",
+ func->num, func->num); // len
+ fprintf (asm_out_file, "\t.long\t0\n"); // DbgStart
+ fprintf (asm_out_file, "\t.long\t0\n"); // DbgEnd
+ fprintf (asm_out_file, "\t.short\t0x%x\n", func->type ? func->type->id : 0);
+ fprintf (asm_out_file, "\t.short\t0\n"); // padding
+
+ fprintf (asm_out_file, "\t.secrel32\t" FUNC_BEGIN_LABEL "%u\n",
+ func->num); // offset
+ fprintf (asm_out_file, "\t.secidx\t" FUNC_BEGIN_LABEL "%u\n",
+ func->num); // section
+
+ fprintf (asm_out_file, "\t.byte\t0\n"); // flags
+
+ if (func->name)
+ ASM_OUTPUT_ASCII (asm_out_file, func->name, name_len + 1);
+ else
+ fprintf (asm_out_file, "\t.byte\t0\n");
+
+ for (unsigned int i = 0; i < align; i++)
+ {
+ fprintf (asm_out_file, "\t.byte\t0\n");
+ }
+
+ // end procedure
+
+ fprintf (asm_out_file, ".Lcvprocend%u:\n", func->num);
+
+ fprintf (asm_out_file, "\t.short\t0x2\n");
+ fprintf (asm_out_file, "\t.short\t0x%x\n", S_END);
+}
+
/* Output DATASYM32 structure, describing a global variable: either
* one with file-level scope (S_LDATA32) or global scope (S_GDATA32). */
static void
@@ -138,6 +227,8 @@ pdbout_data32 (struct pdb_global_var *v)
static void
write_pdb_section (void)
{
+ struct pdb_func *func;
+
fprintf (asm_out_file, "\t.section\t.debug$S, \"ndr\"\n");
fprintf (asm_out_file, "\t.long\t0x%x\n", CV_SIGNATURE_C13);
fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_SYMBOLS);
@@ -164,7 +255,27 @@ write_pdb_section (void)
global_vars = n;
}
+ func = funcs;
+ while (func)
+ {
+ pdbout_proc32 (func);
+
+ func = func->next;
+ }
+
fprintf (asm_out_file, ".Lsymend:\n");
+
+ while (funcs)
+ {
+ struct pdb_func *n = funcs->next;
+
+ if (funcs->name)
+ free (funcs->name);
+
+ free (funcs);
+
+ funcs = n;
+ }
}
/* We've finished compilation - output the .debug$S section
@@ -175,6 +286,38 @@ pdbout_finish (const char *filename ATTRIBUTE_UNUSED)
write_pdb_section ();
}
+/* For a tree t, construct the name. */
+static char *
+get_tree_name (tree t)
+{
+ char *name;
+
+ if (TREE_CODE (t) == FUNCTION_DECL)
+ name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (t)));
+ else
+ return NULL;
+
+ return name;
+}
+
+/* We've been passed a function definition - allocate and initialize a pdb_func
+ * struct to represent it. */
+static void
+pdbout_begin_function (tree func)
+{
+ struct pdb_func *f = (struct pdb_func *) xmalloc (sizeof (struct pdb_func));
+
+ f->next = funcs;
+ f->name = get_tree_name (func);
+ f->num = current_function_funcdef_no;
+ f->public_flag = TREE_PUBLIC (func);
+ f->type = find_type (TREE_TYPE (func));
+
+ funcs = f;
+
+ cur_func = f;
+}
+
/* We've been passed a late global declaration, i.e. a global variable -
* allocate a pdb_global_var struct and add it to the list of globals. */
static void
@@ -20,14 +20,26 @@
#ifndef GCC_PDBOUT_H
#define GCC_PDBOUT_H 1
+#define S_END 0x0006
#define S_LDATA32 0x110c
#define S_GDATA32 0x110d
+#define S_LPROC32 0x110f
+#define S_GPROC32 0x1110
/* Format version as of MSVC 7 */
#define CV_SIGNATURE_C13 4
#define DEBUG_S_SYMBOLS 0xf1
+struct pdb_func
+{
+ struct pdb_func *next;
+ char *name;
+ int num;
+ unsigned int public_flag;
+ struct pdb_type *type;
+};
+
struct pdb_global_var
{
struct pdb_global_var *next;