Find first non-zero jit debug entry.

Sometimes a process will have multiple shared libraries loaded
that have defined __jit_debug_descriptor. Specifically, art testing
will load libart.so and libartd.so, which would have broken unwinding
through jit'd code for art testing if libart.so winds up being found first.
In order to avoid duplicating the code for the linker to figure out
which one is live, change the algorithm to find the first non-zero
first_entry_ set in __jit_debug_descriptor.

Bug: 68396769

Test: Passes unit tests.
Test: Verified this can unwind 137-cfi on arm/arm64.
Change-Id: Ic4d403065d2c6f22476ef0171e7add17cd1464cd
This commit is contained in:
Christopher Ferris 2018-01-12 15:53:19 -08:00
parent 85d0c3adaf
commit ed37aca987
29 changed files with 282 additions and 8 deletions

View File

@ -170,6 +170,7 @@ cc_test {
data: [
"tests/files/elf32.xz",
"tests/files/elf64.xz",
"tests/files/offline/jit_debug_arm32/*",
"tests/files/offline/jit_debug_x86_32/*",
"tests/files/offline/gnu_debugdata_arm32/*",
"tests/files/offline/straddle_arm32/*",

View File

@ -173,7 +173,6 @@ void JitDebug::Init(Maps* maps) {
initialized_ = true;
std::string descriptor_name("__jit_debug_descriptor");
uint64_t descriptor_addr = 0;
for (MapInfo* info : *maps) {
if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
continue;
@ -194,17 +193,16 @@ void JitDebug::Init(Maps* maps) {
}
Elf* elf = info->GetElf(memory_, true);
uint64_t descriptor_addr;
if (elf->GetGlobalVariable(descriptor_name, &descriptor_addr)) {
// Search for the first non-zero entry.
descriptor_addr += info->start;
break;
entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr);
if (entry_addr_ != 0) {
break;
}
}
}
if (descriptor_addr == 0) {
return;
}
entry_addr_ = (this->*read_descriptor_func_)(descriptor_addr);
}
Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {

View File

@ -49,6 +49,7 @@ class JitDebugTest : public ::testing::Test {
"a000-c000 --xp 00000000 00:00 0\n"
"c000-f000 rwxp 00000000 00:00 0\n"
"f000-11000 r-xp 00000000 00:00 0\n"
"12000-14000 r-xp 00000000 00:00 0\n"
"100000-110000 rw-p 0000000 00:00 0\n"
"200000-210000 rw-p 0000000 00:00 0\n"));
ASSERT_TRUE(maps_->Parse());
@ -72,6 +73,16 @@ class JitDebugTest : public ::testing::Test {
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf = elf;
map_info = maps_->Get(6);
ASSERT_TRUE(map_info != nullptr);
elf_memories_.push_back(new MemoryFake);
elf = new ElfFake(elf_memories_.back());
elf->FakeSetValid(true);
interface = new ElfInterfaceFake(elf_memories_.back());
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf = elf;
}
template <typename EhdrType, typename ShdrType>
@ -293,6 +304,27 @@ TEST_F(JitDebugTest, get_elf_32) {
EXPECT_EQ(elf, elf2);
}
TEST_F(JitDebugTest, get_multiple_jit_debug_descriptors_valid) {
CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x5000, ELFCLASS32, EM_ARM, 0x2000, 0x300);
WriteDescriptor32(0xf800, 0x200000);
WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000);
WriteDescriptor32(0x12800, 0x201000);
WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000);
ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr);
// Now clear the descriptor entry for the first one.
WriteDescriptor32(0xf800, 0);
jit_debug_.reset(new JitDebug(process_memory_));
jit_debug_->SetArch(ARCH_ARM);
ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr);
}
TEST_F(JitDebugTest, get_elf_x86) {
CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);

View File

@ -406,4 +406,223 @@ TEST(UnwindOfflineTest, jit_debug_x86_32) {
frame_info);
}
TEST(UnwindOfflineTest, jit_debug_arm32) {
std::string dir(TestGetFileDirectory() + "offline/jit_debug_arm32/");
MemoryOfflineParts* memory = new MemoryOfflineParts;
AddMemory(dir + "descriptor.data", memory);
AddMemory(dir + "descriptor1.data", memory);
AddMemory(dir + "stack.data", memory);
for (size_t i = 0; i < 7; i++) {
AddMemory(dir + "entry" + std::to_string(i) + ".data", memory);
AddMemory(dir + "jit" + std::to_string(i) + ".data", memory);
}
FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
ASSERT_TRUE(fp != nullptr);
RegsArm regs;
uint64_t reg_value;
ASSERT_EQ(1, fscanf(fp, "r0: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R0] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r1: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R1] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r2: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R2] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r3: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R3] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r4: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R4] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r5: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R5] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r6: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R6] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r7: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R7] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r8: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R8] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r9: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R9] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r10: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R10] = reg_value;
ASSERT_EQ(1, fscanf(fp, "r11: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R11] = reg_value;
ASSERT_EQ(1, fscanf(fp, "ip: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_R12] = reg_value;
ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_SP] = reg_value;
ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_LR] = reg_value;
ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_PC] = reg_value;
regs.SetFromRaw();
fclose(fp);
fp = fopen((dir + "maps.txt").c_str(), "r");
ASSERT_TRUE(fp != nullptr);
// The file is guaranteed to be less than 4096 bytes.
std::vector<char> buffer(4096);
ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
fclose(fp);
BufferMaps maps(buffer.data());
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(ARCH_ARM, regs.Arch());
std::shared_ptr<Memory> process_memory(memory);
char* cwd = getcwd(nullptr, 0);
ASSERT_EQ(0, chdir(dir.c_str()));
JitDebug jit_debug(process_memory);
Unwinder unwinder(128, &maps, &regs, process_memory);
unwinder.SetJitDebug(&jit_debug, regs.Arch());
unwinder.Unwind();
ASSERT_EQ(0, chdir(cwd));
free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
" #00 pc 00018a5e libarttestd.so (Java_Main_unwindInProcess+865)\n"
" #01 pc 0000212d (offset 0x2000) 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
"boolean)+92)\n"
" #02 pc 00011cb1 anonymous:e2796000 (boolean Main.bar(boolean)+72)\n"
" #03 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
" #04 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
" #05 pc 000bf7a9 libartd.so "
"(_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+864)\n"
" #06 pc 00247833 libartd.so "
"(_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPNS_"
"11ShadowFrameEtPNS_6JValueE+382)\n"
" #07 pc 0022e935 libartd.so "
"(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
"6JValueEb+244)\n"
" #08 pc 0022f71d libartd.so "
"(_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadERKNS_"
"20CodeItemDataAccessorEPNS_11ShadowFrameE+128)\n"
" #09 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
" #10 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
" #11 pc 00011c31 anonymous:e2796000 (int Main.compare(Main, Main)+64)\n"
" #12 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
" #13 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
" #14 pc 000bf7a9 libartd.so "
"(_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+864)\n"
" #15 pc 00247833 libartd.so "
"(_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPNS_"
"11ShadowFrameEtPNS_6JValueE+382)\n"
" #16 pc 0022e935 libartd.so "
"(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
"6JValueEb+244)\n"
" #17 pc 0022f71d libartd.so "
"(_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadERKNS_"
"20CodeItemDataAccessorEPNS_11ShadowFrameE+128)\n"
" #18 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
" #19 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
" #20 pc 00011b77 anonymous:e2796000 (int Main.compare(java.lang.Object, "
"java.lang.Object)+118)\n"
" #21 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
" #22 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
" #23 pc 000bf7a9 libartd.so "
"(_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+864)\n"
" #24 pc 00247833 libartd.so "
"(_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPNS_"
"11ShadowFrameEtPNS_6JValueE+382)\n"
" #25 pc 0022e935 libartd.so "
"(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
"6JValueEb+244)\n"
" #26 pc 0022f71d libartd.so "
"(_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadERKNS_"
"20CodeItemDataAccessorEPNS_11ShadowFrameE+128)\n"
" #27 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
" #28 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
" #29 pc 00011a29 anonymous:e2796000 (int "
"java.util.Arrays.binarySearch0(java.lang.Object[], int, int, java.lang.Object, "
"java.util.Comparator)+304)\n"
" #30 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
" #31 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
" #32 pc 000bf7bb libartd.so "
"(_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+882)\n"
" #33 pc 00247833 libartd.so "
"(_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPNS_"
"11ShadowFrameEtPNS_6JValueE+382)\n"
" #34 pc 0022e935 libartd.so "
"(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
"6JValueEb+244)\n"
" #35 pc 0022f71d libartd.so "
"(_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadERKNS_"
"20CodeItemDataAccessorEPNS_11ShadowFrameE+128)\n"
" #36 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
" #37 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
" #38 pc 0001139b anonymous:e2796000 (boolean Main.foo()+178)\n"
" #39 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
" #40 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
" #41 pc 000bf7a9 libartd.so "
"(_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+864)\n"
" #42 pc 00247833 libartd.so "
"(_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPNS_"
"11ShadowFrameEtPNS_6JValueE+382)\n"
" #43 pc 0022e935 libartd.so "
"(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
"6JValueEb+244)\n"
" #44 pc 0022f71d libartd.so "
"(_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadERKNS_"
"20CodeItemDataAccessorEPNS_11ShadowFrameE+128)\n"
" #45 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
" #46 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
" #47 pc 00010aa7 anonymous:e2796000 (void Main.runPrimary()+70)\n"
" #48 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
" #49 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
" #50 pc 000bf7a9 libartd.so "
"(_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+864)\n"
" #51 pc 00247833 libartd.so "
"(_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPNS_"
"11ShadowFrameEtPNS_6JValueE+382)\n"
" #52 pc 0022e935 libartd.so "
"(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
"6JValueEb+244)\n"
" #53 pc 0022f71d libartd.so "
"(_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadERKNS_"
"20CodeItemDataAccessorEPNS_11ShadowFrameE+128)\n"
" #54 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
" #55 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
" #56 pc 0000ba99 anonymous:e2796000 (void Main.main(java.lang.String[])+144)\n"
" #57 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
" #58 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
" #59 pc 000bf7bb libartd.so "
"(_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+882)\n"
" #60 pc 00247833 libartd.so "
"(_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPNS_"
"11ShadowFrameEtPNS_6JValueE+382)\n"
" #61 pc 0022e935 libartd.so "
"(_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_"
"6JValueEb+244)\n"
" #62 pc 0022f71d libartd.so "
"(_ZN3art11interpreter30EnterInterpreterFromEntryPointEPNS_6ThreadERKNS_"
"20CodeItemDataAccessorEPNS_11ShadowFrameE+128)\n"
" #63 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
" #64 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
" #65 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
" #66 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
" #67 pc 000bf7bb libartd.so "
"(_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+882)\n"
" #68 pc 003b292d libartd.so "
"(_ZN3artL18InvokeWithArgArrayERKNS_33ScopedObjectAccessAlreadyRunnableEPNS_9ArtMethodEPNS_"
"8ArgArrayEPNS_6JValueEPKc+52)\n"
" #69 pc 003b26c3 libartd.so "
"(_ZN3art17InvokeWithVarArgsERKNS_33ScopedObjectAccessAlreadyRunnableEP8_jobjectP10_"
"jmethodIDSt9__va_list+210)\n"
" #70 pc 00308411 libartd.so "
"(_ZN3art3JNI21CallStaticVoidMethodVEP7_JNIEnvP7_jclassP10_jmethodIDSt9__va_list+76)\n"
" #71 pc 000e6a9f libartd.so "
"(_ZN3art8CheckJNI11CallMethodVEPKcP7_JNIEnvP8_jobjectP7_jclassP10_jmethodIDSt9__va_listNS_"
"9Primitive4TypeENS_10InvokeTypeE+1486)\n"
" #72 pc 000e19b9 libartd.so "
"(_ZN3art8CheckJNI21CallStaticVoidMethodVEP7_JNIEnvP7_jclassP10_jmethodIDSt9__va_list+40)\n"
" #73 pc 0000159f dalvikvm32 "
"(_ZN7_JNIEnv20CallStaticVoidMethodEP7_jclassP10_jmethodIDz+30)\n"
" #74 pc 00001349 dalvikvm32 (main+896)\n"
" #75 pc 000850c9 libc.so\n",
frame_info);
}
} // namespace unwindstack

View File

@ -0,0 +1,8 @@
ab0d3000-ab0d8000 r-xp 0 00:00 0 dalvikvm32
dfe4e000-dfe7b000 r-xp 0 00:00 0 libarttestd.so
e0447000-e0448000 r-xp 2000 00:00 0 137-cfi.odex
e2796000-e4796000 r-xp 0 00:00 0 anonymous:e2796000
e648e000-e690f000 r-xp 00000000 00:00 0 libart.so
ed306000-ed801000 r-xp 0 00:00 0 libartd.so
eda88000-edb23000 r-xp 0 00:00 0 libc.so
ede4e000-ede50000 r-xp 0 00:00 0 anonymous:ede4e000

View File

@ -0,0 +1,16 @@
r0: dfe7c0f8
r1: 0
r2: 0
r3: 40000000
r4: e051ffb4
r5: 0
r6: e051ffc0
r7: ede514e8
r8: ff85d1a8
r9: ed9210c0
r10: 58
r11: 0
ip: edb26d04
sp: ff85d180
lr: edaff5af
pc: dfe66a5e