@@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
1414limitations under the License. 
1515*/ 
1616
17+ #[ cfg( feature = "unwind_guest" ) ]  
18+ use  std:: sync:: Arc ; 
19+ 
1720#[ cfg( target_arch = "aarch64" ) ]  
1821use  goblin:: elf:: reloc:: { R_AARCH64_NONE ,  R_AARCH64_RELATIVE } ; 
1922#[ cfg( target_arch = "x86_64" ) ]  
@@ -23,13 +26,85 @@ use goblin::elf64::program_header::PT_LOAD;
2326
2427use  crate :: { log_then_return,  new_error,  Result } ; 
2528
29+ #[ cfg( feature = "unwind_guest" ) ]  
30+ struct  ResolvedSectionHeader  { 
31+     name :  String , 
32+     addr :  u64 , 
33+     offset :  u64 , 
34+     size :  u64 , 
35+ } 
36+ 
2637pub ( crate )  struct  ElfInfo  { 
2738    payload :  Vec < u8 > , 
2839    phdrs :  ProgramHeaders , 
40+     #[ cfg( feature = "unwind_guest" ) ]  
41+     shdrs :  Vec < ResolvedSectionHeader > , 
2942    entry :  u64 , 
3043    relocs :  Vec < Reloc > , 
3144} 
3245
46+ #[ cfg( feature = "unwind_guest" ) ]  
47+ struct  UnwindInfo  { 
48+     payload :  Vec < u8 > , 
49+     load_addr :  u64 , 
50+     va_size :  u64 , 
51+     base_svma :  u64 , 
52+     shdrs :  Vec < ResolvedSectionHeader > , 
53+ } 
54+ 
55+ #[ cfg( feature = "unwind_guest" ) ]  
56+ impl  super :: exe:: UnwindInfo  for  UnwindInfo  { 
57+     fn  as_module ( & self )  -> framehop:: Module < Vec < u8 > >  { 
58+         framehop:: Module :: new ( 
59+             // TODO: plumb through a name from from_file if this 
60+             // came from a file 
61+             "guest" . to_string ( ) , 
62+             self . load_addr ..self . load_addr  + self . va_size , 
63+             self . load_addr , 
64+             self , 
65+         ) 
66+     } 
67+     fn  hash ( & self )  -> blake3:: Hash  { 
68+         blake3:: hash ( & self . payload ) 
69+     } 
70+ } 
71+ 
72+ #[ cfg( feature = "unwind_guest" ) ]  
73+ impl  UnwindInfo  { 
74+     fn  resolved_section_header ( & self ,  name :  & [ u8 ] )  -> Option < & ResolvedSectionHeader >  { 
75+         self . shdrs 
76+             . iter ( ) 
77+             . find ( |& sh| sh. name . as_bytes ( ) [ 0 ..core:: cmp:: min ( name. len ( ) ,  sh. name . len ( ) ) ]  == * name) 
78+     } 
79+ } 
80+ 
81+ #[ cfg( feature = "unwind_guest" ) ]  
82+ impl  framehop:: ModuleSectionInfo < Vec < u8 > >  for  & UnwindInfo  { 
83+     fn  base_svma ( & self )  -> u64  { 
84+         self . base_svma 
85+     } 
86+     fn  section_svma_range ( & mut  self ,  name :  & [ u8 ] )  -> Option < std:: ops:: Range < u64 > >  { 
87+         let  shdr = self . resolved_section_header ( name) ?; 
88+         Some ( shdr. addr ..shdr. addr  + shdr. size ) 
89+     } 
90+     fn  section_data ( & mut  self ,  name :  & [ u8 ] )  -> Option < Vec < u8 > >  { 
91+         if  name == b".eh_frame"  && self . resolved_section_header ( b".debug_frame" ) . is_some ( )  { 
92+             /* Rustc does not always emit enough information for stack 
93+              * unwinding in .eh_frame, presumably because we use panic = 
94+              * abort in the guest. Framehop defaults to ignoring 
95+              * .debug_frame if .eh_frame exists, but we want the opposite 
96+              * behaviour here, since .debug_frame will actually contain 
97+              * frame information whereas .eh_frame often doesn't because 
98+              * of the aforementioned behaviour.  Consequently, we hack 
99+              * around this by pretending that .eh_frame doesn't exist if 
100+              * .debug_frame does. */ 
101+             return  None ; 
102+         } 
103+         let  shdr = self . resolved_section_header ( name) ?; 
104+         Some ( self . payload [ shdr. offset  as  usize ..( shdr. offset  + shdr. size )  as  usize ] . to_vec ( ) ) 
105+     } 
106+ } 
107+ 
33108impl  ElfInfo  { 
34109    pub ( crate )  fn  new ( bytes :  & [ u8 ] )  -> Result < Self >  { 
35110        let  elf = Elf :: parse ( bytes) ?; 
@@ -44,6 +119,19 @@ impl ElfInfo {
44119        Ok ( ElfInfo  { 
45120            payload :  bytes. to_vec ( ) , 
46121            phdrs :  elf. program_headers , 
122+             #[ cfg( feature = "unwind_guest" ) ]  
123+             shdrs :  elf
124+                 . section_headers 
125+                 . iter ( ) 
126+                 . filter_map ( |sh| { 
127+                     Some ( ResolvedSectionHeader  { 
128+                         name :  elf. shdr_strtab . get_at ( sh. sh_name ) ?. to_string ( ) , 
129+                         addr :  sh. sh_addr , 
130+                         offset :  sh. sh_offset , 
131+                         size :  sh. sh_size , 
132+                     } ) 
133+                 } ) 
134+                 . collect ( ) , 
47135            entry :  elf. entry , 
48136            relocs, 
49137        } ) 
@@ -68,7 +156,11 @@ impl ElfInfo {
68156            . unwrap ( ) ;  // guaranteed not to panic because of the check in new() 
69157        ( max_phdr. p_vaddr  + max_phdr. p_memsz  - self . get_base_va ( ) )  as  usize 
70158    } 
71-     pub ( crate )  fn  load_at ( self ,  load_addr :  usize ,  target :  & mut  [ u8 ] )  -> Result < ( ) >  { 
159+     pub ( crate )  fn  load_at ( 
160+         self , 
161+         load_addr :  usize , 
162+         target :  & mut  [ u8 ] , 
163+     )  -> Result < super :: exe:: LoadInfo >  { 
72164        let  base_va = self . get_base_va ( ) ; 
73165        for  phdr in  self . phdrs . iter ( ) . filter ( |phdr| phdr. p_type  == PT_LOAD )  { 
74166            let  start_va = ( phdr. p_vaddr  - base_va)  as  usize ; 
@@ -108,6 +200,20 @@ impl ElfInfo {
108200                } 
109201            } 
110202        } 
111-         Ok ( ( ) ) 
203+         cfg_if:: cfg_if! { 
204+             if  #[ cfg( feature = "unwind_guest" ) ]  { 
205+                 let  va_size = self . get_va_size( )  as  u64 ; 
206+                 let  base_svma = self . get_base_va( ) ; 
207+                 Ok ( Arc :: new( UnwindInfo  { 
208+                     payload:  self . payload, 
209+                     load_addr:  load_addr as  u64 , 
210+                     va_size, 
211+                     base_svma, 
212+                     shdrs:  self . shdrs, 
213+                 } ) ) 
214+             }  else { 
215+                 Ok ( ( ) ) 
216+             } 
217+         } 
112218    } 
113219} 
0 commit comments