Move dex pc frame creation into libunwindstack.
Test: Compiles, all unit tests pass.
Test: Ran 137-cfi art test in interpreter and verified interpreter
Test: frames still show up.
Change-Id: Icea90194986faa733a873e8cf467fc2513eb5573
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f70ed7b..d22e1e8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -31,8 +31,74 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Unwinder.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
+
namespace unwindstack {
+// Inject extra 'virtual' frame that represents the dex pc data.
+// The dex pc is a magic register defined in the Mterp interpreter,
+// and thus it will be restored/observed in the frame after it.
+// Adding the dex frame first here will create something like:
+// #7 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8
+// #8 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625
+// #9 pc 0039a1ef libartd.so art::interpreter::Execute+719
+void Unwinder::FillInDexFrame() {
+ size_t frame_num = frames_.size();
+ frames_.resize(frame_num + 1);
+ FrameData* frame = &frames_.at(frame_num);
+
+ uint64_t dex_pc = regs_->dex_pc();
+ frame->pc = dex_pc;
+ frame->sp = regs_->sp();
+
+ auto it = maps_->begin();
+ uint64_t rel_dex_pc;
+ MapInfo* info;
+ for (; it != maps_->end(); ++it) {
+ auto entry = *it;
+ if (dex_pc >= entry->start && dex_pc < entry->end) {
+ info = entry;
+ rel_dex_pc = dex_pc - entry->start;
+ frame->map_start = entry->start;
+ frame->map_end = entry->end;
+ frame->map_offset = entry->offset;
+ frame->map_load_bias = entry->load_bias;
+ frame->map_flags = entry->flags;
+ frame->map_name = entry->name;
+ frame->rel_pc = rel_dex_pc;
+ break;
+ }
+ }
+
+ if (it == maps_->end() || ++it == maps_->end()) {
+ return;
+ }
+
+ auto entry = *it;
+ unwindstack::Elf* elf = entry->GetElf(process_memory_, true);
+ if (!elf->valid()) {
+ return;
+ }
+
+ // Adjust the relative dex by the offset.
+ rel_dex_pc += entry->elf_offset;
+
+ uint64_t dex_offset;
+ if (!elf->GetFunctionName(rel_dex_pc, &frame->function_name, &dex_offset)) {
+ return;
+ }
+ frame->function_offset = dex_offset;
+ if (frame->function_name != "$dexfile") {
+ return;
+ }
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ dex_files_->GetMethodInformation(dex_offset, info, &frame->function_name, &frame->function_offset);
+#endif
+}
+
void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t func_pc) {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
@@ -40,7 +106,6 @@
frame->num = frame_num;
frame->sp = regs_->sp();
frame->rel_pc = adjusted_rel_pc;
- frame->dex_pc = regs_->dex_pc();
if (map_info == nullptr) {
frame->pc = regs_->pc();
@@ -128,6 +193,11 @@
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
+ if (regs_->dex_pc() != 0) {
+ // Add a frame to represent the dex file.
+ FillInDexFrame();
+ }
+
FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
// Once a frame is added, stop skipping frames.
@@ -240,4 +310,11 @@
jit_debug_ = jit_debug;
}
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
+ dex_files->SetArch(arch);
+ dex_files_ = dex_files;
+}
+#endif
+
} // namespace unwindstack