1061da546Spatrick //===-- DNBDataRef.cpp ------------------------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick //
9061da546Spatrick // Created by Greg Clayton on 1/11/06.
10061da546Spatrick //
11061da546Spatrick //===----------------------------------------------------------------------===//
12061da546Spatrick
13061da546Spatrick #include "DNBDataRef.h"
14061da546Spatrick #include "DNBLog.h"
15be691f3bSpatrick #include <cassert>
16be691f3bSpatrick #include <cctype>
17061da546Spatrick #include <libkern/OSByteOrder.h>
18061da546Spatrick
19061da546Spatrick // Constructor
20061da546Spatrick
DNBDataRef()21061da546Spatrick DNBDataRef::DNBDataRef()
22061da546Spatrick : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0),
23061da546Spatrick m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS),
24061da546Spatrick m_addrDATA(INVALID_NUB_ADDRESS) {}
25061da546Spatrick
26061da546Spatrick // Constructor
27061da546Spatrick
DNBDataRef(const uint8_t * start,size_t size,bool swap)28061da546Spatrick DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap)
29061da546Spatrick : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0),
30061da546Spatrick m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS),
31061da546Spatrick m_addrDATA(INVALID_NUB_ADDRESS) {}
32061da546Spatrick
33061da546Spatrick // Destructor
34061da546Spatrick
35*f6aab3d8Srobert DNBDataRef::~DNBDataRef() = default;
36061da546Spatrick
37061da546Spatrick // Get8
Get8(offset_t * offset_ptr) const38061da546Spatrick uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const {
39061da546Spatrick uint8_t val = 0;
40061da546Spatrick if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
41061da546Spatrick val = *(m_start + *offset_ptr);
42061da546Spatrick *offset_ptr += sizeof(val);
43061da546Spatrick }
44061da546Spatrick return val;
45061da546Spatrick }
46061da546Spatrick
47061da546Spatrick // Get16
Get16(offset_t * offset_ptr) const48061da546Spatrick uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const {
49061da546Spatrick uint16_t val = 0;
50061da546Spatrick if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
51061da546Spatrick const uint8_t *p = m_start + *offset_ptr;
52061da546Spatrick memcpy(&val, p, sizeof(uint16_t));
53061da546Spatrick
54061da546Spatrick if (m_swap)
55061da546Spatrick val = OSSwapInt16(val);
56061da546Spatrick
57061da546Spatrick // Advance the offset
58061da546Spatrick *offset_ptr += sizeof(val);
59061da546Spatrick }
60061da546Spatrick return val;
61061da546Spatrick }
62061da546Spatrick
63061da546Spatrick // Get32
Get32(offset_t * offset_ptr) const64061da546Spatrick uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const {
65061da546Spatrick uint32_t val = 0;
66061da546Spatrick if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
67061da546Spatrick const uint8_t *p = m_start + *offset_ptr;
68061da546Spatrick memcpy(&val, p, sizeof(uint32_t));
69061da546Spatrick if (m_swap)
70061da546Spatrick val = OSSwapInt32(val);
71061da546Spatrick
72061da546Spatrick // Advance the offset
73061da546Spatrick *offset_ptr += sizeof(val);
74061da546Spatrick }
75061da546Spatrick return val;
76061da546Spatrick }
77061da546Spatrick
78061da546Spatrick // Get64
Get64(offset_t * offset_ptr) const79061da546Spatrick uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const {
80061da546Spatrick uint64_t val = 0;
81061da546Spatrick if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) {
82061da546Spatrick const uint8_t *p = m_start + *offset_ptr;
83061da546Spatrick memcpy(&val, p, sizeof(uint64_t));
84061da546Spatrick if (m_swap)
85061da546Spatrick val = OSSwapInt64(val);
86061da546Spatrick
87061da546Spatrick // Advance the offset
88061da546Spatrick *offset_ptr += sizeof(val);
89061da546Spatrick }
90061da546Spatrick return val;
91061da546Spatrick }
92061da546Spatrick
93061da546Spatrick // GetMax32
94061da546Spatrick //
95061da546Spatrick // Used for calls when the size can vary. Fill in extra cases if they
96061da546Spatrick // are ever needed.
GetMax32(offset_t * offset_ptr,uint32_t byte_size) const97061da546Spatrick uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const {
98061da546Spatrick switch (byte_size) {
99061da546Spatrick case 1:
100061da546Spatrick return Get8(offset_ptr);
101061da546Spatrick break;
102061da546Spatrick case 2:
103061da546Spatrick return Get16(offset_ptr);
104061da546Spatrick break;
105061da546Spatrick case 4:
106061da546Spatrick return Get32(offset_ptr);
107061da546Spatrick break;
108061da546Spatrick default:
109061da546Spatrick assert(false && "GetMax32 unhandled case!");
110061da546Spatrick break;
111061da546Spatrick }
112061da546Spatrick return 0;
113061da546Spatrick }
114061da546Spatrick
115061da546Spatrick // GetMax64
116061da546Spatrick //
117061da546Spatrick // Used for calls when the size can vary. Fill in extra cases if they
118061da546Spatrick // are ever needed.
GetMax64(offset_t * offset_ptr,uint32_t size) const119061da546Spatrick uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const {
120061da546Spatrick switch (size) {
121061da546Spatrick case 1:
122061da546Spatrick return Get8(offset_ptr);
123061da546Spatrick break;
124061da546Spatrick case 2:
125061da546Spatrick return Get16(offset_ptr);
126061da546Spatrick break;
127061da546Spatrick case 4:
128061da546Spatrick return Get32(offset_ptr);
129061da546Spatrick break;
130061da546Spatrick case 8:
131061da546Spatrick return Get64(offset_ptr);
132061da546Spatrick break;
133061da546Spatrick default:
134061da546Spatrick assert(false && "GetMax64 unhandled case!");
135061da546Spatrick break;
136061da546Spatrick }
137061da546Spatrick return 0;
138061da546Spatrick }
139061da546Spatrick
140061da546Spatrick // GetPointer
141061da546Spatrick //
142061da546Spatrick // Extract a pointer value from the buffer. The pointer size must be
143061da546Spatrick // set prior to using this using one of the SetPointerSize functions.
GetPointer(offset_t * offset_ptr) const144061da546Spatrick uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const {
145061da546Spatrick // Must set pointer size prior to using this call
146061da546Spatrick assert(m_ptrSize != 0);
147061da546Spatrick return GetMax64(offset_ptr, m_ptrSize);
148061da546Spatrick }
149061da546Spatrick // GetCStr
GetCStr(offset_t * offset_ptr,uint32_t fixed_length) const150061da546Spatrick const char *DNBDataRef::GetCStr(offset_t *offset_ptr,
151061da546Spatrick uint32_t fixed_length) const {
152061da546Spatrick const char *s = NULL;
153061da546Spatrick if (m_start < m_end) {
154061da546Spatrick s = (const char *)m_start + *offset_ptr;
155061da546Spatrick
156061da546Spatrick // Advance the offset
157061da546Spatrick if (fixed_length)
158061da546Spatrick *offset_ptr += fixed_length;
159061da546Spatrick else
160061da546Spatrick *offset_ptr += strlen(s) + 1;
161061da546Spatrick }
162061da546Spatrick return s;
163061da546Spatrick }
164061da546Spatrick
165061da546Spatrick // GetData
GetData(offset_t * offset_ptr,uint32_t length) const166061da546Spatrick const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr,
167061da546Spatrick uint32_t length) const {
168061da546Spatrick const uint8_t *data = NULL;
169061da546Spatrick if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) {
170061da546Spatrick data = m_start + *offset_ptr;
171061da546Spatrick *offset_ptr += length;
172061da546Spatrick }
173061da546Spatrick return data;
174061da546Spatrick }
175061da546Spatrick
176061da546Spatrick // Get_ULEB128
Get_ULEB128(offset_t * offset_ptr) const177061da546Spatrick uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const {
178061da546Spatrick uint64_t result = 0;
179061da546Spatrick if (m_start < m_end) {
180061da546Spatrick int shift = 0;
181061da546Spatrick const uint8_t *src = m_start + *offset_ptr;
182061da546Spatrick uint8_t byte;
183061da546Spatrick int bytecount = 0;
184061da546Spatrick
185061da546Spatrick while (src < m_end) {
186061da546Spatrick bytecount++;
187061da546Spatrick byte = *src++;
188061da546Spatrick result |= (uint64_t)(byte & 0x7f) << shift;
189061da546Spatrick shift += 7;
190061da546Spatrick if ((byte & 0x80) == 0)
191061da546Spatrick break;
192061da546Spatrick }
193061da546Spatrick
194061da546Spatrick *offset_ptr += bytecount;
195061da546Spatrick }
196061da546Spatrick return result;
197061da546Spatrick }
198061da546Spatrick
199061da546Spatrick // Get_SLEB128
Get_SLEB128(offset_t * offset_ptr) const200061da546Spatrick int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const {
201061da546Spatrick int64_t result = 0;
202061da546Spatrick
203061da546Spatrick if (m_start < m_end) {
204061da546Spatrick int shift = 0;
205061da546Spatrick int size = sizeof(uint32_t) * 8;
206061da546Spatrick const uint8_t *src = m_start + *offset_ptr;
207061da546Spatrick
208061da546Spatrick uint8_t byte = 0;
209061da546Spatrick int bytecount = 0;
210061da546Spatrick
211061da546Spatrick while (src < m_end) {
212061da546Spatrick bytecount++;
213061da546Spatrick byte = *src++;
214061da546Spatrick result |= (int64_t)(byte & 0x7f) << shift;
215061da546Spatrick shift += 7;
216061da546Spatrick if ((byte & 0x80) == 0)
217061da546Spatrick break;
218061da546Spatrick }
219061da546Spatrick
220061da546Spatrick // Sign bit of byte is 2nd high order bit (0x40)
221061da546Spatrick if (shift < size && (byte & 0x40))
222061da546Spatrick result |= -(1ll << shift);
223061da546Spatrick
224061da546Spatrick *offset_ptr += bytecount;
225061da546Spatrick }
226061da546Spatrick return result;
227061da546Spatrick }
228061da546Spatrick
229061da546Spatrick // Skip_LEB128
230061da546Spatrick //
231061da546Spatrick // Skips past ULEB128 and SLEB128 numbers (just updates the offset)
Skip_LEB128(offset_t * offset_ptr) const232061da546Spatrick void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const {
233061da546Spatrick if (m_start < m_end) {
234061da546Spatrick const uint8_t *start = m_start + *offset_ptr;
235061da546Spatrick const uint8_t *src = start;
236061da546Spatrick
237061da546Spatrick while ((src < m_end) && (*src++ & 0x80))
238061da546Spatrick /* Do nothing */;
239061da546Spatrick
240061da546Spatrick *offset_ptr += src - start;
241061da546Spatrick }
242061da546Spatrick }
243061da546Spatrick
Dump(uint32_t startOffset,uint32_t endOffset,uint64_t offsetBase,DNBDataRef::Type type,uint32_t numPerLine,const char * format)244061da546Spatrick uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset,
245061da546Spatrick uint64_t offsetBase, DNBDataRef::Type type,
246061da546Spatrick uint32_t numPerLine, const char *format) {
247061da546Spatrick uint32_t offset;
248061da546Spatrick uint32_t count;
249061da546Spatrick char str[1024];
250061da546Spatrick str[0] = '\0';
251061da546Spatrick size_t str_offset = 0;
252061da546Spatrick
253061da546Spatrick for (offset = startOffset, count = 0;
254061da546Spatrick ValidOffset(offset) && offset < endOffset; ++count) {
255061da546Spatrick if ((count % numPerLine) == 0) {
256061da546Spatrick // Print out any previous string
257061da546Spatrick if (str[0] != '\0')
258061da546Spatrick DNBLog("%s", str);
259061da546Spatrick // Reset string offset and fill the current line string with address:
260061da546Spatrick str_offset = 0;
261061da546Spatrick str_offset += snprintf(str, sizeof(str), "0x%8.8llx:",
262061da546Spatrick (uint64_t)(offsetBase + (offset - startOffset)));
263061da546Spatrick }
264061da546Spatrick
265061da546Spatrick // Make sure we don't pass the bounds of our current string buffer on each
266061da546Spatrick // iteration through this loop
267061da546Spatrick if (str_offset >= sizeof(str)) {
268061da546Spatrick // The last snprintf consumed our string buffer, we will need to dump this
269061da546Spatrick // out
270061da546Spatrick // and reset the string with no address
271061da546Spatrick DNBLog("%s", str);
272061da546Spatrick str_offset = 0;
273061da546Spatrick str[0] = '\0';
274061da546Spatrick }
275061da546Spatrick
276061da546Spatrick // We already checked that there is at least some room in the string str
277061da546Spatrick // above, so it is safe to make
278061da546Spatrick // the snprintf call each time through this loop
279061da546Spatrick switch (type) {
280061da546Spatrick case TypeUInt8:
281061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
282061da546Spatrick format ? format : " %2.2x", Get8(&offset));
283061da546Spatrick break;
284061da546Spatrick case TypeChar: {
285061da546Spatrick char ch = Get8(&offset);
286061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
287061da546Spatrick format ? format : " %c", isprint(ch) ? ch : ' ');
288061da546Spatrick } break;
289061da546Spatrick case TypeUInt16:
290061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
291061da546Spatrick format ? format : " %4.4x", Get16(&offset));
292061da546Spatrick break;
293061da546Spatrick case TypeUInt32:
294061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
295061da546Spatrick format ? format : " %8.8x", Get32(&offset));
296061da546Spatrick break;
297061da546Spatrick case TypeUInt64:
298061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
299061da546Spatrick format ? format : " %16.16llx", Get64(&offset));
300061da546Spatrick break;
301061da546Spatrick case TypePointer:
302061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
303061da546Spatrick format ? format : " 0x%llx", GetPointer(&offset));
304061da546Spatrick break;
305061da546Spatrick case TypeULEB128:
306061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
307061da546Spatrick format ? format : " 0x%llx", Get_ULEB128(&offset));
308061da546Spatrick break;
309061da546Spatrick case TypeSLEB128:
310061da546Spatrick str_offset += snprintf(str + str_offset, sizeof(str) - str_offset,
311061da546Spatrick format ? format : " %lld", Get_SLEB128(&offset));
312061da546Spatrick break;
313061da546Spatrick }
314061da546Spatrick }
315061da546Spatrick
316061da546Spatrick if (str[0] != '\0')
317061da546Spatrick DNBLog("%s", str);
318061da546Spatrick
319061da546Spatrick return offset; // Return the offset at which we ended up
320061da546Spatrick }
321