Skip to content

Commit 7e49b0d

Browse files
authoredApr 16, 2024
[lldb] Fix nullptr dereference on running x86 binary with x86-disabled llvm (#82603)
If `LLVM_TARGETS_TO_BUILD` does not contain `X86` and we try to run an x86 binary in lldb, we get a `nullptr` dereference in `LLVMDisasmInstruction(...)`. We try to call `getDisAsm()` method on a `LLVMDisasmContext *DC` which is null. The pointer is passed from `x86AssemblyInspectionEngine::instruction_length(...)` and is originally `m_disasm_context` member of `x86AssemblyInspectionEngine`. This should be filled by `LLVMCreateDisasm(...)` in the class constructor, but not having X86 target enabled in llvm makes `TargetRegistry::lookupTarget(...)` call return `nullptr`, which results in `m_disasm_context` initialized with `nullptr` as well. This patch adds if statements against `m_disasm_context` in `x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(...)` and `x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction(...)` so subsequent calls to `x86AssemblyInspectionEngine::instruction_length(...)` do not cause a null pointer dereference.
1 parent 3c6f91e commit 7e49b0d

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed
 

‎lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,9 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
909909
if (!m_register_map_initialized)
910910
return false;
911911

912+
if (m_disasm_context == nullptr)
913+
return false;
914+
912915
addr_t current_func_text_offset = 0;
913916
int current_sp_bytes_offset_from_fa = 0;
914917
bool is_aligned = false;
@@ -1570,6 +1573,9 @@ bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction(
15701573
if (!m_register_map_initialized)
15711574
return false;
15721575

1576+
if (m_disasm_context == nullptr)
1577+
return false;
1578+
15731579
while (offset < size) {
15741580
int regno;
15751581
int insn_len;

‎lldb/unittests/UnwindAssembly/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ endif()
99
if ("X86" IN_LIST LLVM_TARGETS_TO_BUILD)
1010
add_subdirectory(x86)
1111
endif()
12+
13+
if (NOT "X86" IN_LIST LLVM_TARGETS_TO_BUILD)
14+
add_subdirectory(x86-but-no-x86-target)
15+
endif()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
add_lldb_unittest(UnwindAssemblyX86ButNoX86TargetTests
2+
Testx86AssemblyInspectionEngine.cpp
3+
LINK_LIBS
4+
lldbCore
5+
lldbSymbol
6+
lldbPluginUnwindAssemblyX86
7+
LINK_COMPONENTS
8+
Support
9+
${LLVM_TARGETS_TO_BUILD}
10+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//===-- Testx86AssemblyInspectionEngine.cpp -------------------------------===//
2+
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "gtest/gtest.h"
11+
12+
#include "Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h"
13+
#include "lldb/Core/AddressRange.h"
14+
#include "lldb/Symbol/UnwindPlan.h"
15+
#include "lldb/Utility/ArchSpec.h"
16+
17+
#include "llvm/Support/TargetSelect.h"
18+
19+
#include <memory>
20+
#include <vector>
21+
22+
using namespace lldb;
23+
using namespace lldb_private;
24+
25+
class Testx86AssemblyInspectionEngine : public testing::Test {
26+
public:
27+
static void SetUpTestCase();
28+
};
29+
30+
void Testx86AssemblyInspectionEngine::SetUpTestCase() {
31+
llvm::InitializeAllTargets();
32+
llvm::InitializeAllAsmPrinters();
33+
llvm::InitializeAllTargetMCs();
34+
llvm::InitializeAllDisassemblers();
35+
}
36+
37+
// only defining the register names / numbers that the unwinder is actually
38+
// using today
39+
40+
// names should match the constants below. These will be the eRegisterKindLLDB
41+
// register numbers.
42+
43+
const char *x86_64_reg_names[] = {"rax", "rbx", "rcx", "rdx", "rsp", "rbp",
44+
"rsi", "rdi", "r8", "r9", "r10", "r11",
45+
"r12", "r13", "r14", "r15", "rip"};
46+
47+
enum x86_64_regs {
48+
k_rax = 0,
49+
k_rbx = 1,
50+
k_rcx = 2,
51+
k_rdx = 3,
52+
k_rsp = 4,
53+
k_rbp = 5,
54+
k_rsi = 6,
55+
k_rdi = 7,
56+
k_r8 = 8,
57+
k_r9 = 9,
58+
k_r10 = 10,
59+
k_r11 = 11,
60+
k_r12 = 12,
61+
k_r13 = 13,
62+
k_r14 = 14,
63+
k_r15 = 15,
64+
k_rip = 16
65+
};
66+
67+
std::unique_ptr<x86AssemblyInspectionEngine> Getx86_64Inspector() {
68+
69+
ArchSpec arch("x86_64-apple-macosx");
70+
std::unique_ptr<x86AssemblyInspectionEngine> engine(
71+
new x86AssemblyInspectionEngine(arch));
72+
73+
std::vector<x86AssemblyInspectionEngine::lldb_reg_info> lldb_regnums;
74+
int i = 0;
75+
for (const auto &name : x86_64_reg_names) {
76+
x86AssemblyInspectionEngine::lldb_reg_info ri;
77+
ri.name = name;
78+
ri.lldb_regnum = i++;
79+
lldb_regnums.push_back(ri);
80+
}
81+
82+
engine->Initialize(lldb_regnums);
83+
return engine;
84+
}
85+
86+
TEST_F(Testx86AssemblyInspectionEngine, TestSimple64bitFrameFunction) {
87+
std::unique_ptr<x86AssemblyInspectionEngine> engine = Getx86_64Inspector();
88+
89+
// 'int main() { }' compiled for x86_64-apple-macosx with clang
90+
uint8_t data[] = {
91+
0x55, // offset 0 -- pushq %rbp
92+
0x48, 0x89, 0xe5, // offset 1 -- movq %rsp, %rbp
93+
0x31, 0xc0, // offset 4 -- xorl %eax, %eax
94+
0x5d, // offset 6 -- popq %rbp
95+
0xc3 // offset 7 -- retq
96+
};
97+
98+
AddressRange sample_range(0x1000, sizeof(data));
99+
100+
UnwindPlan unwind_plan(eRegisterKindLLDB);
101+
EXPECT_FALSE(engine->GetNonCallSiteUnwindPlanFromAssembly(
102+
data, sizeof(data), sample_range, unwind_plan));
103+
}

0 commit comments

Comments
 (0)