blob: 14a90a2806314baf2f9e8a8cc3c67c6c61817454 [file] [log] [blame]
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <header_abi_util.h>
#include <llvm/Object/ELFObjectFile.h>
#include <llvm/Object/Binary.h>
#include <llvm/Object/ELFTypes.h>
#include <llvm/Object/SymbolSize.h>
using llvm::object::ELF32LEObjectFile;
using llvm::object::ELF32BEObjectFile;
using llvm::object::ELF64LEObjectFile;
using llvm::object::ELF64BEObjectFile;
using llvm::dyn_cast;
using llvm::ELF::STV_DEFAULT;
using llvm::ELF::STV_PROTECTED;
using llvm::ELF::STB_WEAK;
using llvm::ELF::STB_GLOBAL;
namespace abi_util {
template <typename T>
static inline T UnWrap(llvm::Expected<T> ValueOrError) {
if (!ValueOrError) {
llvm::errs() << "\nError: "
<< llvm::toString(ValueOrError.takeError())
<< ".\n";
llvm::errs().flush();
exit(1);
}
return std::move(ValueOrError.get());
}
template<typename T>
const std::set<std::string> &ELFSoFileParser<T>::GetFunctions() const {
return functions_;
}
template<typename T>
const std::set<std::string> &ELFSoFileParser<T>::GetGlobVars() const {
return globvars_;
}
template<typename T>
bool ELFSoFileParser<T>::IsSymbolExported(const Elf_Sym *elf_sym) const {
unsigned char visibility = elf_sym->getVisibility();
unsigned char binding = elf_sym->getBinding();
return (binding == STB_GLOBAL || binding == STB_WEAK) &&
(visibility == STV_DEFAULT ||
visibility == STV_PROTECTED);
}
template<typename T>
void ELFSoFileParser<T>::GetSymbols() {
assert(obj_ != nullptr);
for (auto symbol_it : obj_->symbols()) {
const Elf_Sym *elf_sym =
obj_->getSymbol(symbol_it.getRawDataRefImpl());
assert (elf_sym != nullptr);
if (!IsSymbolExported(elf_sym) || elf_sym->isUndefined()) {
continue;
}
llvm::object::SymbolRef::Type type = UnWrap(symbol_it.getType());
std::string symbol_name = UnWrap(symbol_it.getName());
if (type == llvm::object::SymbolRef::Type::ST_Function) {
functions_.insert(symbol_name);
} else if (type == llvm::object::SymbolRef::Type::ST_Data) {
globvars_.insert(symbol_name);
}
}
}
template<typename T>
static std::unique_ptr<SoFileParser> CreateELFSoFileParser(
const llvm::object::ELFObjectFile<T> *elfo) {
return llvm::make_unique<ELFSoFileParser<T>>(elfo);
}
std::unique_ptr<SoFileParser> SoFileParser::Create(
const llvm::object::ObjectFile *objfile) {
// Little-endian 32-bit
if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(objfile)) {
return CreateELFSoFileParser(ELFObj);
}
// Big-endian 32-bit
if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(objfile)) {
return CreateELFSoFileParser(ELFObj);
}
// Little-endian 64-bit
if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(objfile)) {
return CreateELFSoFileParser(ELFObj);
}
// Big-endian 64-bit
if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(objfile)) {
return CreateELFSoFileParser(ELFObj);
}
return nullptr;
}
} // namespace abi_util