blob: 4dfa6a0c4ff0b5f6dcc39f7fd406f40a6c3620ce [file] [log] [blame]
/*
* Copyright 2011-2012, 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 "bcinfo/MetadataExtractor.h"
#define LOG_TAG "bcinfo"
#include <cutils/log.h>
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Support/MemoryBuffer.h"
#include <cstdlib>
namespace bcinfo {
// Name of metadata node where pragma info resides (should be synced with
// slang.cpp)
static const llvm::StringRef PragmaMetadataName = "#pragma";
// Name of metadata node where exported variable names reside (should be
// synced with slang_rs_metadata.h)
static const llvm::StringRef ExportVarMetadataName = "#rs_export_var";
// Name of metadata node where exported function names reside (should be
// synced with slang_rs_metadata.h)
static const llvm::StringRef ExportFuncMetadataName = "#rs_export_func";
// Name of metadata node where exported ForEach name information resides
// (should be synced with slang_rs_metadata.h)
static const llvm::StringRef ExportForEachNameMetadataName =
"#rs_export_foreach_name";
// Name of metadata node where exported ForEach signature information resides
// (should be synced with slang_rs_metadata.h)
static const llvm::StringRef ExportForEachMetadataName = "#rs_export_foreach";
// Name of metadata node where RS object slot info resides (should be
// synced with slang_rs_metadata.h)
static const llvm::StringRef ObjectSlotMetadataName = "#rs_object_slots";
MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize)
: mBitcode(bitcode), mBitcodeSize(bitcodeSize), mExportVarCount(0),
mExportFuncCount(0), mExportForEachSignatureCount(0),
mExportForEachNameList(NULL), mExportForEachSignatureList(NULL),
mPragmaCount(0), mPragmaKeyList(NULL), mPragmaValueList(NULL),
mObjectSlotCount(0), mObjectSlotList(NULL) {
}
MetadataExtractor::~MetadataExtractor() {
if (mExportForEachNameList) {
for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
delete [] mExportForEachNameList[i];
mExportForEachNameList[i] = NULL;
}
}
delete [] mExportForEachNameList;
mExportForEachNameList = NULL;
delete [] mExportForEachSignatureList;
mExportForEachSignatureList = NULL;
for (size_t i = 0; i < mPragmaCount; i++) {
if (mPragmaKeyList) {
delete [] mPragmaKeyList[i];
mPragmaKeyList[i] = NULL;
}
if (mPragmaValueList) {
delete [] mPragmaValueList[i];
mPragmaValueList[i] = NULL;
}
}
delete [] mPragmaKeyList;
mPragmaKeyList = NULL;
delete [] mPragmaValueList;
mPragmaValueList = NULL;
delete [] mObjectSlotList;
mObjectSlotList = NULL;
return;
}
bool MetadataExtractor::populateObjectSlotMetadata(
const llvm::NamedMDNode *ObjectSlotMetadata) {
if (!ObjectSlotMetadata) {
return true;
}
mObjectSlotCount = ObjectSlotMetadata->getNumOperands();
if (!mObjectSlotCount) {
return true;
}
uint32_t *TmpSlotList = new uint32_t[mObjectSlotCount];
memset(TmpSlotList, 0, mObjectSlotCount * sizeof(*TmpSlotList));
for (size_t i = 0; i < mObjectSlotCount; i++) {
llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i);
if (ObjectSlot != NULL && ObjectSlot->getNumOperands() == 1) {
llvm::Value *SlotMDS = ObjectSlot->getOperand(0);
if (SlotMDS->getValueID() == llvm::Value::MDStringVal) {
llvm::StringRef Slot =
static_cast<llvm::MDString*>(SlotMDS)->getString();
uint32_t USlot = 0;
if (Slot.getAsInteger(10, USlot)) {
ALOGE("Non-integer object slot value '%s'", Slot.str().c_str());
return false;
}
TmpSlotList[i] = USlot;
}
}
}
mObjectSlotList = TmpSlotList;
return true;
}
static const char *createStringFromValue(llvm::Value *v) {
if (v->getValueID() != llvm::Value::MDStringVal) {
return NULL;
}
llvm::StringRef ref = static_cast<llvm::MDString*>(v)->getString();
char *c = new char[ref.size() + 1];
memcpy(c, ref.data(), ref.size());
c[ref.size()] = '\0';
return c;
}
void MetadataExtractor::populatePragmaMetadata(
const llvm::NamedMDNode *PragmaMetadata) {
if (!PragmaMetadata) {
return;
}
mPragmaCount = PragmaMetadata->getNumOperands();
if (!mPragmaCount) {
return;
}
mPragmaKeyList = new const char*[mPragmaCount];
mPragmaValueList = new const char*[mPragmaCount];
for (size_t i = 0; i < mPragmaCount; i++) {
llvm::MDNode *Pragma = PragmaMetadata->getOperand(i);
if (Pragma != NULL && Pragma->getNumOperands() == 2) {
llvm::Value *PragmaKeyMDS = Pragma->getOperand(0);
mPragmaKeyList[i] = createStringFromValue(PragmaKeyMDS);
llvm::Value *PragmaValueMDS = Pragma->getOperand(1);
mPragmaValueList[i] = createStringFromValue(PragmaValueMDS);
}
}
return;
}
bool MetadataExtractor::populateForEachMetadata(
const llvm::NamedMDNode *Names,
const llvm::NamedMDNode *Signatures) {
if (!Names || !Signatures) {
// Handle legacy case for pre-ICS bitcode that doesn't contain a metadata
// section for ForEach. We generate a full signature for a "root" function
// which means that we need to set the bottom 5 bits in the mask.
mExportForEachSignatureCount = 1;
char **TmpNameList = new char*[mExportForEachSignatureCount];
TmpNameList[0] = new char[5];
strncpy(TmpNameList[0], "root", 5);
uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount];
TmpSigList[0] = 0x1f;
mExportForEachNameList = (const char**)TmpNameList;
mExportForEachSignatureList = TmpSigList;
return true;
}
mExportForEachSignatureCount = Signatures->getNumOperands();
if (!mExportForEachSignatureCount) {
return true;
}
uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount];
for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
llvm::MDNode *SigNode = Signatures->getOperand(i);
if (SigNode != NULL && SigNode->getNumOperands() == 1) {
llvm::Value *SigVal = SigNode->getOperand(0);
if (SigVal->getValueID() == llvm::Value::MDStringVal) {
llvm::StringRef SigString =
static_cast<llvm::MDString*>(SigVal)->getString();
uint32_t Signature = 0;
if (SigString.getAsInteger(10, Signature)) {
ALOGE("Non-integer signature value '%s'", SigString.str().c_str());
return false;
}
TmpSigList[i] = Signature;
}
}
}
mExportForEachSignatureList = TmpSigList;
mExportForEachNameList = new const char*[mExportForEachSignatureCount];
for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
llvm::MDNode *Name = Names->getOperand(i);
if (Name != NULL && Name->getNumOperands() == 1) {
mExportForEachNameList[i] = createStringFromValue(Name->getOperand(0));
}
}
return true;
}
bool MetadataExtractor::extract() {
if (!mBitcode || !mBitcodeSize) {
ALOGE("Invalid/empty bitcode");
return false;
}
llvm::OwningPtr<llvm::LLVMContext> mContext(new llvm::LLVMContext());
llvm::OwningPtr<llvm::MemoryBuffer> MEM(
llvm::MemoryBuffer::getMemBuffer(
llvm::StringRef(mBitcode, mBitcodeSize)));
std::string error;
// Module ownership is handled by the context, so we don't need to free it.
llvm::Module *module = llvm::ParseBitcodeFile(MEM.get(), *mContext, &error);
if (!module) {
ALOGE("Could not parse bitcode file");
ALOGE("%s", error.c_str());
return false;
}
const llvm::NamedMDNode *ExportVarMetadata =
module->getNamedMetadata(ExportVarMetadataName);
const llvm::NamedMDNode *ExportFuncMetadata =
module->getNamedMetadata(ExportFuncMetadataName);
const llvm::NamedMDNode *ExportForEachNameMetadata =
module->getNamedMetadata(ExportForEachNameMetadataName);
const llvm::NamedMDNode *ExportForEachMetadata =
module->getNamedMetadata(ExportForEachMetadataName);
const llvm::NamedMDNode *PragmaMetadata =
module->getNamedMetadata(PragmaMetadataName);
const llvm::NamedMDNode *ObjectSlotMetadata =
module->getNamedMetadata(ObjectSlotMetadataName);
if (ExportVarMetadata) {
mExportVarCount = ExportVarMetadata->getNumOperands();
}
if (ExportFuncMetadata) {
mExportFuncCount = ExportFuncMetadata->getNumOperands();
}
if (!populateForEachMetadata(ExportForEachNameMetadata,
ExportForEachMetadata)) {
ALOGE("Could not populate ForEach signature metadata");
return false;
}
populatePragmaMetadata(PragmaMetadata);
if (!populateObjectSlotMetadata(ObjectSlotMetadata)) {
ALOGE("Could not populate object slot metadata");
return false;
}
return true;
}
} // namespace bcinfo