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/image.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;
62 std::shared_ptr<Display<offset_t>> secondary_display;
63
64 ChoiceDisplay(std::map<offset_t, std::string> names, std::string default_name, bool missing_on_value, offset_t missing_value, std::shared_ptr<Display<offset_t>> secondary_display)
66 {
67 }
68
69 static std::shared_ptr<ChoiceDisplay> Make(std::map<offset_t, std::string> names, std::string default_name = "unknown", std::shared_ptr<Display<offset_t>> secondary_display = nullptr)
70 {
71 return std::make_shared<ChoiceDisplay>(names, default_name, false, 0, secondary_display);
72 }
73
74 static std::shared_ptr<ChoiceDisplay> Make(std::map<offset_t, std::string> names, offset_t missing_value, std::string default_name = "unknown", std::shared_ptr<Display<offset_t>> secondary_display = nullptr)
75 {
76 return std::make_shared<ChoiceDisplay>(names, default_name, true, missing_value, secondary_display);
77 }
78
79 static std::shared_ptr<ChoiceDisplay> Make(std::map<offset_t, std::string> names, std::shared_ptr<Display<offset_t>> secondary_display)
80 {
81 return std::make_shared<ChoiceDisplay>(names, "unknown", false, 0, secondary_display);
82 }
83
84 static std::shared_ptr<ChoiceDisplay> Make(std::map<offset_t, std::string> names, offset_t missing_value, std::shared_ptr<Display<offset_t>> secondary_display)
85 {
86 return std::make_shared<ChoiceDisplay>(names, "unknown", true, missing_value, secondary_display);
87 }
88
92 static std::shared_ptr<ChoiceDisplay> Make(std::string on_true, std::string on_false)
93 {
94 std::map<offset_t, std::string> names;
95 /* TODO: alternative?
96 default_name = on_true;
97 names[0] = on_false;
98 */
99 names[0] = on_false;
100 names[1] = on_true;
101 return std::make_shared<ChoiceDisplay>(names, "", false, 0, nullptr);
102 }
103
107 static std::shared_ptr<ChoiceDisplay> Make(std::string on_true)
108 {
109 std::map<offset_t, std::string> names;
110 /* TODO: alternative?
111 default_name = on_true;
112 missing_on_value = true;
113 missing_value = 0;
114 */
115 names[1] = on_true;
116 return std::make_shared<ChoiceDisplay>(names, "unknown", false, 0, nullptr);
117 }
118
119 bool IsMissing(std::tuple<offset_t>& values) override;
120 void DisplayValue(Dumper& dump, std::tuple<offset_t> values) override;
121};
122
126class HexDisplay : public Display<offset_t>
127{
128public:
129 unsigned width;
130 HexDisplay(unsigned width)
131 : width(width)
132 {
133 }
134
135 static std::shared_ptr<HexDisplay> Make(unsigned width = 8)
136 {
137 return std::make_shared<HexDisplay>(width);
138 }
139
140 void DisplayValue(Dumper& dump, std::tuple<offset_t> values) override;
141};
142
146class DecDisplay : public Display<offset_t>
147{
148public:
149 std::string suffix;
150 bool enable_signed = false;
151 DecDisplay(std::string suffix, bool enable_signed)
152 : suffix(suffix), enable_signed(enable_signed)
153 {
154 }
155
156 static std::shared_ptr<DecDisplay> Make(bool enable_signed)
157 {
158 return std::make_shared<DecDisplay>("", enable_signed);
159 }
160
161 static std::shared_ptr<DecDisplay> Make(std::string suffix = "", bool enable_signed = false)
162 {
163 return std::make_shared<DecDisplay>(suffix, enable_signed);
164 }
165
166 void DisplayValue(Dumper& dump, std::tuple<offset_t> values) override;
167};
168
172class SegmentedDisplay : public Display<offset_t, offset_t>
173{
174public:
175 unsigned width;
176 SegmentedDisplay(unsigned width)
177 : width(width)
178 {
179 }
180
181 static std::shared_ptr<SegmentedDisplay> Make(unsigned width = 4)
182 {
183 return std::make_shared<SegmentedDisplay>(width);
184 }
185
186 void DisplayValue(Dumper& dump, std::tuple<offset_t, offset_t> values) override;
187};
188
192class VersionDisplay : public Display<offset_t, offset_t>
193{
194public:
195 std::string separator;
196 VersionDisplay(std::string separator)
197 : separator(separator)
198 {
199 }
200
201 static std::shared_ptr<VersionDisplay> Make(std::string separator = ".")
202 {
203 return std::make_shared<VersionDisplay>(separator);
204 }
205
206 void DisplayValue(Dumper& dump, std::tuple<offset_t, offset_t> values) override;
207};
208
212template <typename ... Ts>
213 class SectionedDisplay : public Display<offset_t, Ts...>
214{
215public:
216 std::string suffix;
217 std::shared_ptr<Display<Ts...>> offset_display;
218
219 SectionedDisplay(std::string suffix, std::shared_ptr<Display<Ts...>> offset_display)
220 : suffix(suffix), offset_display(offset_display)
221 {
222 }
223
224 static std::shared_ptr<SectionedDisplay> Make(std::shared_ptr<Display<Ts...>> offset_display)
225 {
226 return Make("", offset_display);
227 }
228
229 static std::shared_ptr<SectionedDisplay> Make(std::string suffix, std::shared_ptr<Display<Ts...>> offset_display)
230 {
231 return std::make_shared<SectionedDisplay>(suffix, offset_display);
232 }
233
234 void DisplayValue(Dumper& dump, std::tuple<offset_t, Ts...> values) override;
235};
236
240class BitFieldDisplay : public HexDisplay, public std::enable_shared_from_this<BitFieldDisplay>
241{
242public:
244 {
245 public:
246 unsigned offset, length;
247 std::shared_ptr<Display<offset_t>> display;
248 bool optional_field;
249 std::string label;
250
251 BitField(unsigned offset, unsigned length, std::shared_ptr<Display<offset_t>> display, bool optional_field, std::string label)
252 : offset(offset), length(length), display(display), optional_field(optional_field), label(label)
253 {
254 }
255
256 bool ShouldDisplay(std::tuple<offset_t>& values)
257 {
258 return !optional_field || !display->IsMissing(values);
259 }
260 };
261
262 std::map<unsigned, std::unique_ptr<BitField>> bitfields;
263
264 BitFieldDisplay(unsigned width)
265 : HexDisplay(width)
266 {
267 }
268
269 static std::shared_ptr<BitFieldDisplay> Make(unsigned width = 8)
270 {
271 return std::make_shared<BitFieldDisplay>(width);
272 }
273
274 std::shared_ptr<BitFieldDisplay> AddBitField(unsigned offset, unsigned length, std::shared_ptr<Display<offset_t>> display, bool optional_field)
275 {
276 bitfields[offset] = std::make_unique<BitField>(offset, length, display, optional_field, "");
277 return shared_from_this();
278 }
279
280 std::shared_ptr<BitFieldDisplay> AddBitField(unsigned offset, unsigned length, std::string label, std::shared_ptr<Display<offset_t>> display, bool optional_field = false)
281 {
282 bitfields[offset] = std::make_unique<BitField>(offset, length, display, optional_field, label);
283 return shared_from_this();
284 }
285
286 void DisplayValue(Dumper& dump, std::tuple<offset_t> values) override;
287};
288
292class StringDisplay : public Display<std::string>
293{
294public:
298 offset_t width;
299 std::string open_quote, close_quote;
300
301 StringDisplay(size_t width, std::string open_quote, std::string close_quote)
302 : width(width), open_quote(open_quote), close_quote(close_quote)
303 {
304 }
305
306 static std::shared_ptr<StringDisplay> Make(size_t width, std::string open_quote, std::string close_quote)
307 {
308 return std::make_shared<StringDisplay>(width, open_quote, close_quote);
309 }
310
311 static std::shared_ptr<StringDisplay> Make(size_t width, std::string quote = "")
312 {
313 return std::make_shared<StringDisplay>(width, quote, quote);
314 }
315
316 static std::shared_ptr<StringDisplay> Make(std::string quote = "")
317 {
318 return std::make_shared<StringDisplay>(-1, quote, quote);
319 }
320
321 bool IsMissing(std::tuple<std::string>& values) override;
322 void DisplayValue(Dumper& dump, std::tuple<std::string> values) override;
323
324 using Display<std::string>::IsMissing;
325 bool IsMissing(std::tuple<offset_t>& values);
326 using Display<std::string>::DisplayValue;
327 void DisplayValue(Dumper& dump, std::tuple<offset_t> values);
328};
329
333class Field
334{
335public:
337 std::string label;
342
343 Field(std::string label, bool optional_field, bool internal)
345 {
346 }
347
348 virtual ~Field();
349
350 virtual bool ShouldDisplay() = 0;
351 virtual void DisplayValue(Dumper& dump) = 0;
352};
353
357template <typename ... Ts>
358 class FieldOf : public Field
359{
360public:
362 std::shared_ptr<Display<Ts...>> display;
363 std::tuple<Ts...> values;
364
365 FieldOf(std::string label, std::shared_ptr<Display<Ts...>> display, Ts... values, bool optional_field = false, bool internal = false)
366 : Field(label, optional_field, internal), display{display}, values{values...}
367 {
368 }
369
370 bool ShouldDisplay() override
371 {
372 return !internal && (!optional_field || !display->IsMissing(values));
373 }
374
375 void DisplayValue(Dumper& dump) override
376 {
377 display->DisplayValue(dump, values);
378 }
379};
380
385{
386public:
387 std::string name;
388
389 std::map<std::string, std::shared_ptr<Field>> field_names;
390 std::vector<std::shared_ptr<Field>> fields;
391
392 Container(std::string name = "")
393 : name(name)
394 {
395 }
396
397 virtual ~Container();
398
399 std::shared_ptr<Field> FindField(std::string name)
400 {
401 auto it = field_names.find(name);
402 if(it == field_names.end())
403 return nullptr;
404 return it->second;
405 }
406
407 template <typename T>
408 T GetField(std::string name, offset_t default_value = T())
409 {
410 auto it = field_names.find(name);
411 if(it == field_names.end())
412 return default_value;
413 if(auto field = std::dynamic_pointer_cast<FieldOf<T>>(it->second))
414 {
415 return std::get<0>(field->values);
416 }
417 return default_value;
418 }
419
420#if 0
421 offset_t GetField(std::string name, int index, offset_t default_value)
422 {
423 auto it = field_names.find(name);
424 if(it == field_names.end())
425 return default_value;
426 return it->second->values[index];
427 }
428#endif
429
430 void AddField(std::shared_ptr<Field> field)
431 {
432 fields.push_back(field);
433 field_names[field->label] = field;
434 }
435
436 void AddField(size_t index, std::shared_ptr<Field> field)
437 {
438 fields.insert(fields.begin() + index, field);
439 field_names[field->label] = field;
440 }
441
442 template <typename D, typename ... Ts>
443 void AddField(std::string label, std::shared_ptr<D> display, Ts... values)
444 {
445 AddField(std::make_shared<FieldOf<Ts...>>(label, display, values..., false, false));
446 }
447
448 template <typename D, typename ... Ts>
449 void AddOptionalField(std::string label, std::shared_ptr<D> display, Ts... values)
450 {
451 AddField(std::make_shared<FieldOf<Ts...>>(label, display, values..., true, false));
452 }
453
454 template <typename D, typename ... Ts>
455 void AddHiddenField(std::string label, std::shared_ptr<D> display, Ts... values)
456 {
457 AddField(std::make_shared<FieldOf<Ts...>>(label, display, values..., false, true));
458 }
459
460 template <typename D, typename ... Ts>
461 void InsertField(size_t index, std::string label, std::shared_ptr<D> display, Ts... values)
462 {
463 AddField(index, std::make_shared<FieldOf<Ts...>>(label, display, values..., false, false));
464 }
465
466 template <typename D, typename ... Ts>
467 void InsertOptionalField(size_t index, std::string label, std::shared_ptr<D> display, Ts... values)
468 {
469 AddField(index, std::make_shared<FieldOf<Ts...>>(label, display, values..., true, false));
470 }
471
472 template <typename D, typename ... Ts>
473 void InsertHiddenField(size_t index, std::string label, std::shared_ptr<D> display, Ts... values)
474 {
475 AddField(index, std::make_shared<FieldOf<Ts...>>(label, display, values..., false, true));
476 }
477
478 virtual void Display(Dumper& dump);
479};
480
484class Region : public Container
485{
486public:
487 Region(std::string name, offset_t offset, offset_t length, unsigned display_width)
488 : Container(name)
489 {
490 AddField("Offset", HexDisplay::Make(display_width), offset);
491 AddField("Length", HexDisplay::Make(display_width), length);
492 }
493
494 static std::shared_ptr<Region> Make(std::string name, offset_t offset, offset_t length, unsigned display_width)
495 {
496 return std::make_shared<Region>(name, offset, length, display_width);
497 }
498
499// void Display(Dumper& dump);
500};
501
505class Entry : public Container
506{
507public:
508 offset_t number;
509 offset_t offset;
510 unsigned display_width;
511
512 Entry(std::string name, offset_t number, offset_t offset = offset_t(-1), unsigned display_width = 8)
513 : Container(name), number(number), offset(offset), display_width(display_width)
514 {
515 }
516
517 void Display(Dumper& dump) override;
518};
519
523class Block : public Region
524{
525public:
532
533 static char32_t encoding_default[256];
534 static char32_t encoding_cp437[256];
535 static char32_t encoding_st[256];
536 static char32_t encoding_iso8859_1[256];
537 static char32_t encoding_windows1252[256];
538
539 std::shared_ptr<Linker::ActualImage> image;
540
541 std::set<offset_t> signal_starts;
542 std::set<offset_t> signal_ends;
543
550 void AddSignal(offset_t off, offset_t len)
551 {
552 offset_t end = off + len - 1;
553 signal_starts.insert(off);
554 signal_ends.insert(end);
555 }
556
557 Block(std::string name, offset_t offset, std::shared_ptr<Linker::ActualImage> image, offset_t address, unsigned display_width,
558 unsigned offset_display_width = 8, unsigned address_display_width = -1u, unsigned position_display_width = -1u)
559 : Region(name, offset, image ? image->ImageSize() : 0, display_width),
564 image(image)
565 {
566 AddField("Address", HexDisplay::Make(display_width), address);
567 }
568
569 static std::shared_ptr<Block> Make(std::string name, offset_t offset, std::shared_ptr<Linker::ActualImage> image, offset_t address, unsigned display_width,
570 unsigned offset_display_width = 8, unsigned address_display_width = -1u, unsigned position_display_width = -1u)
571 {
572 return std::make_shared<Block>(name, offset, image, address, display_width, offset_display_width, address_display_width, position_display_width);
573 }
574
575 void Display(Dumper& dump) override;
576};
577
586{
587public:
588 std::ostream& out;
589 bool use_ansi;
590
591 char32_t (* encoding)[256];
592
593 Dumper(std::ostream& out)
594 : out(out), use_ansi(true), encoding(nullptr)
595 {
596 }
597
598 void SetEncoding(char32_t (& encoding)[256], bool force = false)
599 {
600 if(this->encoding == nullptr || force)
601 {
602 this->encoding = &encoding;
603 }
604 }
605
606 void SetTitle(std::string title)
607 {
608 out << "=== " << title << " ===" << std::endl;
609 }
610
611// std::vector<Field> fields;
612
616 void PrintHex(offset_t value, unsigned width, std::string prefix = "0x")
617 {
618 out << prefix << std::hex << std::setw(width) << std::setfill('0') << value;
619 }
620
621#if 0
625 void PrintHex(offset_t value, unsigned width, bool prefixed)
626 {
627 PrintHex(value, width, prefixed ? "0x" : "");
628 }
629#endif
630
634 void PrintDec(offset_t value, std::string prefix = "#")
635 {
636 out << prefix << std::dec << value;
637 }
638
642 void PrintDecSigned(relative_offset_t value, std::string prefix = "#")
643 {
644 out << prefix << std::dec << value;
645 }
646
647#if 0
651 void PrintDec(offset_t value, bool prefixed)
652 {
653 PrintDec(value, prefixed ? "#" : "");
654 }
655#endif
656
660 void PutChar(char32_t c)
661 {
662 /* TODO: this should be customizable */
663 if(c < 0x80)
664 {
665 out.put(c);
666 }
667 else if(c < 0x800)
668 {
669 out.put((c >> 6) | 0xC0);
670 out.put((c & 0x3F) | 0x80);
671 }
672 else if(c < 0x10000)
673 {
674 out.put((c >> 12) | 0xE0);
675 out.put(((c >> 6) & 0x3F) | 0x80);
676 out.put((c & 0x3F) | 0x80);
677 }
678 else
679 {
680 out.put(((c >> 18) & 0x07) | 0xF0);
681 out.put(((c >> 12) & 0x3F) | 0x80);
682 out.put(((c >> 6) & 0x3F) | 0x80);
683 out.put((c & 0x3F) | 0x80);
684 }
685 }
686
691 {
692 if(use_ansi)
693 out << "\33[4m";
694 }
695
700 {
701 if(use_ansi)
702 out << "\33[m";
703 }
704};
705
706template <unsigned I, size_t ... Is, typename ... Ts>
707 inline auto rest_(std::tuple<Ts...> elements, std::index_sequence<Is...> s)
708{
709 return std::make_tuple(std::get<I + Is>(elements)...);
710}
711
712template <unsigned I, typename ... Ts>
713 inline auto rest(std::tuple<Ts...> elements)
714{
715 return rest_<I>(elements, std::make_index_sequence<sizeof...(Ts) - I>());
716}
717
718template <typename ... Ts>
719 void SectionedDisplay<Ts...>::DisplayValue(Dumper& dump, std::tuple<offset_t, Ts...> values)
720{
721 dump.PrintDec(std::get<0>(values), "");
722 dump.out << suffix << ':';
723 offset_display->DisplayValue(dump, rest<1>(values));
724}
725
726}
727
728#endif /* DUMPER_H */
Definition dumper.h:244
A value that is separated into bitfields, typically bit flags.
Definition dumper.h:241
A region within a file that can be dumped, decompiled, and it may contain fixups.
Definition dumper.h:524
unsigned offset_display_width
Displaying in-file offsets.
Definition dumper.h:527
void AddSignal(offset_t off, offset_t len)
Add a relocation inside the image block.
Definition dumper.h:550
unsigned position_display_width
Displaying in-segment positions.
Definition dumper.h:529
unsigned address_display_width
Displaying in-memory addresses.
Definition dumper.h:531
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
std::shared_ptr< Display< offset_t > > secondary_display
Alternative representation, appearing in parentheses after the value.
Definition dumper.h:62
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:107
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:92
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:385
Represents a field with a decimal display, usually indices into an array or similar,...
Definition dumper.h:147
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.
An abstract interface that separates structure and presentation of the data inside a file.
Definition dumper.h:586
void PrintDecSigned(relative_offset_t value, std::string prefix="#")
Displays a decimal value (default prefix is "#")
Definition dumper.h:642
void PrintHex(offset_t value, unsigned width, std::string prefix="0x")
Displays a hexadecimal value (default prefix is "0x")
Definition dumper.h:616
void EndUnderline()
ANSI escape sequence to remove all formatting.
Definition dumper.h:699
void PrintDec(offset_t value, std::string prefix="#")
Displays a decimal value (default prefix is "#")
Definition dumper.h:634
void BeginUnderline()
ANSI escape sequence to add underline.
Definition dumper.h:690
void PutChar(char32_t c)
Displays a Unicode character as a UTF-8 byte sequence.
Definition dumper.h:660
A brief record, such as a relocation or imported library.
Definition dumper.h:506
A typed representation of a named value within a structure.
Definition dumper.h:359
std::shared_ptr< Display< Ts... > > display
The method to show it in.
Definition dumper.h:362
A representation of a named value within a structure.
Definition dumper.h:334
std::string label
The name to be displayed.
Definition dumper.h:337
bool internal
The field should not be displayed, it is for internal use (alternatively, it can be displayed through...
Definition dumper.h:341
bool optional_field
If the field is optional, it will not be displayed for certain values.
Definition dumper.h:339
Represents a field with a hexadecimal display, typically bitfields, addresses, sizes,...
Definition dumper.h:127
A record that represents a region within the file.
Definition dumper.h:485
A display with a prefix for a section.
Definition dumper.h:214
A value displayed as a colon-separated pair, typically 8086 segmented addresses.
Definition dumper.h:173
A display for a fixed or variable length string field.
Definition dumper.h:293
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:298
A value displayed as a separated pair, such as a version number.
Definition dumper.h:193