xref: /aosp_15_r20/system/unwinding/libunwindstack/DwarfMemory.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
1*eb293b8fSAndroid Build Coastguard Worker /*
2*eb293b8fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*eb293b8fSAndroid Build Coastguard Worker  *
4*eb293b8fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*eb293b8fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*eb293b8fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*eb293b8fSAndroid Build Coastguard Worker  *
8*eb293b8fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*eb293b8fSAndroid Build Coastguard Worker  *
10*eb293b8fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*eb293b8fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*eb293b8fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*eb293b8fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*eb293b8fSAndroid Build Coastguard Worker  * limitations under the License.
15*eb293b8fSAndroid Build Coastguard Worker  */
16*eb293b8fSAndroid Build Coastguard Worker 
17*eb293b8fSAndroid Build Coastguard Worker #include <stdint.h>
18*eb293b8fSAndroid Build Coastguard Worker 
19*eb293b8fSAndroid Build Coastguard Worker #include <string>
20*eb293b8fSAndroid Build Coastguard Worker 
21*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/DwarfMemory.h>
22*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Memory.h>
23*eb293b8fSAndroid Build Coastguard Worker 
24*eb293b8fSAndroid Build Coastguard Worker #include "Check.h"
25*eb293b8fSAndroid Build Coastguard Worker #include "DwarfEncoding.h"
26*eb293b8fSAndroid Build Coastguard Worker 
27*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
28*eb293b8fSAndroid Build Coastguard Worker 
ReadBytes(void * dst,size_t num_bytes)29*eb293b8fSAndroid Build Coastguard Worker bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
30*eb293b8fSAndroid Build Coastguard Worker   if (!memory_->ReadFully(cur_offset_, dst, num_bytes)) {
31*eb293b8fSAndroid Build Coastguard Worker     return false;
32*eb293b8fSAndroid Build Coastguard Worker   }
33*eb293b8fSAndroid Build Coastguard Worker   cur_offset_ += num_bytes;
34*eb293b8fSAndroid Build Coastguard Worker   return true;
35*eb293b8fSAndroid Build Coastguard Worker }
36*eb293b8fSAndroid Build Coastguard Worker 
37*eb293b8fSAndroid Build Coastguard Worker template <typename SignedType>
ReadSigned(uint64_t * value)38*eb293b8fSAndroid Build Coastguard Worker bool DwarfMemory::ReadSigned(uint64_t* value) {
39*eb293b8fSAndroid Build Coastguard Worker   SignedType signed_value;
40*eb293b8fSAndroid Build Coastguard Worker   if (!ReadBytes(&signed_value, sizeof(SignedType))) {
41*eb293b8fSAndroid Build Coastguard Worker     return false;
42*eb293b8fSAndroid Build Coastguard Worker   }
43*eb293b8fSAndroid Build Coastguard Worker   *value = static_cast<int64_t>(signed_value);
44*eb293b8fSAndroid Build Coastguard Worker   return true;
45*eb293b8fSAndroid Build Coastguard Worker }
46*eb293b8fSAndroid Build Coastguard Worker 
ReadULEB128(uint64_t * value)47*eb293b8fSAndroid Build Coastguard Worker bool DwarfMemory::ReadULEB128(uint64_t* value) {
48*eb293b8fSAndroid Build Coastguard Worker   uint64_t cur_value = 0;
49*eb293b8fSAndroid Build Coastguard Worker   uint64_t shift = 0;
50*eb293b8fSAndroid Build Coastguard Worker   uint8_t byte;
51*eb293b8fSAndroid Build Coastguard Worker   do {
52*eb293b8fSAndroid Build Coastguard Worker     if (!ReadBytes(&byte, 1)) {
53*eb293b8fSAndroid Build Coastguard Worker       return false;
54*eb293b8fSAndroid Build Coastguard Worker     }
55*eb293b8fSAndroid Build Coastguard Worker     cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
56*eb293b8fSAndroid Build Coastguard Worker     shift += 7;
57*eb293b8fSAndroid Build Coastguard Worker   } while (byte & 0x80);
58*eb293b8fSAndroid Build Coastguard Worker   *value = cur_value;
59*eb293b8fSAndroid Build Coastguard Worker   return true;
60*eb293b8fSAndroid Build Coastguard Worker }
61*eb293b8fSAndroid Build Coastguard Worker 
ReadSLEB128(int64_t * value)62*eb293b8fSAndroid Build Coastguard Worker bool DwarfMemory::ReadSLEB128(int64_t* value) {
63*eb293b8fSAndroid Build Coastguard Worker   uint64_t cur_value = 0;
64*eb293b8fSAndroid Build Coastguard Worker   uint64_t shift = 0;
65*eb293b8fSAndroid Build Coastguard Worker   uint8_t byte;
66*eb293b8fSAndroid Build Coastguard Worker   do {
67*eb293b8fSAndroid Build Coastguard Worker     if (!ReadBytes(&byte, 1)) {
68*eb293b8fSAndroid Build Coastguard Worker       return false;
69*eb293b8fSAndroid Build Coastguard Worker     }
70*eb293b8fSAndroid Build Coastguard Worker     cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
71*eb293b8fSAndroid Build Coastguard Worker     shift += 7;
72*eb293b8fSAndroid Build Coastguard Worker   } while (byte & 0x80);
73*eb293b8fSAndroid Build Coastguard Worker   if (byte & 0x40) {
74*eb293b8fSAndroid Build Coastguard Worker     // Negative value, need to sign extend.
75*eb293b8fSAndroid Build Coastguard Worker     cur_value |= static_cast<uint64_t>(-1) << shift;
76*eb293b8fSAndroid Build Coastguard Worker   }
77*eb293b8fSAndroid Build Coastguard Worker   *value = static_cast<int64_t>(cur_value);
78*eb293b8fSAndroid Build Coastguard Worker   return true;
79*eb293b8fSAndroid Build Coastguard Worker }
80*eb293b8fSAndroid Build Coastguard Worker 
81*eb293b8fSAndroid Build Coastguard Worker template <typename AddressType>
GetEncodedSize(uint8_t encoding)82*eb293b8fSAndroid Build Coastguard Worker size_t DwarfMemory::GetEncodedSize(uint8_t encoding) {
83*eb293b8fSAndroid Build Coastguard Worker   switch (encoding & 0x0f) {
84*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_absptr:
85*eb293b8fSAndroid Build Coastguard Worker       return sizeof(AddressType);
86*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_udata1:
87*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sdata1:
88*eb293b8fSAndroid Build Coastguard Worker       return 1;
89*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_udata2:
90*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sdata2:
91*eb293b8fSAndroid Build Coastguard Worker       return 2;
92*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_udata4:
93*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sdata4:
94*eb293b8fSAndroid Build Coastguard Worker       return 4;
95*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_udata8:
96*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sdata8:
97*eb293b8fSAndroid Build Coastguard Worker       return 8;
98*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_uleb128:
99*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sleb128:
100*eb293b8fSAndroid Build Coastguard Worker     default:
101*eb293b8fSAndroid Build Coastguard Worker       return 0;
102*eb293b8fSAndroid Build Coastguard Worker   }
103*eb293b8fSAndroid Build Coastguard Worker }
104*eb293b8fSAndroid Build Coastguard Worker 
AdjustEncodedValue(uint8_t encoding,uint64_t * value)105*eb293b8fSAndroid Build Coastguard Worker bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
106*eb293b8fSAndroid Build Coastguard Worker   CHECK((encoding & 0x0f) == 0);
107*eb293b8fSAndroid Build Coastguard Worker 
108*eb293b8fSAndroid Build Coastguard Worker   // Handle the encoding.
109*eb293b8fSAndroid Build Coastguard Worker   switch (encoding) {
110*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_absptr:
111*eb293b8fSAndroid Build Coastguard Worker       // Nothing to do.
112*eb293b8fSAndroid Build Coastguard Worker       break;
113*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_pcrel:
114*eb293b8fSAndroid Build Coastguard Worker       if (pc_offset_ == INT64_MAX) {
115*eb293b8fSAndroid Build Coastguard Worker         // Unsupported encoding.
116*eb293b8fSAndroid Build Coastguard Worker         return false;
117*eb293b8fSAndroid Build Coastguard Worker       }
118*eb293b8fSAndroid Build Coastguard Worker       *value += pc_offset_;
119*eb293b8fSAndroid Build Coastguard Worker       break;
120*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_textrel:
121*eb293b8fSAndroid Build Coastguard Worker       if (text_offset_ == static_cast<uint64_t>(-1)) {
122*eb293b8fSAndroid Build Coastguard Worker         // Unsupported encoding.
123*eb293b8fSAndroid Build Coastguard Worker         return false;
124*eb293b8fSAndroid Build Coastguard Worker       }
125*eb293b8fSAndroid Build Coastguard Worker       *value += text_offset_;
126*eb293b8fSAndroid Build Coastguard Worker       break;
127*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_datarel:
128*eb293b8fSAndroid Build Coastguard Worker       if (data_offset_ == static_cast<uint64_t>(-1)) {
129*eb293b8fSAndroid Build Coastguard Worker         // Unsupported encoding.
130*eb293b8fSAndroid Build Coastguard Worker         return false;
131*eb293b8fSAndroid Build Coastguard Worker       }
132*eb293b8fSAndroid Build Coastguard Worker       *value += data_offset_;
133*eb293b8fSAndroid Build Coastguard Worker       break;
134*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_funcrel:
135*eb293b8fSAndroid Build Coastguard Worker       if (func_offset_ == static_cast<uint64_t>(-1)) {
136*eb293b8fSAndroid Build Coastguard Worker         // Unsupported encoding.
137*eb293b8fSAndroid Build Coastguard Worker         return false;
138*eb293b8fSAndroid Build Coastguard Worker       }
139*eb293b8fSAndroid Build Coastguard Worker       *value += func_offset_;
140*eb293b8fSAndroid Build Coastguard Worker       break;
141*eb293b8fSAndroid Build Coastguard Worker     default:
142*eb293b8fSAndroid Build Coastguard Worker       return false;
143*eb293b8fSAndroid Build Coastguard Worker   }
144*eb293b8fSAndroid Build Coastguard Worker 
145*eb293b8fSAndroid Build Coastguard Worker   return true;
146*eb293b8fSAndroid Build Coastguard Worker }
147*eb293b8fSAndroid Build Coastguard Worker 
148*eb293b8fSAndroid Build Coastguard Worker template <typename AddressType>
ReadEncodedValue(uint8_t encoding,uint64_t * value)149*eb293b8fSAndroid Build Coastguard Worker bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) {
150*eb293b8fSAndroid Build Coastguard Worker   if (encoding == DW_EH_PE_omit) {
151*eb293b8fSAndroid Build Coastguard Worker     *value = 0;
152*eb293b8fSAndroid Build Coastguard Worker     return true;
153*eb293b8fSAndroid Build Coastguard Worker   } else if (encoding == DW_EH_PE_aligned) {
154*eb293b8fSAndroid Build Coastguard Worker     if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) {
155*eb293b8fSAndroid Build Coastguard Worker       return false;
156*eb293b8fSAndroid Build Coastguard Worker     }
157*eb293b8fSAndroid Build Coastguard Worker     cur_offset_ &= -sizeof(AddressType);
158*eb293b8fSAndroid Build Coastguard Worker 
159*eb293b8fSAndroid Build Coastguard Worker     if (sizeof(AddressType) != sizeof(uint64_t)) {
160*eb293b8fSAndroid Build Coastguard Worker       *value = 0;
161*eb293b8fSAndroid Build Coastguard Worker     }
162*eb293b8fSAndroid Build Coastguard Worker     return ReadBytes(value, sizeof(AddressType));
163*eb293b8fSAndroid Build Coastguard Worker   }
164*eb293b8fSAndroid Build Coastguard Worker 
165*eb293b8fSAndroid Build Coastguard Worker   // Get the data.
166*eb293b8fSAndroid Build Coastguard Worker   switch (encoding & 0x0f) {
167*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_absptr:
168*eb293b8fSAndroid Build Coastguard Worker       if (sizeof(AddressType) != sizeof(uint64_t)) {
169*eb293b8fSAndroid Build Coastguard Worker         *value = 0;
170*eb293b8fSAndroid Build Coastguard Worker       }
171*eb293b8fSAndroid Build Coastguard Worker       if (!ReadBytes(value, sizeof(AddressType))) {
172*eb293b8fSAndroid Build Coastguard Worker         return false;
173*eb293b8fSAndroid Build Coastguard Worker       }
174*eb293b8fSAndroid Build Coastguard Worker       break;
175*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_uleb128:
176*eb293b8fSAndroid Build Coastguard Worker       if (!ReadULEB128(value)) {
177*eb293b8fSAndroid Build Coastguard Worker         return false;
178*eb293b8fSAndroid Build Coastguard Worker       }
179*eb293b8fSAndroid Build Coastguard Worker       break;
180*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sleb128:
181*eb293b8fSAndroid Build Coastguard Worker       int64_t signed_value;
182*eb293b8fSAndroid Build Coastguard Worker       if (!ReadSLEB128(&signed_value)) {
183*eb293b8fSAndroid Build Coastguard Worker         return false;
184*eb293b8fSAndroid Build Coastguard Worker       }
185*eb293b8fSAndroid Build Coastguard Worker       *value = static_cast<uint64_t>(signed_value);
186*eb293b8fSAndroid Build Coastguard Worker       break;
187*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_udata1: {
188*eb293b8fSAndroid Build Coastguard Worker       uint8_t value8;
189*eb293b8fSAndroid Build Coastguard Worker       if (!ReadBytes(&value8, 1)) {
190*eb293b8fSAndroid Build Coastguard Worker         return false;
191*eb293b8fSAndroid Build Coastguard Worker       }
192*eb293b8fSAndroid Build Coastguard Worker       *value = value8;
193*eb293b8fSAndroid Build Coastguard Worker     } break;
194*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sdata1:
195*eb293b8fSAndroid Build Coastguard Worker       if (!ReadSigned<int8_t>(value)) {
196*eb293b8fSAndroid Build Coastguard Worker         return false;
197*eb293b8fSAndroid Build Coastguard Worker       }
198*eb293b8fSAndroid Build Coastguard Worker       break;
199*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_udata2: {
200*eb293b8fSAndroid Build Coastguard Worker       uint16_t value16;
201*eb293b8fSAndroid Build Coastguard Worker       if (!ReadBytes(&value16, 2)) {
202*eb293b8fSAndroid Build Coastguard Worker         return false;
203*eb293b8fSAndroid Build Coastguard Worker       }
204*eb293b8fSAndroid Build Coastguard Worker       *value = value16;
205*eb293b8fSAndroid Build Coastguard Worker     } break;
206*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sdata2:
207*eb293b8fSAndroid Build Coastguard Worker       if (!ReadSigned<int16_t>(value)) {
208*eb293b8fSAndroid Build Coastguard Worker         return false;
209*eb293b8fSAndroid Build Coastguard Worker       }
210*eb293b8fSAndroid Build Coastguard Worker       break;
211*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_udata4: {
212*eb293b8fSAndroid Build Coastguard Worker       uint32_t value32;
213*eb293b8fSAndroid Build Coastguard Worker       if (!ReadBytes(&value32, 4)) {
214*eb293b8fSAndroid Build Coastguard Worker         return false;
215*eb293b8fSAndroid Build Coastguard Worker       }
216*eb293b8fSAndroid Build Coastguard Worker       *value = value32;
217*eb293b8fSAndroid Build Coastguard Worker     } break;
218*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sdata4:
219*eb293b8fSAndroid Build Coastguard Worker       if (!ReadSigned<int32_t>(value)) {
220*eb293b8fSAndroid Build Coastguard Worker         return false;
221*eb293b8fSAndroid Build Coastguard Worker       }
222*eb293b8fSAndroid Build Coastguard Worker       break;
223*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_udata8:
224*eb293b8fSAndroid Build Coastguard Worker       if (!ReadBytes(value, sizeof(uint64_t))) {
225*eb293b8fSAndroid Build Coastguard Worker         return false;
226*eb293b8fSAndroid Build Coastguard Worker       }
227*eb293b8fSAndroid Build Coastguard Worker       break;
228*eb293b8fSAndroid Build Coastguard Worker     case DW_EH_PE_sdata8:
229*eb293b8fSAndroid Build Coastguard Worker       if (!ReadSigned<int64_t>(value)) {
230*eb293b8fSAndroid Build Coastguard Worker         return false;
231*eb293b8fSAndroid Build Coastguard Worker       }
232*eb293b8fSAndroid Build Coastguard Worker       break;
233*eb293b8fSAndroid Build Coastguard Worker     default:
234*eb293b8fSAndroid Build Coastguard Worker       return false;
235*eb293b8fSAndroid Build Coastguard Worker   }
236*eb293b8fSAndroid Build Coastguard Worker 
237*eb293b8fSAndroid Build Coastguard Worker   return AdjustEncodedValue(encoding & 0x70, value);
238*eb293b8fSAndroid Build Coastguard Worker }
239*eb293b8fSAndroid Build Coastguard Worker 
240*eb293b8fSAndroid Build Coastguard Worker // Instantiate all of the needed template functions.
241*eb293b8fSAndroid Build Coastguard Worker template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
242*eb293b8fSAndroid Build Coastguard Worker template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
243*eb293b8fSAndroid Build Coastguard Worker template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
244*eb293b8fSAndroid Build Coastguard Worker template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);
245*eb293b8fSAndroid Build Coastguard Worker 
246*eb293b8fSAndroid Build Coastguard Worker template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
247*eb293b8fSAndroid Build Coastguard Worker template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);
248*eb293b8fSAndroid Build Coastguard Worker 
249*eb293b8fSAndroid Build Coastguard Worker template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
250*eb293b8fSAndroid Build Coastguard Worker template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
251*eb293b8fSAndroid Build Coastguard Worker 
252*eb293b8fSAndroid Build Coastguard Worker }  // namespace unwindstack
253