//===-- FormatterBytecode.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "FormatterBytecode.h" #include "lldb/Core/Module.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Utility/LLDBLog.h" using namespace lldb; namespace lldb_private { static void ForEachFormatterInModule( Module &module, SectionType section_type, std::function fn) { auto *sections = module.GetSectionList(); if (!sections) return; auto section_sp = sections->FindSectionByType(section_type, true); if (!section_sp) return; TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString("default"), category); // The type summary record is serialized as follows. // // Each record contains, in order: // * Version number of the record format // * The remaining size of the record // * The size of the type identifier // * The type identifier, either a type name, or a regex // * The size of the entry // * The entry // // Integers are encoded using ULEB. // // Strings are encoded with first a length (ULEB), then the string contents, // and lastly a null terminator. The length includes the null. DataExtractor lldb_extractor; auto section_size = section_sp->GetSectionData(lldb_extractor); llvm::DataExtractor section = lldb_extractor.GetAsLLVM(); bool le = section.isLittleEndian(); uint8_t addr_size = section.getAddressSize(); llvm::DataExtractor::Cursor cursor(0); while (cursor && cursor.tell() < section_size) { while (cursor && cursor.tell() < section_size) { // Skip over 0 padding. if (section.getU8(cursor) == 0) continue; cursor.seek(cursor.tell() - 1); break; } uint64_t version = section.getULEB128(cursor); uint64_t record_size = section.getULEB128(cursor); if (version == 1) { llvm::DataExtractor record(section.getData().drop_front(cursor.tell()), le, addr_size); llvm::DataExtractor::Cursor cursor(0); uint64_t type_size = record.getULEB128(cursor); llvm::StringRef type_name = record.getBytes(cursor, type_size); llvm::Error error = cursor.takeError(); if (!error) fn(llvm::DataExtractor(record.getData().drop_front(cursor.tell()), le, addr_size), type_name); else LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), std::move(error), "{0}"); } else { // Skip unsupported record. LLDB_LOG( GetLog(LLDBLog::DataFormatters), "Skipping unsupported embedded type summary of version {0} in {1}.", version, module.GetFileSpec()); } section.skip(cursor, record_size); } if (!cursor) LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), cursor.takeError(), "{0}"); } void LoadTypeSummariesForModule(ModuleSP module_sp) { ForEachFormatterInModule( *module_sp, eSectionTypeLLDBTypeSummaries, [&](llvm::DataExtractor extractor, llvm::StringRef type_name) { TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString("default"), category); // The type summary record is serialized as follows. // // * The size of the summary string // * The summary string // // Integers are encoded using ULEB. llvm::DataExtractor::Cursor cursor(0); uint64_t summary_size = extractor.getULEB128(cursor); llvm::StringRef summary_string = extractor.getBytes(cursor, summary_size); if (!cursor) { LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), cursor.takeError(), "{0}"); return; } if (type_name.empty() || summary_string.empty()) { LLDB_LOG(GetLog(LLDBLog::DataFormatters), "Missing string(s) in embedded type summary in {0}, " "type_name={1}, summary={2}", module_sp->GetFileSpec(), type_name, summary_string); return; } TypeSummaryImpl::Flags flags; auto summary_sp = std::make_shared( flags, summary_string.str().c_str()); FormatterMatchType match_type = eFormatterMatchExact; if (type_name.front() == '^') match_type = eFormatterMatchRegex; category->AddTypeSummary(type_name, match_type, summary_sp); LLDB_LOG(GetLog(LLDBLog::DataFormatters), "Loaded embedded type summary for '{0}' from {1}.", type_name, module_sp->GetFileSpec()); }); } void LoadFormattersForModule(ModuleSP module_sp) { ForEachFormatterInModule( *module_sp, eSectionTypeLLDBFormatters, [&](llvm::DataExtractor extractor, llvm::StringRef type_name) { // * Function signature (1 byte) // * Length of the program (ULEB128) // * The program bytecode TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString("default"), category); llvm::DataExtractor::Cursor cursor(0); uint64_t flags = extractor.getULEB128(cursor); while (cursor && cursor.tell() < extractor.size()) { uint8_t signature = extractor.getU8(cursor); uint64_t size = extractor.getULEB128(cursor); llvm::StringRef bytecode = extractor.getBytes(cursor, size); if (!cursor) { LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), cursor.takeError(), "{0}"); return; } if (signature == 0) { auto summary_sp = std::make_shared( TypeSummaryImpl::Flags(flags), llvm::MemoryBuffer::getMemBufferCopy(bytecode)); FormatterMatchType match_type = eFormatterMatchExact; if (type_name.front() == '^') match_type = eFormatterMatchRegex; category->AddTypeSummary(type_name, match_type, summary_sp); LLDB_LOG(GetLog(LLDBLog::DataFormatters), "Loaded embedded type summary for '{0}' from {1}.", type_name, module_sp->GetFileSpec()); } else LLDB_LOG(GetLog(LLDBLog::DataFormatters), "Unsupported formatter signature {0} for '{1}' in {2}", signature, type_name, module_sp->GetFileSpec()); } }); } } // namespace lldb_private