• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 
17 #include <cstdint>
18 #include <span>
19 
20 #include "pw_bytes/span.h"
21 #include "pw_status/status.h"
22 
23 namespace pw::dump {
24 
25 // Size, in bytes, of the resulting string after converting an address to a
26 // UTF-8 encoded hex representation. This constant depends on the size
27 // a of a pointer.
28 //
29 // Example (32-bit):
30 //   0x0000F00D
31 //
32 // Note: the +2 accounts for the "0x" prefix.
33 constexpr const size_t kHexAddrStringSize = sizeof(uintptr_t) * 2 + 2;
34 
35 // It is strongly recommended NOT to directly depend on this dump format;
36 // pw_hex_dump does NOT guarantee stability for the output format, but strives
37 // to remain xxd compatible.
38 //
39 // Default:
40 //   Offs.  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  Text
41 //   0000: A4 CC 32 62 9B 46 38 1A 23 1A 2A 7A BC E2 40 A0  ..2b.F8.#.*z..@.
42 //   0010: FF 33 E5 2B 9E 9F 6B 3C BE 9B 89 3C 7E 4A 7A 48  .3.+..k<...<~JzH
43 //   0020: 18                                               .
44 //
45 // Example 1 (32-bit machine, group_every=4, prefix_mode=kAbsolute,
46 //            bytes_per_line = 8):
47 //   Address      0        4        Text
48 //   0x20000000: A4CC3262 9B46381A  ..2b.F8.
49 //   0x20000008: 231A2A7A BCE240A0  #.*z..@.
50 //   0x20000010: FF33E52B 9E9F6B3C  .3.+..k<
51 //   0x20000018: BE9B893C 7E4A7A48  ...<~JzH
52 //   0x20000020: 18                 .
53 //
54 // Example 2 (group_every=1, bytes_per_line = 16):
55 //   Offs.  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
56 //   0000: A4 CC 32 62 9B 46 38 1A 23 1A 2A 7A BC E2 40 A0
57 //   0010: FF 33 E5 2B 9E 9F 6B 3C BE 9B 89 3C 7E 4A 7A 48
58 //   0020: 18
59 //
60 // Example 3 (group_every=0, prefix_mode=kNone, show_header=false,
61 //            show_ascii=false):
62 //   A4CC32629B46381A231A2A7ABCE240A0
63 //   FF33E52B9E9F6B3CBE9B893C7E4A7A48
64 //   18
65 class FormattedHexDumper {
66  public:
67   enum AddressMode {
68     kDisabled = 0,
69     kOffset = 1,
70     kAbsolute = 2,
71   };
72 
73   struct Flags {
74     // Sets the number of source data bytes to print in each formatted line.
75     uint8_t bytes_per_line : 8;
76 
77     // Inserts a space every N bytes for readability. Note that this is in
78     // number of bytes converted to characters. Set to zero to disable. I.e. a
79     // value of 2 results in:
80     //   0x00000000: 0102 0304 0506 0708
81     uint8_t group_every : 8;
82 
83     // Show or hide ascii interpretation of binary data.
84     bool show_ascii : 1;
85 
86     // Show descriptive column headers.
87     bool show_header : 1;
88 
89     // Prefix each line of the dump with an offset or absolute address.
90     AddressMode prefix_mode : 2;
91   };
92 
93   Flags flags = {.bytes_per_line = 16,
94                  .group_every = 1,
95                  .show_ascii = true,
96                  .show_header = true,
97                  .prefix_mode = AddressMode::kOffset};
98 
99   FormattedHexDumper() = default;
FormattedHexDumper(std::span<char> dest)100   FormattedHexDumper(std::span<char> dest) { SetLineBuffer(dest); }
FormattedHexDumper(std::span<char> dest,Flags config_flags)101   FormattedHexDumper(std::span<char> dest, Flags config_flags)
102       : flags(config_flags) {
103     SetLineBuffer(dest);
104   }
105 
106   // TODO(pwbug/218): Add iterator support.
107 
108   // Set the destination buffer that the hex dumper will write to line-by-line.
109   //
110   // Returns:
111   //   RESOURCE_EXHAUSTED - The buffer was set, but is too small to fit the
112   //     current formatting configuration.
113   //   INVALID_ARGUMENT - The destination buffer is invalid (nullptr or zero-
114   //     length).
115   Status SetLineBuffer(std::span<char> dest);
116 
117   // Begin dumping the provided data. Does NOT populate the line buffer with
118   // a string, simply resets the statefulness to track this buffer.
119   //
120   // Returns:
121   //   OK - Ready to begin dump.
122   //   INVALID_ARGUMENT - The source data starts at null, but has been set.
123   //   FAILED_PRECONDITION - Line buffer too small to hold current formatting
124   //     settings.
125   Status BeginDump(ConstByteSpan data);
126 
127   // Dumps a single line to the line buffer.
128   //
129   // Example usage:
130   //
131   //   std::array<char, 80> temp;
132   //   FormattedHexDumper hex_dumper(temp);
133   //   hex_dumper.BeginDump(my_data);
134   //   while(hex_dumper.DumpLine().ok()) {
135   //     LOG_INFO("%s", temp.data());
136   //   }
137   //
138   // Returns:
139   //   OK - A line has been written to the line buffer.
140   //   RESOURCE_EXHAUSTED - All the data has been dumped.
141   //   FAILED_PRECONDITION - Destination line buffer is too small to fit current
142   //     formatting configuration.
143   Status DumpLine();
144 
145  private:
146   Status ValidateBufferSize();
147   Status PrintFormatHeader();
148 
149   size_t current_offset_;
150   std::span<char> dest_;
151   ConstByteSpan source_data_;
152 };
153 
154 // Dumps a uintptr_t to a character buffer as a hex address. This may be useful
155 // to print out an address in a generalized way when %z and %p aren't supported
156 // by a standard library implementation. The destination buffer MUST be large
157 // enough to hold kHexAddrStringSize + 1 (null terminator) bytes.
158 //
159 // Example (64-bit):
160 //   0x000000000022b698
161 // Example (32-bit):
162 //   0x70000000
163 //
164 // Returns:
165 //   OK - Address has been written to the buffer.
166 //   INVALID_ARGUMENT - The destination buffer is invalid (nullptr).
167 //   RESOURCE_EXHAUSTED - The destination buffer is too small. No data written.
168 Status DumpAddr(std::span<char> dest, uintptr_t addr);
DumpAddr(std::span<char> dest,const void * ptr)169 inline Status DumpAddr(std::span<char> dest, const void* ptr) {
170   uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
171   return DumpAddr(dest, addr);
172 }
173 
174 }  // namespace pw::dump
175