/*
* Copyright (C) 2018 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 "read_dex_file.h"
#include <fcntl.h>
#include <algorithm>
#include <iterator>
#include <string>
#include <utility>
#include <vector>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <art_api/dex_file_support.h>
static bool ReadSymbols(
const std::vector<uint64_t>& dex_file_offsets, std::vector<DexFileSymbol>* symbols,
const std::function<std::unique_ptr<art_api::dex::DexFile>(uint64_t offset)>& open_file_cb) {
for (uint64_t offset : dex_file_offsets) {
std::unique_ptr<art_api::dex::DexFile> dex_file = open_file_cb(offset);
if (dex_file == nullptr) {
return false;
}
std::vector<art_api::dex::MethodInfo> file_syms = dex_file->GetAllMethodInfos(false);
// Adjust offsets to be from the start of the combined file.
for (art_api::dex::MethodInfo& sym : file_syms) {
sym.offset += offset;
}
if (symbols->empty()) {
*symbols = std::move(file_syms);
} else {
symbols->reserve(symbols->size() + file_syms.size());
std::move(std::begin(file_syms), std::end(file_syms), std::back_inserter(*symbols));
}
}
return true;
}
bool ReadSymbolsFromDexFileInMemory(void* addr, uint64_t size,
const std::vector<uint64_t>& dex_file_offsets,
std::vector<DexFileSymbol>* symbols) {
return ReadSymbols(
dex_file_offsets, symbols, [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
size_t max_file_size;
if (__builtin_sub_overflow(size, offset, &max_file_size)) {
return nullptr;
}
uint8_t* file_addr = static_cast<uint8_t*>(addr) + offset;
std::string error_msg;
std::unique_ptr<art_api::dex::DexFile> dex_file =
art_api::dex::DexFile::OpenFromMemory(file_addr, &max_file_size, "", &error_msg);
if (dex_file == nullptr) {
LOG(WARNING) << "Failed to read dex file symbols: " << error_msg;
return nullptr;
}
return dex_file;
});
}
bool ReadSymbolsFromDexFile(const std::string& file_path,
const std::vector<uint64_t>& dex_file_offsets,
std::vector<DexFileSymbol>* symbols) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file_path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
return false;
}
return ReadSymbols(
dex_file_offsets, symbols, [&](uint64_t offset) -> std::unique_ptr<art_api::dex::DexFile> {
std::string error_msg;
std::unique_ptr<art_api::dex::DexFile> dex_file =
art_api::dex::DexFile::OpenFromFd(fd, offset, file_path, &error_msg);
if (dex_file == nullptr) {
LOG(WARNING) << "Failed to read dex file symbols from '" << file_path
<< "': " << error_msg;
return nullptr;
}
return dex_file;
});
}