[Lldb-commits] [lldb] [lldb] Support changes to TLS on macOS (PR #77988)
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Wed Jan 17 11:05:59 PST 2024
================
@@ -1048,74 +1048,103 @@ 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;
+
+ 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;
+ };
+
+ // 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;
+ const size_t tls_data_size = addr_size * 3;
+ 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 = 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 (tls_thunk != 0) {
+ Address thunk_load_addr;
+ if (target.ResolveLoadAddress(tls_thunk, thunk_load_addr)) {
----------------
jasonmolenda wrote:
Ah sorry I missed that it was used in the ThreadPlanCallFunction. I saw `addr_t tls_load_addr = tls_addr.GetLoadAddress()` which is just getting the load address out of the Address object and didn't see we were still using hte Address object.
Minor nit, but I don't like to prefix `addr_t`s with the `lldb::` namespace, except in headers where it's required.
https://github.com/llvm/llvm-project/pull/77988
More information about the lldb-commits
mailing list