diff options
Diffstat (limited to 'llvm/lib/Support/ELFAttributeParser.cpp')
-rw-r--r-- | llvm/lib/Support/ELFAttributeParser.cpp | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/llvm/lib/Support/ELFAttributeParser.cpp b/llvm/lib/Support/ELFAttributeParser.cpp new file mode 100644 index 0000000000000..df955cdf5d30a --- /dev/null +++ b/llvm/lib/Support/ELFAttributeParser.cpp @@ -0,0 +1,233 @@ +//===--- ELFAttributeParser.cpp - ELF Attribute Parser --------------------===// +// +// 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 "llvm/Support/ELFAttributeParser.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::ELFAttrs; + +static const EnumEntry<unsigned> tagNames[] = { + {"Tag_File", ELFAttrs::File}, + {"Tag_Section", ELFAttrs::Section}, + {"Tag_Symbol", ELFAttrs::Symbol}, +}; + +Error ELFAttributeParser::parseStringAttribute(const char *name, unsigned tag, + ArrayRef<const char *> strings) { + uint64_t value = de.getULEB128(cursor); + if (value >= strings.size()) { + printAttribute(tag, value, ""); + return createStringError(errc::invalid_argument, + "unknown " + Twine(name) + + " value: " + Twine(value)); + } + printAttribute(tag, value, strings[value]); + return Error::success(); +} + +Error ELFAttributeParser::integerAttribute(unsigned tag) { + StringRef tagName = + ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false); + uint64_t value = de.getULEB128(cursor); + attributes.insert(std::make_pair(tag, value)); + + if (sw) { + DictScope scope(*sw, "Attribute"); + sw->printNumber("Tag", tag); + if (!tagName.empty()) + sw->printString("TagName", tagName); + sw->printNumber("Value", value); + } + return Error::success(); +} + +Error ELFAttributeParser::stringAttribute(unsigned tag) { + StringRef tagName = + ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false); + StringRef desc = de.getCStrRef(cursor); + attributesStr.insert(std::make_pair(tag, desc)); + + if (sw) { + DictScope scope(*sw, "Attribute"); + sw->printNumber("Tag", tag); + if (!tagName.empty()) + sw->printString("TagName", tagName); + sw->printString("Value", desc); + } + return Error::success(); +} + +void ELFAttributeParser::printAttribute(unsigned tag, unsigned value, + StringRef valueDesc) { + attributes.insert(std::make_pair(tag, value)); + + if (sw) { + StringRef tagName = ELFAttrs::attrTypeAsString(tag, tagToStringMap, + /*hasTagPrefix=*/false); + DictScope as(*sw, "Attribute"); + sw->printNumber("Tag", tag); + sw->printNumber("Value", value); + if (!tagName.empty()) + sw->printString("TagName", tagName); + if (!valueDesc.empty()) + sw->printString("Description", valueDesc); + } +} + +void ELFAttributeParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) { + for (;;) { + uint64_t value = de.getULEB128(cursor); + if (!cursor || !value) + break; + indexList.push_back(value); + } +} + +Error ELFAttributeParser::parseAttributeList(uint32_t length) { + uint64_t pos; + uint64_t end = cursor.tell() + length; + while ((pos = cursor.tell()) < end) { + uint64_t tag = de.getULEB128(cursor); + bool handled; + if (Error e = handler(tag, handled)) + return e; + + if (!handled) { + if (tag < 32) { + return createStringError(errc::invalid_argument, + "invalid tag 0x" + Twine::utohexstr(tag) + + " at offset 0x" + Twine::utohexstr(pos)); + } + + if (tag % 2 == 0) { + if (Error e = integerAttribute(tag)) + return e; + } else { + if (Error e = stringAttribute(tag)) + return e; + } + } + } + return Error::success(); +} + +Error ELFAttributeParser::parseSubsection(uint32_t length) { + uint64_t end = cursor.tell() - sizeof(length) + length; + StringRef vendorName = de.getCStrRef(cursor); + if (sw) { + sw->printNumber("SectionLength", length); + sw->printString("Vendor", vendorName); + } + + // Ignore unrecognized vendor-name. + if (vendorName.lower() != vendor) + return createStringError(errc::invalid_argument, + "unrecognized vendor-name: " + vendorName); + + while (cursor.tell() < end) { + /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size + uint8_t tag = de.getU8(cursor); + uint32_t size = de.getU32(cursor); + if (!cursor) + return cursor.takeError(); + + if (sw) { + sw->printEnum("Tag", tag, makeArrayRef(tagNames)); + sw->printNumber("Size", size); + } + if (size < 5) + return createStringError(errc::invalid_argument, + "invalid attribute size " + Twine(size) + + " at offset 0x" + + Twine::utohexstr(cursor.tell() - 5)); + + StringRef scopeName, indexName; + SmallVector<uint8_t, 8> indicies; + switch (tag) { + case ELFAttrs::File: + scopeName = "FileAttributes"; + break; + case ELFAttrs::Section: + scopeName = "SectionAttributes"; + indexName = "Sections"; + parseIndexList(indicies); + break; + case ELFAttrs::Symbol: + scopeName = "SymbolAttributes"; + indexName = "Symbols"; + parseIndexList(indicies); + break; + default: + return createStringError(errc::invalid_argument, + "unrecognized tag 0x" + Twine::utohexstr(tag) + + " at offset 0x" + + Twine::utohexstr(cursor.tell() - 5)); + } + + if (sw) { + DictScope scope(*sw, scopeName); + if (!indicies.empty()) + sw->printList(indexName, indicies); + if (Error e = parseAttributeList(size - 5)) + return e; + } else if (Error e = parseAttributeList(size - 5)) + return e; + } + return Error::success(); +} + +Error ELFAttributeParser::parse(ArrayRef<uint8_t> section, + support::endianness endian) { + unsigned sectionNumber = 0; + de = DataExtractor(section, endian == support::little, 0); + + // For early returns, we have more specific errors, consume the Error in + // cursor. + struct ClearCursorError { + DataExtractor::Cursor &cursor; + ~ClearCursorError() { consumeError(cursor.takeError()); } + } clear{cursor}; + + // Unrecognized format-version. + uint8_t formatVersion = de.getU8(cursor); + if (formatVersion != 'A') + return createStringError(errc::invalid_argument, + "unrecognized format-version: 0x" + + utohexstr(formatVersion)); + + while (!de.eof(cursor)) { + uint32_t sectionLength = de.getU32(cursor); + if (!cursor) + return cursor.takeError(); + + if (sw) { + sw->startLine() << "Section " << ++sectionNumber << " {\n"; + sw->indent(); + } + + if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size()) + return createStringError(errc::invalid_argument, + "invalid section length " + + Twine(sectionLength) + " at offset 0x" + + utohexstr(cursor.tell() - 4)); + + if (Error e = parseSubsection(sectionLength)) + return e; + if (sw) { + sw->unindent(); + sw->startLine() << "}\n"; + } + } + + return cursor.takeError(); +} |