Skip to content

Commit c73b8d9

Browse files
jasonmolendamedismailben
authored andcommitted
Track transition from launch dyld to shared-cache dyld
On macOS, a process will be launched with /usr/lib/dyld (the dynamic linker) and the main binary by the kernel. The first thing the standalone dyld will do is call into the dyld in the shared cache image. This patch tracks the transition between the dyld's at the very beginning of process startup. In DynamicLoaderMacOS::NotifyBreakpointHit() there are two new cases handled: `dyld_image_dyld_moved` which is the launch /usr/lib/dyld indicating that it is about call into the shared cache dyld ane evict itself. lldb will remove the notification breakpoint it set, clear the binary image list entirely, get the notification function pointer value out of the dyld_all_image_infos struct (which is the notification fptr in the to-be-run shared-cache dyld) and put an address breakpoint there. `dyld_notify_adding` is then called by shared-cache dyld, and we detect this case by noticing that we have an empty binary image list, normally impossibe, and treating this as if we'd just started a process attach/launch. Differential Revision: https://reviews.llvm.org/D127247 rdar://84222158
1 parent fc0ab39 commit c73b8d9

File tree

4 files changed

+75
-2
lines changed

4 files changed

+75
-2
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,8 @@ ModuleSP DynamicLoaderDarwin::GetDYLDModule() {
611611
return dyld_sp;
612612
}
613613

614+
void DynamicLoaderDarwin::ClearDYLDModule() { m_dyld_module_wp.reset(); }
615+
614616
bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
615617
ImageInfo::collection &image_infos) {
616618
std::lock_guard<std::recursive_mutex> guard(m_mutex);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
7171

7272
lldb::ModuleSP GetDYLDModule();
7373

74+
void ClearDYLDModule();
75+
7476
class Segment {
7577
public:
7678
Segment() : name() {}

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

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "lldb/Symbol/ObjectFile.h"
1515
#include "lldb/Symbol/SymbolVendor.h"
1616
#include "lldb/Target/ABI.h"
17+
#include "lldb/Target/SectionLoadList.h"
1718
#include "lldb/Target/StackFrame.h"
1819
#include "lldb/Target/Target.h"
1920
#include "lldb/Target/Thread.h"
@@ -76,13 +77,16 @@ DynamicLoader *DynamicLoaderMacOS::CreateInstance(Process *process,
7677
// Constructor
7778
DynamicLoaderMacOS::DynamicLoaderMacOS(Process *process)
7879
: DynamicLoaderDarwin(process), m_image_infos_stop_id(UINT32_MAX),
79-
m_break_id(LLDB_INVALID_BREAK_ID), m_mutex(),
80+
m_break_id(LLDB_INVALID_BREAK_ID),
81+
m_dyld_handover_break_id(LLDB_INVALID_BREAK_ID), m_mutex(),
8082
m_maybe_image_infos_address(LLDB_INVALID_ADDRESS) {}
8183

8284
// Destructor
8385
DynamicLoaderMacOS::~DynamicLoaderMacOS() {
8486
if (LLDB_BREAK_ID_IS_VALID(m_break_id))
8587
m_process->GetTarget().RemoveBreakpointByID(m_break_id);
88+
if (LLDB_BREAK_ID_IS_VALID(m_dyld_handover_break_id))
89+
m_process->GetTarget().RemoveBreakpointByID(m_dyld_handover_break_id);
8690
}
8791

8892
bool DynamicLoaderMacOS::ProcessDidExec() {
@@ -135,8 +139,11 @@ void DynamicLoaderMacOS::DoClear() {
135139

136140
if (LLDB_BREAK_ID_IS_VALID(m_break_id))
137141
m_process->GetTarget().RemoveBreakpointByID(m_break_id);
142+
if (LLDB_BREAK_ID_IS_VALID(m_dyld_handover_break_id))
143+
m_process->GetTarget().RemoveBreakpointByID(m_dyld_handover_break_id);
138144

139145
m_break_id = LLDB_INVALID_BREAK_ID;
146+
m_dyld_handover_break_id = LLDB_INVALID_BREAK_ID;
140147
}
141148

142149
// Check if we have found DYLD yet
@@ -286,13 +293,50 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
286293
}
287294
if (dyld_mode == 0) {
288295
// dyld_notify_adding
289-
dyld_instance->AddBinaries(image_load_addresses);
296+
if (process->GetTarget().GetImages().GetSize() == 0) {
297+
// When all images have been removed, we're doing the
298+
// dyld handover from a launch-dyld to a shared-cache-dyld,
299+
// and we've just hit our one-shot address breakpoint in
300+
// the sc-dyld. Note that the image addresses passed to
301+
// this function are inferior sizeof(void*) not uint64_t's
302+
// like our normal notification, so don't even look at
303+
// image_load_addresses.
304+
305+
dyld_instance->ClearDYLDHandoverBreakpoint();
306+
307+
dyld_instance->DoInitialImageFetch();
308+
dyld_instance->SetNotificationBreakpoint();
309+
} else {
310+
dyld_instance->AddBinaries(image_load_addresses);
311+
}
290312
} else if (dyld_mode == 1) {
291313
// dyld_notify_removing
292314
dyld_instance->UnloadImages(image_load_addresses);
293315
} else if (dyld_mode == 2) {
294316
// dyld_notify_remove_all
295317
dyld_instance->UnloadAllImages();
318+
} else if (dyld_mode == 3 && image_infos_count == 1) {
319+
// dyld_image_dyld_moved
320+
321+
dyld_instance->ClearNotificationBreakpoint();
322+
dyld_instance->UnloadAllImages();
323+
dyld_instance->ClearDYLDModule();
324+
process->GetTarget().GetImages().Clear();
325+
process->GetTarget().GetSectionLoadList().Clear();
326+
327+
addr_t all_image_infos = process->GetImageInfoAddress();
328+
int addr_size =
329+
process->GetTarget().GetArchitecture().GetAddressByteSize();
330+
addr_t notification_location = all_image_infos + 4 + // version
331+
4 + // infoArrayCount
332+
addr_size; // infoArray
333+
Status error;
334+
addr_t notification_addr =
335+
process->ReadPointerFromMemory(notification_location, error);
336+
if (ABISP abi_sp = process->GetABI())
337+
notification_addr = abi_sp->FixCodeAddress(notification_addr);
338+
339+
dyld_instance->SetDYLDHandoverBreakpoint(notification_addr);
296340
}
297341
}
298342
}
@@ -371,6 +415,26 @@ bool DynamicLoaderMacOS::SetNotificationBreakpoint() {
371415
return m_break_id != LLDB_INVALID_BREAK_ID;
372416
}
373417

418+
bool DynamicLoaderMacOS::SetDYLDHandoverBreakpoint(
419+
addr_t notification_address) {
420+
if (m_dyld_handover_break_id == LLDB_INVALID_BREAK_ID) {
421+
BreakpointSP dyld_handover_bp = m_process->GetTarget().CreateBreakpoint(
422+
notification_address, true, false);
423+
dyld_handover_bp->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this,
424+
true);
425+
dyld_handover_bp->SetOneShot(true);
426+
m_dyld_handover_break_id = dyld_handover_bp->GetID();
427+
return true;
428+
}
429+
return false;
430+
}
431+
432+
void DynamicLoaderMacOS::ClearDYLDHandoverBreakpoint() {
433+
if (LLDB_BREAK_ID_IS_VALID(m_dyld_handover_break_id))
434+
m_process->GetTarget().RemoveBreakpointByID(m_dyld_handover_break_id);
435+
m_dyld_handover_break_id = LLDB_INVALID_BREAK_ID;
436+
}
437+
374438
addr_t
375439
DynamicLoaderMacOS::GetDyldLockVariableAddressFromModule(Module *module) {
376440
SymbolContext sc;

lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ class DynamicLoaderMacOS : public lldb_private::DynamicLoaderDarwin {
7171

7272
bool DidSetNotificationBreakpoint() override;
7373

74+
bool SetDYLDHandoverBreakpoint(lldb::addr_t notification_address);
75+
76+
void ClearDYLDHandoverBreakpoint();
77+
7478
void AddBinaries(const std::vector<lldb::addr_t> &load_addresses);
7579

7680
void DoClear() override;
@@ -94,6 +98,7 @@ class DynamicLoaderMacOS : public lldb_private::DynamicLoaderDarwin {
9498
uint32_t m_image_infos_stop_id; // The Stop ID the last time we
9599
// loaded/unloaded images
96100
lldb::user_id_t m_break_id;
101+
lldb::user_id_t m_dyld_handover_break_id;
97102
mutable std::recursive_mutex m_mutex;
98103
lldb::addr_t m_maybe_image_infos_address; // If dyld is still maintaining the
99104
// all_image_infos address, store it

0 commit comments

Comments
 (0)