@@ -418,6 +418,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
418418 void *class_infos_ptr,
419419 uint64_t *relative_selector_offset,
420420 uint32_t class_infos_byte_size,
421+ uint32_t *start_idx,
421422 uint32_t should_log)
422423{
423424 *relative_selector_offset = 0;
@@ -426,6 +427,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
426427 DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);
427428 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
428429 DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
430+ DEBUG_PRINTF ("start_idx = %u\n", *start_idx);
429431 if (objc_opt_ro_ptr)
430432 {
431433 const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
@@ -480,7 +482,11 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
480482 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
481483 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
482484
483- for (uint32_t i=0; i<clsopt->capacity; ++i)
485+ const uint32_t original_start_idx = *start_idx;
486+
487+ // Always start at the start_idx here. If it's greater than the capacity,
488+ // it will skip the loop entirely and go to the duplicate handling below.
489+ for (uint32_t i=*start_idx; i<clsopt->capacity; ++i)
484490 {
485491 const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
486492 DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
@@ -524,59 +530,77 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
524530 else
525531 {
526532 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
533+ *start_idx = i;
534+ break;
527535 }
528536 ++idx;
529537 }
530538
531- const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
532- const uint32_t duplicate_count = *duplicate_count_ptr;
533- const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
539+ if (idx < max_class_infos) {
540+ const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
541+ const uint32_t duplicate_count = *duplicate_count_ptr;
542+ const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
534543
535- DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
536- DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
544+ DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
545+ DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
537546
538- for (uint32_t i=0; i<duplicate_count; ++i)
539- {
540- const uint64_t objectCacheOffset = duplicateClassOffsets[i].objectCacheOffset;
541- DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset) ;
547+ const uint32_t duplicate_start_idx =
548+ *start_idx < clsopt->capacity ?
549+ 0 :
550+ *start_idx - clsopt->capacity ;
542551
543- if (classOffsets[i].isDuplicate) {
544- DEBUG_PRINTF("isDuplicate = true\n");
545- continue; // duplicate
546- }
547-
548- if (objectCacheOffset == 0) {
549- DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
550- continue; // invalid offset
551- }
552-
553- if (class_infos && idx < max_class_infos)
552+ for (uint32_t i=duplicate_start_idx; i<duplicate_count; ++i)
554553 {
555- class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
554+ const uint64_t objectCacheOffset = duplicateClassOffsets[i].objectCacheOffset;
555+ DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
556556
557- // Lookup the class name.
558- const char *name = class_name_lookup_func(class_infos[idx].isa);
559- DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
557+ if (duplicateClassOffsets[i].isDuplicate) {
558+ DEBUG_PRINTF("isDuplicate = true\n");
559+ continue; // duplicate
560+ }
560561
561- // Hash the class name so we don't have to read it.
562- const char *s = name;
563- uint32_t h = 5381;
564- for (unsigned char c = *s; c; c = *++s)
562+ if (objectCacheOffset == 0) {
563+ DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
564+ continue; // invalid offset
565+ }
566+
567+ if (class_infos && idx < max_class_infos)
565568 {
566- // class_getName demangles swift names and the hash must
567- // be calculated on the mangled name. hash==0 means lldb
568- // will fetch the mangled name and compute the hash in
569- // ParseClassInfoArray.
570- if (c == '.')
569+ class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
570+
571+ // Lookup the class name.
572+ const char *name = class_name_lookup_func(class_infos[idx].isa);
573+ DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
574+
575+ // Hash the class name so we don't have to read it.
576+ const char *s = name;
577+ uint32_t h = 5381;
578+ for (unsigned char c = *s; c; c = *++s)
571579 {
572- h = 0;
573- break;
580+ // class_getName demangles swift names and the hash must
581+ // be calculated on the mangled name. hash==0 means lldb
582+ // will fetch the mangled name and compute the hash in
583+ // ParseClassInfoArray.
584+ if (c == '.')
585+ {
586+ h = 0;
587+ break;
588+ }
589+ h = ((h << 5) + h) + c;
574590 }
575- h = ((h << 5) + h) + c;
591+ class_infos[idx].hash = h;
592+ } else {
593+ DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
594+ *start_idx = i;
595+ break;
576596 }
577- class_infos[ idx].hash = h ;
597+ ++ idx;
578598 }
579- ++idx;
599+ }
600+ // Always make sure start_idx gets updated. Otherwise we have an infinite
601+ // loop if there are exactly max_class_infos number of classes.
602+ if (*start_idx == original_start_idx) {
603+ *start_idx = idx;
580604 }
581605 }
582606 else if (objc_opt->version >= 12 && objc_opt->version <= 15)
@@ -1959,6 +1983,9 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
19591983 CompilerType clang_uint64_t_pointer_type =
19601984 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize (eEncodingUint, 64 )
19611985 .GetPointerType ();
1986+ CompilerType clang_uint32_t_pointer_type =
1987+ scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize (eEncodingUint, 32 )
1988+ .GetPointerType ();
19621989
19631990 // Next make the function caller for our implementation utility function.
19641991 ValueList arguments;
@@ -1976,6 +2003,13 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
19762003 value.SetValueType (Value::ValueType::Scalar);
19772004 value.SetCompilerType (clang_uint32_t_type);
19782005 arguments.PushValue (value);
2006+
2007+ value.SetValueType (Value::ValueType::Scalar);
2008+ value.SetCompilerType (clang_uint32_t_pointer_type);
2009+ arguments.PushValue (value);
2010+
2011+ value.SetValueType (Value::ValueType::Scalar);
2012+ value.SetCompilerType (clang_uint32_t_type);
19792013 arguments.PushValue (value);
19802014
19812015 std::unique_ptr<UtilityFunction> utility_fn = std::move (*utility_fn_or_error);
@@ -2313,10 +2347,7 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
23132347
23142348 // The number of entries to pre-allocate room for.
23152349 // Each entry is (addrsize + 4) bytes
2316- // FIXME: It is not sustainable to continue incrementing this value every time
2317- // the shared cache grows. This is because it requires allocating memory in
2318- // the inferior process and some inferior processes have small memory limits.
2319- const uint32_t max_num_classes = 212992 ;
2350+ const uint32_t max_num_classes_in_buffer = 212992 ;
23202351
23212352 UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction (exe_ctx);
23222353 if (!get_class_info_code) {
@@ -2338,22 +2369,40 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
23382369 DiagnosticManager diagnostics;
23392370
23402371 const uint32_t class_info_byte_size = addr_size + 4 ;
2341- const uint32_t class_infos_byte_size = max_num_classes * class_info_byte_size;
2372+ const uint32_t class_infos_byte_size =
2373+ max_num_classes_in_buffer * class_info_byte_size;
23422374 lldb::addr_t class_infos_addr = process->AllocateMemory (
23432375 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
23442376 const uint32_t relative_selector_offset_addr_size = 64 ;
23452377 lldb::addr_t relative_selector_offset_addr =
23462378 process->AllocateMemory (relative_selector_offset_addr_size,
23472379 ePermissionsReadable | ePermissionsWritable, err);
2380+ constexpr uint32_t class_info_start_idx_byte_size = sizeof (uint32_t );
2381+ lldb::addr_t class_info_start_idx_addr =
2382+ process->AllocateMemory (class_info_start_idx_byte_size,
2383+ ePermissionsReadable | ePermissionsWritable, err);
23482384
2349- if (class_infos_addr == LLDB_INVALID_ADDRESS) {
2385+ if (class_infos_addr == LLDB_INVALID_ADDRESS ||
2386+ relative_selector_offset_addr == LLDB_INVALID_ADDRESS ||
2387+ class_info_start_idx_addr == LLDB_INVALID_ADDRESS) {
23502388 LLDB_LOGF (log,
23512389 " unable to allocate %" PRIu32
23522390 " bytes in process for shared cache read" ,
23532391 class_infos_byte_size);
23542392 return DescriptorMapUpdateResult::Fail ();
23552393 }
23562394
2395+ const uint32_t start_idx_init_value = 0 ;
2396+ size_t bytes_written = process->WriteMemory (
2397+ class_info_start_idx_addr, &start_idx_init_value, sizeof (uint32_t ), err);
2398+ if (bytes_written != sizeof (uint32_t )) {
2399+ LLDB_LOGF (log,
2400+ " unable to write %" PRIu32
2401+ " bytes in process for shared cache read" ,
2402+ class_infos_byte_size);
2403+ return DescriptorMapUpdateResult::Fail ();
2404+ }
2405+
23572406 std::lock_guard<std::mutex> guard (m_mutex);
23582407
23592408 // Fill in our function argument values
@@ -2362,12 +2411,13 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
23622411 arguments.GetValueAtIndex (2 )->GetScalar () = class_infos_addr;
23632412 arguments.GetValueAtIndex (3 )->GetScalar () = relative_selector_offset_addr;
23642413 arguments.GetValueAtIndex (4 )->GetScalar () = class_infos_byte_size;
2414+ arguments.GetValueAtIndex (5 )->GetScalar () = class_info_start_idx_addr;
23652415 // Only dump the runtime classes from the expression evaluation if the log is
23662416 // verbose:
23672417 Log *type_log = GetLog (LLDBLog::Types);
23682418 bool dump_log = type_log && type_log->GetVerbose ();
23692419
2370- arguments.GetValueAtIndex (5 )->GetScalar () = dump_log ? 1 : 0 ;
2420+ arguments.GetValueAtIndex (6 )->GetScalar () = dump_log ? 1 : 0 ;
23712421
23722422 bool success = false ;
23732423
@@ -2394,78 +2444,80 @@ AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
23942444
23952445 diagnostics.Clear ();
23962446
2397- // Run the function
2398- ExpressionResults results =
2399- get_shared_cache_class_info_function->ExecuteFunction (
2400- exe_ctx, &m_args, options, diagnostics, return_value);
2401-
2402- if (results == eExpressionCompleted) {
2403- // The result is the number of ClassInfo structures that were filled in
2404- num_class_infos = return_value.GetScalar ().ULong ();
2405- LLDB_LOG (log, " Discovered {0} Objective-C classes in the shared cache" ,
2406- num_class_infos);
2407- // Assert if there were more classes than we pre-allocated
2408- // room for.
2409- assert (num_class_infos <= max_num_classes);
2410- if (num_class_infos > 0 ) {
2411- if (num_class_infos > max_num_classes) {
2412- num_class_infos = max_num_classes;
2413-
2414- success = false ;
2415- } else {
2447+ uint32_t num_class_infos_read = 0 ;
2448+ bool already_read_relative_selector_offset = false ;
2449+
2450+ do {
2451+ // Run the function.
2452+ ExpressionResults results =
2453+ get_shared_cache_class_info_function->ExecuteFunction (
2454+ exe_ctx, &m_args, options, diagnostics, return_value);
2455+
2456+ if (results == eExpressionCompleted) {
2457+ // The result is the number of ClassInfo structures that were filled in.
2458+ num_class_infos_read = return_value.GetScalar ().ULong ();
2459+ num_class_infos += num_class_infos_read;
2460+ LLDB_LOG (log, " Discovered {0} Objective-C classes in the shared cache" ,
2461+ num_class_infos_read);
2462+ if (num_class_infos_read > 0 ) {
24162463 success = true ;
2417- }
24182464
2419- // Read the relative selector offset.
2420- DataBufferHeap relative_selector_offset_buffer (64 , 0 );
2421- if (process->ReadMemory (relative_selector_offset_addr,
2422- relative_selector_offset_buffer.GetBytes (),
2423- relative_selector_offset_buffer.GetByteSize (),
2424- err) ==
2425- relative_selector_offset_buffer.GetByteSize ()) {
2426- DataExtractor relative_selector_offset_data (
2427- relative_selector_offset_buffer.GetBytes (),
2428- relative_selector_offset_buffer.GetByteSize (),
2429- process->GetByteOrder (), addr_size);
2430- lldb::offset_t offset = 0 ;
2431- uint64_t relative_selector_offset =
2432- relative_selector_offset_data.GetU64 (&offset);
2433- if (relative_selector_offset > 0 ) {
2434- // The offset is relative to the objc_opt struct.
2435- m_runtime.SetRelativeSelectorBaseAddr (objc_opt_ptr +
2436- relative_selector_offset);
2465+ // Read the relative selector offset. This only needs to occur once no
2466+ // matter how many times the function is called.
2467+ if (!already_read_relative_selector_offset) {
2468+ DataBufferHeap relative_selector_offset_buffer (64 , 0 );
2469+ if (process->ReadMemory (
2470+ relative_selector_offset_addr,
2471+ relative_selector_offset_buffer.GetBytes (),
2472+ relative_selector_offset_buffer.GetByteSize (),
2473+ err) == relative_selector_offset_buffer.GetByteSize ()) {
2474+ DataExtractor relative_selector_offset_data (
2475+ relative_selector_offset_buffer.GetBytes (),
2476+ relative_selector_offset_buffer.GetByteSize (),
2477+ process->GetByteOrder (), addr_size);
2478+ lldb::offset_t offset = 0 ;
2479+ uint64_t relative_selector_offset =
2480+ relative_selector_offset_data.GetU64 (&offset);
2481+ if (relative_selector_offset > 0 ) {
2482+ // The offset is relative to the objc_opt struct.
2483+ m_runtime.SetRelativeSelectorBaseAddr (objc_opt_ptr +
2484+ relative_selector_offset);
2485+ }
2486+ }
2487+ already_read_relative_selector_offset = true ;
24372488 }
2438- }
2439-
2440- // Read the ClassInfo structures
2441- DataBufferHeap class_infos_buffer (
2442- num_class_infos * class_info_byte_size, 0 );
2443- if (process->ReadMemory (class_infos_addr, class_infos_buffer.GetBytes (),
2444- class_infos_buffer.GetByteSize (),
2445- err) == class_infos_buffer.GetByteSize ()) {
2446- DataExtractor class_infos_data (class_infos_buffer.GetBytes (),
2447- class_infos_buffer.GetByteSize (),
2448- process->GetByteOrder (), addr_size);
24492489
2450- m_runtime.ParseClassInfoArray (class_infos_data, num_class_infos);
2490+ // Read the ClassInfo structures
2491+ DataBufferHeap class_infos_buffer (
2492+ num_class_infos_read * class_info_byte_size, 0 );
2493+ if (process->ReadMemory (class_infos_addr,
2494+ class_infos_buffer.GetBytes (),
2495+ class_infos_buffer.GetByteSize (),
2496+ err) == class_infos_buffer.GetByteSize ()) {
2497+ DataExtractor class_infos_data (class_infos_buffer.GetBytes (),
2498+ class_infos_buffer.GetByteSize (),
2499+ process->GetByteOrder (), addr_size);
2500+
2501+ m_runtime.ParseClassInfoArray (class_infos_data,
2502+ num_class_infos_read);
2503+ }
24512504 }
2452- } else {
2453- success = true ;
2454- }
2455- } else {
2456- if (log) {
2505+ } else if (log) {
24572506 LLDB_LOGF (log, " Error evaluating our find class name function." );
24582507 diagnostics.Dump (log);
2508+ break ;
24592509 }
2460- }
2461- } else {
2462- if (log) {
2463- LLDB_LOGF (log, " Error writing function arguments." );
2464- diagnostics.Dump (log);
2465- }
2510+ } while (num_class_infos_read == max_num_classes_in_buffer);
2511+ } else if (log) {
2512+ LLDB_LOGF (log, " Error writing function arguments." );
2513+ diagnostics.Dump (log);
24662514 }
24672515
2468- // Deallocate the memory we allocated for the ClassInfo array
2516+ LLDB_LOG (log, " Processed {0} Objective-C classes total from the shared cache" ,
2517+ num_class_infos);
2518+ // Cleanup memory we allocated in the process.
2519+ process->DeallocateMemory (relative_selector_offset_addr);
2520+ process->DeallocateMemory (class_info_start_idx_addr);
24692521 process->DeallocateMemory (class_infos_addr);
24702522
24712523 return DescriptorMapUpdateResult (success, false , num_class_infos);
0 commit comments