| // Copyright 2020 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| #pragma once |
| |
| #include <cstdint> |
| |
| #include "pw_bytes/span.h" |
| #include "pw_span/span.h" |
| #include "pw_status/status.h" |
| |
| namespace pw::dump { |
| |
| // Size, in bytes, of the resulting string after converting an address to a |
| // UTF-8 encoded hex representation. This constant depends on the size |
| // a of a pointer. |
| // |
| // Example (32-bit): |
| // 0x0000F00D |
| // |
| // Note: the +2 accounts for the "0x" prefix. |
| constexpr const size_t kHexAddrStringSize = sizeof(uintptr_t) * 2 + 2; |
| |
| // It is strongly recommended NOT to directly depend on this dump format; |
| // pw_hex_dump does NOT guarantee stability for the output format, but strives |
| // to remain xxd compatible. |
| // |
| // Default: |
| // Offs. 0 1 2 3 4 5 6 7 8 9 A B C D E F Text |
| // 0000: A4 CC 32 62 9B 46 38 1A 23 1A 2A 7A BC E2 40 A0 ..2b.F8.#.*z..@. |
| // 0010: FF 33 E5 2B 9E 9F 6B 3C BE 9B 89 3C 7E 4A 7A 48 .3.+..k<...<~JzH |
| // 0020: 18 . |
| // |
| // Example 1 (32-bit machine, group_every=4, prefix_mode=kAbsolute, |
| // bytes_per_line = 8): |
| // Address 0 4 Text |
| // 0x20000000: A4CC3262 9B46381A ..2b.F8. |
| // 0x20000008: 231A2A7A BCE240A0 #.*z..@. |
| // 0x20000010: FF33E52B 9E9F6B3C .3.+..k< |
| // 0x20000018: BE9B893C 7E4A7A48 ...<~JzH |
| // 0x20000020: 18 . |
| // |
| // Example 2 (group_every=1, bytes_per_line = 16): |
| // Offs. 0 1 2 3 4 5 6 7 8 9 A B C D E F |
| // 0000: A4 CC 32 62 9B 46 38 1A 23 1A 2A 7A BC E2 40 A0 |
| // 0010: FF 33 E5 2B 9E 9F 6B 3C BE 9B 89 3C 7E 4A 7A 48 |
| // 0020: 18 |
| // |
| // Example 3 (group_every=0, prefix_mode=kNone, show_header=false, |
| // show_ascii=false): |
| // A4CC32629B46381A231A2A7ABCE240A0 |
| // FF33E52B9E9F6B3CBE9B893C7E4A7A48 |
| // 18 |
| class FormattedHexDumper { |
| public: |
| enum AddressMode { |
| kDisabled = 0, |
| kOffset = 1, |
| kAbsolute = 2, |
| }; |
| |
| struct Flags { |
| // Sets the number of source data bytes to print in each formatted line. |
| uint8_t bytes_per_line : 8; |
| |
| // Inserts a space every N bytes for readability. Note that this is in |
| // number of bytes converted to characters. Set to zero to disable. I.e. a |
| // value of 2 results in: |
| // 0x00000000: 0102 0304 0506 0708 |
| uint8_t group_every : 8; |
| |
| // Show or hide ascii interpretation of binary data. |
| bool show_ascii : 1; |
| |
| // Show descriptive column headers. |
| bool show_header : 1; |
| |
| // Prefix each line of the dump with an offset or absolute address. |
| AddressMode prefix_mode : 2; |
| }; |
| |
| Flags flags = {.bytes_per_line = 16, |
| .group_every = 1, |
| .show_ascii = true, |
| .show_header = true, |
| .prefix_mode = AddressMode::kOffset}; |
| |
| FormattedHexDumper() = default; |
| FormattedHexDumper(span<char> dest) { |
| SetLineBuffer(dest) |
| .IgnoreError(); // TODO(b/242598609): Handle Status properly |
| } |
| FormattedHexDumper(span<char> dest, Flags config_flags) |
| : flags(config_flags) { |
| SetLineBuffer(dest) |
| .IgnoreError(); // TODO(b/242598609): Handle Status properly |
| } |
| |
| // TODO(b/234892215): Add iterator support. |
| |
| // Set the destination buffer that the hex dumper will write to line-by-line. |
| // |
| // Returns: |
| // RESOURCE_EXHAUSTED - The buffer was set, but is too small to fit the |
| // current formatting configuration. |
| // INVALID_ARGUMENT - The destination buffer is invalid (nullptr or zero- |
| // length). |
| Status SetLineBuffer(span<char> dest); |
| |
| // Begin dumping the provided data. Does NOT populate the line buffer with |
| // a string, simply resets the statefulness to track this buffer. |
| // |
| // Returns: |
| // OK - Ready to begin dump. |
| // INVALID_ARGUMENT - The source data starts at null, but has been set. |
| // FAILED_PRECONDITION - Line buffer too small to hold current formatting |
| // settings. |
| Status BeginDump(ConstByteSpan data); |
| |
| // Dumps a single line to the line buffer. |
| // |
| // Example usage: |
| // |
| // std::array<char, 80> temp; |
| // FormattedHexDumper hex_dumper(temp); |
| // hex_dumper.BeginDump(my_data); |
| // while(hex_dumper.DumpLine().ok()) { |
| // LOG_INFO("%s", temp.data()); |
| // } |
| // |
| // Returns: |
| // OK - A line has been written to the line buffer. |
| // RESOURCE_EXHAUSTED - All the data has been dumped. |
| // FAILED_PRECONDITION - Destination line buffer is too small to fit current |
| // formatting configuration. |
| Status DumpLine(); |
| |
| private: |
| Status ValidateBufferSize(); |
| Status PrintFormatHeader(); |
| |
| size_t current_offset_; |
| span<char> dest_; |
| ConstByteSpan source_data_; |
| }; |
| |
| // Dumps a uintptr_t to a character buffer as a hex address. This may be useful |
| // to print out an address in a generalized way when %z and %p aren't supported |
| // by a standard library implementation. The destination buffer MUST be large |
| // enough to hold kHexAddrStringSize + 1 (null terminator) bytes. |
| // |
| // Example (64-bit): |
| // 0x000000000022b698 |
| // Example (32-bit): |
| // 0x70000000 |
| // |
| // Returns: |
| // OK - Address has been written to the buffer. |
| // INVALID_ARGUMENT - The destination buffer is invalid (nullptr). |
| // RESOURCE_EXHAUSTED - The destination buffer is too small. No data written. |
| Status DumpAddr(span<char> dest, uintptr_t addr); |
| inline Status DumpAddr(span<char> dest, const void* ptr) { |
| uintptr_t addr = reinterpret_cast<uintptr_t>(ptr); |
| return DumpAddr(dest, addr); |
| } |
| |
| } // namespace pw::dump |