Index: lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp @@ -102,6 +102,14 @@ MCELFStreamer::ChangeSection(Section, Subsection); } + // Reset state between object emissions + void reset() override { + MappingSymbolCounter = 0; + MCELFStreamer::reset(); + LastMappingSymbols.clear(); + LastEMS = EMS_None; + } + /// This function is the one used to emit instruction data into the ELF /// streamer. We override it to add the appropriate mapping symbol if /// necessary. Index: lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -1171,6 +1171,8 @@ ATS.reset(); MappingSymbolCounter = 0; MCELFStreamer::reset(); + LastMappingSymbols.clear(); + LastEMSInfo.reset(); // MCELFStreamer clear's the assembler's e_flags. However, for // arm we manually set the ABI version on streamer creation, so // do the same here Index: unittests/Target/ARM/CMakeLists.txt =================================================================== --- /dev/null +++ unittests/Target/ARM/CMakeLists.txt @@ -0,0 +1,24 @@ +include_directories( + ${CMAKE_SOURCE_DIR}/lib/Target/ARM + ${CMAKE_BINARY_DIR}/lib/Target/ARM + ) + +set(LLVM_LINK_COMPONENTS + AsmPrinter + ARMCodeGen + ARMDesc + ARMInfo + CodeGen + Core + MC + Object + SelectionDAG + Support + Target + ) + +add_llvm_unittest(ARMTests + ELFStreamer.cpp + ) + +target_link_libraries(ARMTests LLVMTestingSupport) Index: unittests/Target/ARM/ELFStreamer.cpp =================================================================== --- /dev/null +++ unittests/Target/ARM/ELFStreamer.cpp @@ -0,0 +1,160 @@ +#include "ARMSubtarget.h" +#include "ARMTargetMachine.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Testing/Support/Error.h" + +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +struct Generator { + std::unique_ptr MRI; + std::unique_ptr MAI; + std::unique_ptr MOFI; + std::unique_ptr MC; + MCAsmBackend *MAB; // Owned by MCStreamer + std::unique_ptr MII; + std::unique_ptr MSTI; + MCCodeEmitter *MCE; // Owned by MCStreamer + MCStreamer *MS; // Owned by AsmPrinter + std::unique_ptr TM; + std::unique_ptr Asm; + + SmallString<4096> FileBytes; + /// The stream we use to generate the DWARF into as an ELF file. + std::unique_ptr Stream; + + Error init(); + + static Expected>create() { + std::unique_ptr GenUP(new Generator()); + Error error = GenUP->init(); + if (error) + return Expected>(std::move(error)); + return Expected>(std::move(GenUP)); + } +}; + +Error Generator::init() { + Triple TheTriple(Triple::normalize("arm--")); + + LLVMInitializeARMTargetInfo(); + LLVMInitializeARMTarget(); + LLVMInitializeARMTargetMC(); + LLVMInitializeARMAsmPrinter(); + + std::string ErrorStr; + std::string TripleName; + + // Get the target. + const Target *TheTarget = + TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); + if (!TheTarget) + return make_error(ErrorStr, inconvertibleErrorCode()); + + TripleName = TheTriple.getTriple(); + + // Create all the MC Objects. + MRI.reset(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return make_error(Twine("no register info for target ") + + TripleName, + inconvertibleErrorCode()); + + MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName)); + if (!MAI) + return make_error("no asm info for target " + TripleName, + inconvertibleErrorCode()); + + MOFI.reset(new MCObjectFileInfo); + MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get())); + MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, *MC); + + MCTargetOptions Options; + MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "", Options); + if (!MAB) + return make_error("no asm backend for target " + TripleName, + inconvertibleErrorCode()); + + MII.reset(TheTarget->createMCInstrInfo()); + if (!MII) + return make_error("no instr info info for target " + + TripleName, + inconvertibleErrorCode()); + + MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); + if (!MSTI) + return make_error("no subtarget info for target " + TripleName, + inconvertibleErrorCode()); + + MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC); + if (!MCE) + return make_error("no code emitter for target " + TripleName, + inconvertibleErrorCode()); + + Stream = make_unique(FileBytes); + + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); + MS = TheTarget->createMCObjectStreamer( + TheTriple, *MC, *MAB, *Stream, MCE, *MSTI, MCOptions.MCRelaxAll, + MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false); + if (!MS) + return make_error("no object streamer for target " + + TripleName, + inconvertibleErrorCode()); + + // Finally create the AsmPrinter we'll use to emit the DIEs. + TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(), + None)); + if (!TM) + return make_error("no target machine for target " + TripleName, + inconvertibleErrorCode()); + + Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr(MS))); + if (!Asm) + return make_error("no asm printer for target " + TripleName, + inconvertibleErrorCode()); + + return Error::success(); +} + +} // anonymous namespace + +TEST(ELFStreamer, TestReset) { + auto ExpectedGen = Generator::create(); + ASSERT_THAT_EXPECTED(ExpectedGen, Succeeded()); + auto Gen = ExpectedGen.get().get(); + auto Stm = Gen->Asm->OutStreamer.get(); + MCContext *MC = Gen->MC.get(); + + for (int i = 0; i < 10; i++) { + // Switch section back and forth and emit some random data between resets + // to trigger section switching logic. + auto s1 = MC->getELFSection(".zdebug_foo", 0 /*Type*/, 0 /*Flags*/); + auto s2 = MC->getELFSection(".zdebug_bar", 0 /*Type*/, 0 /*Flags*/); + Stm->SwitchSection( s1); + Stm->EmitBytes("0"); + Stm->SwitchSection( s2); + Stm->EmitBytes("0"); + Stm->SwitchSection( s1); + Stm->EmitBytes("0"); + Stm->SwitchSection( s2); + Stm->EmitBytes("0"); + Stm->Finish(); + Stm->reset(); + // Not really sure what to test here. Just to make sure no crash for now... + } +}