@@ -5,13 +5,32 @@ use std::collections::HashMap;
5
5
use std:: path:: PathBuf ;
6
6
use std:: rc:: Rc ;
7
7
8
+ use gimli:: read:: DebuggingInformationEntry ;
8
9
use gimli:: { AttributeValue , EndianRcSlice , Reader , RunTimeEndian } ;
9
10
use object:: { Object , ObjectSection } ;
10
11
use run_make_support:: { gimli, object, rfs, rustc} ;
11
12
12
13
fn main ( ) {
14
+ // Before LLVM 20, 128-bit enums with variants didn't emit debuginfo correctly.
15
+ // This check can be removed once Rust no longer supports LLVM 18 and 19.
16
+ let llvm_version = rustc ( )
17
+ . verbose ( )
18
+ . arg ( "--version" )
19
+ . run ( )
20
+ . stdout_utf8 ( )
21
+ . lines ( )
22
+ . filter_map ( |line| line. strip_prefix ( "LLVM version: " ) )
23
+ . map ( |version| version. split ( "." ) . next ( ) . unwrap ( ) . parse :: < u32 > ( ) . unwrap ( ) )
24
+ . next ( )
25
+ . unwrap ( ) ;
26
+ let is_old_llvm = llvm_version < 20 ;
27
+
13
28
let output = PathBuf :: from ( "repr128" ) ;
14
- rustc ( ) . input ( "main.rs" ) . output ( & output) . arg ( "-Cdebuginfo=2" ) . run ( ) ;
29
+ let mut rustc = rustc ( ) ;
30
+ if is_old_llvm {
31
+ rustc. cfg ( "old_llvm" ) ;
32
+ }
33
+ rustc. input ( "main.rs" ) . output ( & output) . arg ( "-Cdebuginfo=2" ) . run ( ) ;
15
34
// Mach-O uses packed debug info
16
35
let dsym_location = output
17
36
. with_extension ( "dSYM" )
@@ -29,7 +48,8 @@ fn main() {
29
48
} )
30
49
. unwrap ( ) ;
31
50
let mut iter = dwarf. units ( ) ;
32
- let mut still_to_find = HashMap :: from ( [
51
+
52
+ let mut enumerators_to_find = HashMap :: from ( [
33
53
( "U128A" , 0_u128 ) ,
34
54
( "U128B" , 1_u128 ) ,
35
55
( "U128C" , u64:: MAX as u128 + 1 ) ,
@@ -39,35 +59,88 @@ fn main() {
39
59
( "I128C" , i128:: MIN as u128 ) ,
40
60
( "I128D" , i128:: MAX as u128 ) ,
41
61
] ) ;
62
+ let mut variants_to_find = HashMap :: from ( [
63
+ ( "VariantU128A" , 0_u128 ) ,
64
+ ( "VariantU128B" , 1_u128 ) ,
65
+ ( "VariantU128C" , u64:: MAX as u128 + 1 ) ,
66
+ ( "VariantU128D" , u128:: MAX ) ,
67
+ ( "VariantI128A" , 0_i128 as u128 ) ,
68
+ ( "VariantI128B" , ( -1_i128 ) as u128 ) ,
69
+ ( "VariantI128C" , i128:: MIN as u128 ) ,
70
+ ( "VariantI128D" , i128:: MAX as u128 ) ,
71
+ ] ) ;
72
+
42
73
while let Some ( header) = iter. next ( ) . unwrap ( ) {
43
74
let unit = dwarf. unit ( header) . unwrap ( ) ;
44
75
let mut cursor = unit. entries ( ) ;
76
+
77
+ let get_name = |entry : & DebuggingInformationEntry < ' _ , ' _ , _ > | {
78
+ let name = dwarf
79
+ . attr_string (
80
+ & unit,
81
+ entry. attr ( gimli:: constants:: DW_AT_name ) . unwrap ( ) . unwrap ( ) . value ( ) ,
82
+ )
83
+ . unwrap ( ) ;
84
+ name. to_string ( ) . unwrap ( ) . to_string ( )
85
+ } ;
86
+
45
87
while let Some ( ( _, entry) ) = cursor. next_dfs ( ) . unwrap ( ) {
46
- if entry. tag ( ) == gimli:: constants:: DW_TAG_enumerator {
47
- let name = dwarf
48
- . attr_string (
49
- & unit,
50
- entry. attr ( gimli:: constants:: DW_AT_name ) . unwrap ( ) . unwrap ( ) . value ( ) ,
51
- )
52
- . unwrap ( ) ;
53
- let name = name. to_string ( ) . unwrap ( ) ;
54
- if let Some ( expected) = still_to_find. remove ( name. as_ref ( ) ) {
55
- match entry. attr ( gimli:: constants:: DW_AT_const_value ) . unwrap ( ) . unwrap ( ) . value ( )
88
+ match entry. tag ( ) {
89
+ gimli:: constants:: DW_TAG_variant if !is_old_llvm => {
90
+ let value = match entry
91
+ . attr ( gimli:: constants:: DW_AT_discr_value )
92
+ . unwrap ( )
93
+ . unwrap ( )
94
+ . value ( )
56
95
{
57
- AttributeValue :: Block ( value) => {
58
- assert_eq ! (
59
- value. to_slice( ) . unwrap( ) ,
60
- expected. to_le_bytes( ) . as_slice( ) ,
61
- "{name}"
62
- ) ;
96
+ AttributeValue :: Block ( value) => value. to_slice ( ) . unwrap ( ) . to_vec ( ) ,
97
+ value => panic ! ( "unexpected DW_AT_discr_value of {value:?}" ) ,
98
+ } ;
99
+ // The `DW_TAG_member` that is a child of `DW_TAG_variant` will contain the
100
+ // variant's name.
101
+ let Some ( ( 1 , child_entry) ) = cursor. next_dfs ( ) . unwrap ( ) else {
102
+ panic ! ( "Missing child of DW_TAG_variant" ) ;
103
+ } ;
104
+ assert_eq ! ( child_entry. tag( ) , gimli:: constants:: DW_TAG_member ) ;
105
+ let name = get_name ( child_entry) ;
106
+ if let Some ( expected) = variants_to_find. remove ( name. as_str ( ) ) {
107
+ // This test uses LE byte order is used for consistent values across
108
+ // architectures.
109
+ assert_eq ! ( value. as_slice( ) , expected. to_le_bytes( ) . as_slice( ) , "{name}" ) ;
110
+ }
111
+ }
112
+
113
+ gimli:: constants:: DW_TAG_enumerator => {
114
+ let name = get_name ( entry) ;
115
+ if let Some ( expected) = enumerators_to_find. remove ( name. as_str ( ) ) {
116
+ match entry
117
+ . attr ( gimli:: constants:: DW_AT_const_value )
118
+ . unwrap ( )
119
+ . unwrap ( )
120
+ . value ( )
121
+ {
122
+ AttributeValue :: Block ( value) => {
123
+ // This test uses LE byte order is used for consistent values across
124
+ // architectures.
125
+ assert_eq ! (
126
+ value. to_slice( ) . unwrap( ) ,
127
+ expected. to_le_bytes( ) . as_slice( ) ,
128
+ "{name}"
129
+ ) ;
130
+ }
131
+ value => panic ! ( "{name}: unexpected DW_AT_const_value of {value:?}" ) ,
63
132
}
64
- value => panic ! ( "{name}: unexpected DW_AT_const_value of {value:?}" ) ,
65
133
}
66
134
}
135
+
136
+ _ => { }
67
137
}
68
138
}
69
139
}
70
- if !still_to_find. is_empty ( ) {
71
- panic ! ( "Didn't find debug entries for {still_to_find:?}" ) ;
140
+ if !enumerators_to_find. is_empty ( ) {
141
+ panic ! ( "Didn't find debug enumerator entries for {enumerators_to_find:?}" ) ;
142
+ }
143
+ if !is_old_llvm && !variants_to_find. is_empty ( ) {
144
+ panic ! ( "Didn't find debug variant entries for {variants_to_find:?}" ) ;
72
145
}
73
146
}
0 commit comments