Skip to content

Commit dbcc942

Browse files
authored
Merge pull request #7988 from bulbazord/20230725-darwin-tls
[lldb] Support changes to TLS on macOS (llvm#77988)
2 parents db47c9b + c0776cc commit dbcc942

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
@@ -1048,74 +1048,104 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp,
10481048

10491049
std::lock_guard<std::recursive_mutex> guard(m_mutex);
10501050

1051+
lldb_private::Address tls_addr;
1052+
if (!module_sp->ResolveFileAddress(tls_file_addr, tls_addr))
1053+
return LLDB_INVALID_ADDRESS;
1054+
1055+
Target &target = m_process->GetTarget();
1056+
TypeSystemClangSP scratch_ts_sp =
1057+
ScratchTypeSystemClang::GetForTarget(target);
1058+
if (!scratch_ts_sp)
1059+
return LLDB_INVALID_ADDRESS;
1060+
1061+
CompilerType clang_void_ptr_type =
1062+
scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
1063+
1064+
auto evaluate_tls_address = [this, &thread_sp, &clang_void_ptr_type](
1065+
Address func_ptr,
1066+
llvm::ArrayRef<addr_t> args) -> addr_t {
1067+
EvaluateExpressionOptions options;
1068+
1069+
lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
1070+
*thread_sp, func_ptr, clang_void_ptr_type, args, options));
1071+
1072+
DiagnosticManager execution_errors;
1073+
ExecutionContext exe_ctx(thread_sp);
1074+
lldb::ExpressionResults results = m_process->RunThreadPlan(
1075+
exe_ctx, thread_plan_sp, options, execution_errors);
1076+
1077+
if (results == lldb::eExpressionCompleted) {
1078+
if (lldb::ValueObjectSP result_valobj_sp =
1079+
thread_plan_sp->GetReturnValueObject()) {
1080+
return result_valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1081+
}
1082+
}
1083+
return LLDB_INVALID_ADDRESS;
1084+
};
1085+
1086+
// On modern apple platforms, there is a small data structure that looks
1087+
// approximately like this:
1088+
// struct TLS_Thunk {
1089+
// void *(*get_addr)(struct TLS_Thunk *);
1090+
// size_t key;
1091+
// size_t offset;
1092+
// }
1093+
//
1094+
// The strategy is to take get_addr, call it with the address of the
1095+
// containing TLS_Thunk structure, and add the offset to the resulting
1096+
// pointer to get the data block.
1097+
//
1098+
// On older apple platforms, the key is treated as a pthread_key_t and passed
1099+
// to pthread_getspecific. The pointer returned from that call is added to
1100+
// offset to get the relevant data block.
1101+
10511102
const uint32_t addr_size = m_process->GetAddressByteSize();
1052-
uint8_t buf[sizeof(lldb::addr_t) * 3];
1103+
uint8_t buf[sizeof(addr_t) * 3];
1104+
Status error;
1105+
const size_t tls_data_size = addr_size * 3;
1106+
const size_t bytes_read = target.ReadMemory(
1107+
tls_addr, buf, tls_data_size, error, /*force_live_memory = */ true);
1108+
if (bytes_read != tls_data_size || error.Fail())
1109+
return LLDB_INVALID_ADDRESS;
10531110

1054-
lldb_private::Address tls_addr;
1055-
if (module_sp->ResolveFileAddress(tls_file_addr, tls_addr)) {
1056-
Status error;
1057-
const size_t tsl_data_size = addr_size * 3;
1058-
Target &target = m_process->GetTarget();
1059-
if (target.ReadMemory(tls_addr, buf, tsl_data_size, error, true) ==
1060-
tsl_data_size) {
1061-
const ByteOrder byte_order = m_process->GetByteOrder();
1062-
DataExtractor data(buf, sizeof(buf), byte_order, addr_size);
1063-
lldb::offset_t offset = addr_size; // Skip the first pointer
1064-
const lldb::addr_t pthread_key = data.GetAddress(&offset);
1065-
const lldb::addr_t tls_offset = data.GetAddress(&offset);
1066-
if (pthread_key != 0) {
1067-
// First check to see if we have already figured out the location of
1068-
// TLS data for the pthread_key on a specific thread yet. If we have we
1069-
// can re-use it since its location will not change unless the process
1070-
// execs.
1071-
const tid_t tid = thread_sp->GetID();
1072-
auto tid_pos = m_tid_to_tls_map.find(tid);
1073-
if (tid_pos != m_tid_to_tls_map.end()) {
1074-
auto tls_pos = tid_pos->second.find(pthread_key);
1075-
if (tls_pos != tid_pos->second.end()) {
1076-
return tls_pos->second + tls_offset;
1077-
}
1078-
}
1079-
StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0);
1080-
if (frame_sp) {
1081-
TypeSystemClangSP scratch_ts_sp =
1082-
ScratchTypeSystemClang::GetForTarget(target);
1083-
1084-
if (!scratch_ts_sp)
1085-
return LLDB_INVALID_ADDRESS;
1086-
1087-
CompilerType clang_void_ptr_type =
1088-
scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
1089-
Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
1090-
if (pthread_getspecific_addr.IsValid()) {
1091-
EvaluateExpressionOptions options;
1092-
1093-
lldb::ThreadPlanSP thread_plan_sp(new ThreadPlanCallFunction(
1094-
*thread_sp, pthread_getspecific_addr, clang_void_ptr_type,
1095-
llvm::ArrayRef<lldb::addr_t>(pthread_key), options));
1096-
1097-
DiagnosticManager execution_errors;
1098-
ExecutionContext exe_ctx(thread_sp);
1099-
lldb::ExpressionResults results = m_process->RunThreadPlan(
1100-
exe_ctx, thread_plan_sp, options, execution_errors);
1101-
1102-
if (results == lldb::eExpressionCompleted) {
1103-
lldb::ValueObjectSP result_valobj_sp =
1104-
thread_plan_sp->GetReturnValueObject();
1105-
if (result_valobj_sp) {
1106-
const lldb::addr_t pthread_key_data =
1107-
result_valobj_sp->GetValueAsUnsigned(0);
1108-
if (pthread_key_data) {
1109-
m_tid_to_tls_map[tid].insert(
1110-
std::make_pair(pthread_key, pthread_key_data));
1111-
return pthread_key_data + tls_offset;
1112-
}
1113-
}
1114-
}
1115-
}
1116-
}
1111+
DataExtractor data(buf, sizeof(buf), m_process->GetByteOrder(), addr_size);
1112+
lldb::offset_t offset = 0;
1113+
const addr_t tls_thunk = data.GetAddress(&offset);
1114+
const addr_t key = data.GetAddress(&offset);
1115+
const addr_t tls_offset = data.GetAddress(&offset);
1116+
1117+
if (tls_thunk != 0) {
1118+
const addr_t fixed_tls_thunk = m_process->FixCodeAddress(tls_thunk);
1119+
Address thunk_load_addr;
1120+
if (target.ResolveLoadAddress(fixed_tls_thunk, thunk_load_addr)) {
1121+
const addr_t tls_load_addr = tls_addr.GetLoadAddress(&target);
1122+
const addr_t tls_data = evaluate_tls_address(
1123+
thunk_load_addr, llvm::ArrayRef<addr_t>(tls_load_addr));
1124+
if (tls_data != LLDB_INVALID_ADDRESS)
1125+
return tls_data + tls_offset;
1126+
}
1127+
}
1128+
1129+
if (key != 0) {
1130+
// First check to see if we have already figured out the location of
1131+
// TLS data for the pthread_key on a specific thread yet. If we have we
1132+
// can re-use it since its location will not change unless the process
1133+
// execs.
1134+
const tid_t tid = thread_sp->GetID();
1135+
auto tid_pos = m_tid_to_tls_map.find(tid);
1136+
if (tid_pos != m_tid_to_tls_map.end()) {
1137+
auto tls_pos = tid_pos->second.find(key);
1138+
if (tls_pos != tid_pos->second.end()) {
1139+
return tls_pos->second + tls_offset;
11171140
}
11181141
}
1142+
Address pthread_getspecific_addr = GetPthreadSetSpecificAddress();
1143+
if (pthread_getspecific_addr.IsValid()) {
1144+
const addr_t tls_data = evaluate_tls_address(pthread_getspecific_addr,
1145+
llvm::ArrayRef<addr_t>(key));
1146+
if (tls_data != LLDB_INVALID_ADDRESS)
1147+
return tls_data + tls_offset;
1148+
}
11191149
}
11201150
return LLDB_INVALID_ADDRESS;
11211151
}

0 commit comments

Comments
 (0)