@@ -233,12 +233,13 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
233
233
StoppointCallbackContext *context,
234
234
lldb::user_id_t break_id,
235
235
lldb::user_id_t break_loc_id) {
236
- // Let the event know that the images have changed
237
- // DYLD passes three arguments to the notification breakpoint.
238
- // Arg1: enum dyld_notify_mode mode - 0 = adding, 1 = removing, 2 = remove
239
- // all Arg2: unsigned long icount - Number of shared libraries
240
- // added/removed Arg3: uint64_t mach_headers[] - Array of load addresses
241
- // of binaries added/removed
236
+ //
237
+ // Our breakpoint on
238
+ //
239
+ // void lldb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount,
240
+ // const dyld_image_info info[])
241
+ //
242
+ // has been hit. We need to read the arguments.
242
243
243
244
DynamicLoaderMacOS *dyld_instance = (DynamicLoaderMacOS *)baton;
244
245
@@ -268,9 +269,10 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
268
269
ValueList argument_values;
269
270
270
271
Value mode_value; // enum dyld_notify_mode { dyld_notify_adding=0,
271
- // dyld_notify_removing=1, dyld_notify_remove_all=2 };
272
- Value count_value; // unsigned long count
273
- Value headers_value; // uint64_t machHeaders[] (aka void*)
272
+ // dyld_notify_removing=1, dyld_notify_remove_all=2,
273
+ // dyld_notify_dyld_moved=3 };
274
+ Value count_value; // uint32_t
275
+ Value headers_value; // struct dyld_image_info machHeaders[]
274
276
275
277
CompilerType clang_void_ptr_type =
276
278
scratch_ts_sp->GetBasicType (eBasicTypeVoid).GetPointerType ();
@@ -284,13 +286,8 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
284
286
mode_value.SetValueType (Value::ValueType::Scalar);
285
287
mode_value.SetCompilerType (clang_uint32_type);
286
288
287
- if (process->GetTarget ().GetArchitecture ().GetAddressByteSize () == 4 ) {
288
- count_value.SetValueType (Value::ValueType::Scalar);
289
- count_value.SetCompilerType (clang_uint32_type);
290
- } else {
291
- count_value.SetValueType (Value::ValueType::Scalar);
292
- count_value.SetCompilerType (clang_uint64_type);
293
- }
289
+ count_value.SetValueType (Value::ValueType::Scalar);
290
+ count_value.SetCompilerType (clang_uint32_type);
294
291
295
292
headers_value.SetValueType (Value::ValueType::Scalar);
296
293
headers_value.SetCompilerType (clang_void_ptr_type);
@@ -312,12 +309,30 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
312
309
argument_values.GetValueAtIndex (2 )->GetScalar ().ULongLong (-1 );
313
310
if (header_array != static_cast <uint64_t >(-1 )) {
314
311
std::vector<addr_t > image_load_addresses;
312
+ // header_array points to an array of image_infos_count elements,
313
+ // each is
314
+ // struct dyld_image_info {
315
+ // const struct mach_header* imageLoadAddress;
316
+ // const char* imageFilePath;
317
+ // uintptr_t imageFileModDate;
318
+ // };
319
+ //
320
+ // and we only need the imageLoadAddress fields.
321
+
322
+ const int addrsize =
323
+ process->GetTarget ().GetArchitecture ().GetAddressByteSize ();
315
324
for (uint64_t i = 0 ; i < image_infos_count; i++) {
316
325
Status error;
317
- addr_t addr = process->ReadUnsignedIntegerFromMemory (
318
- header_array + (8 * i), 8 , LLDB_INVALID_ADDRESS, error);
319
- if (addr != LLDB_INVALID_ADDRESS) {
326
+ addr_t dyld_image_info = header_array + (addrsize * 3 * i);
327
+ addr_t addr =
328
+ process->ReadPointerFromMemory (dyld_image_info, error);
329
+ if (error.Success ()) {
320
330
image_load_addresses.push_back (addr);
331
+ } else {
332
+ Debugger::ReportWarning (
333
+ " DynamicLoaderMacOS::NotifyBreakpointHit unable "
334
+ " to read binary mach-o load address at 0x%" PRIx64,
335
+ addr);
321
336
}
322
337
}
323
338
if (dyld_mode == 0 ) {
@@ -362,10 +377,16 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
362
377
Status error;
363
378
addr_t notification_addr =
364
379
process->ReadPointerFromMemory (notification_location, error);
365
- if (ABISP abi_sp = process->GetABI ())
366
- notification_addr = abi_sp->FixCodeAddress (notification_addr);
367
-
368
- dyld_instance->SetDYLDHandoverBreakpoint (notification_addr);
380
+ if (!error.Success ()) {
381
+ Debugger::ReportWarning (
382
+ " DynamicLoaderMacOS::NotifyBreakpointHit unable "
383
+ " to read address of dyld-handover notification function at "
384
+ " 0x%" PRIx64,
385
+ notification_location);
386
+ } else {
387
+ notification_addr = process->FixCodeAddress (notification_addr);
388
+ dyld_instance->SetDYLDHandoverBreakpoint (notification_addr);
389
+ }
369
390
}
370
391
}
371
392
}
@@ -417,7 +438,80 @@ void DynamicLoaderMacOS::PutToLog(Log *log) const {
417
438
return ;
418
439
}
419
440
441
+ // Look in dyld's dyld_all_image_infos structure for the address
442
+ // of the notification function.
443
+ // We can find the address of dyld_all_image_infos by a system
444
+ // call, even if we don't have a dyld binary registered in lldb's
445
+ // image list.
446
+ // At process launch time - before dyld has executed any instructions -
447
+ // the address of the notification function is not a resolved vm address
448
+ // yet. dyld_all_image_infos also has a field with its own address
449
+ // in it, and this will also be unresolved when we're at this state.
450
+ // So we can compare the address of the object with this field and if
451
+ // they differ, dyld hasn't started executing yet and we can't get the
452
+ // notification address this way.
453
+ addr_t DynamicLoaderMacOS::GetNotificationFuncAddrFromImageInfos () {
454
+ addr_t notification_addr = LLDB_INVALID_ADDRESS;
455
+ if (!m_process)
456
+ return notification_addr;
457
+
458
+ addr_t all_image_infos_addr = m_process->GetImageInfoAddress ();
459
+ if (all_image_infos_addr == LLDB_INVALID_ADDRESS)
460
+ return notification_addr;
461
+
462
+ const uint32_t addr_size =
463
+ m_process->GetTarget ().GetArchitecture ().GetAddressByteSize ();
464
+ offset_t registered_infos_addr_offset =
465
+ sizeof (uint32_t ) + // version
466
+ sizeof (uint32_t ) + // infoArrayCount
467
+ addr_size + // infoArray
468
+ addr_size + // notification
469
+ addr_size + // processDetachedFromSharedRegion +
470
+ // libSystemInitialized + pad
471
+ addr_size + // dyldImageLoadAddress
472
+ addr_size + // jitInfo
473
+ addr_size + // dyldVersion
474
+ addr_size + // errorMessage
475
+ addr_size + // terminationFlags
476
+ addr_size + // coreSymbolicationShmPage
477
+ addr_size + // systemOrderFlag
478
+ addr_size + // uuidArrayCount
479
+ addr_size; // uuidArray
480
+ // dyldAllImageInfosAddress
481
+
482
+ // If the dyldAllImageInfosAddress does not match
483
+ // the actual address of this struct, dyld has not started
484
+ // executing yet. The 'notification' field can't be used by
485
+ // lldb until it's resolved to an actual address.
486
+ Status error;
487
+ addr_t registered_infos_addr = m_process->ReadPointerFromMemory (
488
+ all_image_infos_addr + registered_infos_addr_offset, error);
489
+ if (!error.Success ())
490
+ return notification_addr;
491
+ if (registered_infos_addr != all_image_infos_addr)
492
+ return notification_addr;
493
+
494
+ offset_t notification_fptr_offset = sizeof (uint32_t ) + // version
495
+ sizeof (uint32_t ) + // infoArrayCount
496
+ addr_size; // infoArray
497
+
498
+ addr_t notification_fptr = m_process->ReadPointerFromMemory (
499
+ all_image_infos_addr + notification_fptr_offset, error);
500
+ if (error.Success ())
501
+ notification_addr = m_process->FixCodeAddress (notification_fptr);
502
+ return notification_addr;
503
+ }
504
+
505
+ // We want to put a breakpoint on dyld's lldb_image_notifier()
506
+ // but we may have attached to the process during the
507
+ // transition from on-disk-dyld to shared-cache-dyld, so there's
508
+ // officially no dyld binary loaded in the process (libdyld will
509
+ // report none when asked), but the kernel can find the dyld_all_image_infos
510
+ // struct and the function pointer for lldb_image_notifier is in
511
+ // that struct.
420
512
bool DynamicLoaderMacOS::SetNotificationBreakpoint () {
513
+
514
+ // First try to find the notification breakpoint function by name
421
515
if (m_break_id == LLDB_INVALID_BREAK_ID) {
422
516
ModuleSP dyld_sp (GetDYLDModule ());
423
517
if (dyld_sp) {
@@ -431,14 +525,56 @@ bool DynamicLoaderMacOS::SetNotificationBreakpoint() {
431
525
Breakpoint *breakpoint =
432
526
m_process->GetTarget ()
433
527
.CreateBreakpoint (&dyld_filelist, source_files,
434
- " _dyld_debugger_notification " ,
435
- eFunctionNameTypeFull, eLanguageTypeC, 0 ,
436
- skip_prologue, internal, hardware)
528
+ " lldb_image_notifier " , eFunctionNameTypeFull ,
529
+ eLanguageTypeUnknown, 0 , skip_prologue ,
530
+ internal, hardware)
437
531
.get ();
438
532
breakpoint->SetCallback (DynamicLoaderMacOS::NotifyBreakpointHit, this ,
439
533
true );
440
534
breakpoint->SetBreakpointKind (" shared-library-event" );
441
- m_break_id = breakpoint->GetID ();
535
+ if (breakpoint->HasResolvedLocations ())
536
+ m_break_id = breakpoint->GetID ();
537
+ else
538
+ m_process->GetTarget ().RemoveBreakpointByID (breakpoint->GetID ());
539
+
540
+ if (m_break_id == LLDB_INVALID_BREAK_ID) {
541
+ Breakpoint *breakpoint =
542
+ m_process->GetTarget ()
543
+ .CreateBreakpoint (&dyld_filelist, source_files,
544
+ " gdb_image_notifier" , eFunctionNameTypeFull,
545
+ eLanguageTypeUnknown, 0 , skip_prologue,
546
+ internal, hardware)
547
+ .get ();
548
+ breakpoint->SetCallback (DynamicLoaderMacOS::NotifyBreakpointHit, this ,
549
+ true );
550
+ breakpoint->SetBreakpointKind (" shared-library-event" );
551
+ if (breakpoint->HasResolvedLocations ())
552
+ m_break_id = breakpoint->GetID ();
553
+ else
554
+ m_process->GetTarget ().RemoveBreakpointByID (breakpoint->GetID ());
555
+ }
556
+ }
557
+ }
558
+
559
+ // Failing that, find dyld_all_image_infos struct in memory,
560
+ // read the notification function pointer at the offset.
561
+ if (m_break_id == LLDB_INVALID_BREAK_ID) {
562
+ addr_t notification_addr = GetNotificationFuncAddrFromImageInfos ();
563
+ if (notification_addr != LLDB_INVALID_ADDRESS) {
564
+ Address so_addr;
565
+ // We may not have a dyld binary mapped to this address yet;
566
+ // don't try to express the Address object as section+offset,
567
+ // only as a raw load address.
568
+ so_addr.SetRawAddress (notification_addr);
569
+ Breakpoint *dyld_break =
570
+ m_process->GetTarget ().CreateBreakpoint (so_addr, true , false ).get ();
571
+ dyld_break->SetCallback (DynamicLoaderMacOS::NotifyBreakpointHit, this ,
572
+ true );
573
+ dyld_break->SetBreakpointKind (" shared-library-event" );
574
+ if (dyld_break->HasResolvedLocations ())
575
+ m_break_id = dyld_break->GetID ();
576
+ else
577
+ m_process->GetTarget ().RemoveBreakpointByID (dyld_break->GetID ());
442
578
}
443
579
}
444
580
return m_break_id != LLDB_INVALID_BREAK_ID;
0 commit comments