[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