1 | //===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Created by Greg Clayton on 1/11/06. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "DNBDataRef.h" |
14 | #include "DNBLog.h" |
15 | #include <cassert> |
16 | #include <cctype> |
17 | #include <libkern/OSByteOrder.h> |
18 | |
19 | // Constructor |
20 | |
21 | DNBDataRef::DNBDataRef() |
22 | : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0), |
23 | m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), |
24 | m_addrDATA(INVALID_NUB_ADDRESS) {} |
25 | |
26 | // Constructor |
27 | |
28 | DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) |
29 | : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0), |
30 | m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), |
31 | m_addrDATA(INVALID_NUB_ADDRESS) {} |
32 | |
33 | // Destructor |
34 | |
35 | DNBDataRef::~DNBDataRef() = default; |
36 | |
37 | // Get8 |
38 | uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const { |
39 | uint8_t val = 0; |
40 | if (ValidOffsetForDataOfSize(offset: *offset_ptr, num_bytes: sizeof(val))) { |
41 | val = *(m_start + *offset_ptr); |
42 | *offset_ptr += sizeof(val); |
43 | } |
44 | return val; |
45 | } |
46 | |
47 | // Get16 |
48 | uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const { |
49 | uint16_t val = 0; |
50 | if (ValidOffsetForDataOfSize(offset: *offset_ptr, num_bytes: sizeof(val))) { |
51 | const uint8_t *p = m_start + *offset_ptr; |
52 | memcpy(dest: &val, src: p, n: sizeof(uint16_t)); |
53 | |
54 | if (m_swap) |
55 | val = OSSwapInt16(val); |
56 | |
57 | // Advance the offset |
58 | *offset_ptr += sizeof(val); |
59 | } |
60 | return val; |
61 | } |
62 | |
63 | // Get32 |
64 | uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const { |
65 | uint32_t val = 0; |
66 | if (ValidOffsetForDataOfSize(offset: *offset_ptr, num_bytes: sizeof(val))) { |
67 | const uint8_t *p = m_start + *offset_ptr; |
68 | memcpy(dest: &val, src: p, n: sizeof(uint32_t)); |
69 | if (m_swap) |
70 | val = OSSwapInt32(val); |
71 | |
72 | // Advance the offset |
73 | *offset_ptr += sizeof(val); |
74 | } |
75 | return val; |
76 | } |
77 | |
78 | // Get64 |
79 | uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const { |
80 | uint64_t val = 0; |
81 | if (ValidOffsetForDataOfSize(offset: *offset_ptr, num_bytes: sizeof(val))) { |
82 | const uint8_t *p = m_start + *offset_ptr; |
83 | memcpy(dest: &val, src: p, n: sizeof(uint64_t)); |
84 | if (m_swap) |
85 | val = OSSwapInt64(val); |
86 | |
87 | // Advance the offset |
88 | *offset_ptr += sizeof(val); |
89 | } |
90 | return val; |
91 | } |
92 | |
93 | // GetMax32 |
94 | // |
95 | // Used for calls when the size can vary. Fill in extra cases if they |
96 | // are ever needed. |
97 | uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const { |
98 | switch (byte_size) { |
99 | case 1: |
100 | return Get8(offset_ptr); |
101 | break; |
102 | case 2: |
103 | return Get16(offset_ptr); |
104 | break; |
105 | case 4: |
106 | return Get32(offset_ptr); |
107 | break; |
108 | default: |
109 | assert(false && "GetMax32 unhandled case!" ); |
110 | break; |
111 | } |
112 | return 0; |
113 | } |
114 | |
115 | // GetMax64 |
116 | // |
117 | // Used for calls when the size can vary. Fill in extra cases if they |
118 | // are ever needed. |
119 | uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const { |
120 | switch (size) { |
121 | case 1: |
122 | return Get8(offset_ptr); |
123 | break; |
124 | case 2: |
125 | return Get16(offset_ptr); |
126 | break; |
127 | case 4: |
128 | return Get32(offset_ptr); |
129 | break; |
130 | case 8: |
131 | return Get64(offset_ptr); |
132 | break; |
133 | default: |
134 | assert(false && "GetMax64 unhandled case!" ); |
135 | break; |
136 | } |
137 | return 0; |
138 | } |
139 | |
140 | // GetPointer |
141 | // |
142 | // Extract a pointer value from the buffer. The pointer size must be |
143 | // set prior to using this using one of the SetPointerSize functions. |
144 | uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const { |
145 | // Must set pointer size prior to using this call |
146 | assert(m_ptrSize != 0); |
147 | return GetMax64(offset_ptr, size: m_ptrSize); |
148 | } |
149 | // GetCStr |
150 | const char *DNBDataRef::GetCStr(offset_t *offset_ptr, |
151 | uint32_t fixed_length) const { |
152 | const char *s = NULL; |
153 | if (m_start < m_end) { |
154 | s = (const char *)m_start + *offset_ptr; |
155 | |
156 | // Advance the offset |
157 | if (fixed_length) |
158 | *offset_ptr += fixed_length; |
159 | else |
160 | *offset_ptr += strlen(s: s) + 1; |
161 | } |
162 | return s; |
163 | } |
164 | |
165 | // GetData |
166 | const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr, |
167 | uint32_t length) const { |
168 | const uint8_t *data = NULL; |
169 | if (length > 0 && ValidOffsetForDataOfSize(offset: *offset_ptr, num_bytes: length)) { |
170 | data = m_start + *offset_ptr; |
171 | *offset_ptr += length; |
172 | } |
173 | return data; |
174 | } |
175 | |
176 | // Get_ULEB128 |
177 | uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const { |
178 | uint64_t result = 0; |
179 | if (m_start < m_end) { |
180 | int shift = 0; |
181 | const uint8_t *src = m_start + *offset_ptr; |
182 | uint8_t byte; |
183 | int bytecount = 0; |
184 | |
185 | while (src < m_end) { |
186 | bytecount++; |
187 | byte = *src++; |
188 | result |= (uint64_t)(byte & 0x7f) << shift; |
189 | shift += 7; |
190 | if ((byte & 0x80) == 0) |
191 | break; |
192 | } |
193 | |
194 | *offset_ptr += bytecount; |
195 | } |
196 | return result; |
197 | } |
198 | |
199 | // Get_SLEB128 |
200 | int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const { |
201 | int64_t result = 0; |
202 | |
203 | if (m_start < m_end) { |
204 | int shift = 0; |
205 | int size = sizeof(uint32_t) * 8; |
206 | const uint8_t *src = m_start + *offset_ptr; |
207 | |
208 | uint8_t byte = 0; |
209 | int bytecount = 0; |
210 | |
211 | while (src < m_end) { |
212 | bytecount++; |
213 | byte = *src++; |
214 | result |= (int64_t)(byte & 0x7f) << shift; |
215 | shift += 7; |
216 | if ((byte & 0x80) == 0) |
217 | break; |
218 | } |
219 | |
220 | // Sign bit of byte is 2nd high order bit (0x40) |
221 | if (shift < size && (byte & 0x40)) |
222 | result |= -(1ll << shift); |
223 | |
224 | *offset_ptr += bytecount; |
225 | } |
226 | return result; |
227 | } |
228 | |
229 | // Skip_LEB128 |
230 | // |
231 | // Skips past ULEB128 and SLEB128 numbers (just updates the offset) |
232 | void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const { |
233 | if (m_start < m_end) { |
234 | const uint8_t *start = m_start + *offset_ptr; |
235 | const uint8_t *src = start; |
236 | |
237 | while ((src < m_end) && (*src++ & 0x80)) |
238 | /* Do nothing */; |
239 | |
240 | *offset_ptr += src - start; |
241 | } |
242 | } |
243 | |
244 | uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset, |
245 | uint64_t offsetBase, DNBDataRef::Type type, |
246 | uint32_t numPerLine, const char *format) { |
247 | uint32_t offset; |
248 | uint32_t count; |
249 | char str[1024]; |
250 | str[0] = '\0'; |
251 | size_t str_offset = 0; |
252 | |
253 | for (offset = startOffset, count = 0; |
254 | ValidOffset(offset) && offset < endOffset; ++count) { |
255 | if ((count % numPerLine) == 0) { |
256 | // Print out any previous string |
257 | if (str[0] != '\0') |
258 | DNBLog("%s" , str); |
259 | // Reset string offset and fill the current line string with address: |
260 | str_offset = 0; |
261 | str_offset += snprintf(s: str, maxlen: sizeof(str), format: "0x%8.8llx:" , |
262 | (uint64_t)(offsetBase + (offset - startOffset))); |
263 | } |
264 | |
265 | // Make sure we don't pass the bounds of our current string buffer on each |
266 | // iteration through this loop |
267 | if (str_offset >= sizeof(str)) { |
268 | // The last snprintf consumed our string buffer, we will need to dump this |
269 | // out |
270 | // and reset the string with no address |
271 | DNBLog("%s" , str); |
272 | str_offset = 0; |
273 | str[0] = '\0'; |
274 | } |
275 | |
276 | // We already checked that there is at least some room in the string str |
277 | // above, so it is safe to make |
278 | // the snprintf call each time through this loop |
279 | switch (type) { |
280 | case TypeUInt8: |
281 | str_offset += snprintf(s: str + str_offset, maxlen: sizeof(str) - str_offset, |
282 | format: format ? format : " %2.2x" , Get8(offset_ptr: &offset)); |
283 | break; |
284 | case TypeChar: { |
285 | char ch = Get8(offset_ptr: &offset); |
286 | str_offset += snprintf(s: str + str_offset, maxlen: sizeof(str) - str_offset, |
287 | format: format ? format : " %c" , isprint(ch) ? ch : ' '); |
288 | } break; |
289 | case TypeUInt16: |
290 | str_offset += snprintf(s: str + str_offset, maxlen: sizeof(str) - str_offset, |
291 | format: format ? format : " %4.4x" , Get16(offset_ptr: &offset)); |
292 | break; |
293 | case TypeUInt32: |
294 | str_offset += snprintf(s: str + str_offset, maxlen: sizeof(str) - str_offset, |
295 | format: format ? format : " %8.8x" , Get32(offset_ptr: &offset)); |
296 | break; |
297 | case TypeUInt64: |
298 | str_offset += snprintf(s: str + str_offset, maxlen: sizeof(str) - str_offset, |
299 | format: format ? format : " %16.16llx" , Get64(offset_ptr: &offset)); |
300 | break; |
301 | case TypePointer: |
302 | str_offset += snprintf(s: str + str_offset, maxlen: sizeof(str) - str_offset, |
303 | format: format ? format : " 0x%llx" , GetPointer(offset_ptr: &offset)); |
304 | break; |
305 | case TypeULEB128: |
306 | str_offset += snprintf(s: str + str_offset, maxlen: sizeof(str) - str_offset, |
307 | format: format ? format : " 0x%llx" , Get_ULEB128(offset_ptr: &offset)); |
308 | break; |
309 | case TypeSLEB128: |
310 | str_offset += snprintf(s: str + str_offset, maxlen: sizeof(str) - str_offset, |
311 | format: format ? format : " %lld" , Get_SLEB128(offset_ptr: &offset)); |
312 | break; |
313 | } |
314 | } |
315 | |
316 | if (str[0] != '\0') |
317 | DNBLog("%s" , str); |
318 | |
319 | return offset; // Return the offset at which we ended up |
320 | } |
321 | |