This is an archive of the discontinued LLVM Phabricator instance.

[AArch64] - Return address signing dwarf support
ClosedPublic

Authored by LukeCheeseman on Aug 1 2018, 4:14 AM.

Details

Summary

Functions that have signed return addresses need additional dwarf support:

  • After signing the LR, and before authenticating it, the LR register is in a state the is unusable by a debugger or unwinder
  • To account for this a new directive, .cfi_negate_ra_state, is added
  • This directive says the signed state of the LR register has now changed, i.e. unsigned -> signed or signed -> unsigned
  • This directive has the same CFA code as the SPARC directive GNU_window_save (0x2d), adding a macro to account for multiply defined codes
  • This patch matches the gcc implementation of this support: https://patchwork.ozlabs.org/patch/800271/

Diff Detail

Event Timeline

LukeCheeseman created this revision.Aug 1 2018, 4:14 AM

I would specifically like some feedback on the duplicated code. I couldn't find a way of adding vendor specific extensions and this seems like it may be a large change for a small result.

  • Don't generate cfi_negate_ra_state when using retaa
  • The signing and return is combined so there isn't a correct point to emit it

I think this needs additional tests to cover:

  • The encoding of the CFI instruction in object files
  • The assembly parser and printer changes, to make sure that IR->assembly->object will work the same as IR->object.
lib/BinaryFormat/Dwarf.cpp
465

Does this get used by llvm-dwarfdump, or is it just for debugging? If it is used by anything user-facing, then we need to select the right one based on the target here.

lib/MC/MCParser/AsmParser.cpp
494

I think this should be done in the AArch64 assembly parser, because it doesn't apply to any other architectures.

lib/Target/AArch64/AArch64FrameLowering.cpp
896

This isn't covered by the test.

  • Removed the emission of negate_ra_state when emitting an AUTIASP. This causes issues when there are multiple exits from a function as the unwinder reads all the CFI directives without understanding control flow and may end up with the incorrect value in the sign state register. This isn't an issue as we currently do not support breaking on function return/tail call.
  • Moved cfi_negate_ra_sign_state directive parsing into the aarch64 backend
  • I haven't yet addressed the issue of printing the wrong cfi directive name with llvm-dwarfdump, I have a patch which I'm not too happy with but will upload shortly

Can you please also add support for the new CFI directive in MIR? Mostly in lib/CodeGen/MIRParser/MIParser.cpp, lib/CodeGen/MIRParser/MILexer.cpp/h, lib/CodeGen/MIRPrinter.cpp and test/CodeGen/MIR/AArch64/cfi.mir.

Also, probably a MIR test with -run-pass prologepilog would be good.

  • Add MIR support (lexing, parsing and printing) for CFI negate_ra_sign_state
  • Added MIR tests
  • Added patch to print the correct CFI name given the target architecture of the object file being dumper:
    • This solution isn't pretty, the issue is that the dumping doesn't have any notion of context. I attempted to create a DwarfDumper class with vendor specific subclasses but this ended up needing significant plumbing and rework to many, far reaching places, in the LLVM code base.
    • I've opted here to pass through only the information that is required to make the dumping decision, in this case the architecture. The DW_CFA_DUP macro now takes a predicate that can be defined for selecting the vendor specific extension
    • An alternative to this is to just accept that the output is incorrect, this doesn't look to have any issues beyond printing the wrong string. Notably it is not an issue for target specific parsing/printing, only when dumping a file via llvm-dwarfdump. Even if overlapping encodings behaved differently (e.g. differing numbers of operands) the dumping would not be any more incorrect that just printing the wrong name. Whilst not a motivating point, it should be highlighted that this is the way that GNU tools handle overlapping encodings, i.e. the encoding not defined as a DUP is used.
    • I've extend a test to check for the correct string be printed
olista01 added inline comments.Sep 13 2018, 5:34 AM
include/llvm/BinaryFormat/Dwarf.def
89

Maybe HANDLE_DW_CFA_TARGET or HANDLE_DW_CFA_PRED would be a better name for this?

829

Now that we have a way to represent target-specific opcodes, should we limit these to their respective targets? I think that GNU_window_save is PowerPC-specific, and GNU_args_size is X86-specific.

lib/BinaryFormat/Dwarf.cpp
460

Should this be #undef'd after these includes? The other macros are cleared at the end of Dwarf.def, but this one isn't.

460

I think this also needs to check Triple::aarch64_be.

lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
5290 ↗(On Diff #164376)

The assembly parsing isn't covered by any of the tests.

5292 ↗(On Diff #164376)

Do we need to check that we are at AsmToken::EndOfStatement (as is done for other directives), or is that checked somewhere else?

tools/llvm-readobj/DwarfCFIEHPrinter.h
190 ↗(On Diff #164376)

Long line, please clang-format this.

LukeCheeseman marked 7 inline comments as done.

Added tests for assembly parsing
Added predicates for the other dwarf vendor extensions

JDevlieghere added inline comments.Sep 17 2018, 2:56 AM
include/llvm/BinaryFormat/Dwarf.def
834

It doesn't seem right that these two predicates have the same ID?

LukeCheeseman marked 2 inline comments as done.Sep 17 2018, 3:44 AM
LukeCheeseman added inline comments.
include/llvm/BinaryFormat/Dwarf.def
834

The two directives are provided by two different vendors. Although it makes selecting the correct one for dumping require more information, I think this is legal based on the DWARF standard. This is also the encoding used for the GNU patch that provides the same functionality (see https://github.com/gcc-mirror/gcc/blob/f47edbb56126b7e8564f22b0b9d55565a995b7f0/include/dwarf2.def)

thegameg added inline comments.Sep 20 2018, 1:37 AM
test/CodeGen/MIR/AArch64/return-address-signing.mir
12 ↗(On Diff #165511)

Are all the attributes needed here? I assume only the sign-* are.

48 ↗(On Diff #165511)

A lot of these are not needed here. In order to dump the MIR file you can use -simplify-mir with -stop-before or -stop-after to skip all the default values.

  • Reduce MIR test case
emaste added a subscriber: emaste.Sep 24 2018, 8:23 AM
olista01 accepted this revision.Sep 26 2018, 3:11 AM

LGTM, thanks!

This revision is now accepted and ready to land.Sep 26 2018, 3:11 AM
This revision was automatically updated to reflect the committed changes.