1 //===-- Stream.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 #include "lldb/Utility/Stream.h"
10 
11 #include "lldb/Utility/Endian.h"
12 #include "lldb/Utility/VASPrintf.h"
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/Support/LEB128.h"
15 
16 #include <string>
17 
18 #include <inttypes.h>
19 #include <stddef.h>
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 
24 Stream::Stream(uint32_t flags, uint32_t addr_size, ByteOrder byte_order)
25     : m_flags(flags), m_addr_size(addr_size), m_byte_order(byte_order),
26       m_indent_level(0), m_forwarder(*this) {}
27 
28 Stream::Stream()
29     : m_flags(0), m_addr_size(4), m_byte_order(endian::InlHostByteOrder()),
30       m_indent_level(0), m_forwarder(*this) {}
31 
32 //------------------------------------------------------------------
33 // Destructor
34 //------------------------------------------------------------------
35 Stream::~Stream() {}
36 
37 ByteOrder Stream::SetByteOrder(ByteOrder byte_order) {
38   ByteOrder old_byte_order = m_byte_order;
39   m_byte_order = byte_order;
40   return old_byte_order;
41 }
42 
43 //------------------------------------------------------------------
44 // Put an offset "uval" out to the stream using the printf format in "format".
45 //------------------------------------------------------------------
46 void Stream::Offset(uint32_t uval, const char *format) { Printf(format, uval); }
47 
48 //------------------------------------------------------------------
49 // Put an SLEB128 "uval" out to the stream using the printf format in "format".
50 //------------------------------------------------------------------
51 size_t Stream::PutSLEB128(int64_t sval) {
52   if (m_flags.Test(eBinary))
53     return llvm::encodeSLEB128(sval, m_forwarder);
54   else
55     return Printf("0x%" PRIi64, sval);
56 }
57 
58 //------------------------------------------------------------------
59 // Put an ULEB128 "uval" out to the stream using the printf format in "format".
60 //------------------------------------------------------------------
61 size_t Stream::PutULEB128(uint64_t uval) {
62   if (m_flags.Test(eBinary))
63     return llvm::encodeULEB128(uval, m_forwarder);
64   else
65     return Printf("0x%" PRIx64, uval);
66 }
67 
68 //------------------------------------------------------------------
69 // Print a raw NULL terminated C string to the stream.
70 //------------------------------------------------------------------
71 size_t Stream::PutCString(llvm::StringRef str) {
72   size_t bytes_written = 0;
73   bytes_written = Write(str.data(), str.size());
74 
75   // when in binary mode, emit the NULL terminator
76   if (m_flags.Test(eBinary))
77     bytes_written += PutChar('\0');
78   return bytes_written;
79 }
80 
81 //------------------------------------------------------------------
82 // Print a double quoted NULL terminated C string to the stream using the
83 // printf format in "format".
84 //------------------------------------------------------------------
85 void Stream::QuotedCString(const char *cstr, const char *format) {
86   Printf(format, cstr);
87 }
88 
89 //------------------------------------------------------------------
90 // Put an address "addr" out to the stream with optional prefix and suffix
91 // strings.
92 //------------------------------------------------------------------
93 void Stream::Address(uint64_t addr, uint32_t addr_size, const char *prefix,
94                      const char *suffix) {
95   if (prefix == nullptr)
96     prefix = "";
97   if (suffix == nullptr)
98     suffix = "";
99   //    int addr_width = m_addr_size << 1;
100   //    Printf ("%s0x%0*" PRIx64 "%s", prefix, addr_width, addr, suffix);
101   Printf("%s0x%0*" PRIx64 "%s", prefix, addr_size * 2, (uint64_t)addr, suffix);
102 }
103 
104 //------------------------------------------------------------------
105 // Put an address range out to the stream with optional prefix and suffix
106 // strings.
107 //------------------------------------------------------------------
108 void Stream::AddressRange(uint64_t lo_addr, uint64_t hi_addr,
109                           uint32_t addr_size, const char *prefix,
110                           const char *suffix) {
111   if (prefix && prefix[0])
112     PutCString(prefix);
113   Address(lo_addr, addr_size, "[");
114   Address(hi_addr, addr_size, "-", ")");
115   if (suffix && suffix[0])
116     PutCString(suffix);
117 }
118 
119 size_t Stream::PutChar(char ch) { return Write(&ch, 1); }
120 
121 //------------------------------------------------------------------
122 // Print some formatted output to the stream.
123 //------------------------------------------------------------------
124 size_t Stream::Printf(const char *format, ...) {
125   va_list args;
126   va_start(args, format);
127   size_t result = PrintfVarArg(format, args);
128   va_end(args);
129   return result;
130 }
131 
132 //------------------------------------------------------------------
133 // Print some formatted output to the stream.
134 //------------------------------------------------------------------
135 size_t Stream::PrintfVarArg(const char *format, va_list args) {
136   llvm::SmallString<1024> buf;
137   VASprintf(buf, format, args);
138 
139   // Include the NULL termination byte for binary output
140   size_t length = buf.size();
141   if (m_flags.Test(eBinary))
142     ++length;
143   return Write(buf.c_str(), length);
144 }
145 
146 //------------------------------------------------------------------
147 // Print and End of Line character to the stream
148 //------------------------------------------------------------------
149 size_t Stream::EOL() { return PutChar('\n'); }
150 
151 //------------------------------------------------------------------
152 // Indent the current line using the current indentation level and print an
153 // optional string following the indentation spaces.
154 //------------------------------------------------------------------
155 size_t Stream::Indent(const char *s) {
156   return Printf("%*.*s%s", m_indent_level, m_indent_level, "", s ? s : "");
157 }
158 
159 size_t Stream::Indent(llvm::StringRef str) {
160   return Printf("%*.*s%s", m_indent_level, m_indent_level, "",
161                 str.str().c_str());
162 }
163 
164 //------------------------------------------------------------------
165 // Stream a character "ch" out to this stream.
166 //------------------------------------------------------------------
167 Stream &Stream::operator<<(char ch) {
168   PutChar(ch);
169   return *this;
170 }
171 
172 //------------------------------------------------------------------
173 // Stream the NULL terminated C string out to this stream.
174 //------------------------------------------------------------------
175 Stream &Stream::operator<<(const char *s) {
176   Printf("%s", s);
177   return *this;
178 }
179 
180 Stream &Stream::operator<<(llvm::StringRef str) {
181   Write(str.data(), str.size());
182   return *this;
183 }
184 
185 //------------------------------------------------------------------
186 // Stream the pointer value out to this stream.
187 //------------------------------------------------------------------
188 Stream &Stream::operator<<(const void *p) {
189   Printf("0x%.*tx", (int)sizeof(const void *) * 2, (ptrdiff_t)p);
190   return *this;
191 }
192 
193 //------------------------------------------------------------------
194 // Stream a uint8_t "uval" out to this stream.
195 //------------------------------------------------------------------
196 Stream &Stream::operator<<(uint8_t uval) {
197   PutHex8(uval);
198   return *this;
199 }
200 
201 //------------------------------------------------------------------
202 // Stream a uint16_t "uval" out to this stream.
203 //------------------------------------------------------------------
204 Stream &Stream::operator<<(uint16_t uval) {
205   PutHex16(uval, m_byte_order);
206   return *this;
207 }
208 
209 //------------------------------------------------------------------
210 // Stream a uint32_t "uval" out to this stream.
211 //------------------------------------------------------------------
212 Stream &Stream::operator<<(uint32_t uval) {
213   PutHex32(uval, m_byte_order);
214   return *this;
215 }
216 
217 //------------------------------------------------------------------
218 // Stream a uint64_t "uval" out to this stream.
219 //------------------------------------------------------------------
220 Stream &Stream::operator<<(uint64_t uval) {
221   PutHex64(uval, m_byte_order);
222   return *this;
223 }
224 
225 //------------------------------------------------------------------
226 // Stream a int8_t "sval" out to this stream.
227 //------------------------------------------------------------------
228 Stream &Stream::operator<<(int8_t sval) {
229   Printf("%i", (int)sval);
230   return *this;
231 }
232 
233 //------------------------------------------------------------------
234 // Stream a int16_t "sval" out to this stream.
235 //------------------------------------------------------------------
236 Stream &Stream::operator<<(int16_t sval) {
237   Printf("%i", (int)sval);
238   return *this;
239 }
240 
241 //------------------------------------------------------------------
242 // Stream a int32_t "sval" out to this stream.
243 //------------------------------------------------------------------
244 Stream &Stream::operator<<(int32_t sval) {
245   Printf("%i", (int)sval);
246   return *this;
247 }
248 
249 //------------------------------------------------------------------
250 // Stream a int64_t "sval" out to this stream.
251 //------------------------------------------------------------------
252 Stream &Stream::operator<<(int64_t sval) {
253   Printf("%" PRIi64, sval);
254   return *this;
255 }
256 
257 //------------------------------------------------------------------
258 // Get the current indentation level
259 //------------------------------------------------------------------
260 int Stream::GetIndentLevel() const { return m_indent_level; }
261 
262 //------------------------------------------------------------------
263 // Set the current indentation level
264 //------------------------------------------------------------------
265 void Stream::SetIndentLevel(int indent_level) { m_indent_level = indent_level; }
266 
267 //------------------------------------------------------------------
268 // Increment the current indentation level
269 //------------------------------------------------------------------
270 void Stream::IndentMore(int amount) { m_indent_level += amount; }
271 
272 //------------------------------------------------------------------
273 // Decrement the current indentation level
274 //------------------------------------------------------------------
275 void Stream::IndentLess(int amount) {
276   if (m_indent_level >= amount)
277     m_indent_level -= amount;
278   else
279     m_indent_level = 0;
280 }
281 
282 //------------------------------------------------------------------
283 // Get the address size in bytes
284 //------------------------------------------------------------------
285 uint32_t Stream::GetAddressByteSize() const { return m_addr_size; }
286 
287 //------------------------------------------------------------------
288 // Set the address size in bytes
289 //------------------------------------------------------------------
290 void Stream::SetAddressByteSize(uint32_t addr_size) { m_addr_size = addr_size; }
291 
292 //------------------------------------------------------------------
293 // The flags get accessor
294 //------------------------------------------------------------------
295 Flags &Stream::GetFlags() { return m_flags; }
296 
297 //------------------------------------------------------------------
298 // The flags const get accessor
299 //------------------------------------------------------------------
300 const Flags &Stream::GetFlags() const { return m_flags; }
301 
302 //------------------------------------------------------------------
303 // The byte order get accessor
304 //------------------------------------------------------------------
305 
306 lldb::ByteOrder Stream::GetByteOrder() const { return m_byte_order; }
307 
308 size_t Stream::PrintfAsRawHex8(const char *format, ...) {
309   va_list args;
310   va_start(args, format);
311 
312   llvm::SmallString<1024> buf;
313   VASprintf(buf, format, args);
314 
315   ByteDelta delta(*this);
316   for (char C : buf)
317     _PutHex8(C, false);
318 
319   va_end(args);
320 
321   return *delta;
322 }
323 
324 size_t Stream::PutNHex8(size_t n, uint8_t uvalue) {
325   ByteDelta delta(*this);
326   for (size_t i = 0; i < n; ++i)
327     _PutHex8(uvalue, false);
328   return *delta;
329 }
330 
331 void Stream::_PutHex8(uint8_t uvalue, bool add_prefix) {
332   if (m_flags.Test(eBinary)) {
333     Write(&uvalue, 1);
334   } else {
335     if (add_prefix)
336       PutCString("0x");
337 
338     static char g_hex_to_ascii_hex_char[16] = {'0', '1', '2', '3', '4', '5',
339                                                '6', '7', '8', '9', 'a', 'b',
340                                                'c', 'd', 'e', 'f'};
341     char nibble_chars[2];
342     nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf];
343     nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf];
344     Write(nibble_chars, sizeof(nibble_chars));
345   }
346 }
347 
348 size_t Stream::PutHex8(uint8_t uvalue) {
349   ByteDelta delta(*this);
350   _PutHex8(uvalue, false);
351   return *delta;
352 }
353 
354 size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) {
355   ByteDelta delta(*this);
356 
357   if (byte_order == eByteOrderInvalid)
358     byte_order = m_byte_order;
359 
360   if (byte_order == eByteOrderLittle) {
361     for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
362       _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
363   } else {
364     for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
365       _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
366   }
367   return *delta;
368 }
369 
370 size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) {
371   ByteDelta delta(*this);
372 
373   if (byte_order == eByteOrderInvalid)
374     byte_order = m_byte_order;
375 
376   if (byte_order == eByteOrderLittle) {
377     for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
378       _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
379   } else {
380     for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
381       _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
382   }
383   return *delta;
384 }
385 
386 size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) {
387   ByteDelta delta(*this);
388 
389   if (byte_order == eByteOrderInvalid)
390     byte_order = m_byte_order;
391 
392   if (byte_order == eByteOrderLittle) {
393     for (size_t byte = 0; byte < sizeof(uvalue); ++byte)
394       _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
395   } else {
396     for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)
397       _PutHex8((uint8_t)(uvalue >> (byte * 8)), false);
398   }
399   return *delta;
400 }
401 
402 size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size,
403                            lldb::ByteOrder byte_order) {
404   switch (byte_size) {
405   case 1:
406     return PutHex8((uint8_t)uvalue);
407   case 2:
408     return PutHex16((uint16_t)uvalue, byte_order);
409   case 4:
410     return PutHex32((uint32_t)uvalue, byte_order);
411   case 8:
412     return PutHex64(uvalue, byte_order);
413   }
414   return 0;
415 }
416 
417 size_t Stream::PutPointer(void *ptr) {
418   return PutRawBytes(&ptr, sizeof(ptr), endian::InlHostByteOrder(),
419                      endian::InlHostByteOrder());
420 }
421 
422 size_t Stream::PutFloat(float f, ByteOrder byte_order) {
423   if (byte_order == eByteOrderInvalid)
424     byte_order = m_byte_order;
425 
426   return PutRawBytes(&f, sizeof(f), endian::InlHostByteOrder(), byte_order);
427 }
428 
429 size_t Stream::PutDouble(double d, ByteOrder byte_order) {
430   if (byte_order == eByteOrderInvalid)
431     byte_order = m_byte_order;
432 
433   return PutRawBytes(&d, sizeof(d), endian::InlHostByteOrder(), byte_order);
434 }
435 
436 size_t Stream::PutLongDouble(long double ld, ByteOrder byte_order) {
437   if (byte_order == eByteOrderInvalid)
438     byte_order = m_byte_order;
439 
440   return PutRawBytes(&ld, sizeof(ld), endian::InlHostByteOrder(), byte_order);
441 }
442 
443 size_t Stream::PutRawBytes(const void *s, size_t src_len,
444                            ByteOrder src_byte_order, ByteOrder dst_byte_order) {
445   ByteDelta delta(*this);
446 
447   if (src_byte_order == eByteOrderInvalid)
448     src_byte_order = m_byte_order;
449 
450   if (dst_byte_order == eByteOrderInvalid)
451     dst_byte_order = m_byte_order;
452 
453   const uint8_t *src = (const uint8_t *)s;
454   bool binary_was_set = m_flags.Test(eBinary);
455   if (!binary_was_set)
456     m_flags.Set(eBinary);
457   if (src_byte_order == dst_byte_order) {
458     for (size_t i = 0; i < src_len; ++i)
459       _PutHex8(src[i], false);
460   } else {
461     for (size_t i = src_len - 1; i < src_len; --i)
462       _PutHex8(src[i], false);
463   }
464   if (!binary_was_set)
465     m_flags.Clear(eBinary);
466 
467   return *delta;
468 }
469 
470 size_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len,
471                                  ByteOrder src_byte_order,
472                                  ByteOrder dst_byte_order) {
473   ByteDelta delta(*this);
474   if (src_byte_order == eByteOrderInvalid)
475     src_byte_order = m_byte_order;
476 
477   if (dst_byte_order == eByteOrderInvalid)
478     dst_byte_order = m_byte_order;
479 
480   const uint8_t *src = (const uint8_t *)s;
481   bool binary_is_set = m_flags.Test(eBinary);
482   m_flags.Clear(eBinary);
483   if (src_byte_order == dst_byte_order) {
484     for (size_t i = 0; i < src_len; ++i)
485       _PutHex8(src[i], false);
486   } else {
487     for (size_t i = src_len - 1; i < src_len; --i)
488       _PutHex8(src[i], false);
489   }
490   if (binary_is_set)
491     m_flags.Set(eBinary);
492 
493   return *delta;
494 }
495 
496 size_t Stream::PutStringAsRawHex8(llvm::StringRef s) {
497   ByteDelta delta(*this);
498   bool binary_is_set = m_flags.Test(eBinary);
499   m_flags.Clear(eBinary);
500   for (char c : s)
501     _PutHex8(c, false);
502   if (binary_is_set)
503     m_flags.Set(eBinary);
504   return *delta;
505 }
506