[Objdump] Assertion failed on my backend

Hi everyone,

I’m currently writing a new backend(gaspardrisc) on LLVM 16 based on Lanai backend.

Everything seems looking good except llvm-objdump.

When I try to run objdump , objdump asserts an error : Assertion failed: (N+M <= size() && "Invalid specifier"), function slice, file ArrayRef.h, line 194.

I think I don’t declare in a specific file my backend, there is the problem.

I have modified the following files to reference my backend:

./tools/llvm-readobj/ELFDumper.cpp
./tools/opt/opt.cpp
./include/llvm/module.modulemap
./include/llvm/TargetParser/Triple.h
./include/llvm/BinaryFormat/ELF.h
./include/llvm/BinaryFormat/ELFRelocs/Gaspardrisc.def
./include/llvm/Object/ELFObjectFile.h
./unittests/TargetParser/TripleTest.cpp
./lib/Target/Gaspardrisc/GaspardriscMemAluCombiner.cpp
./lib/Target/Gaspardrisc/GaspardriscSchedule.td
./lib/Target/Gaspardrisc/GaspardriscISelLowering.cpp
./lib/Target/Gaspardrisc/GaspardriscTargetTransformInfo.h
./lib/Target/Gaspardrisc/GaspardriscTargetObjectFile.h
./lib/Target/Gaspardrisc/GaspardriscCondCode.h
./lib/Target/Gaspardrisc/GaspardriscCallingConv.td
./lib/Target/Gaspardrisc/GaspardriscMachineFunctionInfo.cpp
./lib/Target/Gaspardrisc/GaspardriscRegisterInfo.td
./lib/Target/Gaspardrisc/GaspardriscRegisterInfo.h
./lib/Target/Gaspardrisc/GaspardriscSelectionDAGInfo.h
./lib/Target/Gaspardrisc/GaspardriscISelDAGToDAG.cpp
./lib/Target/Gaspardrisc/GaspardriscAsmPrinter.cpp
./lib/Target/Gaspardrisc/GaspardriscInstrInfo.h
./lib/Target/Gaspardrisc/GaspardriscInstrFormats.td
./lib/Target/Gaspardrisc/GaspardriscTargetMachine.cpp
./lib/Target/Gaspardrisc/GaspardriscSubtarget.h
./lib/Target/Gaspardrisc/Gaspardrisc.td
./lib/Target/Gaspardrisc/Gaspardrisc.h
./lib/Target/Gaspardrisc/GaspardriscMachineFunctionInfo.h
./lib/Target/Gaspardrisc/GaspardriscFrameLowering.h
./lib/Target/Gaspardrisc/GaspardriscFrameLowering.cpp
./lib/Target/Gaspardrisc/GaspardriscSelectionDAGInfo.cpp
./lib/Target/Gaspardrisc/GaspardriscAluCode.h
./lib/Target/Gaspardrisc/GaspardriscInstrInfo.td
./lib/Target/Gaspardrisc/GaspardriscRegisterInfo.cpp
./lib/Target/Gaspardrisc/GaspardriscISelLowering.h
./lib/Target/Gaspardrisc/GaspardriscInstrInfo.cpp
./lib/Target/Gaspardrisc/GaspardriscTargetMachine.h
./lib/Target/Gaspardrisc/GaspardriscTargetObjectFile.cpp
./lib/Target/Gaspardrisc/GaspardriscMCInstLower.h
./lib/Target/Gaspardrisc/GaspardriscSubtarget.cpp
./lib/Target/Gaspardrisc/GaspardriscMCInstLower.cpp
./lib/Target/Gaspardrisc/GaspardriscDelaySlotFiller.cpp
./lib/Target/Gaspardrisc/AsmParser/GaspardriscAsmParser.cpp
./lib/Target/Gaspardrisc/Disassembler/GaspardriscDisassembler.h
./lib/Target/Gaspardrisc/Disassembler/GaspardriscDisassembler.cpp
./lib/Target/Gaspardrisc/TargetInfo/GaspardriscTargetInfo.h
./lib/Target/Gaspardrisc/TargetInfo/GaspardriscTargetInfo.cpp
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscMCAsmInfo.cpp
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscFixupKinds.h
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscInstPrinter.h
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscAsmBackend.cpp
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscMCExpr.h
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscMCTargetDesc.cpp
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscBaseInfo.h
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscInstPrinter.cpp
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscMCExpr.cpp
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscELFObjectWriter.cpp
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscMCTargetDesc.h
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscMCCodeEmitter.cpp
./lib/Target/Gaspardrisc/MCTargetDesc/GaspardriscMCAsmInfo.h
./lib/TargetParser/Triple.cpp
./lib/ObjectYAML/ELFYAML.cpp
./lib/CodeGen/TargetLoweringObjectFileImpl.cpp
./lib/Object/ELF.cpp
./lib/Object/RelocationResolver.cpp


Thanks in advance for your help !
Gaspard

ArrayRef.h is shipped with LLVM and you probably did not modify it, but it is used by objdump. You hit this assert:

Could you run objdump under gdb/lldb to get a backtrace of the issue?

Thanks for you answer.

There is the output of lldb, the function slice() seems to be concerned :

* thread #1, queue = 'com.apple.main-thread', stop reason = hit program assert
    frame #4: 0x000000010004c2a4 llvm-objdump`llvm::ArrayRef<unsigned char>::slice(this=0x000000016fdfcc90, N=0, M=6171906200) const at ArrayRef.h:194:7
   191 	    /// slice(n, m) - Chop off the first N elements of the array, and keep M
   192 	    /// elements in the array.
   193 	    ArrayRef<T> slice(size_t N, size_t M) const {
-> 194 	      assert(N+M <= size() && "Invalid specifier");
   195 	      return ArrayRef<T>(data()+N, M);
   196 	    }
   197 	

Thanks !

Gaspard

Indeed it hits in slice, if you enter bt it should give you a backtrace and more information.

Yes ,

* thread #1, queue = 'com.apple.main-thread', stop reason = hit program assert
    frame #0: 0x00000001aae10724 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x00000001aae47c28 libsystem_pthread.dylib`pthread_kill + 288
    frame #2: 0x00000001aad55ae8 libsystem_c.dylib`abort + 180
    frame #3: 0x00000001aad54e44 libsystem_c.dylib`__assert_rtn + 272
  * frame #4: 0x000000010004c2a4 llvm-objdump`llvm::ArrayRef<unsigned char>::slice(this=0x000000016fdfcc90, N=0, M=6171906200) const at ArrayRef.h:194:7
    frame #5: 0x0000000100045fe8 llvm-objdump`disassembleObject(TheTarget=0x0000000101317ad0, Obj=0x0000600003304140, DbgObj=0x0000600003304140, Ctx=0x000000016fdfe1b0, PrimaryDisAsm=0x0000600000c04510, SecondaryDisAsm=0x0000000000000000, MIA=0x0000600000008000, IP=0x0000600001704040, PrimarySTI=0x0000600003e00000, SecondarySTI=0x0000000000000000, PIP=0x0000000101310010, SP=0x000000016fdfd9c8, InlineRelocs=false)::PrettyPrinter&, llvm::objdump::SourcePrinter&, bool) at llvm-objdump.cpp:1820:58
    frame #6: 0x000000010003f5bc llvm-objdump`disassembleObject(Obj=0x0000600003304140, InlineRelocs=false) at llvm-objdump.cpp:2147:3
    frame #7: 0x0000000100039284 llvm-objdump`dumpObject(O=0x0000600003304140, A=0x0000000000000000, C=0x0000000000000000) at llvm-objdump.cpp:2837:5
    frame #8: 0x000000010000d868 llvm-objdump`dumpInput(file=(Data = "../../test/gaspard/copy.o", Length = 25)) at llvm-objdump.cpp:2920:5
    frame #9: 0x0000000100095220 llvm-objdump`void (__first=(item = "../../test/gaspard/copy.o"), __last=(item = Summary Unavailable), __f=(llvm-objdump`dumpInput(llvm::StringRef) at llvm-objdump.cpp:2904))(llvm::StringRef)>(std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*>, void (*)(llvm::StringRef)))(llvm::StringRef) at for_each.h:26:5
    frame #10: 0x000000010000d758 llvm-objdump`void (Range=size=1, F=(llvm-objdump`dumpInput(llvm::StringRef) at llvm-objdump.cpp:2904))(llvm::StringRef)>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, void (*)(llvm::StringRef)))(llvm::StringRef) at STLExtras.h:1729:10
    frame #11: 0x000000010000b8cc llvm-objdump`main(argc=3, argv=0x000000016fdff640) at llvm-objdump.cpp:3250:3
    frame #12: 0x00000001aaaeff28 dyld`start + 2236

I think the problem is the line 1490 in llvm-objdump.cpp because is the first invocation of ArrayRef in disassembleObject() function.

...
ArrayRef<uint8_t> Bytes = arrayRefFromStringRef( unwrapOrError(Section.getContents(), Obj.getFileName()));

Also, the argument M in slice() is pretty crazy (M=6171906200). Do you think so ?

Thanks,
Gaspard

The root cause is probably the input file. It is either malformed or objdump does not understand its content.

I think the backend have a problem.

When I invoke objdump with --triple=lanai or riscv64 it works and objdump returns with no error.

Obviously the decompiler doesn’t understand the instructions.