33// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44
55use crate :: core:: Core ;
6- use crate :: hubris:: HubrisArchive ;
7- use anyhow:: { Result , anyhow, bail} ;
6+ use crate :: hubris:: OXIDE_NT_HUBRIS_REGISTERS ;
7+ use anyhow:: { Context , Result , anyhow, bail} ;
88use goblin:: elf:: Elf ;
99use humility_arch_arm:: ARMRegister ;
10+ use num_traits:: FromPrimitive ;
1011use std:: collections:: { BTreeMap , HashMap } ;
1112use std:: fs:: File ;
1213use std:: io:: Read ;
@@ -15,11 +16,11 @@ use std::path::Path;
1516pub struct DumpCore {
1617 contents : Vec < u8 > ,
1718 regions : BTreeMap < u32 , ( u32 , usize ) > ,
18- registers : HashMap < ARMRegister , u32 > ,
19+ registers : Option < HashMap < ARMRegister , u32 > > ,
1920}
2021
2122impl DumpCore {
22- pub ( crate ) fn new ( dump : & str , hubris : & HubrisArchive ) -> Result < DumpCore > {
23+ pub ( crate ) fn new ( dump : & str ) -> Result < DumpCore > {
2324 let mut file = File :: open ( dump) ?;
2425 let mut regions = BTreeMap :: new ( ) ;
2526
@@ -41,7 +42,23 @@ impl DumpCore {
4142 ) ;
4243 }
4344
44- Ok ( Self { contents, regions, registers : hubris. dump_registers ( ) } )
45+ let mut registers = None ;
46+ if let Some ( notes) = elf. iter_note_headers ( & contents) {
47+ for note in notes {
48+ let note = note. context ( "failed to parse note" ) ?;
49+ if note. n_type == OXIDE_NT_HUBRIS_REGISTERS {
50+ if registers. is_some ( ) {
51+ bail ! (
52+ "multiple copies of OXIDE_NT_HUBRIS_REGISTERS \
53+ found in dump"
54+ ) ;
55+ }
56+ registers = Some ( load_registers ( note. desc ) ?) ;
57+ }
58+ }
59+ }
60+
61+ Ok ( Self { contents, regions, registers } )
4562 }
4663
4764 fn check_offset ( & self , addr : u32 , rsize : usize , offs : usize ) -> Result < ( ) > {
@@ -67,6 +84,38 @@ impl DumpCore {
6784 }
6885}
6986
87+ fn load_registers ( r : & [ u8 ] ) -> Result < HashMap < ARMRegister , u32 > > {
88+ if !r. len ( ) . is_multiple_of ( 8 ) {
89+ bail ! ( "bad length {} in registers note" , r. len( ) ) ;
90+ }
91+ let mut registers = HashMap :: new ( ) ;
92+ for ( i, chunk) in r. chunks_exact ( 8 ) . enumerate ( ) {
93+ let ( id, val) = chunk. split_at ( 4 ) ;
94+ // We unwrap here because it can only fail if the length is wrong,
95+ // but we've explicitly broken a chunk of 8 into two chunks of 4,
96+ // so a failure here would mean this code has been changed.
97+ let id = u32:: from_le_bytes ( id. try_into ( ) . unwrap ( ) ) ;
98+ let val = u32:: from_le_bytes ( val. try_into ( ) . unwrap ( ) ) ;
99+
100+ let reg = match ARMRegister :: from_u32 ( id) {
101+ Some ( r) => r,
102+ None => {
103+ // This can totally happen if we encounter a future coredump
104+ // where we decided to store, say, additional MSRs or a
105+ // floating point register. Since this version of Humility
106+ // doesn't understand them, we'll just skip it.
107+ continue ;
108+ }
109+ } ;
110+
111+ if registers. insert ( reg, val) . is_some ( ) {
112+ bail ! ( "duplicate register {} ({}) at offset {}" , reg, id, i * 8 ) ;
113+ }
114+ }
115+
116+ Ok ( registers)
117+ }
118+
70119#[ rustfmt:: skip:: macros( bail) ]
71120impl Core for DumpCore {
72121 fn info ( & self ) -> ( String , Option < String > ) {
@@ -114,10 +163,15 @@ impl Core for DumpCore {
114163 }
115164
116165 fn read_reg ( & mut self , reg : ARMRegister ) -> Result < u32 > {
117- if let Some ( val) = self . registers . get ( & reg) {
118- Ok ( * val)
119- } else {
120- bail ! ( "register {} not found in dump" , reg) ;
166+ match & self . registers {
167+ Some ( regs) => {
168+ if let Some ( val) = regs. get ( & reg) {
169+ Ok ( * val)
170+ } else {
171+ bail ! ( "register {} not found in dump" , reg) ;
172+ }
173+ }
174+ None => bail ! ( "dump does not include register info" ) ,
121175 }
122176 }
123177
0 commit comments