@@ -84,10 +84,12 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result
8484 let ip = context. ip ;
8585
8686 if !USING_SJLJ_EXCEPTIONS {
87+ // read the callsite table
8788 while reader. ptr < action_table {
88- let cs_start = read_encoded_pointer ( & mut reader, context, call_site_encoding) ?. addr ( ) ;
89- let cs_len = read_encoded_pointer ( & mut reader, context, call_site_encoding) ?. addr ( ) ;
90- let cs_lpad = read_encoded_pointer ( & mut reader, context, call_site_encoding) ?. addr ( ) ;
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) ?;
9193 let cs_action_entry = reader. read_uleb128 ( ) ;
9294 // Callsite table is sorted by cs_start, so if we've passed the ip, we
9395 // may stop searching.
@@ -161,23 +163,24 @@ fn round_up(unrounded: usize, align: usize) -> Result<usize, ()> {
161163 if align. is_power_of_two ( ) { Ok ( ( unrounded + align - 1 ) & !( align - 1 ) ) } else { Err ( ( ) ) }
162164}
163165
164- unsafe fn read_encoded_pointer (
165- reader : & mut DwarfReader ,
166- context : & EHContext < ' _ > ,
167- encoding : u8 ,
168- ) -> Result < * const u8 , ( ) > {
169- 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 {
170180 return Err ( ( ) ) ;
171181 }
172-
173- // DW_EH_PE_aligned implies it's an absolute pointer value
174- if encoding == DW_EH_PE_aligned {
175- reader. ptr =
176- reader. ptr . with_addr ( round_up ( reader. ptr . addr ( ) , mem:: size_of :: < * const u8 > ( ) ) ?) ;
177- return Ok ( reader. read :: < * const u8 > ( ) ) ;
178- }
179-
180- 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
181184 DW_EH_PE_absptr => reader. read :: < usize > ( ) ,
182185 DW_EH_PE_uleb128 => reader. read_uleb128 ( ) as usize ,
183186 DW_EH_PE_udata2 => reader. read :: < u16 > ( ) as usize ,
@@ -189,28 +192,66 @@ unsafe fn read_encoded_pointer(
189192 DW_EH_PE_sdata8 => reader. read :: < i64 > ( ) as usize ,
190193 _ => return Err ( ( ) ) ,
191194 } ;
195+ Ok ( result)
196+ }
192197
193- result += match encoding & 0x70 {
194- DW_EH_PE_absptr => 0 ,
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+ }
218+
219+ let base_ptr = match encoding & 0x70 {
220+ DW_EH_PE_absptr => core:: ptr:: null ( ) ,
195221 // relative to address of the encoded value, despite the name
196- DW_EH_PE_pcrel => reader. ptr . expose_addr ( ) ,
222+ DW_EH_PE_pcrel => reader. ptr ,
197223 DW_EH_PE_funcrel => {
198224 if context. func_start . is_null ( ) {
199225 return Err ( ( ) ) ;
200226 }
201- context. func_start . expose_addr ( )
227+ context. func_start
228+ }
229+ DW_EH_PE_textrel => ( * context. get_text_start ) ( ) ,
230+ 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 ( )
202236 }
203- DW_EH_PE_textrel => ( * context. get_text_start ) ( ) . expose_addr ( ) ,
204- DW_EH_PE_datarel => ( * context. get_data_start ) ( ) . expose_addr ( ) ,
205237 _ => return Err ( ( ) ) ,
206238 } ;
207239
208- // FIXME(strict provenance)
209- let mut result: * const u8 = ptr:: from_exposed_addr :: < u8 > ( result) ;
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+ } ;
210251
211252 if encoding & DW_EH_PE_indirect != 0 {
212- result = * ( result . cast :: < * const u8 > ( ) ) ;
253+ ptr = * ( ptr . cast :: < * const u8 > ( ) ) ;
213254 }
214255
215- Ok ( result )
256+ Ok ( ptr )
216257}
0 commit comments