[Lldb-commits] [lldb] [lldb] Support changes to TLS on macOS (PR #77988)
Alex Langford via lldb-commits
lldb-commits at lists.llvm.org
Wed Jan 17 11:09:30 PST 2024
https://github.com/bulbazord updated https://github.com/llvm/llvm-project/pull/77988
>From cf2597f907fd2566e202d763a91834515d9c8ae4 Mon Sep 17 00:00:00 2001
From: Alex Langford <alangford at apple.com>
Date: Fri, 12 Jan 2024 13:03:27 -0800
Subject: [PATCH 1/5] [lldb][NFCI] Re-organize
DynamicLoaderDarwin::GetThreadLocalData
This is a small re-organization of GetThreadLocalData. This makes it
easier for me to add support for a newer way of getting thread local
data on apple platforms.
---
.../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 120 +++++++++---------
1 file changed, 59 insertions(+), 61 deletions(-)
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index 1e3e2e5641ad835..2deb7663b42e029 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -1048,70 +1048,68 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ lldb_private::Address tls_addr;
+ if (!module_sp->ResolveFileAddress(tls_file_addr, tls_addr))
+ return LLDB_INVALID_ADDRESS;
+
const uint32_t addr_size = m_process->GetAddressByteSize();
uint8_t buf[sizeof(lldb::addr_t) * 3];
+ Status error;
+ const size_t tls_data_size = addr_size * 3;
+ Target &target = m_process->GetTarget();
+ const size_t bytes_read = target.ReadMemory(
+ tls_addr, buf, tls_data_size, error, /*force_live_memory = */ true);
+ if (bytes_read != tls_data_size || error.Fail())
+ return LLDB_INVALID_ADDRESS;
- lldb_private::Address tls_addr;
- if (module_sp->ResolveFileAddress(tls_file_addr, tls_addr)) {
- Status error;
- const size_t tsl_data_size = addr_size * 3;
- Target &target = m_process->GetTarget();
- if (target.ReadMemory(tls_addr, buf, tsl_data_size, error, true) ==
- tsl_data_size) {
- const ByteOrder byte_order = m_process->GetByteOrder();
- DataExtractor data(buf, sizeof(buf), byte_order, addr_size);
- lldb::offset_t offset = addr_size; // Skip the first pointer
- const lldb::addr_t pthread_key = data.GetAddress(&offset);
- const lldb::addr_t tls_offset = data.GetAddress(&offset);
- if (pthread_key != 0) {
- // First check to see if we have already figured out the location of
- // TLS data for the pthread_key on a specific thread yet. If we have we
- // can re-use it since its location will not change unless the process
- // execs.
- const tid_t tid = thread_sp->GetID();
- auto tid_pos = m_tid_to_tls_map.find(tid);
- if (tid_pos != m_tid_to_tls_map.end()) {
- auto tls_pos = tid_pos->second.find(pthread_key);
- if (tls_pos != tid_pos->second.end()) {
- return tls_pos->second + tls_offset;
- }
- }
- StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0);
- if (frame_sp) {
- TypeSystemClangSP scratch_ts_sp =
- ScratchTypeSystemClang::GetForTarget(target);
-
- if (!scratch_ts_sp)
- return LLDB_INVALID_ADDRESS;
-
- CompilerType clang_void_ptr_type =
- scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
- Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
- if (pthread_getspecific_addr.IsValid()) {
- EvaluateExpressionOptions options;
-
- lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
- *thread_sp, pthread_getspecific_addr, clang_void_ptr_type,
- llvm::ArrayRef<lldb::addr_t>(pthread_key), options));
-
- DiagnosticManager execution_errors;
- ExecutionContext exe_ctx(thread_sp);
- lldb::ExpressionResults results = m_process->RunThreadPlan(
- exe_ctx, thread_plan_sp, options, execution_errors);
-
- if (results == lldb::eExpressionCompleted) {
- lldb::ValueObjectSP result_valobj_sp =
- thread_plan_sp->GetReturnValueObject();
- if (result_valobj_sp) {
- const lldb::addr_t pthread_key_data =
- result_valobj_sp->GetValueAsUnsigned(0);
- if (pthread_key_data) {
- m_tid_to_tls_map[tid].insert(
- std::make_pair(pthread_key, pthread_key_data));
- return pthread_key_data + tls_offset;
- }
- }
- }
+ DataExtractor data(buf, sizeof(buf), m_process->GetByteOrder(), addr_size);
+ lldb::offset_t offset = addr_size; // Skip the first pointer
+ const lldb::addr_t pthread_key = data.GetAddress(&offset);
+ const lldb::addr_t tls_offset = data.GetAddress(&offset);
+ if (pthread_key != 0) {
+ // First check to see if we have already figured out the location of
+ // TLS data for the pthread_key on a specific thread yet. If we have we
+ // can re-use it since its location will not change unless the process
+ // execs.
+ const tid_t tid = thread_sp->GetID();
+ auto tid_pos = m_tid_to_tls_map.find(tid);
+ if (tid_pos != m_tid_to_tls_map.end()) {
+ auto tls_pos = tid_pos->second.find(pthread_key);
+ if (tls_pos != tid_pos->second.end()) {
+ return tls_pos->second + tls_offset;
+ }
+ }
+ TypeSystemClangSP scratch_ts_sp =
+ ScratchTypeSystemClang::GetForTarget(target);
+
+ if (!scratch_ts_sp)
+ return LLDB_INVALID_ADDRESS;
+
+ CompilerType clang_void_ptr_type =
+ scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
+ Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
+ if (pthread_getspecific_addr.IsValid()) {
+ EvaluateExpressionOptions options;
+
+ lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
+ *thread_sp, pthread_getspecific_addr, clang_void_ptr_type,
+ llvm::ArrayRef<lldb::addr_t>(pthread_key), options));
+
+ DiagnosticManager execution_errors;
+ ExecutionContext exe_ctx(thread_sp);
+ lldb::ExpressionResults results = m_process->RunThreadPlan(
+ exe_ctx, thread_plan_sp, options, execution_errors);
+
+ if (results == lldb::eExpressionCompleted) {
+ lldb::ValueObjectSP result_valobj_sp =
+ thread_plan_sp->GetReturnValueObject();
+ if (result_valobj_sp) {
+ const lldb::addr_t pthread_key_data =
+ result_valobj_sp->GetValueAsUnsigned(0);
+ if (pthread_key_data) {
+ m_tid_to_tls_map[tid].insert(
+ std::make_pair(pthread_key, pthread_key_data));
+ return pthread_key_data + tls_offset;
}
}
}
>From 8260d97784d605c8bb75e84614e200cccf451beb Mon Sep 17 00:00:00 2001
From: Alex Langford <alangford at apple.com>
Date: Fri, 12 Jan 2024 13:17:36 -0800
Subject: [PATCH 2/5] [lldb] Generalize DynamicLoaderDarwin::GetThreadLocalData
I am working on adding support for a more modern method of getting TLS
data on apple platforms. It also involves calling a function in the
inferior, so I'm generalizing the pthread implementation.
---
.../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 69 ++++++++++---------
1 file changed, 36 insertions(+), 33 deletions(-)
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index 2deb7663b42e029..44c580857c65beb 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -1052,11 +1052,41 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
if (!module_sp->ResolveFileAddress(tls_file_addr, tls_addr))
return LLDB_INVALID_ADDRESS;
+ Target &target = m_process->GetTarget();
+ TypeSystemClangSP scratch_ts_sp =
+ ScratchTypeSystemClang::GetForTarget(target);
+ if (!scratch_ts_sp)
+ return LLDB_INVALID_ADDRESS;
+
+ CompilerType clang_void_ptr_type =
+ scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
+
+ auto evaluate_tls_address = [this, &thread_sp, &clang_void_ptr_type](
+ Address func_ptr,
+ llvm::ArrayRef<addr_t> args) -> lldb::addr_t {
+ EvaluateExpressionOptions options;
+
+ lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
+ *thread_sp, func_ptr, clang_void_ptr_type, args, options));
+
+ DiagnosticManager execution_errors;
+ ExecutionContext exe_ctx(thread_sp);
+ lldb::ExpressionResults results = m_process->RunThreadPlan(
+ exe_ctx, thread_plan_sp, options, execution_errors);
+
+ if (results == lldb::eExpressionCompleted) {
+ if (lldb::ValueObjectSP result_valobj_sp =
+ thread_plan_sp->GetReturnValueObject()) {
+ return result_valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+ };
+
const uint32_t addr_size = m_process->GetAddressByteSize();
uint8_t buf[sizeof(lldb::addr_t) * 3];
Status error;
const size_t tls_data_size = addr_size * 3;
- Target &target = m_process->GetTarget();
const size_t bytes_read = target.ReadMemory(
tls_addr, buf, tls_data_size, error, /*force_live_memory = */ true);
if (bytes_read != tls_data_size || error.Fail())
@@ -1066,6 +1096,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
lldb::offset_t offset = addr_size; // Skip the first pointer
const lldb::addr_t pthread_key = data.GetAddress(&offset);
const lldb::addr_t tls_offset = data.GetAddress(&offset);
+
if (pthread_key != 0) {
// First check to see if we have already figured out the location of
// TLS data for the pthread_key on a specific thread yet. If we have we
@@ -1079,40 +1110,12 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
return tls_pos->second + tls_offset;
}
}
- TypeSystemClangSP scratch_ts_sp =
- ScratchTypeSystemClang::GetForTarget(target);
-
- if (!scratch_ts_sp)
- return LLDB_INVALID_ADDRESS;
-
- CompilerType clang_void_ptr_type =
- scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
if (pthread_getspecific_addr.IsValid()) {
- EvaluateExpressionOptions options;
-
- lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
- *thread_sp, pthread_getspecific_addr, clang_void_ptr_type,
- llvm::ArrayRef<lldb::addr_t>(pthread_key), options));
-
- DiagnosticManager execution_errors;
- ExecutionContext exe_ctx(thread_sp);
- lldb::ExpressionResults results = m_process->RunThreadPlan(
- exe_ctx, thread_plan_sp, options, execution_errors);
-
- if (results == lldb::eExpressionCompleted) {
- lldb::ValueObjectSP result_valobj_sp =
- thread_plan_sp->GetReturnValueObject();
- if (result_valobj_sp) {
- const lldb::addr_t pthread_key_data =
- result_valobj_sp->GetValueAsUnsigned(0);
- if (pthread_key_data) {
- m_tid_to_tls_map[tid].insert(
- std::make_pair(pthread_key, pthread_key_data));
- return pthread_key_data + tls_offset;
- }
- }
- }
+ const lldb::addr_t tls_data = evaluate_tls_address(
+ pthread_getspecific_addr, llvm::ArrayRef<lldb::addr_t>(pthread_key));
+ if (tls_data != LLDB_INVALID_ADDRESS)
+ return tls_data + tls_offset;
}
}
return LLDB_INVALID_ADDRESS;
>From 1fa6e69735c8a0980d0d917f157a14095cd162d0 Mon Sep 17 00:00:00 2001
From: Alex Langford <alangford at apple.com>
Date: Fri, 12 Jan 2024 13:32:24 -0800
Subject: [PATCH 3/5] [lldb] Add support for changes to TLS on macOS
The TLS implementation on apple platforms has changed. Instead of
invoking pthread_getspecific with a pthread_key_t, we instead perform a
virtual function call.
Note: Some versions of Apple's new linker do not emit debug symbols for
TLS symbols. This causes the TLS tests to fail because LLDB and dsymutil
expects there to be debug symbols to resolve the relevant TLS block. You
may work around this by switchint to the older linker (ld-classic_ or by
disabling the TLS tests until you have a newer version of the new
linker.
---
.../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 38 ++++++++++++++++---
1 file changed, 33 insertions(+), 5 deletions(-)
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index 44c580857c65beb..3bfa3778ad8f9c9 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -1083,6 +1083,22 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
return LLDB_INVALID_ADDRESS;
};
+ // On modern apple platforms, there is a small data structure that looks
+ // approximately like this:
+ // struct TLS_Thunk {
+ // void *(*get_addr)(struct TLS_Thunk *);
+ // size_t key;
+ // size_t offset;
+ // }
+ //
+ // The strategy is to take get_addr, call it with the address of the
+ // containing TLS_Thunk structure, and add the offset to the resulting
+ // pointer to get the data block.
+ //
+ // On older apple platforms, the key is treated as a pthread_key_t and passed
+ // to pthread_getspecific. The pointer returned from that call is added to
+ // offset to get the relevant data block.
+
const uint32_t addr_size = m_process->GetAddressByteSize();
uint8_t buf[sizeof(lldb::addr_t) * 3];
Status error;
@@ -1093,11 +1109,23 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
return LLDB_INVALID_ADDRESS;
DataExtractor data(buf, sizeof(buf), m_process->GetByteOrder(), addr_size);
- lldb::offset_t offset = addr_size; // Skip the first pointer
- const lldb::addr_t pthread_key = data.GetAddress(&offset);
+ lldb::offset_t offset = 0;
+ const lldb::addr_t tls_thunk = data.GetAddress(&offset);
+ const lldb::addr_t key = data.GetAddress(&offset);
const lldb::addr_t tls_offset = data.GetAddress(&offset);
- if (pthread_key != 0) {
+ if (tls_thunk != 0) {
+ Address thunk_load_addr;
+ if (target.ResolveLoadAddress(tls_thunk, thunk_load_addr)) {
+ const lldb::addr_t tls_load_addr = tls_addr.GetLoadAddress(&target);
+ const lldb::addr_t tls_data = evaluate_tls_address(
+ thunk_load_addr, llvm::ArrayRef<lldb::addr_t>(tls_load_addr));
+ if (tls_data != LLDB_INVALID_ADDRESS)
+ return tls_data + tls_offset;
+ }
+ }
+
+ if (key != 0) {
// First check to see if we have already figured out the location of
// TLS data for the pthread_key on a specific thread yet. If we have we
// can re-use it since its location will not change unless the process
@@ -1105,7 +1133,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
const tid_t tid = thread_sp->GetID();
auto tid_pos = m_tid_to_tls_map.find(tid);
if (tid_pos != m_tid_to_tls_map.end()) {
- auto tls_pos = tid_pos->second.find(pthread_key);
+ auto tls_pos = tid_pos->second.find(key);
if (tls_pos != tid_pos->second.end()) {
return tls_pos->second + tls_offset;
}
@@ -1113,7 +1141,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
if (pthread_getspecific_addr.IsValid()) {
const lldb::addr_t tls_data = evaluate_tls_address(
- pthread_getspecific_addr, llvm::ArrayRef<lldb::addr_t>(pthread_key));
+ pthread_getspecific_addr, llvm::ArrayRef<lldb::addr_t>(key));
if (tls_data != LLDB_INVALID_ADDRESS)
return tls_data + tls_offset;
}
>From 95c3ec2087f79d4207149a21d3749357b3e14467 Mon Sep 17 00:00:00 2001
From: Alex Langford <alangford at apple.com>
Date: Wed, 17 Jan 2024 11:06:39 -0800
Subject: [PATCH 4/5] fixup! [lldb] Add support for changes to TLS on macOS
---
.../Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index 3bfa3778ad8f9c9..abae96380092027 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -1115,8 +1115,9 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
const lldb::addr_t tls_offset = data.GetAddress(&offset);
if (tls_thunk != 0) {
+ const lldb::addr_t fixed_tls_thunk = m_process->FixCodeAddress(tls_thunk);
Address thunk_load_addr;
- if (target.ResolveLoadAddress(tls_thunk, thunk_load_addr)) {
+ if (target.ResolveLoadAddress(fixed_tls_thunk, thunk_load_addr)) {
const lldb::addr_t tls_load_addr = tls_addr.GetLoadAddress(&target);
const lldb::addr_t tls_data = evaluate_tls_address(
thunk_load_addr, llvm::ArrayRef<lldb::addr_t>(tls_load_addr));
>From cef8673c1d20203d5072571b898f1ef738b14fb4 Mon Sep 17 00:00:00 2001
From: Alex Langford <alangford at apple.com>
Date: Wed, 17 Jan 2024 11:09:10 -0800
Subject: [PATCH 5/5] [lldb] Remove lldb:: from addr_t in modified code
---
.../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index abae96380092027..6f0eff5472e0850 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -1063,7 +1063,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
auto evaluate_tls_address = [this, &thread_sp, &clang_void_ptr_type](
Address func_ptr,
- llvm::ArrayRef<addr_t> args) -> lldb::addr_t {
+ llvm::ArrayRef<addr_t> args) -> addr_t {
EvaluateExpressionOptions options;
lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
@@ -1100,7 +1100,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
// offset to get the relevant data block.
const uint32_t addr_size = m_process->GetAddressByteSize();
- uint8_t buf[sizeof(lldb::addr_t) * 3];
+ uint8_t buf[sizeof(addr_t) * 3];
Status error;
const size_t tls_data_size = addr_size * 3;
const size_t bytes_read = target.ReadMemory(
@@ -1110,17 +1110,17 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
DataExtractor data(buf, sizeof(buf), m_process->GetByteOrder(), addr_size);
lldb::offset_t offset = 0;
- const lldb::addr_t tls_thunk = data.GetAddress(&offset);
- const lldb::addr_t key = data.GetAddress(&offset);
- const lldb::addr_t tls_offset = data.GetAddress(&offset);
+ const addr_t tls_thunk = data.GetAddress(&offset);
+ const addr_t key = data.GetAddress(&offset);
+ const addr_t tls_offset = data.GetAddress(&offset);
if (tls_thunk != 0) {
- const lldb::addr_t fixed_tls_thunk = m_process->FixCodeAddress(tls_thunk);
+ const addr_t fixed_tls_thunk = m_process->FixCodeAddress(tls_thunk);
Address thunk_load_addr;
if (target.ResolveLoadAddress(fixed_tls_thunk, thunk_load_addr)) {
- const lldb::addr_t tls_load_addr = tls_addr.GetLoadAddress(&target);
- const lldb::addr_t tls_data = evaluate_tls_address(
- thunk_load_addr, llvm::ArrayRef<lldb::addr_t>(tls_load_addr));
+ const addr_t tls_load_addr = tls_addr.GetLoadAddress(&target);
+ const addr_t tls_data = evaluate_tls_address(
+ thunk_load_addr, llvm::ArrayRef<addr_t>(tls_load_addr));
if (tls_data != LLDB_INVALID_ADDRESS)
return tls_data + tls_offset;
}
@@ -1141,8 +1141,8 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
}
Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
if (pthread_getspecific_addr.IsValid()) {
- const lldb::addr_t tls_data = evaluate_tls_address(
- pthread_getspecific_addr, llvm::ArrayRef<lldb::addr_t>(key));
+ const addr_t tls_data = evaluate_tls_address(
+ pthread_getspecific_addr, llvm::ArrayRef<addr_t>(key));
if (tls_data != LLDB_INVALID_ADDRESS)
return tls_data + tls_offset;
}
More information about the lldb-commits
mailing list