@@ -25,6 +25,7 @@ static int process_linebreak(struct die *cache, int n)
25
25
!dwarf_form##attr(&da, value); \
26
26
}
27
27
28
+ DEFINE_GET_ATTR (flag , bool )
28
29
DEFINE_GET_ATTR (udata , Dwarf_Word )
29
30
30
31
static bool get_ref_die_attr (Dwarf_Die * die , unsigned int id , Dwarf_Die * value )
@@ -69,6 +70,13 @@ static bool is_export_symbol(struct state *state, Dwarf_Die *die)
69
70
return !!state -> sym ;
70
71
}
71
72
73
+ static bool is_declaration (Dwarf_Die * die )
74
+ {
75
+ bool value ;
76
+
77
+ return get_flag_attr (die , DW_AT_declaration , & value ) && value ;
78
+ }
79
+
72
80
/*
73
81
* Type string processing
74
82
*/
@@ -421,19 +429,26 @@ static int __process_structure_type(struct state *state, struct die *cache,
421
429
die_callback_t process_func ,
422
430
die_match_callback_t match_func )
423
431
{
432
+ bool is_decl = is_declaration (die );
433
+
424
434
check (process (state , cache , type ));
425
435
check (process_fqn (state , cache , die ));
426
436
check (process (state , cache , " {" ));
427
437
check (process_linebreak (cache , 1 ));
428
438
429
- check (process_die_container (state , cache , die , process_func ,
430
- match_func ));
439
+ if (!is_decl && state -> expand .expand ) {
440
+ check (cache_mark_expanded (& state -> expansion_cache , die -> addr ));
441
+ check (process_die_container (state , cache , die , process_func ,
442
+ match_func ));
443
+ }
431
444
432
445
check (process_linebreak (cache , -1 ));
433
446
check (process (state , cache , "}" ));
434
447
435
- check (process_byte_size_attr (state , cache , die ));
436
- check (process_alignment_attr (state , cache , die ));
448
+ if (!is_decl && state -> expand .expand ) {
449
+ check (process_byte_size_attr (state , cache , die ));
450
+ check (process_alignment_attr (state , cache , die ));
451
+ }
437
452
438
453
return 0 ;
439
454
}
@@ -519,25 +534,99 @@ static int process_cached(struct state *state, struct die *cache,
519
534
return 0 ;
520
535
}
521
536
537
+ static void state_init (struct state * state )
538
+ {
539
+ state -> expand .expand = true;
540
+ state -> expand .in_pointer_type = false;
541
+ state -> expand .ptr_expansion_depth = 0 ;
542
+ hash_init (state -> expansion_cache .cache );
543
+ }
544
+
545
+ static void expansion_state_restore (struct expansion_state * state ,
546
+ struct expansion_state * saved )
547
+ {
548
+ state -> ptr_expansion_depth = saved -> ptr_expansion_depth ;
549
+ state -> in_pointer_type = saved -> in_pointer_type ;
550
+ state -> expand = saved -> expand ;
551
+ }
552
+
553
+ static void expansion_state_save (struct expansion_state * state ,
554
+ struct expansion_state * saved )
555
+ {
556
+ expansion_state_restore (saved , state );
557
+ }
558
+
559
+ static bool is_pointer_type (int tag )
560
+ {
561
+ return tag == DW_TAG_pointer_type || tag == DW_TAG_reference_type ;
562
+ }
563
+
564
+ static bool is_expanded_type (int tag )
565
+ {
566
+ return tag == DW_TAG_class_type || tag == DW_TAG_structure_type ||
567
+ tag == DW_TAG_union_type || tag == DW_TAG_enumeration_type ;
568
+ }
569
+
570
+ /* The maximum depth for expanding structures in pointers */
571
+ #define MAX_POINTER_EXPANSION_DEPTH 2
572
+
522
573
#define PROCESS_TYPE (type ) \
523
574
case DW_TAG_##type##_type: \
524
575
check(process_##type##_type(state, cache, die)); \
525
576
break;
526
577
527
578
static int process_type (struct state * state , struct die * parent , Dwarf_Die * die )
528
579
{
580
+ enum die_state want_state = COMPLETE ;
529
581
struct die * cache = NULL ;
582
+ struct expansion_state saved ;
530
583
int tag = dwarf_tag (die );
531
584
585
+ expansion_state_save (& state -> expand , & saved );
586
+
532
587
/*
533
- * If we have the DIE already cached, use it instead of walking
588
+ * Structures and enumeration types are expanded only once per
589
+ * exported symbol. This is sufficient for detecting ABI changes
590
+ * within the structure.
591
+ *
592
+ * If the exported symbol contains a pointer to a structure,
593
+ * at most MAX_POINTER_EXPANSION_DEPTH levels are expanded into
594
+ * the referenced structure.
595
+ */
596
+ state -> expand .in_pointer_type = saved .in_pointer_type ||
597
+ is_pointer_type (tag );
598
+
599
+ if (state -> expand .in_pointer_type &&
600
+ state -> expand .ptr_expansion_depth >= MAX_POINTER_EXPANSION_DEPTH )
601
+ state -> expand .expand = false;
602
+ else
603
+ state -> expand .expand =
604
+ saved .expand &&
605
+ !cache_was_expanded (& state -> expansion_cache , die -> addr );
606
+
607
+ /* Keep track of pointer expansion depth */
608
+ if (state -> expand .expand && state -> expand .in_pointer_type &&
609
+ is_expanded_type (tag ))
610
+ state -> expand .ptr_expansion_depth ++ ;
611
+
612
+ /*
613
+ * If we have want_state already cached, use it instead of walking
534
614
* through DWARF.
535
615
*/
536
- check (die_map_get (die , COMPLETE , & cache ));
616
+ if (!state -> expand .expand && is_expanded_type (tag ))
617
+ want_state = UNEXPANDED ;
618
+
619
+ check (die_map_get (die , want_state , & cache ));
620
+
621
+ if (cache -> state == want_state ) {
622
+ if (want_state == COMPLETE && is_expanded_type (tag ))
623
+ check (cache_mark_expanded (& state -> expansion_cache ,
624
+ die -> addr ));
537
625
538
- if (cache -> state == COMPLETE ) {
539
626
check (process_cached (state , cache , die ));
540
627
check (die_map_add_die (parent , cache ));
628
+
629
+ expansion_state_restore (& state -> expand , & saved );
541
630
return 0 ;
542
631
}
543
632
@@ -578,9 +667,10 @@ static int process_type(struct state *state, struct die *parent, Dwarf_Die *die)
578
667
579
668
/* Update cache state and append to the parent (if any) */
580
669
cache -> tag = tag ;
581
- cache -> state = COMPLETE ;
670
+ cache -> state = want_state ;
582
671
check (die_map_add_die (parent , cache ));
583
672
673
+ expansion_state_restore (& state -> expand , & saved );
584
674
return 0 ;
585
675
}
586
676
@@ -643,6 +733,7 @@ static int process_exported_symbols(struct state *state, struct die *cache,
643
733
return 0 ;
644
734
645
735
debug ("%s" , state -> sym -> name );
736
+ state_init (state );
646
737
647
738
if (is_symbol_ptr (get_name (& state -> die )))
648
739
check (process_symbol_ptr (state , & state -> die ));
@@ -651,6 +742,7 @@ static int process_exported_symbols(struct state *state, struct die *cache,
651
742
else
652
743
check (process_variable (state , & state -> die ));
653
744
745
+ cache_clear_expanded (& state -> expansion_cache );
654
746
return 0 ;
655
747
default :
656
748
return 0 ;
0 commit comments