239 lines · cpp
1//===--- ELFCompactAttrParser.cpp - ELF Compact Attribute Parser ------ ===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7// ELF Compact Attribute Parser parse ELF build atrributes that are held8// in a single Build Attributes Subsection.9//10//===--------------------------------------------------------------------===//11 12#include "llvm/Support/ELFAttrParserCompact.h"13#include "llvm/ADT/StringExtras.h"14#include "llvm/Support/Errc.h"15#include "llvm/Support/ScopedPrinter.h"16 17using namespace llvm;18using namespace llvm::ELFAttrs;19 20static constexpr EnumEntry<unsigned> tagNames[] = {21 {"Tag_File", ELFAttrs::File},22 {"Tag_Section", ELFAttrs::Section},23 {"Tag_Symbol", ELFAttrs::Symbol},24};25 26Error ELFCompactAttrParser::parseStringAttribute(27 const char *name, unsigned tag, ArrayRef<const char *> strings) {28 uint64_t value = de.getULEB128(cursor);29 if (value >= strings.size()) {30 printAttribute(tag, value, "");31 return createStringError(errc::invalid_argument,32 "unknown " + Twine(name) +33 " value: " + Twine(value));34 }35 printAttribute(tag, value, strings[value]);36 return Error::success();37}38 39Error ELFCompactAttrParser::integerAttribute(unsigned tag) {40 StringRef tagName =41 ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);42 uint64_t value = de.getULEB128(cursor);43 attributes.insert(std::make_pair(tag, value));44 45 if (sw) {46 DictScope scope(*sw, "Attribute");47 sw->printNumber("Tag", tag);48 if (!tagName.empty())49 sw->printString("TagName", tagName);50 sw->printNumber("Value", value);51 }52 return Error::success();53}54 55Error ELFCompactAttrParser::stringAttribute(unsigned tag) {56 StringRef tagName =57 ELFAttrs::attrTypeAsString(tag, tagToStringMap, /*hasTagPrefix=*/false);58 StringRef desc = de.getCStrRef(cursor);59 setAttributeString(tag, desc);60 61 if (sw) {62 DictScope scope(*sw, "Attribute");63 sw->printNumber("Tag", tag);64 if (!tagName.empty())65 sw->printString("TagName", tagName);66 sw->printString("Value", desc);67 }68 return Error::success();69}70 71void ELFCompactAttrParser::printAttribute(unsigned tag, unsigned value,72 StringRef valueDesc) {73 attributes.insert(std::make_pair(tag, value));74 75 if (sw) {76 StringRef tagName = ELFAttrs::attrTypeAsString(tag, tagToStringMap,77 /*hasTagPrefix=*/false);78 DictScope as(*sw, "Attribute");79 sw->printNumber("Tag", tag);80 sw->printNumber("Value", value);81 if (!tagName.empty())82 sw->printString("TagName", tagName);83 if (!valueDesc.empty())84 sw->printString("Description", valueDesc);85 }86}87 88void ELFCompactAttrParser::parseIndexList(SmallVectorImpl<uint8_t> &indexList) {89 for (;;) {90 uint64_t value = de.getULEB128(cursor);91 if (!cursor || !value)92 break;93 indexList.push_back(value);94 }95}96 97Error ELFCompactAttrParser::parseAttributeList(uint32_t length) {98 uint64_t pos;99 uint64_t end = cursor.tell() + length;100 while ((pos = cursor.tell()) < end) {101 uint64_t tag = de.getULEB128(cursor);102 bool handled;103 if (Error e = handler(tag, handled))104 return e;105 106 if (!handled) {107 if (tag < 32) {108 return createStringError(errc::invalid_argument,109 "invalid tag 0x" + Twine::utohexstr(tag) +110 " at offset 0x" + Twine::utohexstr(pos));111 }112 113 if (tag % 2 == 0) {114 if (Error e = integerAttribute(tag))115 return e;116 } else {117 if (Error e = stringAttribute(tag))118 return e;119 }120 }121 }122 return Error::success();123}124 125Error ELFCompactAttrParser::parseSubsection(uint32_t length) {126 uint64_t end = cursor.tell() - sizeof(length) + length;127 StringRef vendorName = de.getCStrRef(cursor);128 if (sw) {129 sw->printNumber("SectionLength", length);130 sw->printString("Vendor", vendorName);131 }132 133 // Handle a subsection with an unrecognized vendor-name by skipping134 // over it to the next subsection. ADDENDA32 in the Arm ABI defines135 // that vendor attribute sections must not affect compatibility, so136 // this should always be safe.137 if (vendorName.lower() != vendor) {138 cursor.seek(end);139 return Error::success();140 }141 142 while (cursor.tell() < end) {143 /// Tag_File | Tag_Section | Tag_Symbol uleb128:byte-size144 uint8_t tag = de.getU8(cursor);145 uint32_t size = de.getU32(cursor);146 if (!cursor)147 return cursor.takeError();148 149 if (sw) {150 sw->printEnum("Tag", tag, ArrayRef(tagNames));151 sw->printNumber("Size", size);152 }153 if (size < 5)154 return createStringError(errc::invalid_argument,155 "invalid attribute size " + Twine(size) +156 " at offset 0x" +157 Twine::utohexstr(cursor.tell() - 5));158 159 StringRef scopeName, indexName;160 SmallVector<uint8_t, 8> indices;161 switch (tag) {162 case ELFAttrs::File:163 scopeName = "FileAttributes";164 break;165 case ELFAttrs::Section:166 scopeName = "SectionAttributes";167 indexName = "Sections";168 parseIndexList(indices);169 break;170 case ELFAttrs::Symbol:171 scopeName = "SymbolAttributes";172 indexName = "Symbols";173 parseIndexList(indices);174 break;175 default:176 return createStringError(errc::invalid_argument,177 "unrecognized tag 0x" + Twine::utohexstr(tag) +178 " at offset 0x" +179 Twine::utohexstr(cursor.tell() - 5));180 }181 182 if (sw) {183 DictScope scope(*sw, scopeName);184 if (!indices.empty())185 sw->printList(indexName, indices);186 if (Error e = parseAttributeList(size - 5))187 return e;188 } else if (Error e = parseAttributeList(size - 5))189 return e;190 }191 return Error::success();192}193 194Error ELFCompactAttrParser::parse(ArrayRef<uint8_t> section,195 llvm::endianness endian) {196 unsigned sectionNumber = 0;197 de = DataExtractor(section, endian == llvm::endianness::little, 0);198 199 // For early returns, we have more specific errors, consume the Error in200 // cursor.201 struct ClearCursorError {202 DataExtractor::Cursor &cursor;203 ~ClearCursorError() { consumeError(cursor.takeError()); }204 } clear{cursor};205 206 // Unrecognized format-version.207 uint8_t formatVersion = de.getU8(cursor);208 if (formatVersion != ELFAttrs::Format_Version)209 return createStringError(errc::invalid_argument,210 "unrecognized format-version: 0x" +211 utohexstr(formatVersion));212 213 while (!de.eof(cursor)) {214 uint32_t sectionLength = de.getU32(cursor);215 if (!cursor)216 return cursor.takeError();217 218 if (sw) {219 sw->startLine() << "Section " << ++sectionNumber << " {\n";220 sw->indent();221 }222 223 if (sectionLength < 4 || cursor.tell() - 4 + sectionLength > section.size())224 return createStringError(errc::invalid_argument,225 "invalid section length " +226 Twine(sectionLength) + " at offset 0x" +227 utohexstr(cursor.tell() - 4));228 229 if (Error e = parseSubsection(sectionLength))230 return e;231 if (sw) {232 sw->unindent();233 sw->startLine() << "}\n";234 }235 }236 237 return cursor.takeError();238}239