[01/24] Add -gcodeview debugging option

Message ID 20210320162652.23346-1-mark@harmstone.com
State New
Headers show
Series
  • [01/24] Add -gcodeview debugging option
Related show

Commit Message

Mark Harmstone March 20, 2021, 4:26 p.m.
This is a series of patches to allow gcc to emit debugging information
in the PE-specific CodeView format, which allows Microsoft debuggers to
work with mingw EXEs. The format is semi-documented: Microsoft have
open-sourced some of their header files at
https://github.com/microsoft/microsoft-pdb, along with a program
cvdump.exe which outputs the textual form of the data.

This works by adding two new sections to every object file: .debug$T,
which contains the type definitions, and .debug$S, which is everything
else (line numbers, file checksums, symbols). The linker then merges
everything together, resolves any duplicate types etc., and outputs this
as a PDB file. Obviously this needs linker support to be useful - lld
does the job, or you can try my binutils patches at
https://github.com/maharmstone/binutils-gdb/tree/for-gcc.

It also needs support for the asm-pseudo directive .secidx, which
outputs the IMAGE_REL_AMD64_SECTION / IMAGE_REL_I386_SECTION PE
relocations. This is likewise not in mainstream binutils - you can
either try llvm-mc instead of gas, or my binutils repo above.

In terms of debuggers and the like, I've tested this successfully with
Visual Studio, windbg, radare2, and of course the aforementioned cvdump
- I don't think there's any other significant tools which use the
 format.

I've only tested this on x86 and amd64, as I've no idea how you go about
compiling Windows EXEs for arm or aarch64 with gcc, or if such a thing
is possible. The other architectures the format provides for are 16-bit
x86, alpha, mips, m68k, ppc, sh3, arm, aarch64, and ia64 - adding these
would at the very least require updating the register mapping.

If you're looking to test this, Wine makes a good victim: set
CROSSCFLAGS to "-gcodeview" when configuring. You probably also want to
set CFLAGS_FOR_TARGET and CXXFLAGS_FOR_TARGET to "-gcodeview" when
configuring gcc, to make sure that debugging information gets generated
for libgcc etc.

---
 gcc/Makefile.in           |  3 ++
 gcc/common.opt            |  4 +++
 gcc/config/i386/cygming.h |  1 +
 gcc/config/i386/x86-64.h  |  2 ++
 gcc/debug.h               |  1 +
 gcc/defaults.h            |  3 ++
 gcc/doc/invoke.texi       |  7 ++++
 gcc/flag-types.h          |  5 +--
 gcc/gcc.c                 |  6 ++++
 gcc/opts.c                |  4 +++
 gcc/pdbout.c              | 70 +++++++++++++++++++++++++++++++++++++++
 gcc/pdbout.h              | 23 +++++++++++++
 gcc/toplev.c              |  4 +++
 13 files changed, 131 insertions(+), 2 deletions(-)
 create mode 100644 gcc/pdbout.c
 create mode 100644 gcc/pdbout.h

-- 
2.26.2

Comments

Hongtao Liu via Gcc-patches March 22, 2021, 8:29 a.m. | #1
On Sat, Mar 20, 2021 at 5:28 PM Mark Harmstone <mark@harmstone.com> wrote:
>

> This is a series of patches to allow gcc to emit debugging information

> in the PE-specific CodeView format, which allows Microsoft debuggers to

> work with mingw EXEs. The format is semi-documented: Microsoft have

> open-sourced some of their header files at

> https://github.com/microsoft/microsoft-pdb, along with a program

> cvdump.exe which outputs the textual form of the data.

>

> This works by adding two new sections to every object file: .debug$T,

> which contains the type definitions, and .debug$S, which is everything

> else (line numbers, file checksums, symbols). The linker then merges

> everything together, resolves any duplicate types etc., and outputs this

> as a PDB file. Obviously this needs linker support to be useful - lld

> does the job, or you can try my binutils patches at

> https://github.com/maharmstone/binutils-gdb/tree/for-gcc.

>

> It also needs support for the asm-pseudo directive .secidx, which

> outputs the IMAGE_REL_AMD64_SECTION / IMAGE_REL_I386_SECTION PE

> relocations. This is likewise not in mainstream binutils - you can

> either try llvm-mc instead of gas, or my binutils repo above.

>

> In terms of debuggers and the like, I've tested this successfully with

> Visual Studio, windbg, radare2, and of course the aforementioned cvdump

> - I don't think there's any other significant tools which use the

>  format.

>

> I've only tested this on x86 and amd64, as I've no idea how you go about

> compiling Windows EXEs for arm or aarch64 with gcc, or if such a thing

> is possible. The other architectures the format provides for are 16-bit

> x86, alpha, mips, m68k, ppc, sh3, arm, aarch64, and ia64 - adding these

> would at the very least require updating the register mapping.

>

> If you're looking to test this, Wine makes a good victim: set

> CROSSCFLAGS to "-gcodeview" when configuring. You probably also want to

> set CFLAGS_FOR_TARGET and CXXFLAGS_FOR_TARGET to "-gcodeview" when

> configuring gcc, to make sure that debugging information gets generated

> for libgcc etc.


I see you're adding another debug format via debug_hooks.  Since the goal is
to make DWARF the only debug interface for the frontends pdbout will be another
road-block towards achieving that (apart from deprecating and removing
stabs & friends).

CTF has already been reworked to be generated off the internal DWARF
representation
(but not yet accepted since that's sth for stage1).  How do CV and
DWARF debug differ
and is emitting CV debug from a DWARF representation possible (I
suppose there might
even exist offline conversion tools?)

Note this was communicated multiple times, but maybe not officially
enough.  I'll see to
add some fat commentary above the debug hooks structure (not sure if
that will help
in practice).

Thanks,
Richard.

> ---

>  gcc/Makefile.in           |  3 ++

>  gcc/common.opt            |  4 +++

>  gcc/config/i386/cygming.h |  1 +

>  gcc/config/i386/x86-64.h  |  2 ++

>  gcc/debug.h               |  1 +

>  gcc/defaults.h            |  3 ++

>  gcc/doc/invoke.texi       |  7 ++++

>  gcc/flag-types.h          |  5 +--

>  gcc/gcc.c                 |  6 ++++

>  gcc/opts.c                |  4 +++

>  gcc/pdbout.c              | 70 +++++++++++++++++++++++++++++++++++++++

>  gcc/pdbout.h              | 23 +++++++++++++

>  gcc/toplev.c              |  4 +++

>  13 files changed, 131 insertions(+), 2 deletions(-)

>  create mode 100644 gcc/pdbout.c

>  create mode 100644 gcc/pdbout.h

>

> diff --git a/gcc/Makefile.in b/gcc/Makefile.in

> index 543b477ff18..f0249bde720 100644

> --- a/gcc/Makefile.in

> +++ b/gcc/Makefile.in

> @@ -1476,6 +1476,7 @@ OBJS = \

>         opts-global.o \

>         ordered-hash-map-tests.o \

>         passes.o \

> +       pdbout.o \

>         plugin.o \

>         postreload-gcse.o \

>         postreload.o \

> @@ -2637,6 +2638,8 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \

>    $(srcdir)/hsa-common.c \

>    $(srcdir)/calls.c \

>    $(srcdir)/omp-general.h \

> +  $(srcdir)/pdbout.c \

> +  $(srcdir)/pdbout.h \

>    @all_gtfiles@

>

>  # Compute the list of GT header files from the corresponding C sources,

> diff --git a/gcc/common.opt b/gcc/common.opt

> index d33383b523c..80c488c0d70 100644

> --- a/gcc/common.opt

> +++ b/gcc/common.opt

> @@ -3127,6 +3127,10 @@ gno-pubnames

>  Common Driver Negative(gpubnames) Var(debug_generate_pub_sections, 0) Init(-1)

>  Don't generate DWARF pubnames and pubtypes sections.

>

> +gcodeview

> +Common Driver JoinedOrMissing

> +Generate debug information in CodeView format.

> +

>  gpubnames

>  Common Driver Negative(ggnu-pubnames) Var(debug_generate_pub_sections, 1)

>  Generate DWARF pubnames and pubtypes sections.

> diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h

> index 1b1ea7d3d8a..42191b16c99 100644

> --- a/gcc/config/i386/cygming.h

> +++ b/gcc/config/i386/cygming.h

> @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3.  If not see

>  <http://www.gnu.org/licenses/>.  */

>

>  #define DBX_DEBUGGING_INFO 1

> +#define PDB_DEBUGGING_INFO 1

>  #if TARGET_64BIT_DEFAULT || defined (HAVE_GAS_PE_SECREL32_RELOC)

>  #define DWARF2_DEBUGGING_INFO 1

>  #endif

> diff --git a/gcc/config/i386/x86-64.h b/gcc/config/i386/x86-64.h

> index 88db428f592..e84ee6c4026 100644

> --- a/gcc/config/i386/x86-64.h

> +++ b/gcc/config/i386/x86-64.h

> @@ -91,6 +91,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see

>  #define DWARF2_DEBUGGING_INFO 1

>  #define DWARF2_UNWIND_INFO 1

>

> +#define PDB_DEBUGGING_INFO 1

> +

>  #undef PREFERRED_DEBUGGING_TYPE

>  #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG

>

> diff --git a/gcc/debug.h b/gcc/debug.h

> index 260325920ea..c8f182962dd 100644

> --- a/gcc/debug.h

> +++ b/gcc/debug.h

> @@ -235,6 +235,7 @@ extern const struct gcc_debug_hooks xcoff_debug_hooks;

>  extern const struct gcc_debug_hooks dwarf2_debug_hooks;

>  extern const struct gcc_debug_hooks dwarf2_lineno_debug_hooks;

>  extern const struct gcc_debug_hooks vmsdbg_debug_hooks;

> +extern const struct gcc_debug_hooks pdb_debug_hooks;

>

>  /* Dwarf2 frame information.  */

>

> diff --git a/gcc/defaults.h b/gcc/defaults.h

> index f1a38626624..c6bbb203ef3 100644

> --- a/gcc/defaults.h

> +++ b/gcc/defaults.h

> @@ -922,6 +922,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see

>  #elif defined XCOFF_DEBUGGING_INFO

>  #define PREFERRED_DEBUGGING_TYPE XCOFF_DEBUG

>

> +#elif defined PDB_DEBUGGING_INFO

> +#define PREFERRED_DEBUGGING_TYPE PDB_DEBUG

> +

>  #else

>  /* No debugging format is supported by this target.  */

>  #define PREFERRED_DEBUGGING_TYPE NO_DEBUG

> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi

> index 527d362533a..f83cec6f5e0 100644

> --- a/gcc/doc/invoke.texi

> +++ b/gcc/doc/invoke.texi

> @@ -435,6 +435,7 @@ Objective-C and Objective-C++ Dialects}.

>  -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol

>  -gas-loc-support  -gno-as-loc-support @gol

>  -gas-locview-support  -gno-as-locview-support @gol

> +-gcodeview @gol

>  -gcolumn-info  -gno-column-info @gol

>  -gstatement-frontiers  -gno-statement-frontiers @gol

>  -gvariable-location-views  -gno-variable-location-views @gol

> @@ -8707,6 +8708,12 @@ assembler (GAS) to fail with an error.

>  Produce debugging information in Alpha/VMS debug format (if that is

>  supported).  This is the format used by DEBUG on Alpha/VMS systems.

>

> +@item -gcodeview

> +@opindex gcodeview

> +Produce debugging information in CodeView debug format (if that is

> +supported).  This is the format used by Microsoft Visual C++ on

> +Windows.

> +

>  @item -g@var{level}

>  @itemx -ggdb@var{level}

>  @itemx -gstabs@var{level}

> diff --git a/gcc/flag-types.h b/gcc/flag-types.h

> index b092c563f3d..d4d7bdd5158 100644

> --- a/gcc/flag-types.h

> +++ b/gcc/flag-types.h

> @@ -27,8 +27,9 @@ enum debug_info_type

>    DWARF2_DEBUG,            /* Write Dwarf v2 debug info (using dwarf2out.c).  */

>    XCOFF_DEBUG,     /* Write IBM/Xcoff debug info (using dbxout.c).  */

>    VMS_DEBUG,        /* Write VMS debug info (using vmsdbgout.c).  */

> -  VMS_AND_DWARF2_DEBUG /* Write VMS debug info (using vmsdbgout.c).

> -                          and DWARF v2 debug info (using dwarf2out.c).  */

> +  VMS_AND_DWARF2_DEBUG, /* Write VMS debug info (using vmsdbgout.c).

> +                          and DWARF v2 debug info (using dwarf2out.c).  */

> +  PDB_DEBUG        /* Write CodeView debug info (using pdbout.c).  */

>  };

>

>  enum debug_info_levels

> diff --git a/gcc/gcc.c b/gcc/gcc.c

> index 9f790db0daf..327cb4387db 100644

> --- a/gcc/gcc.c

> +++ b/gcc/gcc.c

> @@ -4289,6 +4289,12 @@ driver_handle_option (struct gcc_options *opts,

>        handle_foffload_option (arg);

>        break;

>

> +    case OPT_gcodeview:

> +      /* If we've generated CodeView debugging information, make sure

> +       * linker creates a PDB file for it. */

> +      add_infile ("--pdb=", "*");

> +      break;

> +

>      default:

>        /* Various driver options need no special processing at this

>          point, having been handled in a prescan above or being

> diff --git a/gcc/opts.c b/gcc/opts.c

> index c212a1a57dc..09b91aa2b87 100644

> --- a/gcc/opts.c

> +++ b/gcc/opts.c

> @@ -2730,6 +2730,10 @@ common_handle_option (struct gcc_options *opts,

>        set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc);

>        break;

>

> +    case OPT_gcodeview:

> +      set_debug_level (PDB_DEBUG, false, "", opts, opts_set, loc);

> +      break;

> +

>      case OPT_gstabs:

>      case OPT_gstabs_:

>        set_debug_level (DBX_DEBUG, code == OPT_gstabs_, arg, opts, opts_set,

> diff --git a/gcc/pdbout.c b/gcc/pdbout.c

> new file mode 100644

> index 00000000000..e8f39bb64ea

> --- /dev/null

> +++ b/gcc/pdbout.c

> @@ -0,0 +1,70 @@

> +/* Output CodeView debugging information from GNU compiler.

> + * Copyright (C) 2021 Mark Harmstone

> + *

> + * This file is part of GCC.

> + *

> + * GCC 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, or (at your option) any later

> + * version.

> + *

> + * GCC 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 GCC; see the file COPYING3.  If not see

> + * <http://www.gnu.org/licenses/>.  */

> +

> +/* The CodeView structure is partially documented - definitions of structures

> + * output below can be found at:

> + * https://github.com/microsoft/microsoft-pdb/blob/master/include/cvinfo.h

> + */

> +

> +#include "config.h"

> +#include "system.h"

> +#include "coretypes.h"

> +#include "tree.h"

> +#include "debug.h"

> +#include "pdbout.h"

> +

> +const struct gcc_debug_hooks pdb_debug_hooks = {

> +  debug_nothing_charstar,      /* init */

> +  debug_nothing_charstar,      /* 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 */

> +  debug_nothing_int,           /* end_source_file */

> +  debug_nothing_int_int,       /* begin_block */

> +  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 */

> +  debug_nothing_int_charstar,  /* end_prologue */

> +  debug_nothing_int_charstar,  /* begin_epilogue */

> +  debug_nothing_int_charstar,  /* end_epilogue */

> +  debug_nothing_tree,          /* begin_function */

> +  debug_nothing_int,           /* end_function */

> +  debug_nothing_tree,          /* register_main_translation_unit */

> +  debug_nothing_tree,          /* function_decl */

> +  debug_nothing_tree,          /* early_global_decl */

> +  debug_nothing_tree,          /* late_global_decl */

> +  debug_nothing_tree_int,      /* type_decl */

> +  debug_nothing_tree_tree_tree_bool_bool,      /* imported_module_or_decl */

> +  debug_false_tree_charstarstar_uhwistar,      /* die_ref_for_decl */

> +  debug_nothing_tree_charstar_uhwi,    /* register_external_die */

> +  debug_nothing_tree,          /* deferred_inline_function */

> +  debug_nothing_tree,          /* outlining_inline_function */

> +  debug_nothing_rtx_code_label,        /* label */

> +  debug_nothing_int,           /* handle_pch */

> +  debug_nothing_rtx_insn,      /* var_location */

> +  debug_nothing_tree,          /* inline_entry */

> +  debug_nothing_tree,          /* size_function */

> +  debug_nothing_void,          /* switch_text_section */

> +  debug_nothing_tree_tree,     /* set_name */

> +  0,                           /* start_end_main_source_file */

> +  TYPE_SYMTAB_IS_ADDRESS       /* tree_type_symtab_field */

> +};

> diff --git a/gcc/pdbout.h b/gcc/pdbout.h

> new file mode 100644

> index 00000000000..f957cd5eca1

> --- /dev/null

> +++ b/gcc/pdbout.h

> @@ -0,0 +1,23 @@

> +/* CodeView structures and constants

> + * Copyright (c) 2021 Mark Harmstone

> + *

> + * This file is part of GCC.

> + *

> + * GCC 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, or (at your option) any later

> + * version.

> + *

> + * GCC 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 GCC; see the file COPYING3.  If not see

> + * <http://www.gnu.org/licenses/>.  */

> +

> +#ifndef GCC_PDBOUT_H

> +#define GCC_PDBOUT_H 1

> +

> +#endif

> diff --git a/gcc/toplev.c b/gcc/toplev.c

> index 5c026feece2..a14a9177ee3 100644

> --- a/gcc/toplev.c

> +++ b/gcc/toplev.c

> @@ -1588,6 +1588,10 @@ process_options (void)

>  #ifdef DWARF2_LINENO_DEBUGGING_INFO

>    else if (write_symbols == DWARF2_DEBUG)

>      debug_hooks = &dwarf2_lineno_debug_hooks;

> +#endif

> +#ifdef PDB_DEBUGGING_INFO

> +  else if (write_symbols == PDB_DEBUG)

> +    debug_hooks = &pdb_debug_hooks;

>  #endif

>    else

>      error_at (UNKNOWN_LOCATION,

> --

> 2.26.2

>
Mark Harmstone March 22, 2021, 12:39 p.m. | #2
Thanks Richard.

> How do CV and DWARF debug differ and is emitting CV debug from a DWARF

> representation possible (I suppose there might even exist offline

> conversion tools?)


I don't know enough about DWARF internals to answer that, but I'd be surprised
if the answer is "no".

Do you mean that the DWARF code would collect the data, and my code would
process it and output the .debug$S and .debug$T sections? So from the point of
view of the linker, everything will be the same?

> I'll see to add some fat commentary above the debug hooks structure (not

> sure if that will help in practice).


This would definitely help. I'd no idea of this before now, and I would have
spotted a DEPRECATED above the struct definition.

Mark
Hongtao Liu via Gcc-patches March 22, 2021, 12:57 p.m. | #3
On Mon, Mar 22, 2021 at 1:39 PM Mark Harmstone <mark@harmstone.com> wrote:
>

> Thanks Richard.

>

> > How do CV and DWARF debug differ and is emitting CV debug from a DWARF

> > representation possible (I suppose there might even exist offline

> > conversion tools?)

>

> I don't know enough about DWARF internals to answer that, but I'd be surprised

> if the answer is "no".

>

> Do you mean that the DWARF code would collect the data, and my code would

> process it and output the .debug$S and .debug$T sections? So from the point of

> view of the linker, everything will be the same?


Yes.  The rough idea is to hook into either dwarf2out_finish or
dwarf2out_early_finish
(or both), and process the DWARF DIE tree starting from comp_unit_die
() to produce
the .debug$S and .debug$T sections.  It sounds like .debug$T can be emitted
from dwarf2out_early_finish while .debug$S needs dwarf2out_finish since the
section might refer to actual data/code objects?

> > I'll see to add some fat commentary above the debug hooks structure (not

> > sure if that will help in practice).

>

> This would definitely help. I'd no idea of this before now, and I would have

> spotted a DEPRECATED above the struct definition.


Sorry about this, giving a heads-up about the ongoing project would also
have got you this information.  I've posted a patch to add such notice now.

Richard.

> Mark

>

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 543b477ff18..f0249bde720 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1476,6 +1476,7 @@  OBJS = \
 	opts-global.o \
 	ordered-hash-map-tests.o \
 	passes.o \
+	pdbout.o \
 	plugin.o \
 	postreload-gcse.o \
 	postreload.o \
@@ -2637,6 +2638,8 @@  GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(srcdir)/hsa-common.c \
   $(srcdir)/calls.c \
   $(srcdir)/omp-general.h \
+  $(srcdir)/pdbout.c \
+  $(srcdir)/pdbout.h \
   @all_gtfiles@
 
 # Compute the list of GT header files from the corresponding C sources,
diff --git a/gcc/common.opt b/gcc/common.opt
index d33383b523c..80c488c0d70 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3127,6 +3127,10 @@  gno-pubnames
 Common Driver Negative(gpubnames) Var(debug_generate_pub_sections, 0) Init(-1)
 Don't generate DWARF pubnames and pubtypes sections.
 
+gcodeview
+Common Driver JoinedOrMissing
+Generate debug information in CodeView format.
+
 gpubnames
 Common Driver Negative(ggnu-pubnames) Var(debug_generate_pub_sections, 1)
 Generate DWARF pubnames and pubtypes sections.
diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h
index 1b1ea7d3d8a..42191b16c99 100644
--- a/gcc/config/i386/cygming.h
+++ b/gcc/config/i386/cygming.h
@@ -19,6 +19,7 @@  along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 #define DBX_DEBUGGING_INFO 1
+#define PDB_DEBUGGING_INFO 1
 #if TARGET_64BIT_DEFAULT || defined (HAVE_GAS_PE_SECREL32_RELOC)
 #define DWARF2_DEBUGGING_INFO 1
 #endif
diff --git a/gcc/config/i386/x86-64.h b/gcc/config/i386/x86-64.h
index 88db428f592..e84ee6c4026 100644
--- a/gcc/config/i386/x86-64.h
+++ b/gcc/config/i386/x86-64.h
@@ -91,6 +91,8 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define DWARF2_DEBUGGING_INFO 1
 #define DWARF2_UNWIND_INFO 1
 
+#define PDB_DEBUGGING_INFO 1
+
 #undef PREFERRED_DEBUGGING_TYPE
 #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
 
diff --git a/gcc/debug.h b/gcc/debug.h
index 260325920ea..c8f182962dd 100644
--- a/gcc/debug.h
+++ b/gcc/debug.h
@@ -235,6 +235,7 @@  extern const struct gcc_debug_hooks xcoff_debug_hooks;
 extern const struct gcc_debug_hooks dwarf2_debug_hooks;
 extern const struct gcc_debug_hooks dwarf2_lineno_debug_hooks;
 extern const struct gcc_debug_hooks vmsdbg_debug_hooks;
+extern const struct gcc_debug_hooks pdb_debug_hooks;
 
 /* Dwarf2 frame information.  */
 
diff --git a/gcc/defaults.h b/gcc/defaults.h
index f1a38626624..c6bbb203ef3 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -922,6 +922,9 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #elif defined XCOFF_DEBUGGING_INFO
 #define PREFERRED_DEBUGGING_TYPE XCOFF_DEBUG
 
+#elif defined PDB_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE PDB_DEBUG
+
 #else
 /* No debugging format is supported by this target.  */
 #define PREFERRED_DEBUGGING_TYPE NO_DEBUG
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 527d362533a..f83cec6f5e0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -435,6 +435,7 @@  Objective-C and Objective-C++ Dialects}.
 -gstabs  -gstabs+  -gstrict-dwarf  -gno-strict-dwarf @gol
 -gas-loc-support  -gno-as-loc-support @gol
 -gas-locview-support  -gno-as-locview-support @gol
+-gcodeview @gol
 -gcolumn-info  -gno-column-info @gol
 -gstatement-frontiers  -gno-statement-frontiers @gol
 -gvariable-location-views  -gno-variable-location-views @gol
@@ -8707,6 +8708,12 @@  assembler (GAS) to fail with an error.
 Produce debugging information in Alpha/VMS debug format (if that is
 supported).  This is the format used by DEBUG on Alpha/VMS systems.
 
+@item -gcodeview
+@opindex gcodeview
+Produce debugging information in CodeView debug format (if that is
+supported).  This is the format used by Microsoft Visual C++ on
+Windows.
+
 @item -g@var{level}
 @itemx -ggdb@var{level}
 @itemx -gstabs@var{level}
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index b092c563f3d..d4d7bdd5158 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -27,8 +27,9 @@  enum debug_info_type
   DWARF2_DEBUG,	    /* Write Dwarf v2 debug info (using dwarf2out.c).  */
   XCOFF_DEBUG,	    /* Write IBM/Xcoff debug info (using dbxout.c).  */
   VMS_DEBUG,        /* Write VMS debug info (using vmsdbgout.c).  */
-  VMS_AND_DWARF2_DEBUG /* Write VMS debug info (using vmsdbgout.c).
-                          and DWARF v2 debug info (using dwarf2out.c).  */
+  VMS_AND_DWARF2_DEBUG, /* Write VMS debug info (using vmsdbgout.c).
+			   and DWARF v2 debug info (using dwarf2out.c).  */
+  PDB_DEBUG	    /* Write CodeView debug info (using pdbout.c).  */
 };
 
 enum debug_info_levels
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 9f790db0daf..327cb4387db 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -4289,6 +4289,12 @@  driver_handle_option (struct gcc_options *opts,
       handle_foffload_option (arg);
       break;
 
+    case OPT_gcodeview:
+      /* If we've generated CodeView debugging information, make sure
+       * linker creates a PDB file for it. */
+      add_infile ("--pdb=", "*");
+      break;
+
     default:
       /* Various driver options need no special processing at this
 	 point, having been handled in a prescan above or being
diff --git a/gcc/opts.c b/gcc/opts.c
index c212a1a57dc..09b91aa2b87 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2730,6 +2730,10 @@  common_handle_option (struct gcc_options *opts,
       set_debug_level (NO_DEBUG, 2, arg, opts, opts_set, loc);
       break;
 
+    case OPT_gcodeview:
+      set_debug_level (PDB_DEBUG, false, "", opts, opts_set, loc);
+      break;
+
     case OPT_gstabs:
     case OPT_gstabs_:
       set_debug_level (DBX_DEBUG, code == OPT_gstabs_, arg, opts, opts_set,
diff --git a/gcc/pdbout.c b/gcc/pdbout.c
new file mode 100644
index 00000000000..e8f39bb64ea
--- /dev/null
+++ b/gcc/pdbout.c
@@ -0,0 +1,70 @@ 
+/* Output CodeView debugging information from GNU compiler.
+ * Copyright (C) 2021 Mark Harmstone
+ *
+ * This file is part of GCC.
+ *
+ * GCC 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, or (at your option) any later
+ * version.
+ *
+ * GCC 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 GCC; see the file COPYING3.  If not see
+ * <http://www.gnu.org/licenses/>.  */
+
+/* The CodeView structure is partially documented - definitions of structures
+ * output below can be found at:
+ * https://github.com/microsoft/microsoft-pdb/blob/master/include/cvinfo.h
+ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "debug.h"
+#include "pdbout.h"
+
+const struct gcc_debug_hooks pdb_debug_hooks = {
+  debug_nothing_charstar,	/* init */
+  debug_nothing_charstar,	/* 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 */
+  debug_nothing_int,		/* end_source_file */
+  debug_nothing_int_int,	/* begin_block */
+  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 */
+  debug_nothing_int_charstar,	/* end_prologue */
+  debug_nothing_int_charstar,	/* begin_epilogue */
+  debug_nothing_int_charstar,	/* end_epilogue */
+  debug_nothing_tree,		/* begin_function */
+  debug_nothing_int,		/* end_function */
+  debug_nothing_tree,		/* register_main_translation_unit */
+  debug_nothing_tree,		/* function_decl */
+  debug_nothing_tree,		/* early_global_decl */
+  debug_nothing_tree,		/* late_global_decl */
+  debug_nothing_tree_int,	/* type_decl */
+  debug_nothing_tree_tree_tree_bool_bool,	/* imported_module_or_decl */
+  debug_false_tree_charstarstar_uhwistar,	/* die_ref_for_decl */
+  debug_nothing_tree_charstar_uhwi,	/* register_external_die */
+  debug_nothing_tree,		/* deferred_inline_function */
+  debug_nothing_tree,		/* outlining_inline_function */
+  debug_nothing_rtx_code_label,	/* label */
+  debug_nothing_int,		/* handle_pch */
+  debug_nothing_rtx_insn,	/* var_location */
+  debug_nothing_tree,		/* inline_entry */
+  debug_nothing_tree,		/* size_function */
+  debug_nothing_void,		/* switch_text_section */
+  debug_nothing_tree_tree,	/* set_name */
+  0,				/* start_end_main_source_file */
+  TYPE_SYMTAB_IS_ADDRESS	/* tree_type_symtab_field */
+};
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
new file mode 100644
index 00000000000..f957cd5eca1
--- /dev/null
+++ b/gcc/pdbout.h
@@ -0,0 +1,23 @@ 
+/* CodeView structures and constants
+ * Copyright (c) 2021 Mark Harmstone
+ *
+ * This file is part of GCC.
+ *
+ * GCC 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, or (at your option) any later
+ * version.
+ *
+ * GCC 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 GCC; see the file COPYING3.  If not see
+ * <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_PDBOUT_H
+#define GCC_PDBOUT_H 1
+
+#endif
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 5c026feece2..a14a9177ee3 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1588,6 +1588,10 @@  process_options (void)
 #ifdef DWARF2_LINENO_DEBUGGING_INFO
   else if (write_symbols == DWARF2_DEBUG)
     debug_hooks = &dwarf2_lineno_debug_hooks;
+#endif
+#ifdef PDB_DEBUGGING_INFO
+  else if (write_symbols == PDB_DEBUG)
+    debug_hooks = &pdb_debug_hooks;
 #endif
   else
     error_at (UNKNOWN_LOCATION,