11//! Parsing of GCC-style Language-Specific Data Area (LSDA)
22//! For details see:
33//! * <https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html>
4+ //! * <https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html>
45//! * <https://itanium-cxx-abi.github.io/cxx-abi/exceptions.pdf>
56//! * <https://www.airs.com/blog/archives/460>
67//! * <https://www.airs.com/blog/archives/464>
@@ -37,17 +38,19 @@ pub const DW_EH_PE_indirect: u8 = 0x80;
3738
3839#[ derive( Copy , Clone ) ]
3940pub struct EHContext < ' a > {
40- pub ip : usize , // Current instruction pointer
41- pub func_start : usize , // Address of the current function
42- pub get_text_start : & ' a dyn Fn ( ) -> usize , // Get address of the code section
43- pub get_data_start : & ' a dyn Fn ( ) -> usize , // Get address of the data section
41+ pub ip : * const u8 , // Current instruction pointer
42+ pub func_start : * const u8 , // Pointer to the current function
43+ pub get_text_start : & ' a dyn Fn ( ) -> * const u8 , // Get pointer to the code section
44+ pub get_data_start : & ' a dyn Fn ( ) -> * const u8 , // Get pointer to the data section
4445}
4546
47+ /// Landing pad.
48+ type LPad = * const u8 ;
4649pub enum EHAction {
4750 None ,
48- Cleanup ( usize ) ,
49- Catch ( usize ) ,
50- Filter ( usize ) ,
51+ Cleanup ( LPad ) ,
52+ Catch ( LPad ) ,
53+ Filter ( LPad ) ,
5154 Terminate ,
5255}
5356
@@ -81,22 +84,24 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
8184 let ip = context. ip ;
8285
8386 if !USING_SJLJ_EXCEPTIONS {
87+ // read the callsite table
8488 while reader. ptr < action_table {
85- let cs_start = read_encoded_pointer ( & mut reader, context, call_site_encoding) ?;
86- let cs_len = read_encoded_pointer ( & mut reader, context, call_site_encoding) ?;
87- let cs_lpad = read_encoded_pointer ( & mut reader, context, call_site_encoding) ?;
89+ // these are offsets rather than pointers;
90+ let cs_start = read_encoded_offset ( & mut reader, call_site_encoding) ?;
91+ let cs_len = read_encoded_offset ( & mut reader, call_site_encoding) ?;
92+ let cs_lpad = read_encoded_offset ( & mut reader, call_site_encoding) ?;
8893 let cs_action_entry = reader. read_uleb128 ( ) ;
8994 // Callsite table is sorted by cs_start, so if we've passed the ip, we
9095 // may stop searching.
91- if ip < func_start + cs_start {
96+ if ip < func_start. wrapping_add ( cs_start) {
9297 break ;
9398 }
94- if ip < func_start + cs_start + cs_len {
99+ if ip < func_start. wrapping_add ( cs_start + cs_len) {
95100 if cs_lpad == 0 {
96101 return Ok ( EHAction :: None ) ;
97102 } else {
98- let lpad = lpad_base + cs_lpad;
99- return Ok ( interpret_cs_action ( action_table as * mut u8 , cs_action_entry, lpad) ) ;
103+ let lpad = lpad_base. wrapping_add ( cs_lpad) ;
104+ return Ok ( interpret_cs_action ( action_table, cs_action_entry, lpad) ) ;
100105 }
101106 }
102107 }
@@ -106,30 +111,31 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
106111 // SjLj version:
107112 // The "IP" is an index into the call-site table, with two exceptions:
108113 // -1 means 'no-action', and 0 means 'terminate'.
109- match ip as isize {
114+ match ip. addr ( ) as isize {
110115 -1 => return Ok ( EHAction :: None ) ,
111116 0 => return Ok ( EHAction :: Terminate ) ,
112117 _ => ( ) ,
113118 }
114- let mut idx = ip;
119+ let mut idx = ip. addr ( ) ;
115120 loop {
116121 let cs_lpad = reader. read_uleb128 ( ) ;
117122 let cs_action_entry = reader. read_uleb128 ( ) ;
118123 idx -= 1 ;
119124 if idx == 0 {
120125 // Can never have null landing pad for sjlj -- that would have
121126 // been indicated by a -1 call site index.
122- let lpad = ( cs_lpad + 1 ) as usize ;
123- return Ok ( interpret_cs_action ( action_table as * mut u8 , cs_action_entry, lpad) ) ;
127+ // FIXME(strict provenance)
128+ let lpad = ptr:: from_exposed_addr ( ( cs_lpad + 1 ) as usize ) ;
129+ return Ok ( interpret_cs_action ( action_table, cs_action_entry, lpad) ) ;
124130 }
125131 }
126132 }
127133}
128134
129135unsafe fn interpret_cs_action (
130- action_table : * mut u8 ,
136+ action_table : * const u8 ,
131137 cs_action_entry : u64 ,
132- lpad : usize ,
138+ lpad : LPad ,
133139) -> EHAction {
134140 if cs_action_entry == 0 {
135141 // If cs_action_entry is 0 then this is a cleanup (Drop::drop). We run these
@@ -138,7 +144,7 @@ unsafe fn interpret_cs_action(
138144 } else {
139145 // If lpad != 0 and cs_action_entry != 0, we have to check ttype_index.
140146 // If ttype_index == 0 under the condition, we take cleanup action.
141- let action_record = ( action_table as * mut u8 ) . offset ( cs_action_entry as isize - 1 ) ;
147+ let action_record = action_table. offset ( cs_action_entry as isize - 1 ) ;
142148 let mut action_reader = DwarfReader :: new ( action_record) ;
143149 let ttype_index = action_reader. read_sleb128 ( ) ;
144150 if ttype_index == 0 {
@@ -157,22 +163,24 @@ fn round_up(unrounded: usize, align: usize) -> Result<usize, ()> {
157163 if align. is_power_of_two ( ) { Ok ( ( unrounded + align - 1 ) & !( align - 1 ) ) } else { Err ( ( ) ) }
158164}
159165
160- unsafe fn read_encoded_pointer (
161- reader : & mut DwarfReader ,
162- context : & EHContext < ' _ > ,
163- encoding : u8 ,
164- ) -> Result < usize , ( ) > {
165- if encoding == DW_EH_PE_omit {
166+ /// Read a offset (`usize`) from `reader` whose encoding is described by `encoding`.
167+ ///
168+ /// `encoding` must be a [DWARF Exception Header Encoding as described by the LSB spec][LSB-dwarf-ext].
169+ /// In addition the upper ("application") part must be zero.
170+ ///
171+ /// # Errors
172+ /// Returns `Err` if `encoding`
173+ /// * is not a valid DWARF Exception Header Encoding,
174+ /// * is `DW_EH_PE_omit`, or
175+ /// * has a non-zero application part.
176+ ///
177+ /// [LSB-dwarf-ext]: https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
178+ unsafe fn read_encoded_offset ( reader : & mut DwarfReader , encoding : u8 ) -> Result < usize , ( ) > {
179+ if encoding == DW_EH_PE_omit || encoding & 0xF0 != 0 {
166180 return Err ( ( ) ) ;
167181 }
168-
169- // DW_EH_PE_aligned implies it's an absolute pointer value
170- if encoding == DW_EH_PE_aligned {
171- reader. ptr = reader. ptr . with_addr ( round_up ( reader. ptr . addr ( ) , mem:: size_of :: < usize > ( ) ) ?) ;
172- return Ok ( reader. read :: < usize > ( ) ) ;
173- }
174-
175- let mut result = match encoding & 0x0F {
182+ let result = match encoding & 0x0F {
183+ // despite the name, LLVM also uses absptr for offsets instead of pointers
176184 DW_EH_PE_absptr => reader. read :: < usize > ( ) ,
177185 DW_EH_PE_uleb128 => reader. read_uleb128 ( ) as usize ,
178186 DW_EH_PE_udata2 => reader. read :: < u16 > ( ) as usize ,
@@ -184,25 +192,66 @@ unsafe fn read_encoded_pointer(
184192 DW_EH_PE_sdata8 => reader. read :: < i64 > ( ) as usize ,
185193 _ => return Err ( ( ) ) ,
186194 } ;
195+ Ok ( result)
196+ }
197+
198+ /// Read a pointer from `reader` whose encoding is described by `encoding`.
199+ ///
200+ /// `encoding` must be a [DWARF Exception Header Encoding as described by the LSB spec][LSB-dwarf-ext].
201+ ///
202+ /// # Errors
203+ /// Returns `Err` if `encoding`
204+ /// * is not a valid DWARF Exception Header Encoding,
205+ /// * is `DW_EH_PE_omit`, or
206+ /// * combines `DW_EH_PE_absptr` or `DW_EH_PE_aligned` application part with an integer encoding
207+ /// (not `DW_EH_PE_absptr`) in the value format part.
208+ ///
209+ /// [LSB-dwarf-ext]: https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
210+ unsafe fn read_encoded_pointer (
211+ reader : & mut DwarfReader ,
212+ context : & EHContext < ' _ > ,
213+ encoding : u8 ,
214+ ) -> Result < * const u8 , ( ) > {
215+ if encoding == DW_EH_PE_omit {
216+ return Err ( ( ) ) ;
217+ }
187218
188- result + = match encoding & 0x70 {
189- DW_EH_PE_absptr => 0 ,
219+ let base_ptr = match encoding & 0x70 {
220+ DW_EH_PE_absptr => core :: ptr :: null ( ) ,
190221 // relative to address of the encoded value, despite the name
191- DW_EH_PE_pcrel => reader. ptr . expose_addr ( ) ,
222+ DW_EH_PE_pcrel => reader. ptr ,
192223 DW_EH_PE_funcrel => {
193- if context. func_start == 0 {
224+ if context. func_start . is_null ( ) {
194225 return Err ( ( ) ) ;
195226 }
196227 context. func_start
197228 }
198229 DW_EH_PE_textrel => ( * context. get_text_start ) ( ) ,
199230 DW_EH_PE_datarel => ( * context. get_data_start ) ( ) ,
231+ // aligned means the value is aligned to the size of a pointer
232+ DW_EH_PE_aligned => {
233+ reader. ptr =
234+ reader. ptr . with_addr ( round_up ( reader. ptr . addr ( ) , mem:: size_of :: < * const u8 > ( ) ) ?) ;
235+ core:: ptr:: null ( )
236+ }
200237 _ => return Err ( ( ) ) ,
201238 } ;
202239
240+ let mut ptr = if base_ptr. is_null ( ) {
241+ // any value encoding other than absptr would be nonsensical here;
242+ // there would be no source of pointer provenance
243+ if encoding & 0x0F != DW_EH_PE_absptr {
244+ return Err ( ( ) ) ;
245+ }
246+ reader. read :: < * const u8 > ( )
247+ } else {
248+ let offset = read_encoded_offset ( reader, encoding & 0x0F ) ?;
249+ base_ptr. wrapping_add ( offset)
250+ } ;
251+
203252 if encoding & DW_EH_PE_indirect != 0 {
204- result = * ptr:: from_exposed_addr :: < usize > ( result ) ;
253+ ptr = * ( ptr. cast :: < * const u8 > ( ) ) ;
205254 }
206255
207- Ok ( result )
256+ Ok ( ptr )
208257}
0 commit comments