• 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 
19 #include "pw_bytes/span.h"
20 #include "pw_span/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(span<char> dest)100   FormattedHexDumper(span<char> dest) {
101     SetLineBuffer(dest)
102         .IgnoreError();  // TODO(b/242598609): Handle Status properly
103   }
FormattedHexDumper(span<char> dest,Flags config_flags)104   FormattedHexDumper(span<char> dest, Flags config_flags)
105       : flags(config_flags) {
106     SetLineBuffer(dest)
107         .IgnoreError();  // TODO(b/242598609): Handle Status properly
108   }
109 
110   // TODO(b/234892215): Add iterator support.
111 
112   // Set the destination buffer that the hex dumper will write to line-by-line.
113   //
114   // Returns:
115   //   RESOURCE_EXHAUSTED - The buffer was set, but is too small to fit the
116   //     current formatting configuration.
117   //   INVALID_ARGUMENT - The destination buffer is invalid (nullptr or zero-
118   //     length).
119   Status SetLineBuffer(span<char> dest);
120 
121   // Begin dumping the provided data. Does NOT populate the line buffer with
122   // a string, simply resets the statefulness to track this buffer.
123   //
124   // Returns:
125   //   OK - Ready to begin dump.
126   //   INVALID_ARGUMENT - The source data starts at null, but has been set.
127   //   FAILED_PRECONDITION - Line buffer too small to hold current formatting
128   //     settings.
129   Status BeginDump(ConstByteSpan data);
130 
131   // Dumps a single line to the line buffer.
132   //
133   // Example usage:
134   //
135   //   std::array<char, 80> temp;
136   //   FormattedHexDumper hex_dumper(temp);
137   //   hex_dumper.BeginDump(my_data);
138   //   while(hex_dumper.DumpLine().ok()) {
139   //     LOG_INFO("%s", temp.data());
140   //   }
141   //
142   // Returns:
143   //   OK - A line has been written to the line buffer.
144   //   RESOURCE_EXHAUSTED - All the data has been dumped.
145   //   FAILED_PRECONDITION - Destination line buffer is too small to fit current
146   //     formatting configuration.
147   Status DumpLine();
148 
149  private:
150   Status ValidateBufferSize();
151   Status PrintFormatHeader();
152 
153   size_t current_offset_;
154   span<char> dest_;
155   ConstByteSpan source_data_;
156 };
157 
158 // Dumps a uintptr_t to a character buffer as a hex address. This may be useful
159 // to print out an address in a generalized way when %z and %p aren't supported
160 // by a standard library implementation. The destination buffer MUST be large
161 // enough to hold kHexAddrStringSize + 1 (null terminator) bytes.
162 //
163 // Example (64-bit):
164 //   0x000000000022b698
165 // Example (32-bit):
166 //   0x70000000
167 //
168 // Returns:
169 //   OK - Address has been written to the buffer.
170 //   INVALID_ARGUMENT - The destination buffer is invalid (nullptr).
171 //   RESOURCE_EXHAUSTED - The destination buffer is too small. No data written.
172 Status DumpAddr(span<char> dest, uintptr_t addr);
DumpAddr(span<char> dest,const void * ptr)173 inline Status DumpAddr(span<char> dest, const void* ptr) {
174   uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
175   return DumpAddr(dest, addr);
176 }
177 
178 }  // namespace pw::dump
179