RetroLinker
Linker for several 8-bit, 16-bit and 32-bit formats
Loading...
Searching...
No Matches
dumper.h
1#ifndef DUMPER_H
2#define DUMPER_H
3
4#include <iostream>
5#include <iomanip>
6#include <set>
7#include <vector>
8#include "../common.h"
9#include "../linker/writable.h"
10
11namespace Dumper
12{
13
14class Dumper;
15
19template <typename ... Ts>
20 class Display
21{
22public:
23 virtual ~Display() { }
24
26 virtual bool IsMissing(std::tuple<Ts...>& values)
27 {
28 //return is_missing(values);
29 return values == std::tuple<Ts...>();
30 }
31
33 virtual void DisplayValue(Dumper& dump, std::tuple<Ts...> values) = 0;
34};
35
39class ChoiceDisplay : public Display<offset_t>
40{
41public:
45 std::map<offset_t, std::string> names;
49 std::string default_name;
50
58 offset_t missing_value;
59
60 ChoiceDisplay(std::map<offset_t, std::string> names, std::string default_name, bool missing_on_value, offset_t missing_value)
62 {
63 }
64
65 static std::shared_ptr<ChoiceDisplay> Make(std::map<offset_t, std::string> names, std::string default_name = "unknown")
66 {
67 return std::make_shared<ChoiceDisplay>(names, default_name, false, 0);
68 }
69
70 static std::shared_ptr<ChoiceDisplay> Make(std::map<offset_t, std::string> names, offset_t missing_value, std::string default_name = "unknown")
71 {
72 return std::make_shared<ChoiceDisplay>(names, default_name, true, missing_value);
73 }
74
78 static std::shared_ptr<ChoiceDisplay> Make(std::string on_true, std::string on_false)
79 {
80 std::map<offset_t, std::string> names;
81 /* TODO: alternative?
82 default_name = on_true;
83 names[0] = on_false;
84 */
85 names[0] = on_false;
86 names[1] = on_true;
87 return std::make_shared<ChoiceDisplay>(names, "", false, 0);
88 }
89
93 static std::shared_ptr<ChoiceDisplay> Make(std::string on_true)
94 {
95 std::map<offset_t, std::string> names;
96 /* TODO: alternative?
97 default_name = on_true;
98 missing_on_value = true;
99 missing_value = 0;
100 */
101 names[1] = on_true;
102 return std::make_shared<ChoiceDisplay>(names, "unknown", false, 0);
103 }
104
105 bool IsMissing(std::tuple<offset_t>& values) override;
106 void DisplayValue(Dumper& dump, std::tuple<offset_t> values) override;
107};
108
112class HexDisplay : public Display<offset_t>
113{
114public:
115 unsigned width;
116 HexDisplay(unsigned width)
117 : width(width)
118 {
119 }
120
121 static std::shared_ptr<HexDisplay> Make(unsigned width = 8)
122 {
123 return std::make_shared<HexDisplay>(width);
124 }
125
126 void DisplayValue(Dumper& dump, std::tuple<offset_t> values) override;
127};
128
132class DecDisplay : public Display<offset_t>
133{
134public:
135 std::string suffix;
136 DecDisplay(std::string suffix)
137 : suffix(suffix)
138 {
139 }
140
141 static std::shared_ptr<DecDisplay> Make(std::string suffix = "")
142 {
143 return std::make_shared<DecDisplay>(suffix);
144 }
145
146 void DisplayValue(Dumper& dump, std::tuple<offset_t> values) override;
147};
148
152class SegmentedDisplay : public Display<offset_t, offset_t>
153{
154public:
155 unsigned width;
156 SegmentedDisplay(unsigned width)
157 : width(width)
158 {
159 }
160
161 static std::shared_ptr<SegmentedDisplay> Make(unsigned width = 4)
162 {
163 return std::make_shared<SegmentedDisplay>(width);
164 }
165
166 void DisplayValue(Dumper& dump, std::tuple<offset_t, offset_t> values) override;
167};
168
172class VersionDisplay : public Display<offset_t, offset_t>
173{
174public:
175 std::string separator;
176 VersionDisplay(std::string separator)
177 : separator(separator)
178 {
179 }
180
181 static std::shared_ptr<VersionDisplay> Make(std::string separator = ".")
182 {
183 return std::make_shared<VersionDisplay>(separator);
184 }
185
186 void DisplayValue(Dumper& dump, std::tuple<offset_t, offset_t> values) override;
187};
188
192template <typename ... Ts>
193 class SectionedDisplay : public Display<offset_t, Ts...>
194{
195public:
196 std::string suffix;
197 std::shared_ptr<Display<Ts...>> offset_display;
198
199 SectionedDisplay(std::string suffix, std::shared_ptr<Display<Ts...>> offset_display)
200 : suffix(suffix), offset_display(offset_display)
201 {
202 }
203
204 static std::shared_ptr<SectionedDisplay> Make(std::shared_ptr<Display<Ts...>> offset_display)
205 {
206 return Make("", offset_display);
207 }
208
209 static std::shared_ptr<SectionedDisplay> Make(std::string suffix, std::shared_ptr<Display<Ts...>> offset_display)
210 {
211 return std::make_shared<SectionedDisplay>(suffix, offset_display);
212 }
213
214 void DisplayValue(Dumper& dump, std::tuple<offset_t, Ts...> values) override;
215};
216
220class BitFieldDisplay : public HexDisplay, public std::enable_shared_from_this<BitFieldDisplay>
221{
222public:
224 {
225 public:
226 unsigned offset, length;
227 std::shared_ptr<Display<offset_t>> display;
228 bool optional_field;
229 BitField(unsigned offset, unsigned length, std::shared_ptr<Display<offset_t>> display, bool optional_field)
230 : offset(offset), length(length), display(display), optional_field(optional_field)
231 {
232 }
233
234 bool ShouldDisplay(std::tuple<offset_t>& values)
235 {
236 return !optional_field || !display->IsMissing(values);
237 }
238 };
239
240 std::map<unsigned, std::unique_ptr<BitField>> bitfields;
241
242 BitFieldDisplay(unsigned width)
243 : HexDisplay(width)
244 {
245 }
246
247 static std::shared_ptr<BitFieldDisplay> Make(unsigned width = 8)
248 {
249 return std::make_shared<BitFieldDisplay>(width);
250 }
251
252 std::shared_ptr<BitFieldDisplay> AddBitField(unsigned offset, unsigned length, std::shared_ptr<Display<offset_t>> display, bool optional_field)
253 {
254 bitfields[offset] = std::make_unique<BitField>(offset, length, display, optional_field);
255 return shared_from_this();
256 }
257
258 void DisplayValue(Dumper& dump, std::tuple<offset_t> values) override;
259};
260
264class StringDisplay : public Display<std::string>
265{
266public:
270 offset_t width;
271 std::string open_quote, close_quote;
272
273 StringDisplay(size_t width, std::string open_quote, std::string close_quote)
274 : width(width), open_quote(open_quote), close_quote(close_quote)
275 {
276 }
277
278 static std::shared_ptr<StringDisplay> Make(size_t width, std::string open_quote, std::string close_quote)
279 {
280 return std::make_shared<StringDisplay>(width, open_quote, close_quote);
281 }
282
283 static std::shared_ptr<StringDisplay> Make(size_t width, std::string quote = "")
284 {
285 return std::make_shared<StringDisplay>(width, quote, quote);
286 }
287
288 static std::shared_ptr<StringDisplay> Make(std::string quote = "")
289 {
290 return std::make_shared<StringDisplay>(-1, quote, quote);
291 }
292
293 bool IsMissing(std::tuple<std::string>& values) override;
294 void DisplayValue(Dumper& dump, std::tuple<std::string> values) override;
295
296 using Display<std::string>::IsMissing;
297 bool IsMissing(std::tuple<offset_t>& values);
298 using Display<std::string>::DisplayValue;
299 void DisplayValue(Dumper& dump, std::tuple<offset_t> values);
300};
301
305class Field
306{
307public:
309 std::string label;
314
315 Field(std::string label, bool optional_field, bool internal)
317 {
318 }
319
320 virtual ~Field();
321
322 virtual bool ShouldDisplay() = 0;
323 virtual void DisplayValue(Dumper& dump) = 0;
324};
325
329template <typename ... Ts>
330 class FieldOf : public Field
331{
332public:
334 std::shared_ptr<Display<Ts...>> display;
335 std::tuple<Ts...> values;
336
337 FieldOf(std::string label, std::shared_ptr<Display<Ts...>> display, Ts... values, bool optional_field = false, bool internal = false)
338 : Field(label, optional_field, internal), display{display}, values{values...}
339 {
340 }
341
342 bool ShouldDisplay() override
343 {
344 return !internal && (!optional_field || !display->IsMissing(values));
345 }
346
347 void DisplayValue(Dumper& dump) override
348 {
349 display->DisplayValue(dump, values);
350 }
351};
352
357{
358public:
359 std::string name;
360
361 std::map<std::string, std::shared_ptr<Field>> field_names;
362 std::vector<std::shared_ptr<Field>> fields;
363
364 Container(std::string name = "")
365 : name(name)
366 {
367 }
368
369 std::shared_ptr<Field> FindField(std::string name)
370 {
371 auto it = field_names.find(name);
372 if(it == field_names.end())
373 return nullptr;
374 return it->second;
375 }
376
377 template <typename T>
378 T GetField(std::string name, offset_t default_value = T())
379 {
380 auto it = field_names.find(name);
381 if(it == field_names.end())
382 return default_value;
383 if(auto field = std::dynamic_pointer_cast<FieldOf<T>>(it->second))
384 {
385 return std::get<0>(field->values);
386 }
387 return default_value;
388 }
389
390#if 0
391 offset_t GetField(std::string name, int index, offset_t default_value)
392 {
393 auto it = field_names.find(name);
394 if(it == field_names.end())
395 return default_value;
396 return it->second->values[index];
397 }
398#endif
399
400 void AddField(std::shared_ptr<Field> field)
401 {
402 fields.push_back(field);
403 field_names[field->label] = field;
404 }
405
406 void AddField(size_t index, std::shared_ptr<Field> field)
407 {
408 fields.insert(fields.begin() + index, field);
409 field_names[field->label] = field;
410 }
411
412 template <typename D, typename ... Ts>
413 void AddField(std::string label, std::shared_ptr<D> display, Ts... values)
414 {
415 AddField(std::make_shared<FieldOf<Ts...>>(label, display, values..., false, false));
416 }
417
418 template <typename D, typename ... Ts>
419 void AddOptionalField(std::string label, std::shared_ptr<D> display, Ts... values)
420 {
421 AddField(std::make_shared<FieldOf<Ts...>>(label, display, values..., true, false));
422 }
423
424 template <typename D, typename ... Ts>
425 void AddHiddenField(std::string label, std::shared_ptr<D> display, Ts... values)
426 {
427 AddField(std::make_shared<FieldOf<Ts...>>(label, display, values..., false, true));
428 }
429
430 template <typename D, typename ... Ts>
431 void InsertField(size_t index, std::string label, std::shared_ptr<D> display, Ts... values)
432 {
433 AddField(index, std::make_shared<FieldOf<Ts...>>(label, display, values..., false, false));
434 }
435
436 template <typename D, typename ... Ts>
437 void InsertOptionalField(size_t index, std::string label, std::shared_ptr<D> display, Ts... values)
438 {
439 AddField(index, std::make_shared<FieldOf<Ts...>>(label, display, values..., true, false));
440 }
441
442 template <typename D, typename ... Ts>
443 void InsertHiddenField(size_t index, std::string label, std::shared_ptr<D> display, Ts... values)
444 {
445 AddField(index, std::make_shared<FieldOf<Ts...>>(label, display, values..., false, true));
446 }
447
448 virtual void Display(Dumper& dump);
449};
450
454class Region : public Container
455{
456public:
457 Region(std::string name, offset_t offset, offset_t length, unsigned display_width)
458 : Container(name)
459 {
460 AddField("Offset", HexDisplay::Make(display_width), offset);
461 AddField("Length", HexDisplay::Make(display_width), length);
462 }
463
464 static std::shared_ptr<Region> Make(std::string name, offset_t offset, offset_t length, unsigned display_width)
465 {
466 return std::make_shared<Region>(name, offset, length, display_width);
467 }
468
469// void Display(Dumper& dump);
470};
471
475class Entry : public Container
476{
477public:
478 offset_t number;
479 offset_t offset;
480 unsigned display_width;
481
482 Entry(std::string name, offset_t number, offset_t offset = offset_t(-1), unsigned display_width = 8)
483 : Container(name), number(number), offset(offset), display_width(display_width)
484 {
485 }
486
487 void Display(Dumper& dump) override;
488};
489
493class Block : public Region
494{
495public:
502
503 static char32_t encoding_default[256];
504 static char32_t encoding_cp437[256];
505 static char32_t encoding_st[256];
506
507 std::shared_ptr<Linker::Writable> image;
508
509 std::set<offset_t> signal_starts;
510 std::set<offset_t> signal_ends;
511
518 void AddSignal(offset_t off, offset_t len)
519 {
520 offset_t end = off + len - 1;
521 signal_starts.insert(off);
522 signal_ends.insert(end);
523 }
524
525 Block(std::string name, offset_t offset, std::shared_ptr<Linker::Writable> image, offset_t address, unsigned display_width,
526 unsigned offset_display_width = 8, unsigned address_display_width = -1u, unsigned position_display_width = -1u)
527 : Region(name, offset, image ? image->ActualDataSize() : 0, display_width),
532 image(image)
533 {
534 AddField("Address", HexDisplay::Make(display_width), address);
535 }
536
537 static std::shared_ptr<Block> Make(std::string name, offset_t offset, std::shared_ptr<Linker::Writable> image, offset_t address, unsigned display_width,
538 unsigned offset_display_width = 8, unsigned address_display_width = -1u, unsigned position_display_width = -1u)
539 {
540 return std::make_shared<Block>(name, offset, image, address, display_width, offset_display_width, address_display_width, position_display_width);
541 }
542
543 void Display(Dumper& dump) override;
544};
545
550{
551public:
552 std::ostream& out;
553 bool use_ansi;
554
555 char32_t (* encoding)[256];
556
557 Dumper(std::ostream& out)
558 : out(out), use_ansi(true), encoding(nullptr)
559 {
560 }
561
562 void SetEncoding(char32_t (& encoding)[256], bool force = false)
563 {
564 if(this->encoding == nullptr || force)
565 {
566 this->encoding = &encoding;
567 }
568 }
569
570 void SetTitle(std::string title)
571 {
572 out << "=== " << title << " ===" << std::endl;
573 }
574
575// std::vector<Field> fields;
576
580 void PrintHex(offset_t value, unsigned width, std::string prefix = "0x")
581 {
582 out << prefix << std::hex << std::setw(width) << std::setfill('0') << value;
583 }
584
585#if 0
589 void PrintHex(offset_t value, unsigned width, bool prefixed)
590 {
591 PrintHex(value, width, prefixed ? "0x" : "");
592 }
593#endif
594
598 void PrintDec(offset_t value, std::string prefix = "#")
599 {
600 out << prefix << std::dec << value;
601 }
602
603#if 0
607 void PrintDec(offset_t value, bool prefixed)
608 {
609 PrintDec(value, prefixed ? "#" : "");
610 }
611#endif
612
616 void PutChar(char32_t c)
617 {
618 /* TODO: this should be customizable */
619 if(c < 0x80)
620 {
621 out.put(c);
622 }
623 else if(c < 0x800)
624 {
625 out.put((c >> 6) | 0xC0);
626 out.put((c & 0x3F) | 0x80);
627 }
628 else if(c < 0x10000)
629 {
630 out.put((c >> 12) | 0xE0);
631 out.put(((c >> 6) & 0x3F) | 0x80);
632 out.put((c & 0x3F) | 0x80);
633 }
634 else
635 {
636 out.put(((c >> 18) & 0x07) | 0xF0);
637 out.put(((c >> 12) & 0x3F) | 0x80);
638 out.put(((c >> 6) & 0x3F) | 0x80);
639 out.put((c & 0x3F) | 0x80);
640 }
641 }
642
647 {
648 if(use_ansi)
649 out << "\33[4m";
650 }
651
656 {
657 if(use_ansi)
658 out << "\33[m";
659 }
660};
661
662template <unsigned I, size_t ... Is, typename ... Ts>
663 inline auto rest_(std::tuple<Ts...> elements, std::index_sequence<Is...> s)
664{
665 return std::make_tuple(std::get<I + Is>(elements)...);
666}
667
668template <unsigned I, typename ... Ts>
669 inline auto rest(std::tuple<Ts...> elements)
670{
671 return rest_<I>(elements, std::make_index_sequence<sizeof...(Ts) - I>());
672}
673
674template <typename ... Ts>
675 void SectionedDisplay<Ts...>::DisplayValue(Dumper& dump, std::tuple<offset_t, Ts...> values)
676{
677 dump.PrintDec(std::get<0>(values), "");
678 dump.out << suffix << ':';
679 offset_display->DisplayValue(dump, rest<1>(values));
680}
681
682}
683
684#endif /* DUMPER_H */
Definition dumper.h:224
A value that is separated into bitfields, typically bit flags.
Definition dumper.h:221
A region within a file that can be dumped, decompiled, and it may contain fixups.
Definition dumper.h:494
unsigned offset_display_width
Displaying in-file offsets.
Definition dumper.h:497
void AddSignal(offset_t off, offset_t len)
Add a relocation inside the image block.
Definition dumper.h:518
unsigned position_display_width
Displaying in-segment positions.
Definition dumper.h:499
unsigned address_display_width
Displaying in-memory addresses.
Definition dumper.h:501
Represents an enumerated value, with named options.
Definition dumper.h:40
std::map< offset_t, std::string > names
Maps values to names.
Definition dumper.h:45
static std::shared_ptr< ChoiceDisplay > Make(std::string on_true)
Creates a boolean choice that is either present with name or not present at all.
Definition dumper.h:93
bool missing_on_value
If false, any value not listed in names is missing, otherwise only missing_value is missing.
Definition dumper.h:54
static std::shared_ptr< ChoiceDisplay > Make(std::string on_true, std::string on_false)
Creates a boolean choice.
Definition dumper.h:78
std::string default_name
Name for values not contained in names.
Definition dumper.h:49
offset_t missing_value
The single missing value, only used for missing_on_value true.
Definition dumper.h:58
A record whose values should be displayed together, as a collection.
Definition dumper.h:357
Represents a field with a decimal display, usually indices into an array or similar,...
Definition dumper.h:133
This class represents an entry that can be displayed in a file dump.
Definition dumper.h:21
virtual bool IsMissing(std::tuple< Ts... > &values)
Returns true if the specified value is such that it should not be displayed.
Definition dumper.h:26
virtual void DisplayValue(Dumper &dump, std::tuple< Ts... > values)=0
Prints the value through the Dumper, different types of fields can be displayed in different ways.
A class to control the output of a file analysis.
Definition dumper.h:550
void PrintHex(offset_t value, unsigned width, std::string prefix="0x")
Displays a hexadecimal value (default prefix is "0x")
Definition dumper.h:580
void EndUnderline()
ANSI escape sequence to remove all formatting.
Definition dumper.h:655
void PrintDec(offset_t value, std::string prefix="#")
Displays a decimal value (default prefix is "#")
Definition dumper.h:598
void BeginUnderline()
ANSI escape sequence to add underline.
Definition dumper.h:646
void PutChar(char32_t c)
Displays a Unicode character as a UTF-8 byte sequence.
Definition dumper.h:616
A brief record, such as a relocation or imported library.
Definition dumper.h:476
A typed representation of a named value within a structure.
Definition dumper.h:331
std::shared_ptr< Display< Ts... > > display
The method to show it in.
Definition dumper.h:334
A representation of a named value within a structure.
Definition dumper.h:306
std::string label
The name to be displayed.
Definition dumper.h:309
bool internal
The field should not be displayed, it is for internal use (alternatively, it can be displayed through...
Definition dumper.h:313
bool optional_field
If the field is optional, it will not be displayed for certain values.
Definition dumper.h:311
Represents a field with a hexadecimal display, typically bitfields, addresses, sizes,...
Definition dumper.h:113
A record that represents a region within the file.
Definition dumper.h:455
A display with a prefix for a section.
Definition dumper.h:194
A value displayed as a colon-separated pair, typically 8086 segmented addresses.
Definition dumper.h:153
A display for a fixed or variable length string field.
Definition dumper.h:265
offset_t width
The width of the string field, exactly this many characters will be shown, unless it is offset_t(-1),...
Definition dumper.h:270
A value displayed as a separated pair, such as a version number.
Definition dumper.h:173