/// addDefinedSymbol - Add a defined symbol to the list. void LTOModule::addDefinedSymbol(const GlobalValue *def, bool isFunction) { // ignore all llvm.* symbols if (def->getName().startswith("llvm.")) return; // string is owned by _defines SmallString<64> Buffer; _mangler.getNameWithPrefix(Buffer, def, false); // set alignment part log2() can have rounding errors uint32_t align = def->getAlignment(); uint32_t attr = align ? countTrailingZeros(def->getAlignment()) : 0; // set permissions part if (isFunction) { attr |= LTO_SYMBOL_PERMISSIONS_CODE; } else { const GlobalVariable *gv = dyn_cast<GlobalVariable>(def); if (gv && gv->isConstant()) attr |= LTO_SYMBOL_PERMISSIONS_RODATA; else attr |= LTO_SYMBOL_PERMISSIONS_DATA; } // set definition part if (def->hasWeakLinkage() || def->hasLinkOnceLinkage() || def->hasLinkerPrivateWeakLinkage()) attr |= LTO_SYMBOL_DEFINITION_WEAK; else if (def->hasCommonLinkage()) attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; else attr |= LTO_SYMBOL_DEFINITION_REGULAR; // set scope part if (def->hasHiddenVisibility()) attr |= LTO_SYMBOL_SCOPE_HIDDEN; else if (def->hasProtectedVisibility()) attr |= LTO_SYMBOL_SCOPE_PROTECTED; else if (def->hasExternalLinkage() || def->hasWeakLinkage() || def->hasLinkOnceLinkage() || def->hasCommonLinkage() || def->hasLinkerPrivateWeakLinkage()) attr |= LTO_SYMBOL_SCOPE_DEFAULT; else if (def->hasLinkOnceODRAutoHideLinkage()) attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; else attr |= LTO_SYMBOL_SCOPE_INTERNAL; StringSet::value_type &entry = _defines.GetOrCreateValue(Buffer); entry.setValue(1); // fill information structure NameAndAttributes info; StringRef Name = entry.getKey(); info.name = Name.data(); assert(info.name[Name.size()] == '\0'); info.attributes = attr; info.isFunction = isFunction; info.symbol = def; // add to table of symbols _symbols.push_back(info); }
uint32_t zlib::crc32(StringRef Buffer) { return ::crc32(0, (const Bytef *)Buffer.data(), Buffer.size()); }
/// ParseBlock - Read a block, updating statistics, etc. static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, unsigned IndentLevel) { std::string Indent(IndentLevel*2, ' '); uint64_t BlockBitStart = Stream.GetCurrentBitNo(); // Get the statistics for this BlockID. PerBlockIDStats &BlockStats = BlockIDStats[BlockID]; BlockStats.NumInstances++; // BLOCKINFO is a special part of the stream. if (BlockID == bitc::BLOCKINFO_BLOCK_ID) { if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n"; if (Stream.ReadBlockInfoBlock()) return Error("Malformed BlockInfoBlock"); uint64_t BlockBitEnd = Stream.GetCurrentBitNo(); BlockStats.NumBits += BlockBitEnd-BlockBitStart; return false; } unsigned NumWords = 0; if (Stream.EnterSubBlock(BlockID, &NumWords)) return Error("Malformed block record"); const char *BlockName = 0; if (Dump) { outs() << Indent << "<"; if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader()))) outs() << BlockName; else outs() << "UnknownBlock" << BlockID; if (NonSymbolic && BlockName) outs() << " BlockID=" << BlockID; outs() << " NumWords=" << NumWords << " BlockCodeSize=" << Stream.getAbbrevIDWidth() << ">\n"; } SmallVector<uint64_t, 64> Record; // Read all the records for this block. while (1) { if (Stream.AtEndOfStream()) return Error("Premature end of bitstream"); uint64_t RecordStartBit = Stream.GetCurrentBitNo(); BitstreamEntry Entry = Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); switch (Entry.Kind) { case BitstreamEntry::Error: return Error("malformed bitcode file"); case BitstreamEntry::EndBlock: { uint64_t BlockBitEnd = Stream.GetCurrentBitNo(); BlockStats.NumBits += BlockBitEnd-BlockBitStart; if (Dump) { outs() << Indent << "</"; if (BlockName) outs() << BlockName << ">\n"; else outs() << "UnknownBlock" << BlockID << ">\n"; } return false; } case BitstreamEntry::SubBlock: { uint64_t SubBlockBitStart = Stream.GetCurrentBitNo(); if (ParseBlock(Stream, Entry.ID, IndentLevel+1)) return true; ++BlockStats.NumSubBlocks; uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo(); // Don't include subblock sizes in the size of this block. BlockBitStart += SubBlockBitEnd-SubBlockBitStart; continue; } case BitstreamEntry::Record: // The interesting case. break; } if (Entry.ID == bitc::DEFINE_ABBREV) { Stream.ReadAbbrevRecord(); ++BlockStats.NumAbbrevs; continue; } Record.clear(); ++BlockStats.NumRecords; StringRef Blob; unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob); // Increment the # occurrences of this code. if (BlockStats.CodeFreq.size() <= Code) BlockStats.CodeFreq.resize(Code+1); BlockStats.CodeFreq[Code].NumInstances++; BlockStats.CodeFreq[Code].TotalBits += Stream.GetCurrentBitNo()-RecordStartBit; if (Entry.ID != bitc::UNABBREV_RECORD) { BlockStats.CodeFreq[Code].NumAbbrev++; ++BlockStats.NumAbbreviatedRecords; } if (Dump) { outs() << Indent << " <"; if (const char *CodeName = GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) outs() << CodeName; else outs() << "UnknownCode" << Code; if (NonSymbolic && GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) outs() << " codeid=" << Code; if (Entry.ID != bitc::UNABBREV_RECORD) outs() << " abbrevid=" << Entry.ID; for (unsigned i = 0, e = Record.size(); i != e; ++i) outs() << " op" << i << "=" << (int64_t)Record[i]; outs() << "/>"; if (Blob.data()) { outs() << " blob data = "; bool BlobIsPrintable = true; for (unsigned i = 0, e = Blob.size(); i != e; ++i) if (!isprint(static_cast<unsigned char>(Blob[i]))) { BlobIsPrintable = false; break; } if (BlobIsPrintable) outs() << "'" << Blob << "'"; else outs() << "unprintable, " << Blob.size() << " bytes."; } outs() << "\n"; } } }
void RuntimeDyldMachO::processRelocationRef(unsigned SectionID, RelocationRef RelI, ObjectImage &Obj, ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols, StubMap &Stubs) { const ObjectFile *OF = Obj.getObjectFile(); const MachOObjectFile *MachO = static_cast<const MachOObjectFile*>(OF); MachO::any_relocation_info RE= MachO->getRelocation(RelI.getRawDataRefImpl()); uint32_t RelType = MachO->getAnyRelocationType(RE); // FIXME: Properly handle scattered relocations. // For now, optimistically skip these: they can often be ignored, as // the static linker will already have applied the relocation, and it // only needs to be reapplied if symbols move relative to one another. // Note: This will fail horribly where the relocations *do* need to be // applied, but that was already the case. if (MachO->isRelocationScattered(RE)) return; RelocationValueRef Value; SectionEntry &Section = Sections[SectionID]; bool isExtern = MachO->getPlainRelocationExternal(RE); bool IsPCRel = MachO->getAnyRelocationPCRel(RE); unsigned Size = MachO->getAnyRelocationLength(RE); uint64_t Offset; RelI.getOffset(Offset); uint8_t *LocalAddress = Section.Address + Offset; unsigned NumBytes = 1 << Size; uint64_t Addend = 0; memcpy(&Addend, LocalAddress, NumBytes); if (isExtern) { // Obtain the symbol name which is referenced in the relocation symbol_iterator Symbol = RelI.getSymbol(); StringRef TargetName; Symbol->getName(TargetName); // First search for the symbol in the local symbol table SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); if (lsi != Symbols.end()) { Value.SectionID = lsi->second.first; Value.Addend = lsi->second.second + Addend; } else { // Search for the symbol in the global symbol table SymbolTableMap::const_iterator gsi = GlobalSymbolTable.find(TargetName.data()); if (gsi != GlobalSymbolTable.end()) { Value.SectionID = gsi->second.first; Value.Addend = gsi->second.second + Addend; } else { Value.SymbolName = TargetName.data(); Value.Addend = Addend; } } } else { SectionRef Sec = MachO->getRelocationSection(RE); Value.SectionID = findOrEmitSection(Obj, Sec, true, ObjSectionToID); uint64_t Addr; Sec.getAddress(Addr); Value.Addend = Addend - Addr; } if (Arch == Triple::x86_64 && (RelType == MachO::X86_64_RELOC_GOT || RelType == MachO::X86_64_RELOC_GOT_LOAD)) { assert(IsPCRel); assert(Size == 2); StubMap::const_iterator i = Stubs.find(Value); uint8_t *Addr; if (i != Stubs.end()) { Addr = Section.Address + i->second; } else { Stubs[Value] = Section.StubOffset; uint8_t *GOTEntry = Section.Address + Section.StubOffset; RelocationEntry RE(SectionID, Section.StubOffset, MachO::X86_64_RELOC_UNSIGNED, 0, false, 3); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else addRelocationForSection(RE, Value.SectionID); Section.StubOffset += 8; Addr = GOTEntry; } resolveRelocation(Section, Offset, (uint64_t)Addr, MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, 2); } else if (Arch == Triple::arm && (RelType & 0xf) == MachO::ARM_RELOC_BR24) { // This is an ARM branch relocation, need to use a stub function. // Look up for existing stub. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, RelType, 0, IsPCRel, Size); else { // Create a new stub function. Stubs[Value] = Section.StubOffset; uint8_t *StubTargetAddr = createStubFunction(Section.Address + Section.StubOffset); RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, MachO::GENERIC_RELOC_VANILLA, Value.Addend); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else addRelocationForSection(RE, Value.SectionID); resolveRelocation(Section, Offset, (uint64_t)Section.Address + Section.StubOffset, RelType, 0, IsPCRel, Size); Section.StubOffset += getMaxStubSize(); } } else { RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, IsPCRel, Size); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else addRelocationForSection(RE, Value.SectionID); } }
static CXCodeCompleteResults * clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename, unsigned complete_line, unsigned complete_column, ArrayRef<CXUnsavedFile> unsaved_files, unsigned options) { bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); #endif #endif bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != nullptr; if (cxtu::isNotUsableTU(TU)) { LOG_BAD_TU(TU); return nullptr; } ASTUnit *AST = cxtu::getASTUnit(TU); if (!AST) return nullptr; CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) setThreadBackgroundPriority(); ASTUnit::ConcurrencyCheck Check(*AST); // Perform the remapping of source files. SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; for (auto &UF : unsaved_files) { std::unique_ptr<llvm::MemoryBuffer> MB = llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); RemappedFiles.push_back(std::make_pair(UF.Filename, MB.release())); } if (EnableLogging) { // FIXME: Add logging. } // Parse the resulting source file to find code-completion results. AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults( &AST->getFileManager()); Results->Results = nullptr; Results->NumResults = 0; // Create a code-completion consumer to capture the results. CodeCompleteOptions Opts; Opts.IncludeBriefComments = IncludeBriefComments; CaptureCompletionResults Capture(Opts, *Results, &TU); // Perform completion. AST->CodeComplete(complete_filename, complete_line, complete_column, RemappedFiles, (options & CXCodeComplete_IncludeMacros), (options & CXCodeComplete_IncludeCodePatterns), IncludeBriefComments, Capture, CXXIdx->getPCHContainerOperations(), *Results->Diag, Results->LangOpts, *Results->SourceMgr, *Results->FileMgr, Results->Diagnostics, Results->TemporaryBuffers); Results->DiagnosticsWrappers.resize(Results->Diagnostics.size()); // Keep a reference to the allocator used for cached global completions, so // that we can be sure that the memory used by our code completion strings // doesn't get freed due to subsequent reparses (while the code completion // results are still active). Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); SmallString<256> LogResult; llvm::raw_svector_ostream os(LogResult); // Figure out the language and whether or not it uses PCH. const char *lang = 0; bool usesPCH = false; for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); I != E; ++I) { if (*I == 0) continue; if (strcmp(*I, "-x") == 0) { if (I + 1 != E) { lang = *(++I); continue; } } else if (strcmp(*I, "-include") == 0) { if (I+1 != E) { const char *arg = *(++I); SmallString<512> pchName; { llvm::raw_svector_ostream os(pchName); os << arg << ".pth"; } pchName.push_back('\0'); struct stat stat_results; if (stat(pchName.str().c_str(), &stat_results) == 0) usesPCH = true; continue; } } } os << "{ "; os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); os << ", \"numRes\": " << Results->NumResults; os << ", \"diags\": " << Results->Diagnostics.size(); os << ", \"pch\": " << (usesPCH ? "true" : "false"); os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; const char *name = getlogin(); os << ", \"user\": \"" << (name ? name : "unknown") << '"'; os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; os << " }"; StringRef res = os.str(); if (res.size() > 0) { do { // Setup the UDP socket. struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, &servaddr.sin_addr) <= 0) break; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) break; sendto(sockfd, res.data(), res.size(), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); close(sockfd); } while (false); } #endif #endif return Results; }
/// Mangle this entity as a std::string. std::string LinkEntity::mangleAsString() const { IRGenMangler mangler; switch (getKind()) { case Kind::DispatchThunk: return mangler.mangleEntity(getDecl(), /*isCurried=*/false, ASTMangler::SymbolKind::SwiftDispatchThunk); case Kind::DispatchThunkInitializer: return mangler.mangleConstructorEntity( cast<ConstructorDecl>(getDecl()), /*isAllocating=*/false, /*isCurried=*/false, ASTMangler::SymbolKind::SwiftDispatchThunk); case Kind::DispatchThunkAllocator: return mangler.mangleConstructorEntity( cast<ConstructorDecl>(getDecl()), /*isAllocating=*/true, /*isCurried=*/false, ASTMangler::SymbolKind::SwiftDispatchThunk); case Kind::ValueWitness: return mangler.mangleValueWitness(getType(), getValueWitness()); case Kind::ValueWitnessTable: return mangler.mangleValueWitnessTable(getType()); case Kind::TypeMetadataAccessFunction: return mangler.mangleTypeMetadataAccessFunction(getType()); case Kind::TypeMetadataLazyCacheVariable: return mangler.mangleTypeMetadataLazyCacheVariable(getType()); case Kind::TypeMetadataInstantiationCache: return mangler.mangleTypeMetadataInstantiationCache( cast<NominalTypeDecl>(getDecl())); case Kind::TypeMetadataInstantiationFunction: return mangler.mangleTypeMetadataInstantiationFunction( cast<NominalTypeDecl>(getDecl())); case Kind::TypeMetadataInPlaceInitializationCache: return mangler.mangleTypeMetadataInPlaceInitializationCache( cast<NominalTypeDecl>(getDecl())); case Kind::TypeMetadataCompletionFunction: return mangler.mangleTypeMetadataCompletionFunction( cast<NominalTypeDecl>(getDecl())); case Kind::TypeMetadata: switch (getMetadataAddress()) { case TypeMetadataAddress::FullMetadata: return mangler.mangleTypeFullMetadataFull(getType()); case TypeMetadataAddress::AddressPoint: return mangler.mangleTypeMetadataFull(getType()); } llvm_unreachable("invalid metadata address"); case Kind::TypeMetadataPattern: return mangler.mangleTypeMetadataPattern( cast<NominalTypeDecl>(getDecl())); case Kind::ForeignTypeMetadataCandidate: return mangler.mangleTypeMetadataFull(getType()); case Kind::SwiftMetaclassStub: return mangler.mangleClassMetaClass(cast<ClassDecl>(getDecl())); case Kind::ClassMetadataBaseOffset: // class metadata base offset return mangler.mangleClassMetadataBaseOffset(cast<ClassDecl>(getDecl())); case Kind::NominalTypeDescriptor: return mangler.mangleNominalTypeDescriptor( cast<NominalTypeDecl>(getDecl())); case Kind::PropertyDescriptor: return mangler.manglePropertyDescriptor( cast<AbstractStorageDecl>(getDecl())); case Kind::ModuleDescriptor: return mangler.mangleModuleDescriptor(cast<ModuleDecl>(getDecl())); case Kind::ExtensionDescriptor: return mangler.mangleExtensionDescriptor(getExtension()); case Kind::AnonymousDescriptor: return mangler.mangleAnonymousDescriptor(getDeclContext()); case Kind::ProtocolDescriptor: return mangler.mangleProtocolDescriptor(cast<ProtocolDecl>(getDecl())); case Kind::ProtocolConformanceDescriptor: return mangler.mangleProtocolConformanceDescriptor( cast<NormalProtocolConformance>(getProtocolConformance())); case Kind::EnumCase: return mangler.mangleEnumCase(getDecl()); case Kind::FieldOffset: return mangler.mangleFieldOffset(getDecl()); case Kind::DirectProtocolWitnessTable: return mangler.mangleDirectProtocolWitnessTable(getProtocolConformance()); case Kind::GenericProtocolWitnessTableCache: return mangler.mangleGenericProtocolWitnessTableCache( getProtocolConformance()); case Kind::GenericProtocolWitnessTableInstantiationFunction: return mangler.mangleGenericProtocolWitnessTableInstantiationFunction( getProtocolConformance()); case Kind::ResilientProtocolWitnessTable: return mangler.mangleResilientProtocolWitnessTable(getProtocolConformance()); case Kind::ProtocolWitnessTableAccessFunction: return mangler.mangleProtocolWitnessTableAccessFunction( getProtocolConformance()); case Kind::ProtocolWitnessTablePattern: return mangler.mangleProtocolWitnessTablePattern(getProtocolConformance()); case Kind::ProtocolWitnessTableLazyAccessFunction: return mangler.mangleProtocolWitnessTableLazyAccessFunction(getType(), getProtocolConformance()); case Kind::ProtocolWitnessTableLazyCacheVariable: return mangler.mangleProtocolWitnessTableLazyCacheVariable(getType(), getProtocolConformance()); case Kind::AssociatedTypeMetadataAccessFunction: return mangler.mangleAssociatedTypeMetadataAccessFunction( getProtocolConformance(), getAssociatedType()->getNameStr()); case Kind::AssociatedTypeWitnessTableAccessFunction: { auto assocConf = getAssociatedConformance(); return mangler.mangleAssociatedTypeWitnessTableAccessFunction( getProtocolConformance(), assocConf.first, assocConf.second); } case Kind::CoroutineContinuationPrototype: return mangler.mangleCoroutineContinuationPrototype( cast<SILFunctionType>(getType())); // An Objective-C class reference reference. The symbol is private, so // the mangling is unimportant; it should just be readable in LLVM IR. case Kind::ObjCClassRef: { llvm::SmallString<64> tempBuffer; StringRef name = cast<ClassDecl>(getDecl())->getObjCRuntimeName(tempBuffer); std::string Result("\01l_OBJC_CLASS_REF_$_"); Result.append(name.data(), name.size()); return Result; } // An Objective-C class reference; not a swift mangling. case Kind::ObjCClass: { llvm::SmallString<64> TempBuffer; StringRef Name = cast<ClassDecl>(getDecl())->getObjCRuntimeName(TempBuffer); std::string Result("OBJC_CLASS_$_"); Result.append(Name.data(), Name.size()); return Result; } // An Objective-C metaclass reference; not a swift mangling. case Kind::ObjCMetaclass: { llvm::SmallString<64> TempBuffer; StringRef Name = cast<ClassDecl>(getDecl())->getObjCRuntimeName(TempBuffer); std::string Result("OBJC_METACLASS_$_"); Result.append(Name.data(), Name.size()); return Result; } case Kind::SILFunction: return getSILFunction()->getName(); case Kind::SILGlobalVariable: return getSILGlobalVariable()->getName(); case Kind::ReflectionBuiltinDescriptor: return mangler.mangleReflectionBuiltinDescriptor(getType()); case Kind::ReflectionFieldDescriptor: return mangler.mangleReflectionFieldDescriptor(getType()); case Kind::ReflectionAssociatedTypeDescriptor: return mangler.mangleReflectionAssociatedTypeDescriptor( getProtocolConformance()); } llvm_unreachable("bad entity kind!"); }
static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnname, uint8_t *Section, size_t Allocated, uint8_t *UnwindData) { DWORD mod_size = 0; #if defined(_CPU_X86_64_) #if !defined(USE_MCJIT) uint8_t *catchjmp = Section+Allocated; UnwindData = (uint8_t*)(((uintptr_t)catchjmp+12+3)&~(uintptr_t)3); if (!catchjmp[0]) { catchjmp[0] = 0x48; catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [...] *(uint64_t*)(&catchjmp[2]) = (uint64_t)&_seh_exception_handler; catchjmp[10] = 0xff; catchjmp[11] = 0xe0; // jmp RAX UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER UnwindData[1] = 4; // size of prolog (bytes) UnwindData[2] = 2; // count of unwind codes (slots) UnwindData[3] = 0x05; // frame register (rbp) = rsp UnwindData[4] = 4; // second instruction UnwindData[5] = 0x03; // mov RBP, RSP UnwindData[6] = 1; // first instruction UnwindData[7] = 0x50; // push RBP *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - Section); // relative location of catchjmp mod_size = (DWORD)Allocated+48; } PRUNTIME_FUNCTION tbl = (PRUNTIME_FUNCTION)(UnwindData+12); #else PRUNTIME_FUNCTION tbl = (PRUNTIME_FUNCTION)malloc(sizeof(RUNTIME_FUNCTION)); #endif tbl->BeginAddress = (DWORD)(Code - Section); tbl->EndAddress = (DWORD)(Code - Section + Size); tbl->UnwindData = (DWORD)(UnwindData - Section); #else // defined(_CPU_X86_64_) Section += (uintptr_t)Code; mod_size = Size; #endif if (0) { assert(!jl_in_stackwalk); jl_in_stackwalk = 1; if (mod_size && !SymLoadModuleEx(GetCurrentProcess(), NULL, NULL, NULL, (DWORD64)Section, mod_size, NULL, SLMFLAG_VIRTUAL)) { #if defined(_CPU_X86_64_) && !defined(USE_MCJIT) catchjmp[0] = 0; #endif static int warned = 0; if (!warned) { jl_printf(JL_STDERR, "WARNING: failed to insert module info for backtrace: %lu\n", GetLastError()); warned = 1; } } else { size_t len = fnname.size()+1; if (len > MAX_SYM_NAME) len = MAX_SYM_NAME; char *name = (char*)alloca(len); memcpy(name, fnname.data(), len-1); name[len-1] = 0; if (!SymAddSymbol(GetCurrentProcess(), (ULONG64)Section, name, (DWORD64)Code, (DWORD)Size, 0)) { jl_printf(JL_STDERR, "WARNING: failed to insert function name %s into debug info: %lu\n", name, GetLastError()); } } jl_in_stackwalk = 0; } #if defined(_CPU_X86_64_) if (!RtlAddFunctionTable(tbl, 1, (DWORD64)Section)) { static int warned = 0; if (!warned) { jl_printf(JL_STDERR, "WARNING: failed to insert function stack unwind info: %lu\n", GetLastError()); warned = 1; } } #endif }
bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, const DWARFUnit *cu) { bool indirect = false; bool is_block = false; Value.data = nullptr; // Read the value for the form into value and follow and DW_FORM_indirect // instances we run into do { indirect = false; switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: { if (!cu) return false; uint16_t AddrSize = (Form == DW_FORM_addr) ? cu->getAddressByteSize() : getRefAddrSize(cu->getAddressByteSize(), cu->getVersion()); RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); if (AI != cu->getRelocMap()->end()) { const std::pair<uint8_t, int64_t> &R = AI->second; Value.uval = data.getUnsigned(offset_ptr, AddrSize) + R.second; } else Value.uval = data.getUnsigned(offset_ptr, AddrSize); break; } case DW_FORM_exprloc: case DW_FORM_block: Value.uval = data.getULEB128(offset_ptr); is_block = true; break; case DW_FORM_block1: Value.uval = data.getU8(offset_ptr); is_block = true; break; case DW_FORM_block2: Value.uval = data.getU16(offset_ptr); is_block = true; break; case DW_FORM_block4: Value.uval = data.getU32(offset_ptr); is_block = true; break; case DW_FORM_data1: case DW_FORM_ref1: case DW_FORM_flag: Value.uval = data.getU8(offset_ptr); break; case DW_FORM_data2: case DW_FORM_ref2: Value.uval = data.getU16(offset_ptr); break; case DW_FORM_data4: case DW_FORM_ref4: { Value.uval = data.getU32(offset_ptr); if (!cu) break; RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr-4); if (AI != cu->getRelocMap()->end()) Value.uval += AI->second.second; break; } case DW_FORM_data8: case DW_FORM_ref8: Value.uval = data.getU64(offset_ptr); break; case DW_FORM_sdata: Value.sval = data.getSLEB128(offset_ptr); break; case DW_FORM_strp: { Value.uval = data.getU32(offset_ptr); if (!cu) break; RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr-4); if (AI != cu->getRelocMap()->end()) Value.uval += AI->second.second; break; } case DW_FORM_udata: case DW_FORM_ref_udata: Value.uval = data.getULEB128(offset_ptr); break; case DW_FORM_string: Value.cstr = data.getCStr(offset_ptr); break; case DW_FORM_indirect: Form = data.getULEB128(offset_ptr); indirect = true; break; case DW_FORM_sec_offset: { // FIXME: This is 64-bit for DWARF64. Value.uval = data.getU32(offset_ptr); if (!cu) break; RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr-4); if (AI != cu->getRelocMap()->end()) Value.uval += AI->second.second; break; } case DW_FORM_flag_present: Value.uval = 1; break; case DW_FORM_ref_sig8: Value.uval = data.getU64(offset_ptr); break; case DW_FORM_GNU_addr_index: case DW_FORM_GNU_str_index: Value.uval = data.getULEB128(offset_ptr); break; default: return false; } } while (indirect); if (is_block) { StringRef str = data.getData().substr(*offset_ptr, Value.uval); Value.data = nullptr; if (!str.empty()) { Value.data = reinterpret_cast<const uint8_t *>(str.data()); *offset_ptr += Value.uval; } } return true; }
static void DisassembleInputMachO2(StringRef Filename, MachOObjectFile *MachOOF) { const Target *TheTarget = GetTarget(MachOOF); if (!TheTarget) { // GetTarget prints out stuff. return; } OwningPtr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo()); OwningPtr<MCInstrAnalysis> InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo.get())); // Set up disassembler. OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); OwningPtr<const MCAsmInfo> AsmInfo( TheTarget->createMCAsmInfo(*MRI, TripleName)); OwningPtr<const MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, "", "")); OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI)); int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI, *STI)); if (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) { errs() << "error: couldn't initialize disassembler for target " << TripleName << '\n'; return; } outs() << '\n' << Filename << ":\n\n"; MachO::mach_header Header = MachOOF->getHeader(); // FIXME: FoundFns isn't used anymore. Using symbols/LC_FUNCTION_STARTS to // determine function locations will eventually go in MCObjectDisassembler. // FIXME: Using the -cfg command line option, this code used to be able to // annotate relocations with the referenced symbol's name, and if this was // inside a __[cf]string section, the data it points to. This is now replaced // by the upcoming MCSymbolizer, which needs the appropriate setup done above. std::vector<SectionRef> Sections; std::vector<SymbolRef> Symbols; SmallVector<uint64_t, 8> FoundFns; uint64_t BaseSegmentAddress; getSectionsAndSymbols(Header, MachOOF, Sections, Symbols, FoundFns, BaseSegmentAddress); // Sort the symbols by address, just in case they didn't come in that way. std::sort(Symbols.begin(), Symbols.end(), SymbolSorter()); // Build a data in code table that is sorted on by the address of each entry. uint64_t BaseAddress = 0; if (Header.filetype == MachO::MH_OBJECT) Sections[0].getAddress(BaseAddress); else BaseAddress = BaseSegmentAddress; DiceTable Dices; for (dice_iterator DI = MachOOF->begin_dices(), DE = MachOOF->end_dices(); DI != DE; ++DI) { uint32_t Offset; DI->getOffset(Offset); Dices.push_back(std::make_pair(BaseAddress + Offset, *DI)); } array_pod_sort(Dices.begin(), Dices.end()); #ifndef NDEBUG raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); #else raw_ostream &DebugOut = nulls(); #endif OwningPtr<DIContext> diContext; ObjectFile *DbgObj = MachOOF; // Try to find debug info and set up the DIContext for it. if (UseDbg) { // A separate DSym file path was specified, parse it as a macho file, // get the sections and supply it to the section name parsing machinery. if (!DSYMFile.empty()) { OwningPtr<MemoryBuffer> Buf; if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile, Buf)) { errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n'; return; } DbgObj = ObjectFile::createMachOObjectFile(Buf.take()).get(); } // Setup the DIContext diContext.reset(DIContext::getDWARFContext(DbgObj)); } for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { bool SectIsText = false; Sections[SectIdx].isText(SectIsText); if (SectIsText == false) continue; StringRef SectName; if (Sections[SectIdx].getName(SectName) || SectName != "__text") continue; // Skip non-text sections DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl(); StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR); if (SegmentName != "__TEXT") continue; StringRef Bytes; Sections[SectIdx].getContents(Bytes); StringRefMemoryObject memoryObject(Bytes); bool symbolTableWorked = false; // Parse relocations. std::vector<std::pair<uint64_t, SymbolRef> > Relocs; for (relocation_iterator RI = Sections[SectIdx].relocation_begin(), RE = Sections[SectIdx].relocation_end(); RI != RE; ++RI) { uint64_t RelocOffset, SectionAddress; RI->getOffset(RelocOffset); Sections[SectIdx].getAddress(SectionAddress); RelocOffset -= SectionAddress; symbol_iterator RelocSym = RI->getSymbol(); Relocs.push_back(std::make_pair(RelocOffset, *RelocSym)); } array_pod_sort(Relocs.begin(), Relocs.end()); // Disassemble symbol by symbol. for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) { StringRef SymName; Symbols[SymIdx].getName(SymName); SymbolRef::Type ST; Symbols[SymIdx].getType(ST); if (ST != SymbolRef::ST_Function) continue; // Make sure the symbol is defined in this section. bool containsSym = false; Sections[SectIdx].containsSymbol(Symbols[SymIdx], containsSym); if (!containsSym) continue; // Start at the address of the symbol relative to the section's address. uint64_t SectionAddress = 0; uint64_t Start = 0; Sections[SectIdx].getAddress(SectionAddress); Symbols[SymIdx].getAddress(Start); Start -= SectionAddress; // Stop disassembling either at the beginning of the next symbol or at // the end of the section. bool containsNextSym = false; uint64_t NextSym = 0; uint64_t NextSymIdx = SymIdx+1; while (Symbols.size() > NextSymIdx) { SymbolRef::Type NextSymType; Symbols[NextSymIdx].getType(NextSymType); if (NextSymType == SymbolRef::ST_Function) { Sections[SectIdx].containsSymbol(Symbols[NextSymIdx], containsNextSym); Symbols[NextSymIdx].getAddress(NextSym); NextSym -= SectionAddress; break; } ++NextSymIdx; } uint64_t SectSize; Sections[SectIdx].getSize(SectSize); uint64_t End = containsNextSym ? NextSym : SectSize; uint64_t Size; symbolTableWorked = true; outs() << SymName << ":\n"; DILineInfo lastLine; for (uint64_t Index = Start; Index < End; Index += Size) { MCInst Inst; uint64_t SectAddress = 0; Sections[SectIdx].getAddress(SectAddress); outs() << format("%8" PRIx64 ":\t", SectAddress + Index); // Check the data in code table here to see if this is data not an // instruction to be disassembled. DiceTable Dice; Dice.push_back(std::make_pair(SectAddress + Index, DiceRef())); dice_table_iterator DTI = std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(), compareDiceTableEntries); if (DTI != Dices.end()){ uint16_t Length; DTI->second.getLength(Length); DumpBytes(StringRef(Bytes.data() + Index, Length)); uint16_t Kind; DTI->second.getKind(Kind); DumpDataInCode(Bytes.data() + Index, Length, Kind); continue; } if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, DebugOut, nulls())) { DumpBytes(StringRef(Bytes.data() + Index, Size)); IP->printInst(&Inst, outs(), ""); // Print debug info. if (diContext) { DILineInfo dli = diContext->getLineInfoForAddress(SectAddress + Index); // Print valid line info if it changed. if (dli != lastLine && dli.getLine() != 0) outs() << "\t## " << dli.getFileName() << ':' << dli.getLine() << ':' << dli.getColumn(); lastLine = dli; } outs() << "\n"; } else { errs() << "llvm-objdump: warning: invalid instruction encoding\n"; if (Size == 0) Size = 1; // skip illegible bytes } } } if (!symbolTableWorked) { // Reading the symbol table didn't work, disassemble the whole section. uint64_t SectAddress; Sections[SectIdx].getAddress(SectAddress); uint64_t SectSize; Sections[SectIdx].getSize(SectSize); uint64_t InstSize; for (uint64_t Index = 0; Index < SectSize; Index += InstSize) { MCInst Inst; if (DisAsm->getInstruction(Inst, InstSize, memoryObject, Index, DebugOut, nulls())) { outs() << format("%8" PRIx64 ":\t", SectAddress + Index); DumpBytes(StringRef(Bytes.data() + Index, InstSize)); IP->printInst(&Inst, outs(), ""); outs() << "\n"; } else { errs() << "llvm-objdump: warning: invalid instruction encoding\n"; if (InstSize == 0) InstSize = 1; // skip illegible bytes } } } } }
static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, const LangOptions &LO, const TargetInfo &Target, bool Warn, bool isFreeBSDKPrintf) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; const char *I = Beg; const char *Start = nullptr; UpdateOnReturn <const char*> UpdateBeg(Beg, I); // Look for a '%' character that indicates the start of a format specifier. for ( ; I != E ; ++I) { char c = *I; if (c == '\0') { // Detect spurious null characters, which are likely errors. H.HandleNullChar(I); return true; } if (c == '%') { Start = I++; // Record the start of the format specifier. break; } } // No format specifier found? if (!Start) return false; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } PrintfSpecifier FS; if (ParseArgPosition(H, FS, Start, I, E)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } if (*I == '{') { ++I; unsigned char PrivacyFlags = 0; StringRef MatchedStr; do { StringRef Str(I, E - I); std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r ]*(,|})"; llvm::Regex R(Match); SmallVector<StringRef, 2> Matches; if (R.match(Str, &Matches)) { MatchedStr = Matches[1]; I += Matches[0].size(); // Set the privacy flag if the privacy annotation in the // comma-delimited segment is at least as strict as the privacy // annotations in previous comma-delimited segments. if (MatchedStr.equals("private")) PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate; else if (PrivacyFlags == 0 && MatchedStr.equals("public")) PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic; } else { size_t CommaOrBracePos = Str.find_if([](char c) { return c == ',' || c == '}'; }); if (CommaOrBracePos == StringRef::npos) { // Neither a comma nor the closing brace was found. if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } I += CommaOrBracePos + 1; } // Continue until the closing brace is found. } while (*(I - 1) == ','); // Set the privacy flag. switch (PrivacyFlags) { case 0: break; case clang::analyze_os_log::OSLogBufferItem::IsPrivate: FS.setIsPrivate(MatchedStr.data()); break; case clang::analyze_os_log::OSLogBufferItem::IsPublic: FS.setIsPublic(MatchedStr.data()); break; default: llvm_unreachable("Unexpected privacy flag value"); } } // Look for flags (if any). bool hasMore = true; for ( ; I != E; ++I) { switch (*I) { default: hasMore = false; break; case '\'': // FIXME: POSIX specific. Always accept? FS.setHasThousandsGrouping(I); break; case '-': FS.setIsLeftJustified(I); break; case '+': FS.setHasPlusPrefix(I); break; case ' ': FS.setHasSpacePrefix(I); break; case '#': FS.setHasAlternativeForm(I); break; case '0': FS.setHasLeadingZeros(I); break; } if (!hasMore) break; } if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the field width (if any). if (ParseFieldWidth(H, FS, Start, I, E, FS.usesPositionalArg() ? nullptr : &argIndex)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the precision (if any). if (*I == '.') { ++I; if (I == E) { if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } if (ParsePrecision(H, FS, Start, I, E, FS.usesPositionalArg() ? nullptr : &argIndex)) return true; if (I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } } // Look for the length modifier. if (ParseLengthModifier(FS, I, E, LO) && I == E) { // No more characters left? if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Look for the Objective-C modifier flags, if any. // We parse these here, even if they don't apply to // the conversion specifier, and then emit an error // later if the conversion specifier isn't '@'. This // enables better recovery, and we don't know if // these flags are applicable until later. const char *ObjCModifierFlagsStart = nullptr, *ObjCModifierFlagsEnd = nullptr; if (*I == '[') { ObjCModifierFlagsStart = I; ++I; auto flagStart = I; for (;; ++I) { ObjCModifierFlagsEnd = I; if (I == E) { if (Warn) H.HandleIncompleteSpecifier(Start, E - Start); return true; } // Did we find the closing ']'? if (*I == ']') { if (ParseObjCFlags(H, FS, flagStart, I, Warn)) return true; ++I; break; } // There are no separators defined yet for multiple // Objective-C modifier flags. When those are // defined, this is the place to check. } } if (*I == '\0') { // Detect spurious null characters, which are likely errors. H.HandleNullChar(I); return true; } // Finally, look for the conversion specifier. const char *conversionPosition = I++; ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; switch (*conversionPosition) { default: break; // C99: 7.19.6.1 (section 8). case '%': k = ConversionSpecifier::PercentArg; break; case 'A': k = ConversionSpecifier::AArg; break; case 'E': k = ConversionSpecifier::EArg; break; case 'F': k = ConversionSpecifier::FArg; break; case 'G': k = ConversionSpecifier::GArg; break; case 'X': k = ConversionSpecifier::XArg; break; case 'a': k = ConversionSpecifier::aArg; break; case 'c': k = ConversionSpecifier::cArg; break; case 'd': k = ConversionSpecifier::dArg; break; case 'e': k = ConversionSpecifier::eArg; break; case 'f': k = ConversionSpecifier::fArg; break; case 'g': k = ConversionSpecifier::gArg; break; case 'i': k = ConversionSpecifier::iArg; break; case 'n': k = ConversionSpecifier::nArg; break; case 'o': k = ConversionSpecifier::oArg; break; case 'p': k = ConversionSpecifier::pArg; break; case 's': k = ConversionSpecifier::sArg; break; case 'u': k = ConversionSpecifier::uArg; break; case 'x': k = ConversionSpecifier::xArg; break; // POSIX specific. case 'C': k = ConversionSpecifier::CArg; break; case 'S': k = ConversionSpecifier::SArg; break; // Apple extension for os_log case 'P': k = ConversionSpecifier::PArg; break; // Objective-C. case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; // FreeBSD kernel specific. case 'b': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDbArg; // int followed by char * break; case 'r': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDrArg; // int break; case 'y': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDyArg; // int break; // Apple-specific. case 'D': if (isFreeBSDKPrintf) k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * else if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::DArg; break; case 'O': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::OArg; break; case 'U': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::UArg; break; // MS specific. case 'Z': if (Target.getTriple().isOSMSVCRT()) k = ConversionSpecifier::ZArg; } // Check to see if we used the Objective-C modifier flags with // a conversion specifier other than '@'. if (k != ConversionSpecifier::ObjCObjArg && k != ConversionSpecifier::InvalidSpecifier && ObjCModifierFlagsStart) { H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, ObjCModifierFlagsEnd + 1, conversionPosition); return true; } PrintfConversionSpecifier CS(conversionPosition, k); FS.setConversionSpecifier(CS); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); // FreeBSD kernel specific. if (k == ConversionSpecifier::FreeBSDbArg || k == ConversionSpecifier::FreeBSDDArg) argIndex++; if (k == ConversionSpecifier::InvalidSpecifier) { unsigned Len = I - Start; if (ParseUTF8InvalidSpecifier(Start, E, Len)) { CS.setEndScanList(Start + Len); FS.setConversionSpecifier(CS); } // Assume the conversion takes one argument. return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len); } return PrintfSpecifierResult(Start, FS); }
/// GetDwarfFile - takes a file name an number to place in the dwarf file and /// directory tables. If the file number has already been allocated it is an /// error and zero is returned and the client reports the error, else the /// allocated file number is returned. The file numbers may be in any order. unsigned MCContext::GetDwarfFile(StringRef Directory, StringRef FileName, unsigned FileNumber, unsigned CUID) { // TODO: a FileNumber of zero says to use the next available file number. // Note: in GenericAsmParser::ParseDirectiveFile() FileNumber was checked // to not be less than one. This needs to be change to be not less than zero. SmallVectorImpl<MCDwarfFile *>& MCDwarfFiles = MCDwarfFilesCUMap[CUID]; SmallVectorImpl<StringRef>& MCDwarfDirs = MCDwarfDirsCUMap[CUID]; // Make space for this FileNumber in the MCDwarfFiles vector if needed. if (FileNumber >= MCDwarfFiles.size()) { MCDwarfFiles.resize(FileNumber + 1); } else { MCDwarfFile *&ExistingFile = MCDwarfFiles[FileNumber]; if (ExistingFile) // It is an error to use see the same number more than once. return 0; } // Get the new MCDwarfFile slot for this FileNumber. MCDwarfFile *&File = MCDwarfFiles[FileNumber]; if (Directory.empty()) { // Separate the directory part from the basename of the FileName. StringRef tFileName = sys::path::filename(FileName); if (!tFileName.empty()) { Directory = sys::path::parent_path(FileName); if (!Directory.empty()) FileName = tFileName; } } // Find or make a entry in the MCDwarfDirs vector for this Directory. // Capture directory name. unsigned DirIndex; if (Directory.empty()) { // For FileNames with no directories a DirIndex of 0 is used. DirIndex = 0; } else { DirIndex = 0; for (unsigned End = MCDwarfDirs.size(); DirIndex < End; DirIndex++) { if (Directory == MCDwarfDirs[DirIndex]) break; } if (DirIndex >= MCDwarfDirs.size()) { char *Buf = static_cast<char *>(Allocate(Directory.size())); memcpy(Buf, Directory.data(), Directory.size()); MCDwarfDirs.push_back(StringRef(Buf, Directory.size())); } // The DirIndex is one based, as DirIndex of 0 is used for FileNames with // no directories. MCDwarfDirs[] is unlike MCDwarfFiles[] in that the // directory names are stored at MCDwarfDirs[DirIndex-1] where FileNames // are stored at MCDwarfFiles[FileNumber].Name . DirIndex++; } // Now make the MCDwarfFile entry and place it in the slot in the MCDwarfFiles // vector. char *Buf = static_cast<char *>(Allocate(FileName.size())); memcpy(Buf, FileName.data(), FileName.size()); File = new (*this) MCDwarfFile(StringRef(Buf, FileName.size()), DirIndex); // return the allocated FileNumber. return FileNumber; }
extern "C" const char* LLVMRustGetHostCPUName(size_t *len) { StringRef Name = sys::getHostCPUName(); *len = Name.size(); return Name.data(); }
StringRef StringScratchSpace::copyString(StringRef string) { void *memory = Allocator.Allocate(string.size(), alignof(char)); memcpy(memory, string.data(), string.size()); return StringRef(static_cast<char *>(memory), string.size()); }
bool swift::omitNeedlessWords(StringRef &baseName, MutableArrayRef<StringRef> argNames, StringRef firstParamName, OmissionTypeName resultType, OmissionTypeName contextType, ArrayRef<OmissionTypeName> paramTypes, bool returnsSelf, bool isProperty, const InheritedNameSet *allPropertyNames, StringScratchSpace &scratch) { bool anyChanges = false; /// Local function that lowercases all of the base names and /// argument names before returning. auto lowercaseAcronymsForReturn = [&] { StringRef newBaseName = toLowercaseInitialisms(baseName, scratch); if (baseName.data() != newBaseName.data()) { baseName = newBaseName; anyChanges = true; } for (StringRef &argName : argNames) { StringRef newArgName = toLowercaseInitialisms(argName, scratch); if (argName.data() != newArgName.data()) { argName = newArgName; anyChanges = true; } } return anyChanges; }; // If the result type matches the context, remove the context type from the // prefix of the name. bool resultTypeMatchesContext = returnsSelf || (resultType == contextType); if (resultTypeMatchesContext) { StringRef newBaseName = omitNeedlessWordsFromPrefix(baseName, contextType, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } // Strip the context type from the base name of a method. if (!isProperty) { StringRef newBaseName = ::omitNeedlessWords(baseName, contextType, NameRole::BaseNameSelf, allPropertyNames, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } if (paramTypes.empty()) { if (resultTypeMatchesContext) { StringRef newBaseName = ::omitNeedlessWords( baseName, returnsSelf ? contextType : resultType, NameRole::Property, allPropertyNames, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } return lowercaseAcronymsForReturn(); } if (camel_case::getFirstWord(baseName) == "set") { StringRef newBaseName = ::omitNeedlessWords( baseName, contextType, NameRole::Property, allPropertyNames, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } // If needed, split the base name. if (!argNames.empty() && splitBaseName(baseName, argNames[0], paramTypes[0], firstParamName)) anyChanges = true; // Omit needless words based on parameter types. for (unsigned i = 0, n = argNames.size(); i != n; ++i) { // If there is no corresponding parameter, there is nothing to // omit. if (i >= paramTypes.size()) continue; // Omit needless words based on the type of the parameter. NameRole role = i > 0 ? NameRole::SubsequentParameter : argNames[0].empty() ? NameRole::BaseName : baseName == "init" ? NameRole::SubsequentParameter : paramTypes[0].hasDefaultArgument() ? NameRole::SubsequentParameter : NameRole::FirstParameter; // Omit needless words from the name. StringRef name = role == NameRole::BaseName ? baseName : argNames[i]; StringRef newName = ::omitNeedlessWords(name, paramTypes[i], role, role == NameRole::BaseName ? allPropertyNames : nullptr, scratch); if (name == newName) continue; // Record this change. anyChanges = true; if (role == NameRole::BaseName) { baseName = newName; } else { argNames[i] = newName; } } return lowercaseAcronymsForReturn(); }
unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, const SectionRef &Section, bool IsCode) { StringRef data; uint64_t Alignment64; Check(Section.getContents(data)); Check(Section.getAlignment(Alignment64)); unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; bool IsRequired; bool IsVirtual; bool IsZeroInit; bool IsReadOnly; uint64_t DataSize; unsigned PaddingSize = 0; unsigned StubBufSize = 0; StringRef Name; Check(Section.isRequiredForExecution(IsRequired)); Check(Section.isVirtual(IsVirtual)); Check(Section.isZeroInit(IsZeroInit)); Check(Section.isReadOnlyData(IsReadOnly)); Check(Section.getSize(DataSize)); Check(Section.getName(Name)); StubBufSize = computeSectionStubBufSize(Obj, Section); // The .eh_frame section (at least on Linux) needs an extra four bytes padded // with zeroes added at the end. For MachO objects, this section has a // slightly different name, so this won't have any effect for MachO objects. if (Name == ".eh_frame") PaddingSize = 4; uintptr_t Allocate; unsigned SectionID = Sections.size(); uint8_t *Addr; const char *pData = 0; // Some sections, such as debug info, don't need to be loaded for execution. // Leave those where they are. if (IsRequired) { Allocate = DataSize + PaddingSize + StubBufSize; Addr = IsCode ? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID, Name) : MemMgr->allocateDataSection(Allocate, Alignment, SectionID, Name, IsReadOnly); if (!Addr) report_fatal_error("Unable to allocate section memory!"); // Virtual sections have no data in the object image, so leave pData = 0 if (!IsVirtual) pData = data.data(); // Zero-initialize or copy the data from the image if (IsZeroInit || IsVirtual) memset(Addr, 0, DataSize); else memcpy(Addr, pData, DataSize); // Fill in any extra bytes we allocated for padding if (PaddingSize != 0) { memset(Addr + DataSize, 0, PaddingSize); // Update the DataSize variable so that the stub offset is set correctly. DataSize += PaddingSize; } DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name << " obj addr: " << format("%p", pData) << " new addr: " << format("%p", Addr) << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize << " Allocate: " << Allocate << "\n"); Obj.updateSectionAddress(Section, (uint64_t)Addr); } else { // Even if we didn't load the section, we need to record an entry for it // to handle later processing (and by 'handle' I mean don't do anything // with these sections). Allocate = 0; Addr = 0; DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name << " obj addr: " << format("%p", data.data()) << " new addr: 0" << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize << " Allocate: " << Allocate << "\n"); } Sections.push_back(SectionEntry(Name, Addr, DataSize, (uintptr_t)pData)); return SectionID; }
void ClangCommentPrinter::printCommentsUntil(ClangNode Node) { const auto &Ctx = ClangLoader.getClangASTContext(); const auto &SM = Ctx.getSourceManager(); clang::SourceLocation NodeLoc = SM.getFileLoc(Node.getSourceRange().getBegin()); if (NodeLoc.isInvalid()) return; unsigned NodeLineNo = SM.getSpellingLineNumber(NodeLoc); clang::FileID FID = SM.getFileID(NodeLoc); if (FID.isInvalid()) return; clang::SourceLocation FileLoc = SM.getLocForStartOfFile(FID); StringRef Text = SM.getBufferData(FID); if (Text.empty()) return; const char *BufStart = Text.data(); const char *BufPtr = BufStart + getResumeOffset(FID); const char *BufEnd = BufStart + Text.size(); assert(BufPtr <= BufEnd); if (BufPtr == BufEnd) return; // nothing left. clang::Lexer Lex(FileLoc, Ctx.getLangOpts(), BufStart, BufPtr, BufEnd); Lex.SetCommentRetentionState(true); unsigned &LastPrintedLineNo = LastEntityLines[FID]; clang::Token Tok; do { BufPtr = Lex.getBufferLocation(); Lex.LexFromRawLexer(Tok); if (Tok.is(clang::tok::eof)) break; if (Tok.isNot(clang::tok::comment)) continue; // Reached a comment. clang::SourceLocation CommentLoc = Tok.getLocation(); std::pair<clang::FileID, unsigned> LocInfo = SM.getDecomposedLoc(CommentLoc); assert(LocInfo.first == FID); unsigned LineNo = SM.getLineNumber(LocInfo.first, LocInfo.second); if (LineNo > NodeLineNo) break; // Comment is past the clang node. bool IsDocComment = isDocumentationComment(CommentLoc, Node); // Print out the comment. StringRef CommentText(BufStart + LocInfo.second, Tok.getLength()); // Check if comment is on same line but after the declaration. if (SM.isBeforeInTranslationUnit(NodeLoc, Tok.getLocation())) { if (!IsDocComment) PendingComments.push_back(CommentText); continue; } if (LastPrintedLineNo && LineNo - LastPrintedLineNo > 1) { *this << "\n"; printIndent(); } if (!IsDocComment) { unsigned StartLocCol = SM.getSpellingColumnNumber(Tok.getLocation()); printComment(CommentText, StartLocCol); } LastPrintedLineNo = SM.getLineNumber(LocInfo.first, LocInfo.second + Tok.getLength()); } while (true); // Resume printing comments from this point. setResumeOffset(FID, BufPtr - BufStart); }
ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) { MutexGuard locked(lock); std::unique_ptr<ObjectImage> Obj(InputObject); if (!Obj) return NULL; // Save information about our target Arch = (Triple::ArchType)Obj->getArch(); IsTargetLittleEndian = Obj->getObjectFile()->isLittleEndian(); // Compute the memory size required to load all sections to be loaded // and pass this information to the memory manager if (MemMgr->needsToReserveAllocationSpace()) { uint64_t CodeSize = 0, DataSizeRO = 0, DataSizeRW = 0; computeTotalAllocSize(*Obj, CodeSize, DataSizeRO, DataSizeRW); MemMgr->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW); } // Symbols found in this object StringMap<SymbolLoc> LocalSymbols; // Used sections from the object file ObjSectionToIDMap LocalSections; // Common symbols requiring allocation, with their sizes and alignments CommonSymbolMap CommonSymbols; // Maximum required total memory to allocate all common symbols uint64_t CommonSize = 0; // Parse symbols DEBUG(dbgs() << "Parse symbols:\n"); for (symbol_iterator I = Obj->begin_symbols(), E = Obj->end_symbols(); I != E; ++I) { object::SymbolRef::Type SymType; StringRef Name; Check(I->getType(SymType)); Check(I->getName(Name)); uint32_t Flags = I->getFlags(); bool IsCommon = Flags & SymbolRef::SF_Common; if (IsCommon) { // Add the common symbols to a list. We'll allocate them all below. uint32_t Align; Check(I->getAlignment(Align)); uint64_t Size = 0; Check(I->getSize(Size)); CommonSize += Size + Align; CommonSymbols[*I] = CommonSymbolInfo(Size, Align); } else { if (SymType == object::SymbolRef::ST_Function || SymType == object::SymbolRef::ST_Data || SymType == object::SymbolRef::ST_Unknown) { uint64_t FileOffset; StringRef SectionData; bool IsCode; section_iterator SI = Obj->end_sections(); Check(I->getFileOffset(FileOffset)); Check(I->getSection(SI)); if (SI == Obj->end_sections()) continue; Check(SI->getContents(SectionData)); Check(SI->isText(IsCode)); const uint8_t *SymPtr = (const uint8_t *)Obj->getData().data() + (uintptr_t)FileOffset; uintptr_t SectOffset = (uintptr_t)(SymPtr - (const uint8_t *)SectionData.begin()); unsigned SectionID = findOrEmitSection(*Obj, *SI, IsCode, LocalSections); LocalSymbols[Name.data()] = SymbolLoc(SectionID, SectOffset); DEBUG(dbgs() << "\tFileOffset: " << format("%p", (uintptr_t)FileOffset) << " flags: " << Flags << " SID: " << SectionID << " Offset: " << format("%p", SectOffset)); GlobalSymbolTable[Name] = SymbolLoc(SectionID, SectOffset); } } DEBUG(dbgs() << "\tType: " << SymType << " Name: " << Name << "\n"); } // Allocate common symbols if (CommonSize != 0) emitCommonSymbols(*Obj, CommonSymbols, CommonSize, LocalSymbols); // Parse and process relocations DEBUG(dbgs() << "Parse relocations:\n"); for (section_iterator SI = Obj->begin_sections(), SE = Obj->end_sections(); SI != SE; ++SI) { unsigned SectionID = 0; StubMap Stubs; section_iterator RelocatedSection = SI->getRelocatedSection(); if (SI->relocation_empty() && !ProcessAllSections) continue; bool IsCode = false; Check(RelocatedSection->isText(IsCode)); SectionID = findOrEmitSection(*Obj, *RelocatedSection, IsCode, LocalSections); DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n"); for (relocation_iterator I = SI->relocation_begin(), E = SI->relocation_end(); I != E;) I = processRelocationRef(SectionID, I, *Obj, LocalSections, LocalSymbols, Stubs); } // Give the subclasses a chance to tie-up any loose ends. finalizeLoad(LocalSections); return Obj.release(); }
SourceCompleteResult ide::isSourceInputComplete(std::unique_ptr<llvm::MemoryBuffer> MemBuf, SourceFileKind SFKind) { SourceManager SM; auto BufferID = SM.addNewSourceBuffer(std::move(MemBuf)); ParserUnit Parse(SM, SFKind, BufferID); Parser &P = Parse.getParser(); bool Done; do { P.parseTopLevel(); Done = P.Tok.is(tok::eof); } while (!Done); SourceCompleteResult SCR; SCR.IsComplete = !P.isInputIncomplete(); // Use the same code that was in the REPL code to track the indent level // for now. In the future we should get this from the Parser if possible. CharSourceRange entireRange = SM.getRangeForBuffer(BufferID); StringRef Buffer = SM.extractText(entireRange); const char *SourceStart = Buffer.data(); const char *SourceEnd = Buffer.data() + Buffer.size(); const char *LineStart = SourceStart; const char *LineSourceStart = nullptr; uint32_t LineIndent = 0; struct IndentInfo { StringRef Prefix; uint32_t Indent; IndentInfo(const char *s, size_t n, uint32_t i) : Prefix(s, n), Indent(i) {} }; SmallVector<IndentInfo, 4> IndentInfos; for (const char *p = SourceStart; p<SourceEnd; ++p) { switch (*p) { case '\r': case '\n': LineIndent = 0; LineSourceStart = nullptr; LineStart = p + 1; break; case '"': p = skipStringInCode (p, SourceEnd); break; case '{': case '(': case '[': ++LineIndent; if (LineSourceStart == nullptr) IndentInfos.push_back(IndentInfo(LineStart, p - LineStart, LineIndent)); else IndentInfos.push_back(IndentInfo(LineStart, LineSourceStart - LineStart, LineIndent)); break; case '}': case ')': case ']': if (LineIndent > 0) --LineIndent; if (!IndentInfos.empty()) IndentInfos.pop_back(); break; default: if (LineSourceStart == nullptr && !isspace(*p)) LineSourceStart = p; break; } if (*p == '\0') break; } if (!IndentInfos.empty()) { SCR.IndentPrefix = IndentInfos.back().Prefix.str(); // Trim off anything that follows a non-space character const size_t pos = SCR.IndentPrefix.find_first_not_of(" \t"); if (pos != std::string::npos) SCR.IndentPrefix.erase(pos); SCR.IndentLevel = IndentInfos.back().Indent; } return SCR; }
virtual void NotifyObjectEmitted(const ObjectImage &obj) #endif { uint64_t Addr; uint64_t Size; object::SymbolRef::Type SymbolType; #ifdef LLVM36 object::section_iterator Section = obj.section_begin(); object::section_iterator EndSection = obj.section_end(); uint64_t SectionAddr = 0; StringRef sName; #else object::section_iterator Section = obj.begin_sections(); object::section_iterator EndSection = obj.end_sections(); bool isText; #ifndef _OS_LINUX_ StringRef sName; #endif #endif #ifndef LLVM36 uint64_t SectionAddr = 0; #endif uint64_t SectionSize = 0; #if defined(_OS_WINDOWS_) uint64_t SectionAddrCheck = 0; // assert that all of the Sections are at the same location #if defined(_CPU_X86_64_) uint8_t *UnwindData = NULL; uint8_t *catchjmp = NULL; for (const object::SymbolRef &sym_iter : obj.symbols()) { # ifdef LLVM37 sName = sym_iter.getName().get(); # else sym_iter.getName(sName); # endif if (sName.equals("__UnwindData")) { # ifdef LLVM37 Addr = sym_iter.getAddress().get(); # else sym_iter.getAddress(Addr); # endif sym_iter.getSection(Section); # ifdef LLVM36 assert(Section->isText()); # ifdef LLVM38 SectionAddr = L.getSectionLoadAddress(*Section); # else Section->getName(sName); SectionAddr = L.getSectionLoadAddress(sName); # endif Addr += SectionAddr; # else if (Section->isText(isText) || !isText) assert(0 && "!isText"); Section->getAddress(SectionAddr); # endif UnwindData = (uint8_t*)Addr; if (SectionAddrCheck) assert(SectionAddrCheck == SectionAddr); else SectionAddrCheck = SectionAddr; } if (sName.equals("__catchjmp")) { # ifdef LLVM37 Addr = sym_iter.getAddress().get(); # else sym_iter.getAddress(Addr); # endif sym_iter.getSection(Section); # ifdef LLVM36 assert(Section->isText()); # ifdef LLVM38 SectionAddr = L.getSectionLoadAddress(*Section); # else Section->getName(sName); SectionAddr = L.getSectionLoadAddress(sName); # endif Addr += SectionAddr; # else if (Section->isText(isText) || !isText) assert(0 && "!isText"); Section->getAddress(SectionAddr); # endif catchjmp = (uint8_t*)Addr; if (SectionAddrCheck) assert(SectionAddrCheck == SectionAddr); else SectionAddrCheck = SectionAddr; } } assert(catchjmp); assert(UnwindData); catchjmp[0] = 0x48; catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [&_seh_exception_handle] *(uint64_t*)(&catchjmp[2]) = (uint64_t)&_seh_exception_handler; catchjmp[10] = 0xff; catchjmp[11] = 0xe0; // jmp RAX UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER UnwindData[1] = 4; // size of prolog (bytes) UnwindData[2] = 2; // count of unwind codes (slots) UnwindData[3] = 0x05; // frame register (rbp) = rsp UnwindData[4] = 4; // second instruction UnwindData[5] = 0x03; // mov RBP, RSP UnwindData[6] = 1; // first instruction UnwindData[7] = 0x50; // push RBP *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - (uint8_t*)SectionAddr); // relative location of catchjmp #else // defined(_OS_X86_64_) uint8_t *UnwindData = NULL; #endif // defined(_OS_X86_64_) #endif // defined(_OS_WINDOWS_) #ifdef LLVM35 for (const object::SymbolRef &sym_iter : obj.symbols()) { # ifdef LLVM37 SymbolType = sym_iter.getType(); # else sym_iter.getType(SymbolType); # endif if (SymbolType != object::SymbolRef::ST_Function) continue; # ifdef LLVM37 Addr = sym_iter.getAddress().get(); # else sym_iter.getAddress(Addr); # endif # ifdef LLVM38 Section = sym_iter.getSection().get(); # else sym_iter.getSection(Section); # endif if (Section == EndSection) continue; #if defined(LLVM36) if (!Section->isText()) continue; # ifdef LLVM38 SectionAddr = L.getSectionLoadAddress(*Section); # else Section->getName(sName); SectionAddr = L.getSectionLoadAddress(sName); # endif Addr += SectionAddr; #else if (Section->isText(isText) || !isText) continue; #endif #if defined(LLVM36) SectionSize = Section->getSize(); #else Section->getAddress(SectionAddr); Section->getSize(SectionSize); #endif #ifdef _OS_DARWIN_ # if defined(LLVM37) Size = Section->getSize(); sName = sym_iter.getName().get(); # else sym_iter.getName(sName); # endif # if defined(LLVM36) if (sName[0] == '_') { sName = sName.substr(1); } # else Addr = ((MCJIT*)jl_ExecutionEngine)->getSymbolAddress(sName, true); if (!Addr && sName[0] == '_') { sName = sName.substr(1); Addr = ((MCJIT*)jl_ExecutionEngine)->getSymbolAddress(sName, true); } if (!Addr) continue; # endif #elif defined(_OS_WINDOWS_) # if defined(LLVM37) assert(obj.isELF()); Size = ((llvm::object::ELFSymbolRef)sym_iter).getSize(); sName = sym_iter.getName().get(); # else sym_iter.getSize(Size); sym_iter.getName(sName); # endif # ifdef _CPU_X86_ if (sName[0] == '_') sName = sName.substr(1); # endif if (SectionAddrCheck) assert(SectionAddrCheck == SectionAddr); else SectionAddrCheck = SectionAddr; create_PRUNTIME_FUNCTION( (uint8_t*)(intptr_t)Addr, (size_t)Size, sName, (uint8_t*)(intptr_t)SectionAddr, (size_t)SectionSize, UnwindData); #endif const object::ObjectFile *objfile = #ifdef LLVM36 &obj; #else obj.getObjectFile(); #endif ObjectInfo tmp = {objfile, SectionSize #ifdef LLVM37 ,L.clone().release() #elif defined(LLVM36) ,(size_t)SectionAddr #endif #ifdef _OS_DARWIN_ ,strndup(sName.data(), sName.size()) #endif }; objectmap[Addr] = tmp; } #else //LLVM34 error_code itererr; object::symbol_iterator sym_iter = obj.begin_symbols(); object::symbol_iterator sym_end = obj.end_symbols(); for (; sym_iter != sym_end; sym_iter.increment(itererr)) { sym_iter->getType(SymbolType); if (SymbolType != object::SymbolRef::ST_Function) continue; sym_iter->getAddress(Addr); sym_iter->getSize(Size); ObjectInfo tmp = {obj.getObjectFile(), (size_t)Size}; objectmap[Addr] = tmp; } #endif }
/// CopyStringRef - Copies contents of a StringRef into a block of memory and /// null-terminates it. static void CopyStringRef(char *Memory, StringRef Data) { memcpy(Memory, Data.data(), Data.size()); Memory[Data.size()] = 0; // Null terminate string. }
virtual void NotifyObjectEmitted(const ObjectImage &obj) #endif { int8_t gc_state = jl_gc_safe_enter(); uv_rwlock_wrlock(&threadsafe); jl_gc_safe_leave(gc_state); #ifdef LLVM36 object::section_iterator Section = obj.section_begin(); object::section_iterator EndSection = obj.section_end(); #else object::section_iterator Section = obj.begin_sections(); object::section_iterator EndSection = obj.end_sections(); #endif #if defined(_OS_WINDOWS_) uint64_t SectionAddrCheck = 0; // assert that all of the Sections are at the same location uint8_t *UnwindData = NULL; #if defined(_CPU_X86_64_) uint8_t *catchjmp = NULL; for (const object::SymbolRef &sym_iter : obj.symbols()) { StringRef sName; #ifdef LLVM37 sName = sym_iter.getName().get(); #else sym_iter.getName(sName); #endif uint8_t **pAddr = NULL; if (sName.equals("__UnwindData")) { pAddr = &UnwindData; } else if (sName.equals("__catchjmp")) { pAddr = &catchjmp; } if (pAddr) { uint64_t Addr, SectionAddr; #if defined(LLVM38) Addr = sym_iter.getAddress().get(); Section = sym_iter.getSection().get(); assert(Section != EndSection && Section->isText()); SectionAddr = L.getSectionLoadAddress(*Section); #elif defined(LLVM37) Addr = sym_iter.getAddress().get(); sym_iter.getSection(Section); assert(Section != EndSection && Section->isText()); Section->getName(sName); SectionAddr = L.getSectionLoadAddress(sName); #elif defined(LLVM36) sym_iter.getAddress(Addr); sym_iter.getSection(Section); assert(Section != EndSection && Section->isText()); Section->getName(sName); SectionAddr = L.getSectionLoadAddress(sName); #else // LLVM35 sym_iter.getAddress(Addr); sym_iter.getSection(Section); assert(Section != EndSection); assert(!Section->isText(isText) && isText); Section->getAddress(SectionAddr); #endif #ifdef LLVM36 Addr += SectionAddr; #endif *pAddr = (uint8_t*)Addr; if (SectionAddrCheck) assert(SectionAddrCheck == SectionAddr); else SectionAddrCheck = SectionAddr; } } assert(catchjmp); assert(UnwindData); assert(SectionAddrCheck); catchjmp[0] = 0x48; catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [&_seh_exception_handle] *(uint64_t*)(&catchjmp[2]) = (uint64_t)&_seh_exception_handler; catchjmp[10] = 0xff; catchjmp[11] = 0xe0; // jmp RAX UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER UnwindData[1] = 4; // size of prolog (bytes) UnwindData[2] = 2; // count of unwind codes (slots) UnwindData[3] = 0x05; // frame register (rbp) = rsp UnwindData[4] = 4; // second instruction UnwindData[5] = 0x03; // mov RBP, RSP UnwindData[6] = 1; // first instruction UnwindData[7] = 0x50; // push RBP *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - (uint8_t*)SectionAddrCheck); // relative location of catchjmp #endif // defined(_OS_X86_64_) #endif // defined(_OS_WINDOWS_) #ifdef LLVM37 auto symbols = object::computeSymbolSizes(obj); for(const auto &sym_size : symbols) { const object::SymbolRef &sym_iter = sym_size.first; object::SymbolRef::Type SymbolType = sym_iter.getType(); if (SymbolType != object::SymbolRef::ST_Function) continue; uint64_t Size = sym_size.second; uint64_t Addr = sym_iter.getAddress().get(); #ifdef LLVM38 Section = sym_iter.getSection().get(); #else sym_iter.getSection(Section); #endif if (Section == EndSection) continue; if (!Section->isText()) continue; #ifdef LLVM38 uint64_t SectionAddr = L.getSectionLoadAddress(*Section); #else StringRef secName; Section->getName(secName); uint64_t SectionAddr = L.getSectionLoadAddress(secName); #endif Addr += SectionAddr; StringRef sName = sym_iter.getName().get(); #if defined(_OS_WINDOWS_) uint64_t SectionSize = Section->getSize(); if (SectionAddrCheck) assert(SectionAddrCheck == SectionAddr); else SectionAddrCheck = SectionAddr; create_PRUNTIME_FUNCTION( (uint8_t*)(intptr_t)Addr, (size_t)Size, sName, (uint8_t*)(intptr_t)SectionAddr, (size_t)SectionSize, UnwindData); #endif StringMap<jl_lambda_info_t*>::iterator linfo_it = linfo_in_flight.find(sName); jl_lambda_info_t *linfo = NULL; if (linfo_it != linfo_in_flight.end()) { linfo = linfo_it->second; linfo_in_flight.erase(linfo_it); } ObjectInfo tmp = {&debugObj, (size_t)Size, L.clone().release(), linfo}; objectmap[Addr] = tmp; } #else // pre-LLVM37 uint64_t Addr; uint64_t Size; object::SymbolRef::Type SymbolType; StringRef sName; #ifdef LLVM36 uint64_t SectionAddr = 0; #else bool isText; #ifdef _OS_WINDOWS_ uint64_t SectionAddr = 0; #endif #endif #if defined(LLVM35) for (const object::SymbolRef &sym_iter : obj.symbols()) { sym_iter.getType(SymbolType); if (SymbolType != object::SymbolRef::ST_Function) continue; sym_iter.getSize(Size); sym_iter.getAddress(Addr); sym_iter.getSection(Section); if (Section == EndSection) continue; #if defined(LLVM36) if (!Section->isText()) continue; Section->getName(sName); SectionAddr = L.getSectionLoadAddress(sName); Addr += SectionAddr; #else if (Section->isText(isText) || !isText) continue; #endif sym_iter.getName(sName); #ifdef _OS_DARWIN_ # if !defined(LLVM36) Addr = ((MCJIT*)jl_ExecutionEngine)->getSymbolAddress(sName, true); if (!Addr && sName[0] == '_') { Addr = ((MCJIT*)jl_ExecutionEngine)->getSymbolAddress(sName.substr(1), true); } if (!Addr) continue; # endif #elif defined(_OS_WINDOWS_) uint64_t SectionSize = 0; # if defined(LLVM36) SectionSize = Section->getSize(); # else Section->getAddress(SectionAddr); Section->getSize(SectionSize); # endif if (SectionAddrCheck) assert(SectionAddrCheck == SectionAddr); else SectionAddrCheck = SectionAddr; create_PRUNTIME_FUNCTION( (uint8_t*)(intptr_t)Addr, (size_t)Size, sName, (uint8_t*)(intptr_t)SectionAddr, (size_t)SectionSize, UnwindData); #endif StringMap<jl_lambda_info_t*>::iterator linfo_it = linfo_in_flight.find(sName); jl_lambda_info_t *linfo = NULL; if (linfo_it != linfo_in_flight.end()) { linfo = linfo_it->second; linfo_in_flight.erase(linfo_it); } const object::ObjectFile *objfile = #ifdef LLVM36 &obj; #else obj.getObjectFile(); #endif ObjectInfo tmp = {objfile, (size_t)Size, #ifdef LLVM37 L.clone().release(), #elif defined(LLVM36) (size_t)SectionAddr, #endif #ifdef _OS_DARWIN_ strndup(sName.data(), sName.size()), #endif linfo }; objectmap[Addr] = tmp; } #else //LLVM34 error_code itererr; object::symbol_iterator sym_iter = obj.begin_symbols(); object::symbol_iterator sym_end = obj.end_symbols(); for (; sym_iter != sym_end; sym_iter.increment(itererr)) { sym_iter->getType(SymbolType); if (SymbolType != object::SymbolRef::ST_Function) continue; sym_iter->getAddress(Addr); sym_iter->getSize(Size); ObjectInfo tmp = {obj.getObjectFile(), (size_t)Size}; objectmap[Addr] = tmp; } #endif #endif uv_rwlock_wrunlock(&threadsafe); }
bool Pattern::ParsePattern(StringRef PatternStr, SourceMgr &SM) { PatternLoc = SMLoc::getFromPointer(PatternStr.data()); // Ignore trailing whitespace. while (!PatternStr.empty() && (PatternStr.back() == ' ' || PatternStr.back() == '\t')) PatternStr = PatternStr.substr(0, PatternStr.size()-1); // Check that there is something on the line. if (PatternStr.empty()) { SM.PrintMessage(PatternLoc, "found empty check string with prefix '" + CheckPrefix+":'", "error"); return true; } // Check to see if this is a fixed string, or if it has regex pieces. if (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos && PatternStr.find("[[") == StringRef::npos)) { FixedStr = PatternStr; return false; } // Paren value #0 is for the fully matched string. Any new parenthesized // values add from their. unsigned CurParen = 1; // Otherwise, there is at least one regex piece. Build up the regex pattern // by escaping scary characters in fixed strings, building up one big regex. while (!PatternStr.empty()) { // RegEx matches. if (PatternStr.size() >= 2 && PatternStr[0] == '{' && PatternStr[1] == '{') { // Otherwise, this is the start of a regex match. Scan for the }}. size_t End = PatternStr.find("}}"); if (End == StringRef::npos) { SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), "found start of regex string with no end '}}'", "error"); return true; } if (AddRegExToRegEx(PatternStr.substr(2, End-2), CurParen, SM)) return true; PatternStr = PatternStr.substr(End+2); continue; } // Named RegEx matches. These are of two forms: [[foo:.*]] which matches .* // (or some other regex) and assigns it to the FileCheck variable 'foo'. The // second form is [[foo]] which is a reference to foo. The variable name // itself must be of the form "[a-zA-Z_][0-9a-zA-Z_]*", otherwise we reject // it. This is to catch some common errors. if (PatternStr.size() >= 2 && PatternStr[0] == '[' && PatternStr[1] == '[') { // Verify that it is terminated properly. size_t End = PatternStr.find("]]"); if (End == StringRef::npos) { SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()), "invalid named regex reference, no ]] found", "error"); return true; } StringRef MatchStr = PatternStr.substr(2, End-2); PatternStr = PatternStr.substr(End+2); // Get the regex name (e.g. "foo"). size_t NameEnd = MatchStr.find(':'); StringRef Name = MatchStr.substr(0, NameEnd); if (Name.empty()) { SM.PrintMessage(SMLoc::getFromPointer(Name.data()), "invalid name in named regex: empty name", "error"); return true; } // Verify that the name is well formed. for (unsigned i = 0, e = Name.size(); i != e; ++i) if (Name[i] != '_' && (Name[i] < 'a' || Name[i] > 'z') && (Name[i] < 'A' || Name[i] > 'Z') && (Name[i] < '0' || Name[i] > '9')) { SM.PrintMessage(SMLoc::getFromPointer(Name.data()+i), "invalid name in named regex", "error"); return true; } // Name can't start with a digit. if (isdigit(Name[0])) { SM.PrintMessage(SMLoc::getFromPointer(Name.data()), "invalid name in named regex", "error"); return true; } // Handle [[foo]]. if (NameEnd == StringRef::npos) { VariableUses.push_back(std::make_pair(Name, RegExStr.size())); continue; } // Handle [[foo:.*]]. VariableDefs.push_back(std::make_pair(Name, CurParen)); RegExStr += '('; ++CurParen; if (AddRegExToRegEx(MatchStr.substr(NameEnd+1), CurParen, SM)) return true; RegExStr += ')'; } // Handle fixed string matches. // Find the end, which is the start of the next regex. size_t FixedMatchEnd = PatternStr.find("{{"); FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[[")); AddFixedStringToRegEx(PatternStr.substr(0, FixedMatchEnd), RegExStr); PatternStr = PatternStr.substr(FixedMatchEnd); continue; } return false; }
/// Check if this string starts with the given \p Prefix. bool StringRef::startswith(StringRef pPrefix) const { return (m_Length >= pPrefix.length() && 0 == compareMemory(m_Data, pPrefix.data(), pPrefix.length())); }
void Pattern::PrintFailureInfo(const SourceMgr &SM, StringRef Buffer, const StringMap<StringRef> &VariableTable) const{ // If this was a regular expression using variables, print the current // variable values. if (!VariableUses.empty()) { for (unsigned i = 0, e = VariableUses.size(); i != e; ++i) { StringRef Var = VariableUses[i].first; StringMap<StringRef>::const_iterator it = VariableTable.find(Var); SmallString<256> Msg; raw_svector_ostream OS(Msg); // Check for undefined variable references. if (it == VariableTable.end()) { OS << "uses undefined variable \""; OS.write_escaped(Var) << "\"";; } else { OS << "with variable \""; OS.write_escaped(Var) << "\" equal to \""; OS.write_escaped(it->second) << "\""; } SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), OS.str(), "note", /*ShowLine=*/false); } } // Attempt to find the closest/best fuzzy match. Usually an error happens // because some string in the output didn't exactly match. In these cases, we // would like to show the user a best guess at what "should have" matched, to // save them having to actually check the input manually. size_t NumLinesForward = 0; size_t Best = StringRef::npos; double BestQuality = 0; // Use an arbitrary 4k limit on how far we will search. for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) { if (Buffer[i] == '\n') ++NumLinesForward; // Patterns have leading whitespace stripped, so skip whitespace when // looking for something which looks like a pattern. if (Buffer[i] == ' ' || Buffer[i] == '\t') continue; // Compute the "quality" of this match as an arbitrary combination of the // match distance and the number of lines skipped to get to this match. unsigned Distance = ComputeMatchDistance(Buffer.substr(i), VariableTable); double Quality = Distance + (NumLinesForward / 100.); if (Quality < BestQuality || Best == StringRef::npos) { Best = i; BestQuality = Quality; } } // Print the "possible intended match here" line if we found something // reasonable and not equal to what we showed in the "scanning from here" // line. if (Best && Best != StringRef::npos && BestQuality < 50) { SM.PrintMessage(SMLoc::getFromPointer(Buffer.data() + Best), "possible intended match here", "note"); // FIXME: If we wanted to be really friendly we would show why the match // failed, as it can be hard to spot simple one character differences. } }
static void mergeInstrProfile(const WeightedFileVector &Inputs, StringRef OutputFilename, ProfileFormat OutputFormat, bool OutputSparse, unsigned NumThreads) { if (OutputFilename.compare("-") == 0) exitWithError("Cannot write indexed profdata format to stdout."); if (OutputFormat != PF_Binary && OutputFormat != PF_Text) exitWithError("Unknown format is specified."); std::error_code EC; raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None); if (EC) exitWithErrorCode(EC, OutputFilename); std::mutex ErrorLock; SmallSet<instrprof_error, 4> WriterErrorCodes; // If NumThreads is not specified, auto-detect a good default. if (NumThreads == 0) NumThreads = std::max(1U, std::min(std::thread::hardware_concurrency(), unsigned(Inputs.size() / 2))); // Initialize the writer contexts. SmallVector<std::unique_ptr<WriterContext>, 4> Contexts; for (unsigned I = 0; I < NumThreads; ++I) Contexts.emplace_back(llvm::make_unique<WriterContext>( OutputSparse, ErrorLock, WriterErrorCodes)); if (NumThreads == 1) { for (const auto &Input : Inputs) loadInput(Input, Contexts[0].get()); } else { ThreadPool Pool(NumThreads); // Load the inputs in parallel (N/NumThreads serial steps). unsigned Ctx = 0; for (const auto &Input : Inputs) { Pool.async(loadInput, Input, Contexts[Ctx].get()); Ctx = (Ctx + 1) % NumThreads; } Pool.wait(); // Merge the writer contexts together (~ lg(NumThreads) serial steps). unsigned Mid = Contexts.size() / 2; unsigned End = Contexts.size(); assert(Mid > 0 && "Expected more than one context"); do { for (unsigned I = 0; I < Mid; ++I) Pool.async(mergeWriterContexts, Contexts[I].get(), Contexts[I + Mid].get()); Pool.wait(); if (End & 1) { Pool.async(mergeWriterContexts, Contexts[0].get(), Contexts[End - 1].get()); Pool.wait(); } End = Mid; Mid /= 2; } while (Mid > 0); } // Handle deferred hard errors encountered during merging. for (std::unique_ptr<WriterContext> &WC : Contexts) if (WC->Err) exitWithError(std::move(WC->Err), WC->ErrWhence); InstrProfWriter &Writer = Contexts[0]->Writer; if (OutputFormat == PF_Text) Writer.writeText(Output); else Writer.write(Output); }
/// ReadCheckFile - Read the check file, which specifies the sequence of /// expected strings. The strings are added to the CheckStrings vector. static bool ReadCheckFile(SourceMgr &SM, std::vector<CheckString> &CheckStrings) { // Open the check file, and tell SourceMgr about it. std::string ErrorStr; MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), &ErrorStr); if (F == 0) { errs() << "Could not open check file '" << CheckFilename << "': " << ErrorStr << '\n'; return true; } // If we want to canonicalize whitespace, strip excess whitespace from the // buffer containing the CHECK lines. if (!NoCanonicalizeWhiteSpace) F = CanonicalizeInputFile(F); SM.AddNewSourceBuffer(F, SMLoc()); // Find all instances of CheckPrefix followed by : in the file. StringRef Buffer = F->getBuffer(); std::vector<std::pair<SMLoc, Pattern> > NotMatches; while (1) { // See if Prefix occurs in the memory buffer. Buffer = Buffer.substr(Buffer.find(CheckPrefix)); // If we didn't find a match, we're done. if (Buffer.empty()) break; const char *CheckPrefixStart = Buffer.data(); // When we find a check prefix, keep track of whether we find CHECK: or // CHECK-NEXT: bool IsCheckNext = false, IsCheckNot = false; // Verify that the : is present after the prefix. if (Buffer[CheckPrefix.size()] == ':') { Buffer = Buffer.substr(CheckPrefix.size()+1); } else if (Buffer.size() > CheckPrefix.size()+6 && memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) { Buffer = Buffer.substr(CheckPrefix.size()+7); IsCheckNext = true; } else if (Buffer.size() > CheckPrefix.size()+5 && memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) { Buffer = Buffer.substr(CheckPrefix.size()+6); IsCheckNot = true; } else { Buffer = Buffer.substr(1); continue; } // Okay, we found the prefix, yay. Remember the rest of the line, but // ignore leading and trailing whitespace. Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); // Scan ahead to the end of line. size_t EOL = Buffer.find_first_of("\n\r"); // Remember the location of the start of the pattern, for diagnostics. SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. Pattern P; if (P.ParsePattern(Buffer.substr(0, EOL), SM)) return true; Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. if (IsCheckNext && CheckStrings.empty()) { SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), "found '"+CheckPrefix+"-NEXT:' without previous '"+ CheckPrefix+ ": line", "error"); return true; } // Handle CHECK-NOT. if (IsCheckNot) { NotMatches.push_back(std::make_pair(SMLoc::getFromPointer(Buffer.data()), P)); continue; } // Okay, add the string we captured to the output vector and move on. CheckStrings.push_back(CheckString(P, PatternLoc, IsCheckNext)); std::swap(NotMatches, CheckStrings.back().NotStrings); } if (CheckStrings.empty()) { errs() << "error: no check strings found with prefix '" << CheckPrefix << ":'\n"; return true; } if (!NotMatches.empty()) { errs() << "error: '" << CheckPrefix << "-NOT:' not supported after last check line.\n"; return true; } return false; }
static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, bool SupportsForcingFramePointer, const char *ExpandChar, const OptTable &Opts) { assert(A->getOption().matches(options::OPT__SLASH_O)); StringRef OptStr = A->getValue(); for (size_t I = 0, E = OptStr.size(); I != E; ++I) { const char &OptChar = *(OptStr.data() + I); switch (OptChar) { default: break; case '1': case '2': case 'x': case 'd': if (&OptChar == ExpandChar) { if (OptChar == 'd') { DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); } else { if (OptChar == '1') { DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); } else if (OptChar == '2' || OptChar == 'x') { DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); } if (SupportsForcingFramePointer && !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); if (OptChar == '1' || OptChar == '2') DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); } } break; case 'b': if (I + 1 != E && isdigit(OptStr[I + 1])) { switch (OptStr[I + 1]) { case '0': DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline)); break; case '1': DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions)); break; case '2': DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions)); break; } ++I; } break; case 'g': break; case 'i': if (I + 1 != E && OptStr[I + 1] == '-') { ++I; DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin)); } else { DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); } break; case 's': DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); break; case 't': DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); break; case 'y': { bool OmitFramePointer = true; if (I + 1 != E && OptStr[I + 1] == '-') { OmitFramePointer = false; ++I; } if (SupportsForcingFramePointer) { if (OmitFramePointer) DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); else DAL.AddFlagArg( A, Opts.getOption(options::OPT_fno_omit_frame_pointer)); } else { // Don't warn about /Oy- in 64-bit builds (where // SupportsForcingFramePointer is false). The flag having no effect // there is a compiler-internal optimization, and people shouldn't have // to special-case their build files for 64-bit clang-cl. A->claim(); } break; } } } }
int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); SourceMgr SM; // Read the expected strings from the check file. std::vector<CheckString> CheckStrings; if (ReadCheckFile(SM, CheckStrings)) return 2; // Open the file to check and add it to SourceMgr. std::string ErrorStr; MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), &ErrorStr); if (F == 0) { errs() << "Could not open input file '" << InputFilename << "': " << ErrorStr << '\n'; return true; } // Remove duplicate spaces in the input file if requested. if (!NoCanonicalizeWhiteSpace) F = CanonicalizeInputFile(F); SM.AddNewSourceBuffer(F, SMLoc()); /// VariableTable - This holds all the current filecheck variables. StringMap<StringRef> VariableTable; // Check that we have all of the expected strings, in order, in the input // file. StringRef Buffer = F->getBuffer(); const char *LastMatch = Buffer.data(); for (unsigned StrNo = 0, e = CheckStrings.size(); StrNo != e; ++StrNo) { const CheckString &CheckStr = CheckStrings[StrNo]; StringRef SearchFrom = Buffer; // Find StrNo in the file. size_t MatchLen = 0; Buffer = Buffer.substr(CheckStr.Pat.Match(Buffer, MatchLen, VariableTable)); // If we didn't find a match, reject the input. if (Buffer.empty()) { PrintCheckFailed(SM, CheckStr, SearchFrom, VariableTable); return 1; } StringRef SkippedRegion(LastMatch, Buffer.data()-LastMatch); // If this check is a "CHECK-NEXT", verify that the previous match was on // the previous line (i.e. that there is one newline between them). if (CheckStr.IsCheckNext) { // Count the number of newlines between the previous match and this one. assert(LastMatch != F->getBufferStart() && "CHECK-NEXT can't be the first check in a file"); unsigned NumNewLines = CountNumNewlinesBetween(SkippedRegion); if (NumNewLines == 0) { SM.PrintMessage(CheckStr.Loc, CheckPrefix+"-NEXT: is on the same line as previous match", "error"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), "'next' match was here", "note"); SM.PrintMessage(SMLoc::getFromPointer(LastMatch), "previous match was here", "note"); return 1; } if (NumNewLines != 1) { SM.PrintMessage(CheckStr.Loc, CheckPrefix+ "-NEXT: is not on the line after the previous match", "error"); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), "'next' match was here", "note"); SM.PrintMessage(SMLoc::getFromPointer(LastMatch), "previous match was here", "note"); return 1; } } // If this match had "not strings", verify that they don't exist in the // skipped region. for (unsigned ChunkNo = 0, e = CheckStr.NotStrings.size(); ChunkNo != e; ++ChunkNo) { size_t MatchLen = 0; size_t Pos = CheckStr.NotStrings[ChunkNo].second.Match(SkippedRegion, MatchLen, VariableTable); if (Pos == StringRef::npos) continue; SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos), CheckPrefix+"-NOT: string occurred!", "error"); SM.PrintMessage(CheckStr.NotStrings[ChunkNo].first, CheckPrefix+"-NOT: pattern specified here", "note"); return 1; } // Otherwise, everything is good. Step over the matched text and remember // the position after the match as the end of the last match. Buffer = Buffer.substr(MatchLen); LastMatch = Buffer.data(); } return 0; }
/// \brief Emit a code snippet and caret line. /// /// This routine emits a single line's code snippet and caret line.. /// /// \param Loc The location for the caret. /// \param Ranges The underlined ranges for this code snippet. /// \param Hints The FixIt hints active for this diagnostic. void TextDiagnostic::emitSnippetAndCaret( SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange>& Ranges, ArrayRef<FixItHint> Hints, const SourceManager &SM) { assert(Loc.isValid() && "must have a valid source location here"); assert(Loc.isFileID() && "must have a file location here"); // If caret diagnostics are enabled and we have location, we want to // emit the caret. However, we only do this if the location moved // from the last diagnostic, if the last diagnostic was a note that // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. if (!DiagOpts->ShowCarets) return; if (Loc == LastLoc && Ranges.empty() && Hints.empty() && (LastLevel != DiagnosticsEngine::Note || Level == LastLevel)) return; // Decompose the location into a FID/Offset pair. std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; // Get information about the buffer it points into. bool Invalid = false; StringRef BufData = SM.getBufferData(FID, &Invalid); if (Invalid) return; const char *BufStart = BufData.data(); const char *BufEnd = BufStart + BufData.size(); unsigned LineNo = SM.getLineNumber(FID, FileOffset); unsigned ColNo = SM.getColumnNumber(FID, FileOffset); // Arbitrarily stop showing snippets when the line is too long. static const size_t MaxLineLengthToPrint = 4096; if (ColNo > MaxLineLengthToPrint) return; // Rewind from the current position to the start of the line. const char *TokPtr = BufStart+FileOffset; const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. // Compute the line end. Scan forward from the error position to the end of // the line. const char *LineEnd = TokPtr; while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd) ++LineEnd; // Arbitrarily stop showing snippets when the line is too long. if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) return; // Trim trailing null-bytes. StringRef Line(LineStart, LineEnd - LineStart); while (Line.size() > ColNo && Line.back() == '\0') Line = Line.drop_back(); // Copy the line of code into an std::string for ease of manipulation. std::string SourceLine(Line.begin(), Line.end()); // Build the byte to column map. const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); // Create a line for the caret that is filled with spaces that is the same // number of columns as the line of source code. std::string CaretLine(sourceColMap.columns(), ' '); // Highlight all of the characters covered by Ranges with ~ characters. for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts); // Next, insert the caret itself. ColNo = sourceColMap.byteToContainingColumn(ColNo-1); if (CaretLine.size()<ColNo+1) CaretLine.resize(ColNo+1, ' '); CaretLine[ColNo] = '^'; std::string FixItInsertionLine = buildFixItInsertionLine(LineNo, sourceColMap, Hints, SM, DiagOpts.get()); // If the source line is too long for our terminal, select only the // "interesting" source region within that line. unsigned Columns = DiagOpts->MessageLength; if (Columns) selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, Columns, sourceColMap); // If we are in -fdiagnostics-print-source-range-info mode, we are trying // to produce easily machine parsable output. Add a space before the // source line and the caret to make it trivial to tell the main diagnostic // line from what the user is intended to see. if (DiagOpts->ShowSourceRanges) { SourceLine = ' ' + SourceLine; CaretLine = ' ' + CaretLine; } // Finally, remove any blank spaces from the end of CaretLine. while (CaretLine[CaretLine.size()-1] == ' ') CaretLine.erase(CaretLine.end()-1); // Emit what we have computed. emitSnippet(SourceLine); if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; if (DiagOpts->ShowColors) OS.resetColor(); if (!FixItInsertionLine.empty()) { if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); if (DiagOpts->ShowSourceRanges) OS << ' '; OS << FixItInsertionLine << '\n'; if (DiagOpts->ShowColors) OS.resetColor(); } // Print out any parseable fixit information requested by the options. emitParseableFixits(Hints, SM); }
bool swift::omitNeedlessWords(StringRef &baseName, MutableArrayRef<StringRef> argNames, StringRef firstParamName, OmissionTypeName resultType, OmissionTypeName contextType, ArrayRef<OmissionTypeName> paramTypes, bool returnsSelf, bool isProperty, const InheritedNameSet *allPropertyNames, StringScratchSpace &scratch) { bool anyChanges = false; /// Local function that lowercases all of the base names and /// argument names before returning. auto lowercaseAcronymsForReturn = [&] { StringRef newBaseName = toLowercaseWordAndAcronym(baseName, scratch); if (baseName.data() != newBaseName.data()) { baseName = newBaseName; anyChanges = true; } for (StringRef &argName : argNames) { StringRef newArgName = toLowercaseWordAndAcronym(argName, scratch); if (argName.data() != newArgName.data()) { argName = newArgName; anyChanges = true; } } return anyChanges; }; // If the result type matches the context, remove the context type from the // prefix of the name. bool resultTypeMatchesContext = returnsSelf || (resultType == contextType); if (resultTypeMatchesContext) { StringRef newBaseName = omitNeedlessWordsFromPrefix(baseName, contextType, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } // Treat zero-parameter methods and properties the same way. if (paramTypes.empty()) { if (resultTypeMatchesContext) { StringRef newBaseName = ::omitNeedlessWords( baseName, returnsSelf ? contextType : resultType, NameRole::Property, allPropertyNames, scratch); if (newBaseName != baseName) { baseName = newBaseName; anyChanges = true; } } // Boolean properties should start with "is", unless their // first word already implies a Boolean result. if (resultType.isBoolean() && isProperty && !nameIndicatesBooleanResult(baseName)) { SmallString<32> newName("is"); camel_case::appendSentenceCase(newName, baseName); baseName = scratch.copyString(newName); anyChanges = true; } return lowercaseAcronymsForReturn(); } // Omit needless words based on parameter types. for (unsigned i = 0, n = argNames.size(); i != n; ++i) { // If there is no corresponding parameter, there is nothing to // omit. if (i >= paramTypes.size()) continue; // Omit needless words based on the type of the parameter. NameRole role = i > 0 ? NameRole::SubsequentParameter : argNames[0].empty() ? NameRole::BaseName : NameRole::FirstParameter; // Omit needless words from the name. StringRef name = role == NameRole::BaseName ? baseName : argNames[i]; StringRef newName = ::omitNeedlessWords(name, paramTypes[i], role, role == NameRole::BaseName ? allPropertyNames : nullptr, scratch); // Did the name change? if (name != newName) anyChanges = true; // If the first parameter has a default argument, and there is a // preposition in the base name, split the base name at that preposition. if (role == NameRole::BaseName && argNames[0].empty() && paramTypes[0].hasDefaultArgument()) { // Scan backwards for a preposition. auto nameWords = camel_case::getWords(newName); auto nameWordRevIter = nameWords.rbegin(), nameWordRevIterEnd = nameWords.rend(); bool found = false, done = false; while (nameWordRevIter != nameWordRevIterEnd && !done) { switch (getPartOfSpeech(*nameWordRevIter)) { case PartOfSpeech::Preposition: found = true; done = true; break; case PartOfSpeech::Verb: case PartOfSpeech::Gerund: // Don't skip over verbs or gerunds. done = true; break; case PartOfSpeech::Unknown: case PartOfSpeech::AuxiliaryVerb: ++nameWordRevIter; break; } } // If we found a split point that's not at the beginning of the // name, split there. if (found) { ++nameWordRevIter; unsigned splitPos = nameWordRevIter.base().getPosition(); if (splitPos > 0) { unsigned afterSplitPos = splitPos; // Create a first argument name with the remainder of the base name, // lowercased. If we would end up with a vacuous name, go // back and get the original. StringRef newArgName = newName.substr(afterSplitPos); if (isVacuousName(newArgName)) { size_t pos = name.rfind(newArgName); newArgName = name.substr(pos); } // If there is a leading "with" on the first argument, drop it. if (newArgName.size() > 4 && camel_case::sameWordIgnoreFirstCase( camel_case::getFirstWord(newArgName), "with")) { newArgName = newArgName.substr(4); } argNames[0] = toLowercaseWord(newArgName, scratch); // Update the base name by splitting at the preposition. newName = newName.substr(0, splitPos); anyChanges = true; } } } if (name == newName) continue; // Record this change. if (role == NameRole::BaseName) { baseName = newName; } else { argNames[i] = newName; } } return lowercaseAcronymsForReturn(); }