@@ -177,6 +177,8 @@ def test_default_no_run(self):
177
177
"totalDebugInfoIndexLoadedFromCache" ,
178
178
"totalDebugInfoIndexSavedToCache" ,
179
179
"totalDebugInfoParseTime" ,
180
+ "totalDwoFileCount" ,
181
+ "totalLoadedDwoFileCount" ,
180
182
]
181
183
self .verify_keys (debug_stats , '"debug_stats"' , debug_stat_keys , None )
182
184
if self .getPlatform () != "windows" :
@@ -287,6 +289,8 @@ def test_default_with_run(self):
287
289
"totalDebugInfoIndexLoadedFromCache" ,
288
290
"totalDebugInfoIndexSavedToCache" ,
289
291
"totalDebugInfoParseTime" ,
292
+ "totalDwoFileCount" ,
293
+ "totalLoadedDwoFileCount" ,
290
294
]
291
295
self .verify_keys (debug_stats , '"debug_stats"' , debug_stat_keys , None )
292
296
stats = debug_stats ["targets" ][0 ]
@@ -325,6 +329,8 @@ def test_memory(self):
325
329
"totalDebugInfoIndexLoadedFromCache" ,
326
330
"totalDebugInfoIndexSavedToCache" ,
327
331
"totalDebugInfoByteSize" ,
332
+ "totalDwoFileCount" ,
333
+ "totalLoadedDwoFileCount" ,
328
334
]
329
335
self .verify_keys (debug_stats , '"debug_stats"' , debug_stat_keys , None )
330
336
@@ -377,6 +383,8 @@ def test_modules(self):
377
383
"totalDebugInfoIndexLoadedFromCache" ,
378
384
"totalDebugInfoIndexSavedToCache" ,
379
385
"totalDebugInfoByteSize" ,
386
+ "totalDwoFileCount" ,
387
+ "totalLoadedDwoFileCount" ,
380
388
]
381
389
self .verify_keys (debug_stats , '"debug_stats"' , debug_stat_keys , None )
382
390
stats = debug_stats ["targets" ][0 ]
@@ -397,6 +405,8 @@ def test_modules(self):
397
405
"symbolTableLoadedFromCache" ,
398
406
"symbolTableParseTime" ,
399
407
"symbolTableSavedToCache" ,
408
+ "dwoFileCount" ,
409
+ "loadedDwoFileCount" ,
400
410
"triple" ,
401
411
"uuid" ,
402
412
]
@@ -485,6 +495,8 @@ def test_breakpoints(self):
485
495
"totalDebugInfoIndexLoadedFromCache" ,
486
496
"totalDebugInfoIndexSavedToCache" ,
487
497
"totalDebugInfoByteSize" ,
498
+ "totalDwoFileCount" ,
499
+ "totalLoadedDwoFileCount" ,
488
500
]
489
501
self .verify_keys (debug_stats , '"debug_stats"' , debug_stat_keys , None )
490
502
target_stats = debug_stats ["targets" ][0 ]
@@ -512,6 +524,132 @@ def test_breakpoints(self):
512
524
self .verify_keys (
513
525
breakpoint , 'target_stats["breakpoints"]' , bp_keys_exist , None
514
526
)
527
+ def test_non_split_dwarf_has_no_dwo_files (self ):
528
+ """
529
+ Test "statistics dump" and the dwo file count.
530
+ Builds a binary without split-dwarf mode, and then
531
+ verifies the dwo file count is zero after running "statistics dump"
532
+ """
533
+ da = {"CXX_SOURCES" : "third.cpp baz.cpp" , "EXE" : self .getBuildArtifact ("a.out" )}
534
+ self .build (dictionary = da , debug_info = ["debug_names" ])
535
+ self .addTearDownCleanup (dictionary = da )
536
+ exe = self .getBuildArtifact ("a.out" )
537
+ target = self .createTestTarget (file_path = exe )
538
+ debug_stats = self .get_stats ()
539
+ self .assertIn ("totalDwoFileCount" , debug_stats )
540
+ self .assertIn ("totalLoadedDwoFileCount" , debug_stats )
541
+
542
+ # Verify that the dwo file count is zero
543
+ self .assertEqual (debug_stats ["totalDwoFileCount" ], 0 )
544
+ self .assertEqual (debug_stats ["totalLoadedDwoFileCount" ], 0 )
545
+
546
+ def test_no_debug_names_eager_loads_dwo_files (self ):
547
+ """
548
+ Test the eager loading behavior of DWO files when debug_names is absent by
549
+ building a split-dwarf binary without debug_names and then running "statistics dump".
550
+ DWO file loading behavior:
551
+ - With debug_names: DebugNamesDWARFIndex allows for lazy loading.
552
+ DWO files are loaded on-demand when symbols are actually looked up
553
+ - Without debug_names: ManualDWARFIndex uses eager loading.
554
+ All DWO files are loaded upfront during the first symbol lookup to build a manual index.
555
+ """
556
+ da = {"CXX_SOURCES" : "third.cpp baz.cpp" , "EXE" : self .getBuildArtifact ("a.out" )}
557
+ self .build (dictionary = da , debug_info = ["dwo" ])
558
+ self .addTearDownCleanup (dictionary = da )
559
+ exe = self .getBuildArtifact ("a.out" )
560
+ target = self .createTestTarget (file_path = exe )
561
+ debug_stats = self .get_stats ()
562
+ self .assertIn ("totalDwoFileCount" , debug_stats )
563
+ self .assertIn ("totalLoadedDwoFileCount" , debug_stats )
564
+
565
+ # Verify that all DWO files are loaded
566
+ self .assertEqual (debug_stats ["totalDwoFileCount" ], 2 )
567
+ self .assertEqual (debug_stats ["totalLoadedDwoFileCount" ], 2 )
568
+
569
+ def test_split_dwarf_dwo_file_count (self ):
570
+ """
571
+ Test "statistics dump" and the dwo file count.
572
+ Builds a binary w/ separate .dwo files and debug_names, and then
573
+ verifies the loaded dwo file count is the expected count after running
574
+ various commands
575
+ """
576
+ da = {"CXX_SOURCES" : "third.cpp baz.cpp" , "EXE" : self .getBuildArtifact ("a.out" )}
577
+ # -gsplit-dwarf creates separate .dwo files,
578
+ # -gpubnames enables the debug_names accelerator tables for faster symbol lookup
579
+ # and lazy loading of DWO files
580
+ # Expected output: third.dwo (contains main) and baz.dwo (contains Baz struct/function)
581
+ self .build (dictionary = da , debug_info = ["dwo" , "debug_names" ])
582
+ self .addTearDownCleanup (dictionary = da )
583
+ exe = self .getBuildArtifact ("a.out" )
584
+ target = self .createTestTarget (file_path = exe )
585
+ debug_stats = self .get_stats ()
586
+
587
+ # 1) 2 DWO files available but none loaded yet
588
+ self .assertEqual (len (debug_stats ["modules" ]), 1 )
589
+ self .assertIn ("totalLoadedDwoFileCount" , debug_stats )
590
+ self .assertIn ("totalDwoFileCount" , debug_stats )
591
+ self .assertEqual (debug_stats ["totalLoadedDwoFileCount" ], 0 )
592
+ self .assertEqual (debug_stats ["totalDwoFileCount" ], 2 )
593
+
594
+ # Since there's only one module, module stats should have the same counts as total counts
595
+ self .assertIn ("dwoFileCount" , debug_stats ["modules" ][0 ])
596
+ self .assertIn ("loadedDwoFileCount" , debug_stats ["modules" ][0 ])
597
+ self .assertEqual (debug_stats ["modules" ][0 ]["loadedDwoFileCount" ], 0 )
598
+ self .assertEqual (debug_stats ["modules" ][0 ]["dwoFileCount" ], 2 )
599
+
600
+ # 2) Setting breakpoint in main triggers loading of third.dwo (contains main function)
601
+ self .runCmd ("b main" )
602
+ debug_stats = self .get_stats ()
603
+ self .assertEqual (debug_stats ["totalLoadedDwoFileCount" ], 1 )
604
+ self .assertEqual (debug_stats ["totalDwoFileCount" ], 2 )
605
+
606
+ self .assertEqual (debug_stats ["modules" ][0 ]["loadedDwoFileCount" ], 1 )
607
+ self .assertEqual (debug_stats ["modules" ][0 ]["dwoFileCount" ], 2 )
608
+
609
+ # 3) Type lookup forces loading of baz.dwo (contains struct Baz definition)
610
+ self .runCmd ("type lookup Baz" )
611
+ debug_stats = self .get_stats ()
612
+ self .assertEqual (debug_stats ["totalLoadedDwoFileCount" ], 2 )
613
+ self .assertEqual (debug_stats ["totalDwoFileCount" ], 2 )
614
+
615
+ self .assertEqual (debug_stats ["modules" ][0 ]["loadedDwoFileCount" ], 2 )
616
+ self .assertEqual (debug_stats ["modules" ][0 ]["dwoFileCount" ], 2 )
617
+
618
+ def test_dwp_dwo_file_count (self ):
619
+ """
620
+ Test "statistics dump" and the loaded dwo file count.
621
+ Builds a binary w/ a separate .dwp file and debug_names, and then
622
+ verifies the loaded dwo file count is the expected count after running
623
+ various commands.
624
+
625
+ We expect the DWO file counters to reflect the number of compile units
626
+ loaded from the DWP file (each representing what was originally a separate DWO file)
627
+ """
628
+ da = {"CXX_SOURCES" : "third.cpp baz.cpp" , "EXE" : self .getBuildArtifact ("a.out" )}
629
+ self .build (dictionary = da , debug_info = ["dwp" , "debug_names" ])
630
+ self .addTearDownCleanup (dictionary = da )
631
+ exe = self .getBuildArtifact ("a.out" )
632
+ target = self .createTestTarget (file_path = exe )
633
+ debug_stats = self .get_stats ()
634
+
635
+ # Initially: 2 DWO files available but none loaded yet
636
+ self .assertIn ("totalLoadedDwoFileCount" , debug_stats )
637
+ self .assertIn ("totalDwoFileCount" , debug_stats )
638
+ self .assertEqual (debug_stats ["totalLoadedDwoFileCount" ], 0 )
639
+ self .assertEqual (debug_stats ["totalDwoFileCount" ], 2 )
640
+
641
+ # Setting breakpoint in main triggers parsing of the CU within a.dwp corresponding to third.dwo (contains main function)
642
+ self .runCmd ("b main" )
643
+ debug_stats = self .get_stats ()
644
+ self .assertEqual (debug_stats ["totalLoadedDwoFileCount" ], 1 )
645
+ self .assertEqual (debug_stats ["totalDwoFileCount" ], 2 )
646
+
647
+ # Type lookup forces parsing of the CU within a.dwp corresponding to baz.dwo (contains struct Baz definition)
648
+ self .runCmd ("type lookup Baz" )
649
+ debug_stats = self .get_stats ()
650
+ self .assertEqual (debug_stats ["totalDwoFileCount" ], 2 )
651
+ self .assertEqual (debug_stats ["totalLoadedDwoFileCount" ], 2 )
652
+
515
653
516
654
@skipUnlessDarwin
517
655
@no_debug_info_test
0 commit comments