diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index feaab37cc37..17011134d7a 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -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
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index e3430793ee7..85a1eb548cb 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -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;
