summaryrefslogtreecommitdiff
path: root/simpleperf/JITDebugReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/JITDebugReader.cpp')
-rw-r--r--simpleperf/JITDebugReader.cpp213
1 files changed, 37 insertions, 176 deletions
diff --git a/simpleperf/JITDebugReader.cpp b/simpleperf/JITDebugReader.cpp
index 7ef3f25f..4e688eea 100644
--- a/simpleperf/JITDebugReader.cpp
+++ b/simpleperf/JITDebugReader.cpp
@@ -49,7 +49,7 @@ static constexpr size_t MAX_JIT_SYMFILE_SIZE = 1024 * 1024u;
// avoid spending all time checking, wait 100 ms between any two checks.
static constexpr size_t kUpdateJITDebugInfoIntervalInMs = 100;
-// Match the format of JITDescriptor in art/runtime/jit/debugger_interface.cc.
+// Match the format of JITDescriptor in art/runtime/jit/debugger_itnerface.cc.
template <typename ADDRT>
struct JITDescriptor {
uint32_t version;
@@ -63,15 +63,12 @@ struct JITDescriptor {
uint32_t action_seqlock; // incremented before and after any modification
uint64_t action_timestamp; // CLOCK_MONOTONIC time of last action
- bool Valid() const;
-
- int AndroidVersion() const {
- return magic[7] - '0';
+ bool Valid() const {
+ return version == 1 && strncmp(reinterpret_cast<const char*>(magic), "Android1", 8) == 0;
}
};
-// Match the format of JITCodeEntry in art/runtime/jit/debugger_interface.cc
-// with JITDescriptor.magic == "Android1".
+// Match the format of JITCodeEntry in art/runtime/jit/debugger_itnerface.cc.
template <typename ADDRT>
struct JITCodeEntry {
ADDRT next_addr;
@@ -85,8 +82,7 @@ struct JITCodeEntry {
}
};
-// Match the format of JITCodeEntry in art/runtime/jit/debugger_interface.cc
-// with JITDescriptor.magic == "Android1".
+// Match the format of JITCodeEntry in art/runtime/jit/debugger_interface.cc.
template <typename ADDRT>
struct __attribute__((packed)) PackedJITCodeEntry {
ADDRT next_addr;
@@ -100,110 +96,28 @@ struct __attribute__((packed)) PackedJITCodeEntry {
}
};
-// Match the format of JITCodeEntry in art/runtime/jit/debugger_interface.cc
-// with JITDescriptor.magic == "Android2".
-template <typename ADDRT>
-struct JITCodeEntryV2 {
- ADDRT next_addr;
- ADDRT prev_addr;
- ADDRT symfile_addr;
- uint64_t symfile_size;
- uint64_t register_timestamp; // CLOCK_MONOTONIC time of entry registration
- uint32_t seqlock; // even value if valid
-
- bool Valid() const {
- return (seqlock & 1) == 0;
- }
-};
-
-// Match the format of JITCodeEntry in art/runtime/jit/debugger_interface.cc
-// with JITDescriptor.magic == "Android2".
-template <typename ADDRT>
-struct __attribute__((packed)) PackedJITCodeEntryV2 {
- ADDRT next_addr;
- ADDRT prev_addr;
- ADDRT symfile_addr;
- uint64_t symfile_size;
- uint64_t register_timestamp;
- uint32_t seqlock;
-
- bool Valid() const {
- return (seqlock & 1) == 0;
- }
-};
-
-// Match the format of JITCodeEntry in art/runtime/jit/debugger_interface.cc
-// with JITDescriptor.magic == "Android2".
-template <typename ADDRT>
-struct __attribute__((packed)) PaddedJITCodeEntryV2 {
- ADDRT next_addr;
- ADDRT prev_addr;
- ADDRT symfile_addr;
- uint64_t symfile_size;
- uint64_t register_timestamp;
- uint32_t seqlock;
- uint32_t pad;
-
- bool Valid() const {
- return (seqlock & 1) == 0;
- }
-};
-
using JITDescriptor32 = JITDescriptor<uint32_t>;
using JITDescriptor64 = JITDescriptor<uint64_t>;
#if defined(__x86_64__)
// Make sure simpleperf built for i386 and x86_64 see the correct JITCodeEntry layout of i386.
using JITCodeEntry32 = PackedJITCodeEntry<uint32_t>;
-using JITCodeEntry32V2 = PackedJITCodeEntryV2<uint32_t>;
#else
using JITCodeEntry32 = JITCodeEntry<uint32_t>;
-using JITCodeEntry32V2 = JITCodeEntryV2<uint32_t>;
#endif
-
using JITCodeEntry64 = JITCodeEntry<uint64_t>;
-#if defined(__i386__)
-// Make sure simpleperf built for i386 and x86_64 see the correct JITCodeEntry layout of x86_64.
-using JITCodeEntry64V2 = PaddedJITCodeEntryV2<uint64_t>;
-#else
-using JITCodeEntry64V2 = JITCodeEntryV2<uint64_t>;
-#endif
-
-template <typename ADDRT>
-bool JITDescriptor<ADDRT>::Valid() const {
- const char* magic_str = reinterpret_cast<const char*>(magic);
- if (version != 1 ||
- !(strncmp(magic_str, "Android1", 8) == 0 || strncmp(magic_str, "Android2", 8) == 0)) {
- return false;
- }
- if (sizeof(*this) != sizeof_descriptor) {
- return false;
- }
- if (sizeof(ADDRT) == 4) {
- return sizeof_entry == (AndroidVersion() == 1) ? sizeof(JITCodeEntry32)
- : sizeof(JITCodeEntry32V2);
- }
- return sizeof_entry == (AndroidVersion() == 1) ? sizeof(JITCodeEntry64)
- : sizeof(JITCodeEntry64V2);
-}
// We want to support both 64-bit and 32-bit simpleperf when profiling either 64-bit or 32-bit
// apps. So using static_asserts to make sure that simpleperf on arm and aarch64 having the same
// view of structures, and simpleperf on i386 and x86_64 having the same view of structures.
static_assert(sizeof(JITDescriptor32) == 48, "");
static_assert(sizeof(JITDescriptor64) == 56, "");
-
#if defined(__i386__) or defined(__x86_64__)
static_assert(sizeof(JITCodeEntry32) == 28, "");
-static_assert(sizeof(JITCodeEntry32V2) == 32, "");
-static_assert(sizeof(JITCodeEntry64) == 40, "");
-static_assert(sizeof(JITCodeEntry64V2) == 48, "");
#else
static_assert(sizeof(JITCodeEntry32) == 32, "");
-static_assert(sizeof(JITCodeEntry32V2) == 40, "");
-static_assert(sizeof(JITCodeEntry64) == 40, "");
-static_assert(sizeof(JITCodeEntry64V2) == 48, "");
#endif
+static_assert(sizeof(JITCodeEntry64) == 40, "");
bool JITDebugReader::RegisterDebugInfoCallback(IOEventLoop* loop,
const debug_info_callback_t& callback) {
@@ -496,22 +410,22 @@ bool JITDebugReader::ReadDescriptors(Process& process, Descriptor* jit_descripto
bool JITDebugReader::LoadDescriptor(bool is_64bit, const char* data, Descriptor* descriptor) {
if (is_64bit) {
- return LoadDescriptorImpl<JITDescriptor64>(data, descriptor);
+ return LoadDescriptorImpl<JITDescriptor64, JITCodeEntry64>(data, descriptor);
}
- return LoadDescriptorImpl<JITDescriptor32>(data, descriptor);
+ return LoadDescriptorImpl<JITDescriptor32, JITCodeEntry32>(data, descriptor);
}
-template <typename DescriptorT>
+template <typename DescriptorT, typename CodeEntryT>
bool JITDebugReader::LoadDescriptorImpl(const char* data, Descriptor* descriptor) {
DescriptorT raw_descriptor;
MoveFromBinaryFormat(raw_descriptor, data);
- if (!raw_descriptor.Valid()) {
+ if (!raw_descriptor.Valid() || sizeof(raw_descriptor) != raw_descriptor.sizeof_descriptor ||
+ sizeof(CodeEntryT) != raw_descriptor.sizeof_entry) {
return false;
}
descriptor->action_seqlock = raw_descriptor.action_seqlock;
descriptor->action_timestamp = raw_descriptor.action_timestamp;
descriptor->first_entry_addr = raw_descriptor.first_entry_addr;
- descriptor->version = raw_descriptor.AndroidVersion();
return true;
}
@@ -521,26 +435,15 @@ bool JITDebugReader::LoadDescriptorImpl(const char* data, Descriptor* descriptor
bool JITDebugReader::ReadNewCodeEntries(Process& process, const Descriptor& descriptor,
uint64_t last_action_timestamp, uint32_t read_entry_limit,
std::vector<CodeEntry>* new_code_entries) {
- if (descriptor.version == 1) {
- if (process.is_64bit) {
- return ReadNewCodeEntriesImpl<JITCodeEntry64>(
- process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
- }
- return ReadNewCodeEntriesImpl<JITCodeEntry32>(
- process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
- }
- if (descriptor.version == 2) {
- if (process.is_64bit) {
- return ReadNewCodeEntriesImplV2<JITCodeEntry64V2>(
- process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
- }
- return ReadNewCodeEntriesImplV2<JITCodeEntry32V2>(
+ if (process.is_64bit) {
+ return ReadNewCodeEntriesImpl<JITDescriptor64, JITCodeEntry64>(
process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
}
- return false;
+ return ReadNewCodeEntriesImpl<JITDescriptor32, JITCodeEntry32>(
+ process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
}
-template <typename CodeEntryT>
+template <typename DescriptorT, typename CodeEntryT>
bool JITDebugReader::ReadNewCodeEntriesImpl(Process& process, const Descriptor& descriptor,
uint64_t last_action_timestamp,
uint32_t read_entry_limit,
@@ -548,7 +451,6 @@ bool JITDebugReader::ReadNewCodeEntriesImpl(Process& process, const Descriptor&
uint64_t current_entry_addr = descriptor.first_entry_addr;
uint64_t prev_entry_addr = 0u;
std::unordered_set<uint64_t> entry_addr_set;
-
for (size_t i = 0u; i < read_entry_limit && current_entry_addr != 0u; ++i) {
if (entry_addr_set.find(current_entry_addr) != entry_addr_set.end()) {
// We enter a loop, which means a broken linked list.
@@ -567,54 +469,12 @@ bool JITDebugReader::ReadNewCodeEntriesImpl(Process& process, const Descriptor&
// once we hit an entry with timestamp <= last_action_timestmap.
break;
}
- if (entry.symfile_size > 0) {
- CodeEntry code_entry;
- code_entry.addr = current_entry_addr;
- code_entry.symfile_addr = entry.symfile_addr;
- code_entry.symfile_size = entry.symfile_size;
- code_entry.timestamp = entry.register_timestamp;
- new_code_entries->push_back(code_entry);
- }
- entry_addr_set.insert(current_entry_addr);
- prev_entry_addr = current_entry_addr;
- current_entry_addr = entry.next_addr;
- }
- return true;
-}
-
-// Temporary work around for patch "JIT mini-debug-info: Append packed entries towards end.", which
-// adds new entries at the end of the list and forces simpleperf to read the whole list.
-template <typename CodeEntryT>
-bool JITDebugReader::ReadNewCodeEntriesImplV2(Process& process, const Descriptor& descriptor,
- uint64_t last_action_timestamp,
- uint32_t /* read_entry_limit */,
- std::vector<CodeEntry>* new_code_entries) {
- uint64_t current_entry_addr = descriptor.first_entry_addr;
- uint64_t prev_entry_addr = 0u;
- std::unordered_set<uint64_t> entry_addr_set;
- const size_t READ_ENTRY_LIMIT = 10000; // to avoid endless loop
-
- for (size_t i = 0u; i < READ_ENTRY_LIMIT && current_entry_addr != 0u; ++i) {
- if (entry_addr_set.find(current_entry_addr) != entry_addr_set.end()) {
- // We enter a loop, which means a broken linked list.
- return false;
- }
- CodeEntryT entry;
- if (!ReadRemoteMem(process, current_entry_addr, sizeof(entry), &entry)) {
- return false;
- }
- if (entry.prev_addr != prev_entry_addr || !entry.Valid()) {
- // A broken linked list
- return false;
- }
- if (entry.symfile_size > 0 && entry.register_timestamp > last_action_timestamp) {
- CodeEntry code_entry;
- code_entry.addr = current_entry_addr;
- code_entry.symfile_addr = entry.symfile_addr;
- code_entry.symfile_size = entry.symfile_size;
- code_entry.timestamp = entry.register_timestamp;
- new_code_entries->push_back(code_entry);
- }
+ CodeEntry code_entry;
+ code_entry.addr = current_entry_addr;
+ code_entry.symfile_addr = entry.symfile_addr;
+ code_entry.symfile_size = entry.symfile_size;
+ code_entry.timestamp = entry.register_timestamp;
+ new_code_entries->push_back(code_entry);
entry_addr_set.insert(current_entry_addr);
prev_entry_addr = current_entry_addr;
current_entry_addr = entry.next_addr;
@@ -639,6 +499,18 @@ void JITDebugReader::ReadJITCodeDebugInfo(Process& process,
if (!IsValidElfFileMagic(data.data(), jit_entry.symfile_size)) {
continue;
}
+ uint64_t min_addr = UINT64_MAX;
+ uint64_t max_addr = 0;
+ auto callback = [&](const ElfFileSymbol& symbol) {
+ min_addr = std::min(min_addr, symbol.vaddr);
+ max_addr = std::max(max_addr, symbol.vaddr + symbol.len);
+ LOG(VERBOSE) << "JITSymbol " << symbol.name << " at [" << std::hex << symbol.vaddr
+ << " - " << (symbol.vaddr + symbol.len) << " with size " << symbol.len;
+ };
+ if (ParseSymbolsFromElfFileInMemory(data.data(), jit_entry.symfile_size, callback) !=
+ ElfStatus::NO_ERROR || min_addr >= max_addr) {
+ continue;
+ }
std::unique_ptr<TemporaryFile> tmp_file = ScopedTempFiles::CreateTempFile(!keep_symfiles_);
if (tmp_file == nullptr || !android::base::WriteFully(tmp_file->fd, data.data(),
jit_entry.symfile_size)) {
@@ -647,16 +519,8 @@ void JITDebugReader::ReadJITCodeDebugInfo(Process& process,
if (keep_symfiles_) {
tmp_file->DoNotRemove();
}
- auto callback = [&](const ElfFileSymbol& symbol) {
- if (symbol.len == 0) { // Some arm labels can have zero length.
- return;
- }
- LOG(VERBOSE) << "JITSymbol " << symbol.name << " at [" << std::hex << symbol.vaddr
- << " - " << (symbol.vaddr + symbol.len) << " with size " << symbol.len;
- debug_info->emplace_back(process.pid, jit_entry.timestamp, symbol.vaddr, symbol.len,
- tmp_file->path);
- };
- ParseSymbolsFromElfFileInMemory(data.data(), jit_entry.symfile_size, callback);
+ debug_info->emplace_back(process.pid, jit_entry.timestamp, min_addr, max_addr - min_addr,
+ tmp_file->path);
}
}
@@ -684,10 +548,8 @@ void JITDebugReader::ReadDexFileDebugInfo(Process& process,
std::string file_path;
std::string zip_path;
std::string entry_path;
- std::shared_ptr<ThreadMmap> extracted_dex_file_map;
if (ParseExtractedInMemoryPath(it->name, &zip_path, &entry_path)) {
file_path = GetUrlInApk(zip_path, entry_path);
- extracted_dex_file_map = std::make_shared<ThreadMmap>(*it);
} else {
if (!IsRegularFile(it->name)) {
// TODO: read dex file only exist in memory?
@@ -697,8 +559,7 @@ void JITDebugReader::ReadDexFileDebugInfo(Process& process,
}
// Offset of dex file in .vdex file or .apk file.
uint64_t dex_file_offset = dex_entry.symfile_addr - it->start_addr + it->pgoff;
- debug_info->emplace_back(process.pid, dex_entry.timestamp, dex_file_offset, file_path,
- extracted_dex_file_map);
+ debug_info->emplace_back(process.pid, dex_entry.timestamp, dex_file_offset, file_path);
LOG(VERBOSE) << "DexFile " << file_path << "+" << std::hex << dex_file_offset
<< " in map [" << it->start_addr << " - " << (it->start_addr + it->len)
<< "] with size " << dex_entry.symfile_size;