Skip to content

Commit 29b8f0b

Browse files
bulbazordjasonmolenda
authored andcommitted
[lldb] Support changes to TLS on macOS (llvm#77988)
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 switching to the older linker (ld-classic) or by disabling the TLS tests until you have a newer version of the new linker. rdar://120676969 (cherry picked from commit a451c3b) (cherry picked from commit c0776cc)
1 parent 5286130 commit 29b8f0b

File tree

1 file changed

+94
-64
lines changed

1 file changed

+94
-64
lines changed

lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp

Lines changed: 94 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,74 +1076,104 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
10761076

10771077
std::lock_guard<std::recursive_mutex> guard(m_mutex);
10781078

1079+
lldb_private::Address tls_addr;
1080+
if (!module_sp->ResolveFileAddress(tls_file_addr, tls_addr))
1081+
return LLDB_INVALID_ADDRESS;
1082+
1083+
Target &target = m_process->GetTarget();
1084+
TypeSystemClangSP scratch_ts_sp =
1085+
ScratchTypeSystemClang::GetForTarget(target);
1086+
if (!scratch_ts_sp)
1087+
return LLDB_INVALID_ADDRESS;
1088+
1089+
CompilerType clang_void_ptr_type =
1090+
scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
1091+
1092+
auto evaluate_tls_address = [this, &thread_sp, &clang_void_ptr_type](
1093+
Address func_ptr,
1094+
llvm::ArrayRef<addr_t> args) -> addr_t {
1095+
EvaluateExpressionOptions options;
1096+
1097+
lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
1098+
*thread_sp, func_ptr, clang_void_ptr_type, args, options));
1099+
1100+
DiagnosticManager execution_errors;
1101+
ExecutionContext exe_ctx(thread_sp);
1102+
lldb::ExpressionResults results = m_process->RunThreadPlan(
1103+
exe_ctx, thread_plan_sp, options, execution_errors);
1104+
1105+
if (results == lldb::eExpressionCompleted) {
1106+
if (lldb::ValueObjectSP result_valobj_sp =
1107+
thread_plan_sp->GetReturnValueObject()) {
1108+
return result_valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1109+
}
1110+
}
1111+
return LLDB_INVALID_ADDRESS;
1112+
};
1113+
1114+
// On modern apple platforms, there is a small data structure that looks
1115+
// approximately like this:
1116+
// struct TLS_Thunk {
1117+
// void *(*get_addr)(struct TLS_Thunk *);
1118+
// size_t key;
1119+
// size_t offset;
1120+
// }
1121+
//
1122+
// The strategy is to take get_addr, call it with the address of the
1123+
// containing TLS_Thunk structure, and add the offset to the resulting
1124+
// pointer to get the data block.
1125+
//
1126+
// On older apple platforms, the key is treated as a pthread_key_t and passed
1127+
// to pthread_getspecific. The pointer returned from that call is added to
1128+
// offset to get the relevant data block.
1129+
10791130
const uint32_t addr_size = m_process->GetAddressByteSize();
1080-
uint8_t buf[sizeof(lldb::addr_t) * 3];
1131+
uint8_t buf[sizeof(addr_t) * 3];
1132+
Status error;
1133+
const size_t tls_data_size = addr_size * 3;
1134+
const size_t bytes_read = target.ReadMemory(
1135+
tls_addr, buf, tls_data_size, error, /*force_live_memory = */ true);
1136+
if (bytes_read != tls_data_size || error.Fail())
1137+
return LLDB_INVALID_ADDRESS;
10811138

1082-
lldb_private::Address tls_addr;
1083-
if (module_sp->ResolveFileAddress(tls_file_addr, tls_addr)) {
1084-
Status error;
1085-
const size_t tsl_data_size = addr_size * 3;
1086-
Target &target = m_process->GetTarget();
1087-
if (target.ReadMemory(tls_addr, buf, tsl_data_size, error, true) ==
1088-
tsl_data_size) {
1089-
const ByteOrder byte_order = m_process->GetByteOrder();
1090-
DataExtractor data(buf, sizeof(buf), byte_order, addr_size);
1091-
lldb::offset_t offset = addr_size; // Skip the first pointer
1092-
const lldb::addr_t pthread_key = data.GetAddress(&offset);
1093-
const lldb::addr_t tls_offset = data.GetAddress(&offset);
1094-
if (pthread_key != 0) {
1095-
// First check to see if we have already figured out the location of
1096-
// TLS data for the pthread_key on a specific thread yet. If we have we
1097-
// can re-use it since its location will not change unless the process
1098-
// execs.
1099-
const tid_t tid = thread_sp->GetID();
1100-
auto tid_pos = m_tid_to_tls_map.find(tid);
1101-
if (tid_pos != m_tid_to_tls_map.end()) {
1102-
auto tls_pos = tid_pos->second.find(pthread_key);
1103-
if (tls_pos != tid_pos->second.end()) {
1104-
return tls_pos->second + tls_offset;
1105-
}
1106-
}
1107-
StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0);
1108-
if (frame_sp) {
1109-
TypeSystemClangSP scratch_ts_sp =
1110-
ScratchTypeSystemClang::GetForTarget(target);
1111-
1112-
if (!scratch_ts_sp)
1113-
return LLDB_INVALID_ADDRESS;
1114-
1115-
CompilerType clang_void_ptr_type =
1116-
scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
1117-
Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
1118-
if (pthread_getspecific_addr.IsValid()) {
1119-
EvaluateExpressionOptions options;
1120-
1121-
lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
1122-
*thread_sp, pthread_getspecific_addr, clang_void_ptr_type,
1123-
llvm::ArrayRef<lldb::addr_t>(pthread_key), options));
1124-
1125-
DiagnosticManager execution_errors;
1126-
ExecutionContext exe_ctx(thread_sp);
1127-
lldb::ExpressionResults results = m_process->RunThreadPlan(
1128-
exe_ctx, thread_plan_sp, options, execution_errors);
1129-
1130-
if (results == lldb::eExpressionCompleted) {
1131-
lldb::ValueObjectSP result_valobj_sp =
1132-
thread_plan_sp->GetReturnValueObject();
1133-
if (result_valobj_sp) {
1134-
const lldb::addr_t pthread_key_data =
1135-
result_valobj_sp->GetValueAsUnsigned(0);
1136-
if (pthread_key_data) {
1137-
m_tid_to_tls_map[tid].insert(
1138-
std::make_pair(pthread_key, pthread_key_data));
1139-
return pthread_key_data + tls_offset;
1140-
}
1141-
}
1142-
}
1143-
}
1144-
}
1139+
DataExtractor data(buf, sizeof(buf), m_process->GetByteOrder(), addr_size);
1140+
lldb::offset_t offset = 0;
1141+
const addr_t tls_thunk = data.GetAddress(&offset);
1142+
const addr_t key = data.GetAddress(&offset);
1143+
const addr_t tls_offset = data.GetAddress(&offset);
1144+
1145+
if (tls_thunk != 0) {
1146+
const addr_t fixed_tls_thunk = m_process->FixCodeAddress(tls_thunk);
1147+
Address thunk_load_addr;
1148+
if (target.ResolveLoadAddress(fixed_tls_thunk, thunk_load_addr)) {
1149+
const addr_t tls_load_addr = tls_addr.GetLoadAddress(&target);
1150+
const addr_t tls_data = evaluate_tls_address(
1151+
thunk_load_addr, llvm::ArrayRef<addr_t>(tls_load_addr));
1152+
if (tls_data != LLDB_INVALID_ADDRESS)
1153+
return tls_data + tls_offset;
1154+
}
1155+
}
1156+
1157+
if (key != 0) {
1158+
// First check to see if we have already figured out the location of
1159+
// TLS data for the pthread_key on a specific thread yet. If we have we
1160+
// can re-use it since its location will not change unless the process
1161+
// execs.
1162+
const tid_t tid = thread_sp->GetID();
1163+
auto tid_pos = m_tid_to_tls_map.find(tid);
1164+
if (tid_pos != m_tid_to_tls_map.end()) {
1165+
auto tls_pos = tid_pos->second.find(key);
1166+
if (tls_pos != tid_pos->second.end()) {
1167+
return tls_pos->second + tls_offset;
11451168
}
11461169
}
1170+
Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
1171+
if (pthread_getspecific_addr.IsValid()) {
1172+
const addr_t tls_data = evaluate_tls_address(pthread_getspecific_addr,
1173+
llvm::ArrayRef<addr_t>(key));
1174+
if (tls_data != LLDB_INVALID_ADDRESS)
1175+
return tls_data + tls_offset;
1176+
}
11471177
}
11481178
return LLDB_INVALID_ADDRESS;
11491179
}

0 commit comments

Comments
 (0)