Versioning DWARF constants

In https://reviews.llvm.org/D30664 Greg Clayton suggested adding a new
version parameter to the macros that define DWARF constants (see
include/Support/Dwarf.def). This would enable various things:
- a "verify" mode to dwarfdump that could warn about using features that
  are newer than the stated version in a unit or other section;
- a compiler assertion that guarded against using FORMs that are newer
  than the requested version;
- if we ever supported -gstrict-dwarf, a compiler assertion that we do
  not emit any vendor extensions;
- maybe other things.

(Greg brought up "verify" mode, I am motivated by the FORM check.)

It's easy enough (if tedious) to do the mechanical work to add a version
to each constant, and some accessor functions to retrieve those values.
The question is how to handle the vendor extensions.

My thought was to define a fake version number for each "vendor" so we
can easily identify them as nonstandard, and also identify which "vendor"
defined a given extension. Looking through Dwarf.def, the vendors are:
MIPS, GNU, Apple, Borland, Google, LLVM. DWARF does not define a "user"
range for version numbers, but I should think it's safe enough to use
values in the range 0xf0..0xff for this sort of thing.

Class DwarfDebug already has a predicate to indicate it's okay to use
Apple extensions, and tagging all Apple extensions with an Apple "version"
would make it pretty trivial to add assertions in the emitter that this
flag was obeyed. For example.

I would want to add a predicate to DwarfDebug that looked like this:

  bool isValidFormForVersion(dwarf::Form Form) const {
    unsigned FormVersion = dwarf::FormVersion(Form);
    if (FormVersion <= getDwarfVersion())
      return FormVersion != 0;
    // The only extensions are GNU for split DWARF, pre-v5.
    return (FormVersion == DWARF_VERSION_GNU && useSplitDwarf() &&
            getDwarfVersion() <= 4);
  }

Then DIEAbbrev::Emit() could have an assertion along the lines of:
  assert(AP->DD->isValidFormForVersion(Form) &&
         "Form not defined in this DWARF version");

Does this all seem like a reasonable direction?
Thanks,
--paulr

Seems pretty plausible to me.

In https://reviews.llvm.org/D30664 Greg Clayton suggested adding a new
version parameter to the macros that define DWARF constants (see
include/Support/Dwarf.def). This would enable various things:
- a "verify" mode to dwarfdump that could warn about using features that
are newer than the stated version in a unit or other section;
- a compiler assertion that guarded against using FORMs that are newer
than the requested version;
- if we ever supported -gstrict-dwarf, a compiler assertion that we do
not emit any vendor extensions;
- maybe other things.

(Greg brought up "verify" mode, I am motivated by the FORM check.)

Yes, implementing dwarfdump -verify is still relatively high on my list.

It's easy enough (if tedious) to do the mechanical work to add a version
to each constant, and some accessor functions to retrieve those values.
The question is how to handle the vendor extensions.

My thought was to define a fake version number for each "vendor" so we
can easily identify them as nonstandard, and also identify which "vendor"
defined a given extension. Looking through Dwarf.def, the vendors are:
MIPS, GNU, Apple, Borland, Google, LLVM. DWARF does not define a "user"
range for version numbers, but I should think it's safe enough to use
values in the range 0xf0..0xff for this sort of thing.

Class DwarfDebug already has a predicate to indicate it's okay to use
Apple extensions, and tagging all Apple extensions with an Apple "version"
would make it pretty trivial to add assertions in the emitter that this
flag was obeyed. For example.

I would want to add a predicate to DwarfDebug that looked like this:

bool isValidFormForVersion(dwarf::Form Form) const {
   unsigned FormVersion = dwarf::FormVersion(Form);
   if (FormVersion <= getDwarfVersion())
     return FormVersion != 0;
   // The only extensions are GNU for split DWARF, pre-v5.
   return (FormVersion == DWARF_VERSION_GNU && useSplitDwarf() &&
           getDwarfVersion() <= 4);
}

Then DIEAbbrev::Emit() could have an assertion along the lines of:
assert(AP->DD->isValidFormForVersion(Form) &&
        "Form not defined in this DWARF version");

Does this all seem like a reasonable direction?

Thanks, that sounds like a good direction.

-- adrian