@@ -423,6 +423,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
423423 void *class_infos_ptr,
424424 uint64_t *relative_selector_offset,
425425 uint32_t class_infos_byte_size,
426+ uint32_t *start_idx,
426427 uint32_t should_log)
427428{
428429 *relative_selector_offset = 0;
@@ -431,6 +432,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
431432 DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);
432433 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
433434 DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
435+ DEBUG_PRINTF ("start_idx = %u\n", *start_idx);
434436 if (objc_opt_ro_ptr)
435437 {
436438 const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
@@ -485,7 +487,11 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
485487 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
486488 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
487489
488- for (uint32_t i=0; i<clsopt->capacity; ++i)
490+ const uint32_t original_start_idx = *start_idx;
491+
492+ // Always start at the start_idx here. If it's greater than the capacity,
493+ // it will skip the loop entirely and go to the duplicate handling below.
494+ for (uint32_t i=*start_idx; i<clsopt->capacity; ++i)
489495 {
490496 const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
491497 DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
@@ -529,59 +535,77 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
529535 else
530536 {
531537 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
538+ *start_idx = i;
539+ break;
532540 }
533541 ++idx;
534542 }
535543
536- const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
537- const uint32_t duplicate_count = *duplicate_count_ptr;
538- const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
544+ if (idx < max_class_infos) {
545+ const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
546+ const uint32_t duplicate_count = *duplicate_count_ptr;
547+ const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
539548
540- DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
541- DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
549+ DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
550+ DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
542551
543- for (uint32_t i=0; i<duplicate_count; ++i)
544- {
545- const uint64_t objectCacheOffset = duplicateClassOffsets[i].objectCacheOffset;
546- DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset) ;
552+ const uint32_t duplicate_start_idx =
553+ *start_idx < clsopt->capacity ?
554+ 0 :
555+ *start_idx - clsopt->capacity ;
547556
548- if (classOffsets[i].isDuplicate) {
549- DEBUG_PRINTF("isDuplicate = true\n");
550- continue; // duplicate
551- }
552-
553- if (objectCacheOffset == 0) {
554- DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
555- continue; // invalid offset
556- }
557-
558- if (class_infos && idx < max_class_infos)
557+ for (uint32_t i=duplicate_start_idx; i<duplicate_count; ++i)
559558 {
560- class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
559+ const uint64_t objectCacheOffset = duplicateClassOffsets[i].objectCacheOffset;
560+ DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
561561
562- // Lookup the class name.
563- const char *name = class_name_lookup_func(class_infos[idx].isa);
564- DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
562+ if (duplicateClassOffsets[i].isDuplicate) {
563+ DEBUG_PRINTF("isDuplicate = true\n");
564+ continue; // duplicate
565+ }
565566
566- // Hash the class name so we don't have to read it.
567- const char *s = name;
568- uint32_t h = 5381;
569- for (unsigned char c = *s; c; c = *++s)
567+ if (objectCacheOffset == 0) {
568+ DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
569+ continue; // invalid offset
570+ }
571+
572+ if (class_infos && idx < max_class_infos)
570573 {
571- // class_getName demangles swift names and the hash must
572- // be calculated on the mangled name. hash==0 means lldb
573- // will fetch the mangled name and compute the hash in
574- // ParseClassInfoArray.
575- if (c == '.')
574+ class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
575+
576+ // Lookup the class name.
577+ const char *name = class_name_lookup_func(class_infos[idx].isa);
578+ DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
579+
580+ // Hash the class name so we don't have to read it.
581+ const char *s = name;
582+ uint32_t h = 5381;
583+ for (unsigned char c = *s; c; c = *++s)
576584 {
577- h = 0;
578- break;
585+ // class_getName demangles swift names and the hash must
586+ // be calculated on the mangled name. hash==0 means lldb
587+ // will fetch the mangled name and compute the hash in
588+ // ParseClassInfoArray.
589+ if (c == '.')
590+ {
591+ h = 0;
592+ break;
593+ }
594+ h = ((h << 5) + h) + c;
579595 }
580- h = ((h << 5) + h) + c;
596+ class_infos[idx].hash = h;
597+ } else {
598+ DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
599+ *start_idx = i;
600+ break;
581601 }
582- class_infos[ idx].hash = h ;
602+ ++ idx;
583603 }
584- ++idx;
604+ }
605+ // Always make sure start_idx gets updated. Otherwise we have an infinite
606+ // loop if there are exactly max_class_infos number of classes.
607+ if (*start_idx == original_start_idx) {
608+ *start_idx = idx;
585609 }
586610 }
587611 else if (objc_opt->version >= 12 && objc_opt->version <= 15)
@@ -1972,6 +1996,9 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
19721996 CompilerType clang_uint64_t_pointer_type =
19731997 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize (eEncodingUint, 64 )
19741998 .GetPointerType ();
1999+ CompilerType clang_uint32_t_pointer_type =
2000+ scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize (eEncodingUint, 32 )
2001+ .GetPointerType ();
19752002
19762003 // Next make the function caller for our implementation utility function.
19772004 ValueList arguments;
@@ -1989,6 +2016,13 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
19892016 value.SetValueType (Value::ValueType::Scalar);
19902017 value.SetCompilerType (clang_uint32_t_type);
19912018 arguments.PushValue (value);
2019+
2020+ value.SetValueType (Value::ValueType::Scalar);
2021+ value.SetCompilerType (clang_uint32_t_pointer_type);
2022+ arguments.PushValue (value);
2023+
2024+ value.SetValueType (Value::ValueType::Scalar);
2025+ value.SetCompilerType (clang_uint32_t_type);
19922026 arguments.PushValue (value);
19932027
19942028 std::unique_ptr<UtilityFunction> utility_fn = std::move (*utility_fn_or_error);
@@ -2326,10 +2360,7 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
23262360
23272361 // The number of entries to pre-allocate room for.
23282362 // Each entry is (addrsize + 4) bytes
2329- // FIXME: It is not sustainable to continue incrementing this value every time
2330- // the shared cache grows. This is because it requires allocating memory in
2331- // the inferior process and some inferior processes have small memory limits.
2332- const uint32_t max_num_classes = 212992 ;
2363+ const uint32_t max_num_classes_in_buffer = 212992 ;
23332364
23342365 UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction (exe_ctx);
23352366 if (!get_class_info_code) {
@@ -2351,22 +2382,40 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
23512382 DiagnosticManager diagnostics;
23522383
23532384 const uint32_t class_info_byte_size = addr_size + 4 ;
2354- const uint32_t class_infos_byte_size = max_num_classes * class_info_byte_size;
2385+ const uint32_t class_infos_byte_size =
2386+ max_num_classes_in_buffer * class_info_byte_size;
23552387 lldb::addr_t class_infos_addr = process->AllocateMemory (
23562388 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
23572389 const uint32_t relative_selector_offset_addr_size = 64 ;
23582390 lldb::addr_t relative_selector_offset_addr =
23592391 process->AllocateMemory (relative_selector_offset_addr_size,
23602392 ePermissionsReadable | ePermissionsWritable, err);
2393+ constexpr uint32_t class_info_start_idx_byte_size = sizeof (uint32_t );
2394+ lldb::addr_t class_info_start_idx_addr =
2395+ process->AllocateMemory (class_info_start_idx_byte_size,
2396+ ePermissionsReadable | ePermissionsWritable, err);
23612397
2362- if (class_infos_addr == LLDB_INVALID_ADDRESS) {
2398+ if (class_infos_addr == LLDB_INVALID_ADDRESS ||
2399+ relative_selector_offset_addr == LLDB_INVALID_ADDRESS ||
2400+ class_info_start_idx_addr == LLDB_INVALID_ADDRESS) {
23632401 LLDB_LOGF (log,
23642402 " unable to allocate %" PRIu32
23652403 " bytes in process for shared cache read" ,
23662404 class_infos_byte_size);
23672405 return DescriptorMapUpdateResult::Fail ();
23682406 }
23692407
2408+ const uint32_t start_idx_init_value = 0 ;
2409+ size_t bytes_written = process->WriteMemory (
2410+ class_info_start_idx_addr, &start_idx_init_value, sizeof (uint32_t ), err);
2411+ if (bytes_written != sizeof (uint32_t )) {
2412+ LLDB_LOGF (log,
2413+ " unable to write %" PRIu32
2414+ " bytes in process for shared cache read" ,
2415+ class_infos_byte_size);
2416+ return DescriptorMapUpdateResult::Fail ();
2417+ }
2418+
23702419 std::lock_guard<std::mutex> guard (m_mutex);
23712420
23722421 // Fill in our function argument values
@@ -2375,12 +2424,13 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
23752424 arguments.GetValueAtIndex (2 )->GetScalar () = class_infos_addr;
23762425 arguments.GetValueAtIndex (3 )->GetScalar () = relative_selector_offset_addr;
23772426 arguments.GetValueAtIndex (4 )->GetScalar () = class_infos_byte_size;
2427+ arguments.GetValueAtIndex (5 )->GetScalar () = class_info_start_idx_addr;
23782428 // Only dump the runtime classes from the expression evaluation if the log is
23792429 // verbose:
23802430 Log *type_log = GetLog (LLDBLog::Types);
23812431 bool dump_log = type_log && type_log->GetVerbose ();
23822432
2383- arguments.GetValueAtIndex (5 )->GetScalar () = dump_log ? 1 : 0 ;
2433+ arguments.GetValueAtIndex (6 )->GetScalar () = dump_log ? 1 : 0 ;
23842434
23852435 bool success = false ;
23862436
@@ -2407,78 +2457,80 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
24072457
24082458 diagnostics.Clear ();
24092459
2410- // Run the function
2411- ExpressionResults results =
2412- get_shared_cache_class_info_function->ExecuteFunction (
2413- exe_ctx, &m_args, options, diagnostics, return_value);
2414-
2415- if (results == eExpressionCompleted) {
2416- // The result is the number of ClassInfo structures that were filled in
2417- num_class_infos = return_value.GetScalar ().ULong ();
2418- LLDB_LOG (log, " Discovered {0} Objective-C classes in the shared cache" ,
2419- num_class_infos);
2420- // Assert if there were more classes than we pre-allocated
2421- // room for.
2422- assert (num_class_infos <= max_num_classes);
2423- if (num_class_infos > 0 ) {
2424- if (num_class_infos > max_num_classes) {
2425- num_class_infos = max_num_classes;
2426-
2427- success = false ;
2428- } else {
2460+ uint32_t num_class_infos_read = 0 ;
2461+ bool already_read_relative_selector_offset = false ;
2462+
2463+ do {
2464+ // Run the function.
2465+ ExpressionResults results =
2466+ get_shared_cache_class_info_function->ExecuteFunction (
2467+ exe_ctx, &m_args, options, diagnostics, return_value);
2468+
2469+ if (results == eExpressionCompleted) {
2470+ // The result is the number of ClassInfo structures that were filled in.
2471+ num_class_infos_read = return_value.GetScalar ().ULong ();
2472+ num_class_infos += num_class_infos_read;
2473+ LLDB_LOG (log, " Discovered {0} Objective-C classes in the shared cache" ,
2474+ num_class_infos_read);
2475+ if (num_class_infos_read > 0 ) {
24292476 success = true ;
2430- }
24312477
2432- // Read the relative selector offset.
2433- DataBufferHeap relative_selector_offset_buffer (64 , 0 );
2434- if (process->ReadMemory (relative_selector_offset_addr,
2435- relative_selector_offset_buffer.GetBytes (),
2436- relative_selector_offset_buffer.GetByteSize (),
2437- err) ==
2438- relative_selector_offset_buffer.GetByteSize ()) {
2439- DataExtractor relative_selector_offset_data (
2440- relative_selector_offset_buffer.GetBytes (),
2441- relative_selector_offset_buffer.GetByteSize (),
2442- process->GetByteOrder (), addr_size);
2443- lldb::offset_t offset = 0 ;
2444- uint64_t relative_selector_offset =
2445- relative_selector_offset_data.GetU64 (&offset);
2446- if (relative_selector_offset > 0 ) {
2447- // The offset is relative to the objc_opt struct.
2448- m_runtime.SetRelativeSelectorBaseAddr (objc_opt_ptr +
2449- relative_selector_offset);
2478+ // Read the relative selector offset. This only needs to occur once no
2479+ // matter how many times the function is called.
2480+ if (!already_read_relative_selector_offset) {
2481+ DataBufferHeap relative_selector_offset_buffer (64 , 0 );
2482+ if (process->ReadMemory (
2483+ relative_selector_offset_addr,
2484+ relative_selector_offset_buffer.GetBytes (),
2485+ relative_selector_offset_buffer.GetByteSize (),
2486+ err) == relative_selector_offset_buffer.GetByteSize ()) {
2487+ DataExtractor relative_selector_offset_data (
2488+ relative_selector_offset_buffer.GetBytes (),
2489+ relative_selector_offset_buffer.GetByteSize (),
2490+ process->GetByteOrder (), addr_size);
2491+ lldb::offset_t offset = 0 ;
2492+ uint64_t relative_selector_offset =
2493+ relative_selector_offset_data.GetU64 (&offset);
2494+ if (relative_selector_offset > 0 ) {
2495+ // The offset is relative to the objc_opt struct.
2496+ m_runtime.SetRelativeSelectorBaseAddr (objc_opt_ptr +
2497+ relative_selector_offset);
2498+ }
2499+ }
2500+ already_read_relative_selector_offset = true ;
24502501 }
2451- }
2452-
2453- // Read the ClassInfo structures
2454- DataBufferHeap class_infos_buffer (
2455- num_class_infos * class_info_byte_size, 0 );
2456- if (process->ReadMemory (class_infos_addr, class_infos_buffer.GetBytes (),
2457- class_infos_buffer.GetByteSize (),
2458- err) == class_infos_buffer.GetByteSize ()) {
2459- DataExtractor class_infos_data (class_infos_buffer.GetBytes (),
2460- class_infos_buffer.GetByteSize (),
2461- process->GetByteOrder (), addr_size);
24622502
2463- m_runtime.ParseClassInfoArray (class_infos_data, num_class_infos);
2503+ // Read the ClassInfo structures
2504+ DataBufferHeap class_infos_buffer (
2505+ num_class_infos_read * class_info_byte_size, 0 );
2506+ if (process->ReadMemory (class_infos_addr,
2507+ class_infos_buffer.GetBytes (),
2508+ class_infos_buffer.GetByteSize (),
2509+ err) == class_infos_buffer.GetByteSize ()) {
2510+ DataExtractor class_infos_data (class_infos_buffer.GetBytes (),
2511+ class_infos_buffer.GetByteSize (),
2512+ process->GetByteOrder (), addr_size);
2513+
2514+ m_runtime.ParseClassInfoArray (class_infos_data,
2515+ num_class_infos_read);
2516+ }
24642517 }
2465- } else {
2466- success = true ;
2467- }
2468- } else {
2469- if (log) {
2518+ } else if (log) {
24702519 LLDB_LOGF (log, " Error evaluating our find class name function." );
24712520 diagnostics.Dump (log);
2521+ break ;
24722522 }
2473- }
2474- } else {
2475- if (log) {
2476- LLDB_LOGF (log, " Error writing function arguments." );
2477- diagnostics.Dump (log);
2478- }
2523+ } while (num_class_infos_read == max_num_classes_in_buffer);
2524+ } else if (log) {
2525+ LLDB_LOGF (log, " Error writing function arguments." );
2526+ diagnostics.Dump (log);
24792527 }
24802528
2481- // Deallocate the memory we allocated for the ClassInfo array
2529+ LLDB_LOG (log, " Processed {0} Objective-C classes total from the shared cache" ,
2530+ num_class_infos);
2531+ // Cleanup memory we allocated in the process.
2532+ process->DeallocateMemory (relative_selector_offset_addr);
2533+ process->DeallocateMemory (class_info_start_idx_addr);
24822534 process->DeallocateMemory (class_infos_addr);
24832535
24842536 return DescriptorMapUpdateResult (success, false , num_class_infos);
0 commit comments