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