xref: /aosp_15_r20/external/zucchini/disassembler_ztf.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1*a03ca8b9SKrzysztof Kosiński // Copyright 2018 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński 
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/disassembler_ztf.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <algorithm>
8*a03ca8b9SKrzysztof Kosiński #include <cmath>
9*a03ca8b9SKrzysztof Kosiński #include <iterator>
10*a03ca8b9SKrzysztof Kosiński #include <limits>
11*a03ca8b9SKrzysztof Kosiński #include <numeric>
12*a03ca8b9SKrzysztof Kosiński 
13*a03ca8b9SKrzysztof Kosiński #include "base/check_op.h"
14*a03ca8b9SKrzysztof Kosiński #include "base/numerics/checked_math.h"
15*a03ca8b9SKrzysztof Kosiński #include "base/numerics/safe_conversions.h"
16*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/algorithm.h"
17*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_source.h"
18*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/buffer_view.h"
19*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/io_utils.h"
20*a03ca8b9SKrzysztof Kosiński 
21*a03ca8b9SKrzysztof Kosiński namespace zucchini {
22*a03ca8b9SKrzysztof Kosiński 
23*a03ca8b9SKrzysztof Kosiński namespace {
24*a03ca8b9SKrzysztof Kosiński 
25*a03ca8b9SKrzysztof Kosiński constexpr uint8_t kDelimiter = ',';
26*a03ca8b9SKrzysztof Kosiński 
27*a03ca8b9SKrzysztof Kosiński constexpr int kHeaderMagicSize = 4;
28*a03ca8b9SKrzysztof Kosiński constexpr int kFooterMagicSize = 5;
29*a03ca8b9SKrzysztof Kosiński constexpr int kTotalMagicSize = kHeaderMagicSize + kFooterMagicSize;
30*a03ca8b9SKrzysztof Kosiński 
31*a03ca8b9SKrzysztof Kosiński // Number of characters that aren't digits in each type of reference.
32*a03ca8b9SKrzysztof Kosiński constexpr int kNumConstCharInAbs = 3;
33*a03ca8b9SKrzysztof Kosiński constexpr int kNumConstCharInRel = 5;
34*a03ca8b9SKrzysztof Kosiński 
35*a03ca8b9SKrzysztof Kosiński /******** ZtfConfig ********/
36*a03ca8b9SKrzysztof Kosiński 
37*a03ca8b9SKrzysztof Kosiński // For passing around metadata about the type of reference to match.
38*a03ca8b9SKrzysztof Kosiński // - |digits_per_dim| is the length of the offset in lines/cols of a
39*a03ca8b9SKrzysztof Kosiński //   reference.
40*a03ca8b9SKrzysztof Kosiński // - |open_char| is an ASCII character representing the opening char.
41*a03ca8b9SKrzysztof Kosiński // - |close_char| is an ASCII character representing the closing char.
42*a03ca8b9SKrzysztof Kosiński struct ZtfConfig {
43*a03ca8b9SKrzysztof Kosiński   uint8_t digits_per_dim;
44*a03ca8b9SKrzysztof Kosiński   uint8_t open_char;
45*a03ca8b9SKrzysztof Kosiński   uint8_t close_char;
46*a03ca8b9SKrzysztof Kosiński 
abs_widthzucchini::__anond77e67580111::ZtfConfig47*a03ca8b9SKrzysztof Kosiński   constexpr uint8_t abs_width() const {
48*a03ca8b9SKrzysztof Kosiński     return digits_per_dim * 2 + kNumConstCharInAbs;
49*a03ca8b9SKrzysztof Kosiński   }
50*a03ca8b9SKrzysztof Kosiński 
rel_widthzucchini::__anond77e67580111::ZtfConfig51*a03ca8b9SKrzysztof Kosiński   constexpr uint8_t rel_width() const {
52*a03ca8b9SKrzysztof Kosiński     return digits_per_dim * 2 + kNumConstCharInRel;
53*a03ca8b9SKrzysztof Kosiński   }
54*a03ca8b9SKrzysztof Kosiński 
Widthzucchini::__anond77e67580111::ZtfConfig55*a03ca8b9SKrzysztof Kosiński   uint8_t Width(ztf::LineCol /* lc */) const { return abs_width(); }
56*a03ca8b9SKrzysztof Kosiński 
Widthzucchini::__anond77e67580111::ZtfConfig57*a03ca8b9SKrzysztof Kosiński   uint8_t Width(ztf::DeltaLineCol /* dlc */) const { return rel_width(); }
58*a03ca8b9SKrzysztof Kosiński };
59*a03ca8b9SKrzysztof Kosiński 
60*a03ca8b9SKrzysztof Kosiński // Creates a ZtfConfig for parsing or writing based on the desired |digits| and
61*a03ca8b9SKrzysztof Kosiński // |pool|.
62*a03ca8b9SKrzysztof Kosiński template <DisassemblerZtf::ReferencePool pool>
MakeZtfConfig(uint8_t digits)63*a03ca8b9SKrzysztof Kosiński constexpr ZtfConfig MakeZtfConfig(uint8_t digits) {
64*a03ca8b9SKrzysztof Kosiński   switch (pool) {
65*a03ca8b9SKrzysztof Kosiński     case DisassemblerZtf::kAngles:
66*a03ca8b9SKrzysztof Kosiński       return ZtfConfig{digits, '<', '>'};
67*a03ca8b9SKrzysztof Kosiński     case DisassemblerZtf::kBraces:
68*a03ca8b9SKrzysztof Kosiński       return ZtfConfig{digits, '{', '}'};
69*a03ca8b9SKrzysztof Kosiński     case DisassemblerZtf::kBrackets:
70*a03ca8b9SKrzysztof Kosiński       return ZtfConfig{digits, '[', ']'};
71*a03ca8b9SKrzysztof Kosiński     case DisassemblerZtf::kParentheses:
72*a03ca8b9SKrzysztof Kosiński       break;  // Handled below.
73*a03ca8b9SKrzysztof Kosiński   }
74*a03ca8b9SKrzysztof Kosiński   return ZtfConfig{digits, '(', ')'};
75*a03ca8b9SKrzysztof Kosiński }
76*a03ca8b9SKrzysztof Kosiński 
77*a03ca8b9SKrzysztof Kosiński /******** ZtfParser ********/
78*a03ca8b9SKrzysztof Kosiński 
79*a03ca8b9SKrzysztof Kosiński // ZtfParser is used to extract (absolute) LineCol and (relative) DeltaLineCol
80*a03ca8b9SKrzysztof Kosiński // from a ZTF file, and contains various helpers for character, digits, and sign
81*a03ca8b9SKrzysztof Kosiński // matching.
82*a03ca8b9SKrzysztof Kosiński class ZtfParser {
83*a03ca8b9SKrzysztof Kosiński  public:
ZtfParser(offset_t hi,ConstBufferView image,ZtfConfig config)84*a03ca8b9SKrzysztof Kosiński   ZtfParser(offset_t hi, ConstBufferView image, ZtfConfig config)
85*a03ca8b9SKrzysztof Kosiński       : image_(image), hi_(hi), config_(config) {
86*a03ca8b9SKrzysztof Kosiński     DCHECK_LE(static_cast<size_t>(std::pow(10U, config_.digits_per_dim)),
87*a03ca8b9SKrzysztof Kosiński               ztf::kMaxDimValue);
88*a03ca8b9SKrzysztof Kosiński   }
89*a03ca8b9SKrzysztof Kosiński 
90*a03ca8b9SKrzysztof Kosiński   ZtfParser(const ZtfParser&) = delete;
91*a03ca8b9SKrzysztof Kosiński   const ZtfParser& operator=(const ZtfParser&) = delete;
92*a03ca8b9SKrzysztof Kosiński 
93*a03ca8b9SKrzysztof Kosiński   // Attempts to match an absolute reference at |offset|. If successful then
94*a03ca8b9SKrzysztof Kosiński   // assigns the result to |abs_lc| and returns true. Otherwise returns false.
95*a03ca8b9SKrzysztof Kosiński   // An absolute reference takes the form:
96*a03ca8b9SKrzysztof Kosiński   // <open><digits><delimiter><digits><close>
MatchAtOffset(offset_t offset,ztf::LineCol * abs_lc)97*a03ca8b9SKrzysztof Kosiński   bool MatchAtOffset(offset_t offset, ztf::LineCol* abs_lc) {
98*a03ca8b9SKrzysztof Kosiński     if (hi_ < config_.abs_width() || offset > hi_ - config_.abs_width())
99*a03ca8b9SKrzysztof Kosiński       return false;
100*a03ca8b9SKrzysztof Kosiński     offset_ = offset;
101*a03ca8b9SKrzysztof Kosiński     return MatchChar(config_.open_char) && MatchDigits(+1, &abs_lc->line) &&
102*a03ca8b9SKrzysztof Kosiński            MatchChar(kDelimiter) && MatchDigits(+1, &abs_lc->col) &&
103*a03ca8b9SKrzysztof Kosiński            MatchChar(config_.close_char);
104*a03ca8b9SKrzysztof Kosiński   }
105*a03ca8b9SKrzysztof Kosiński 
106*a03ca8b9SKrzysztof Kosiński   // Attempts to match an absolute reference at |offset|. If successful then
107*a03ca8b9SKrzysztof Kosiński   // assigns the result to |rel_lc| and returns true. Otherwise returns false. A
108*a03ca8b9SKrzysztof Kosiński   // relative reference takes the form:
109*a03ca8b9SKrzysztof Kosiński   // <open><sign><digits><delimiter><sign><digits><close>
MatchAtOffset(offset_t offset,ztf::DeltaLineCol * rel_dlc)110*a03ca8b9SKrzysztof Kosiński   bool MatchAtOffset(offset_t offset, ztf::DeltaLineCol* rel_dlc) {
111*a03ca8b9SKrzysztof Kosiński     if (hi_ < config_.rel_width() || offset > hi_ - config_.rel_width())
112*a03ca8b9SKrzysztof Kosiński       return false;
113*a03ca8b9SKrzysztof Kosiński     offset_ = offset;
114*a03ca8b9SKrzysztof Kosiński     ztf::dim_t line_sign;
115*a03ca8b9SKrzysztof Kosiński     ztf::dim_t col_sign;
116*a03ca8b9SKrzysztof Kosiński     return MatchChar(config_.open_char) && MatchSign(&line_sign) &&
117*a03ca8b9SKrzysztof Kosiński            MatchDigits(line_sign, &rel_dlc->line) && MatchChar(kDelimiter) &&
118*a03ca8b9SKrzysztof Kosiński            MatchSign(&col_sign) && MatchDigits(col_sign, &rel_dlc->col) &&
119*a03ca8b9SKrzysztof Kosiński            MatchChar(config_.close_char);
120*a03ca8b9SKrzysztof Kosiński   }
121*a03ca8b9SKrzysztof Kosiński 
122*a03ca8b9SKrzysztof Kosiński  private:
123*a03ca8b9SKrzysztof Kosiński   // The Match*() functions below can advance |offset_|, and return a bool to
124*a03ca8b9SKrzysztof Kosiński   // indicate success to allow chaining using &&.
125*a03ca8b9SKrzysztof Kosiński 
126*a03ca8b9SKrzysztof Kosiński   // Returns true if |character| is at location |offset_| in |image_| and
127*a03ca8b9SKrzysztof Kosiński   // increments |offset_|.
MatchChar(uint8_t character)128*a03ca8b9SKrzysztof Kosiński   bool MatchChar(uint8_t character) {
129*a03ca8b9SKrzysztof Kosiński     return character == image_.read<uint8_t>(offset_++);
130*a03ca8b9SKrzysztof Kosiński   }
131*a03ca8b9SKrzysztof Kosiński 
132*a03ca8b9SKrzysztof Kosiński   // Looks for '+' or '-' at |offset_|. If found, stores +1 or -1 in |sign| and
133*a03ca8b9SKrzysztof Kosiński   // returns true. Otherwise returns false.
MatchSign(ztf::dim_t * sign)134*a03ca8b9SKrzysztof Kosiński   bool MatchSign(ztf::dim_t* sign) {
135*a03ca8b9SKrzysztof Kosiński     uint8_t val = image_.read<uint8_t>(offset_++);
136*a03ca8b9SKrzysztof Kosiński     if (val == static_cast<uint8_t>(ztf::SignChar::kMinus)) {
137*a03ca8b9SKrzysztof Kosiński       *sign = -1;
138*a03ca8b9SKrzysztof Kosiński       return true;
139*a03ca8b9SKrzysztof Kosiński     }
140*a03ca8b9SKrzysztof Kosiński     if (val == static_cast<uint8_t>(ztf::SignChar::kPlus)) {
141*a03ca8b9SKrzysztof Kosiński       *sign = 1;
142*a03ca8b9SKrzysztof Kosiński       return true;
143*a03ca8b9SKrzysztof Kosiński     }
144*a03ca8b9SKrzysztof Kosiński     return false;
145*a03ca8b9SKrzysztof Kosiński   }
146*a03ca8b9SKrzysztof Kosiński 
147*a03ca8b9SKrzysztof Kosiński   // Attempts to extract a number with the number of base 10 digits equal to
148*a03ca8b9SKrzysztof Kosiński   // |config_.digits_per_dim| from |image_| starting from |offset_|. Returns
149*a03ca8b9SKrzysztof Kosiński   // true and assigns the integer value to |value| if successful.
MatchDigits(ztf::dim_t sign,ztf::dim_t * value)150*a03ca8b9SKrzysztof Kosiński   bool MatchDigits(ztf::dim_t sign, ztf::dim_t* value) {
151*a03ca8b9SKrzysztof Kosiński     ztf::dim_t output = 0;
152*a03ca8b9SKrzysztof Kosiński     for (int i = 0; i < config_.digits_per_dim; ++i) {
153*a03ca8b9SKrzysztof Kosiński       auto digit = image_.read<uint8_t>(offset_++);
154*a03ca8b9SKrzysztof Kosiński       if (digit >= '0' && digit < '0' + 10)
155*a03ca8b9SKrzysztof Kosiński         output = output * 10 + digit - '0';
156*a03ca8b9SKrzysztof Kosiński       else
157*a03ca8b9SKrzysztof Kosiński         return false;
158*a03ca8b9SKrzysztof Kosiński     }
159*a03ca8b9SKrzysztof Kosiński     if (!output && sign < 0)  // Disallow "-0", "-00", etc.
160*a03ca8b9SKrzysztof Kosiński       return false;
161*a03ca8b9SKrzysztof Kosiński     *value = sign * output;
162*a03ca8b9SKrzysztof Kosiński     return true;
163*a03ca8b9SKrzysztof Kosiński   }
164*a03ca8b9SKrzysztof Kosiński 
165*a03ca8b9SKrzysztof Kosiński   ConstBufferView image_;
166*a03ca8b9SKrzysztof Kosiński   const offset_t hi_;
167*a03ca8b9SKrzysztof Kosiński   const ZtfConfig config_;
168*a03ca8b9SKrzysztof Kosiński   offset_t offset_ = 0;
169*a03ca8b9SKrzysztof Kosiński };
170*a03ca8b9SKrzysztof Kosiński 
171*a03ca8b9SKrzysztof Kosiński /******** ZtfWriter ********/
172*a03ca8b9SKrzysztof Kosiński 
173*a03ca8b9SKrzysztof Kosiński // ZtfWriter is used to write references to an image. This includes writing
174*a03ca8b9SKrzysztof Kosiński // the enclosing characters around the reference.
175*a03ca8b9SKrzysztof Kosiński class ZtfWriter {
176*a03ca8b9SKrzysztof Kosiński  public:
ZtfWriter(MutableBufferView image,ZtfConfig config)177*a03ca8b9SKrzysztof Kosiński   ZtfWriter(MutableBufferView image, ZtfConfig config)
178*a03ca8b9SKrzysztof Kosiński       : image_(image),
179*a03ca8b9SKrzysztof Kosiński         config_(config),
180*a03ca8b9SKrzysztof Kosiński         val_bound_(
181*a03ca8b9SKrzysztof Kosiński             static_cast<ztf::dim_t>(std::pow(10, config_.digits_per_dim))) {}
182*a03ca8b9SKrzysztof Kosiński 
183*a03ca8b9SKrzysztof Kosiński   ZtfWriter(const ZtfWriter&) = delete;
184*a03ca8b9SKrzysztof Kosiński   const ZtfWriter& operator=(const ZtfWriter&) = delete;
185*a03ca8b9SKrzysztof Kosiński 
186*a03ca8b9SKrzysztof Kosiński   // Write an absolute reference |abs_ref| at |offset|. Note that references
187*a03ca8b9SKrzysztof Kosiński   // that would overwrite a newline are skipped as this would invalidate all
188*a03ca8b9SKrzysztof Kosiński   // the other reference line numbers.
Write(offset_t offset,ztf::LineCol abs_ref)189*a03ca8b9SKrzysztof Kosiński   void Write(offset_t offset, ztf::LineCol abs_ref) {
190*a03ca8b9SKrzysztof Kosiński     offset_ = offset;
191*a03ca8b9SKrzysztof Kosiński     if (!SafeToWriteNumber(abs_ref.line) || !SafeToWriteNumber(abs_ref.col) ||
192*a03ca8b9SKrzysztof Kosiński         !SafeToWriteData(offset_, offset_ + config_.abs_width())) {
193*a03ca8b9SKrzysztof Kosiński       return;
194*a03ca8b9SKrzysztof Kosiński     }
195*a03ca8b9SKrzysztof Kosiński     WriteChar(config_.open_char);
196*a03ca8b9SKrzysztof Kosiński     WriteNumber(abs_ref.line);
197*a03ca8b9SKrzysztof Kosiński     WriteChar(kDelimiter);
198*a03ca8b9SKrzysztof Kosiński     WriteNumber(abs_ref.col);
199*a03ca8b9SKrzysztof Kosiński     WriteChar(config_.close_char);
200*a03ca8b9SKrzysztof Kosiński   }
201*a03ca8b9SKrzysztof Kosiński 
202*a03ca8b9SKrzysztof Kosiński   // Write a relative reference |rel_ref| at |offset|. Note that references
203*a03ca8b9SKrzysztof Kosiński   // that would overwrite a newline are skipped as this would invalidate all
204*a03ca8b9SKrzysztof Kosiński   // the other reference line numbers.
Write(offset_t offset,ztf::DeltaLineCol rel_ref)205*a03ca8b9SKrzysztof Kosiński   void Write(offset_t offset, ztf::DeltaLineCol rel_ref) {
206*a03ca8b9SKrzysztof Kosiński     offset_ = offset;
207*a03ca8b9SKrzysztof Kosiński     if (!SafeToWriteNumber(rel_ref.line) || !SafeToWriteNumber(rel_ref.col) ||
208*a03ca8b9SKrzysztof Kosiński         !SafeToWriteData(offset_, offset_ + config_.rel_width())) {
209*a03ca8b9SKrzysztof Kosiński       return;
210*a03ca8b9SKrzysztof Kosiński     }
211*a03ca8b9SKrzysztof Kosiński     WriteChar(config_.open_char);
212*a03ca8b9SKrzysztof Kosiński     WriteSign(rel_ref.line);
213*a03ca8b9SKrzysztof Kosiński     WriteNumber(rel_ref.line);
214*a03ca8b9SKrzysztof Kosiński     WriteChar(kDelimiter);
215*a03ca8b9SKrzysztof Kosiński     WriteSign(rel_ref.col);
216*a03ca8b9SKrzysztof Kosiński     WriteNumber(rel_ref.col);
217*a03ca8b9SKrzysztof Kosiński     WriteChar(config_.close_char);
218*a03ca8b9SKrzysztof Kosiński   }
219*a03ca8b9SKrzysztof Kosiński 
220*a03ca8b9SKrzysztof Kosiński  private:
221*a03ca8b9SKrzysztof Kosiński   // Returns whether it is safe to modify bytes in |[lo, hi)| in |image_| for
222*a03ca8b9SKrzysztof Kosiński   // Reference correction. Failure cases are:
223*a03ca8b9SKrzysztof Kosiński   // - Out-of-bound writes.
224*a03ca8b9SKrzysztof Kosiński   // - Overwriting '\n'. This is a ZTF special case since '\n' dictates file
225*a03ca8b9SKrzysztof Kosiński   //   structure, and Reference correction should never mess with this.
SafeToWriteData(offset_t lo,offset_t hi) const226*a03ca8b9SKrzysztof Kosiński   bool SafeToWriteData(offset_t lo, offset_t hi) const {
227*a03ca8b9SKrzysztof Kosiński     DCHECK_LE(lo, hi);
228*a03ca8b9SKrzysztof Kosiński     // Out of bounds.
229*a03ca8b9SKrzysztof Kosiński     if (hi > image_.size())
230*a03ca8b9SKrzysztof Kosiński       return false;
231*a03ca8b9SKrzysztof Kosiński     for (offset_t i = lo; i < hi; ++i) {
232*a03ca8b9SKrzysztof Kosiński       if (image_.read<uint8_t>(i) == '\n')
233*a03ca8b9SKrzysztof Kosiński         return false;
234*a03ca8b9SKrzysztof Kosiński     }
235*a03ca8b9SKrzysztof Kosiński     return true;
236*a03ca8b9SKrzysztof Kosiński   }
237*a03ca8b9SKrzysztof Kosiński 
238*a03ca8b9SKrzysztof Kosiński   // Checks whether it is safe to write a |val| based on
239*a03ca8b9SKrzysztof Kosiński   // |config_.digits_per_dim|.
SafeToWriteNumber(ztf::dim_t val) const240*a03ca8b9SKrzysztof Kosiński   bool SafeToWriteNumber(ztf::dim_t val) const {
241*a03ca8b9SKrzysztof Kosiński     return std::abs(val) < val_bound_;
242*a03ca8b9SKrzysztof Kosiński   }
243*a03ca8b9SKrzysztof Kosiński 
244*a03ca8b9SKrzysztof Kosiński   // The Write*() functions each advance |offset_| by a fixed distance. The
245*a03ca8b9SKrzysztof Kosiński   // caller should ensure there's enough space to write data.
246*a03ca8b9SKrzysztof Kosiński 
247*a03ca8b9SKrzysztof Kosiński   // Write |character| at |offset_| and increment |offset_|.
WriteChar(uint8_t character)248*a03ca8b9SKrzysztof Kosiński   void WriteChar(uint8_t character) { image_.write(offset_++, character); }
249*a03ca8b9SKrzysztof Kosiński 
250*a03ca8b9SKrzysztof Kosiński   // Write the sign of |value| at |offset_| and increment |offset_|.
WriteSign(ztf::dim_t value)251*a03ca8b9SKrzysztof Kosiński   void WriteSign(ztf::dim_t value) {
252*a03ca8b9SKrzysztof Kosiński     image_.write(offset_++,
253*a03ca8b9SKrzysztof Kosiński                  value >= 0 ? ztf::SignChar::kPlus : ztf::SignChar::kMinus);
254*a03ca8b9SKrzysztof Kosiński   }
255*a03ca8b9SKrzysztof Kosiński 
256*a03ca8b9SKrzysztof Kosiński   // Writes the absolute value of the number represented by |value| at |offset_|
257*a03ca8b9SKrzysztof Kosiński   // using zero padding to fill |config_.digits_per_dim|.
WriteNumber(ztf::dim_t value)258*a03ca8b9SKrzysztof Kosiński   void WriteNumber(ztf::dim_t value) {
259*a03ca8b9SKrzysztof Kosiński     size_t size = config_.digits_per_dim + 1;
260*a03ca8b9SKrzysztof Kosiński     DCHECK_LE(size, kMaxDigitCount + 1);
261*a03ca8b9SKrzysztof Kosiński     char digits[kMaxDigitCount + 1];  // + 1 for terminator.
262*a03ca8b9SKrzysztof Kosiński     int len =
263*a03ca8b9SKrzysztof Kosiński         snprintf(digits, size, "%0*u", config_.digits_per_dim, std::abs(value));
264*a03ca8b9SKrzysztof Kosiński     DCHECK_EQ(len, config_.digits_per_dim);
265*a03ca8b9SKrzysztof Kosiński     for (int i = 0; i < len; ++i)
266*a03ca8b9SKrzysztof Kosiński       image_.write(offset_++, digits[i]);
267*a03ca8b9SKrzysztof Kosiński   }
268*a03ca8b9SKrzysztof Kosiński 
269*a03ca8b9SKrzysztof Kosiński   MutableBufferView image_;
270*a03ca8b9SKrzysztof Kosiński   const ZtfConfig config_;
271*a03ca8b9SKrzysztof Kosiński   // Bound on numeric values, as limited by |config_.digits_per_dim|.
272*a03ca8b9SKrzysztof Kosiński   const ztf::dim_t val_bound_;
273*a03ca8b9SKrzysztof Kosiński   offset_t offset_ = 0;
274*a03ca8b9SKrzysztof Kosiński };
275*a03ca8b9SKrzysztof Kosiński 
276*a03ca8b9SKrzysztof Kosiński // Specialization of ReferenceReader for reading text references.
277*a03ca8b9SKrzysztof Kosiński template <typename T>
278*a03ca8b9SKrzysztof Kosiński class ZtfReferenceReader : public ReferenceReader {
279*a03ca8b9SKrzysztof Kosiński  public:
ZtfReferenceReader(offset_t lo,offset_t hi,ConstBufferView image,const ZtfTranslator & translator,ZtfConfig config)280*a03ca8b9SKrzysztof Kosiński   ZtfReferenceReader(offset_t lo,
281*a03ca8b9SKrzysztof Kosiński                      offset_t hi,
282*a03ca8b9SKrzysztof Kosiński                      ConstBufferView image,
283*a03ca8b9SKrzysztof Kosiński                      const ZtfTranslator& translator,
284*a03ca8b9SKrzysztof Kosiński                      ZtfConfig config)
285*a03ca8b9SKrzysztof Kosiński       : offset_(lo),
286*a03ca8b9SKrzysztof Kosiński         hi_(hi),
287*a03ca8b9SKrzysztof Kosiński         translator_(translator),
288*a03ca8b9SKrzysztof Kosiński         config_(config),
289*a03ca8b9SKrzysztof Kosiński         parser_(hi_, image, config_) {
290*a03ca8b9SKrzysztof Kosiński     DCHECK_LE(hi_, image.size());
291*a03ca8b9SKrzysztof Kosiński   }
292*a03ca8b9SKrzysztof Kosiński 
293*a03ca8b9SKrzysztof Kosiński   // Walks |offset_| from |lo| to |hi_| running |parser_|. If any matches are
294*a03ca8b9SKrzysztof Kosiński   // found they are returned.
GetNext()295*a03ca8b9SKrzysztof Kosiński   std::optional<Reference> GetNext() override {
296*a03ca8b9SKrzysztof Kosiński     T line_col;
297*a03ca8b9SKrzysztof Kosiński     for (; offset_ < hi_; ++offset_) {
298*a03ca8b9SKrzysztof Kosiński       if (!parser_.MatchAtOffset(offset_, &line_col))
299*a03ca8b9SKrzysztof Kosiński         continue;
300*a03ca8b9SKrzysztof Kosiński 
301*a03ca8b9SKrzysztof Kosiński       auto target = ConvertToTargetOffset(offset_, line_col);
302*a03ca8b9SKrzysztof Kosiński       // Ignore targets that point outside the file.
303*a03ca8b9SKrzysztof Kosiński       if (target == kInvalidOffset)
304*a03ca8b9SKrzysztof Kosiński         continue;
305*a03ca8b9SKrzysztof Kosiński       offset_t location = offset_;
306*a03ca8b9SKrzysztof Kosiński       offset_ += config_.Width(line_col);
307*a03ca8b9SKrzysztof Kosiński       return Reference{location, target};
308*a03ca8b9SKrzysztof Kosiński     }
309*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
310*a03ca8b9SKrzysztof Kosiński   }
311*a03ca8b9SKrzysztof Kosiński 
312*a03ca8b9SKrzysztof Kosiński  private:
313*a03ca8b9SKrzysztof Kosiński   // Converts |lc| (an absolute reference) to an offset using |translator_|.
ConvertToTargetOffset(offset_t,ztf::LineCol lc) const314*a03ca8b9SKrzysztof Kosiński   offset_t ConvertToTargetOffset(offset_t /* location */,
315*a03ca8b9SKrzysztof Kosiński                                  ztf::LineCol lc) const {
316*a03ca8b9SKrzysztof Kosiński     return translator_.LineColToOffset(lc);
317*a03ca8b9SKrzysztof Kosiński   }
318*a03ca8b9SKrzysztof Kosiński 
319*a03ca8b9SKrzysztof Kosiński   // Converts |dlc| (a relative reference) to an offset using |translator_|.
320*a03ca8b9SKrzysztof Kosiński   // This requires converting the |dlc| to a ztf::LineCol to find the offset.
ConvertToTargetOffset(offset_t location,ztf::DeltaLineCol dlc) const321*a03ca8b9SKrzysztof Kosiński   offset_t ConvertToTargetOffset(offset_t location,
322*a03ca8b9SKrzysztof Kosiński                                  ztf::DeltaLineCol dlc) const {
323*a03ca8b9SKrzysztof Kosiński     auto lc = translator_.OffsetToLineCol(location);
324*a03ca8b9SKrzysztof Kosiński     if (!lc.has_value())
325*a03ca8b9SKrzysztof Kosiński       return kInvalidOffset;
326*a03ca8b9SKrzysztof Kosiński     return translator_.LineColToOffset(lc.value() + dlc);
327*a03ca8b9SKrzysztof Kosiński   }
328*a03ca8b9SKrzysztof Kosiński 
329*a03ca8b9SKrzysztof Kosiński   offset_t offset_;
330*a03ca8b9SKrzysztof Kosiński   const offset_t hi_;
331*a03ca8b9SKrzysztof Kosiński   const ZtfTranslator& translator_;
332*a03ca8b9SKrzysztof Kosiński   const ZtfConfig config_;
333*a03ca8b9SKrzysztof Kosiński   ZtfParser parser_;
334*a03ca8b9SKrzysztof Kosiński };
335*a03ca8b9SKrzysztof Kosiński 
336*a03ca8b9SKrzysztof Kosiński // Specialization of ReferenceWriter for writing text references.
337*a03ca8b9SKrzysztof Kosiński template <typename T>
338*a03ca8b9SKrzysztof Kosiński class ZtfReferenceWriter : public ReferenceWriter {
339*a03ca8b9SKrzysztof Kosiński  public:
ZtfReferenceWriter(MutableBufferView image,const ZtfTranslator & translator,ZtfConfig config)340*a03ca8b9SKrzysztof Kosiński   ZtfReferenceWriter(MutableBufferView image,
341*a03ca8b9SKrzysztof Kosiński                      const ZtfTranslator& translator,
342*a03ca8b9SKrzysztof Kosiński                      ZtfConfig config)
343*a03ca8b9SKrzysztof Kosiński       : translator_(translator), writer_(image, config) {}
344*a03ca8b9SKrzysztof Kosiński 
PutNext(Reference reference)345*a03ca8b9SKrzysztof Kosiński   void PutNext(Reference reference) override {
346*a03ca8b9SKrzysztof Kosiński     T line_col;
347*a03ca8b9SKrzysztof Kosiński     if (!ConvertToTargetLineCol(reference, &line_col))
348*a03ca8b9SKrzysztof Kosiński       return;
349*a03ca8b9SKrzysztof Kosiński 
350*a03ca8b9SKrzysztof Kosiński     writer_.Write(reference.location, line_col);
351*a03ca8b9SKrzysztof Kosiński   }
352*a03ca8b9SKrzysztof Kosiński 
353*a03ca8b9SKrzysztof Kosiński  private:
354*a03ca8b9SKrzysztof Kosiński   // Converts |reference| to an absolute reference to be stored in |out_lc|.
355*a03ca8b9SKrzysztof Kosiński   // Returns true on success.
ConvertToTargetLineCol(Reference reference,ztf::LineCol * out_lc)356*a03ca8b9SKrzysztof Kosiński   bool ConvertToTargetLineCol(Reference reference, ztf::LineCol* out_lc) {
357*a03ca8b9SKrzysztof Kosiński     auto temp_lc = translator_.OffsetToLineCol(reference.target);
358*a03ca8b9SKrzysztof Kosiński     if (!temp_lc.has_value() || !translator_.IsValid(temp_lc.value()))
359*a03ca8b9SKrzysztof Kosiński       return false;
360*a03ca8b9SKrzysztof Kosiński 
361*a03ca8b9SKrzysztof Kosiński     *out_lc = temp_lc.value();
362*a03ca8b9SKrzysztof Kosiński     return true;
363*a03ca8b9SKrzysztof Kosiński   }
364*a03ca8b9SKrzysztof Kosiński 
365*a03ca8b9SKrzysztof Kosiński   // Converts |reference| to a relative reference to be stored in |out_dlc|.
366*a03ca8b9SKrzysztof Kosiński   // Will return true on success.
ConvertToTargetLineCol(Reference reference,ztf::DeltaLineCol * out_dlc)367*a03ca8b9SKrzysztof Kosiński   bool ConvertToTargetLineCol(Reference reference, ztf::DeltaLineCol* out_dlc) {
368*a03ca8b9SKrzysztof Kosiński     auto location_lc = translator_.OffsetToLineCol(reference.location);
369*a03ca8b9SKrzysztof Kosiński     if (!location_lc.has_value())
370*a03ca8b9SKrzysztof Kosiński       return false;
371*a03ca8b9SKrzysztof Kosiński 
372*a03ca8b9SKrzysztof Kosiński     auto target_lc = translator_.OffsetToLineCol(reference.target);
373*a03ca8b9SKrzysztof Kosiński     if (!target_lc.has_value())
374*a03ca8b9SKrzysztof Kosiński       return false;
375*a03ca8b9SKrzysztof Kosiński 
376*a03ca8b9SKrzysztof Kosiński     *out_dlc = target_lc.value() - location_lc.value();
377*a03ca8b9SKrzysztof Kosiński     return translator_.IsValid(reference.location, *out_dlc);
378*a03ca8b9SKrzysztof Kosiński   }
379*a03ca8b9SKrzysztof Kosiński 
380*a03ca8b9SKrzysztof Kosiński   const ZtfTranslator& translator_;
381*a03ca8b9SKrzysztof Kosiński   ZtfWriter writer_;
382*a03ca8b9SKrzysztof Kosiński };
383*a03ca8b9SKrzysztof Kosiński 
384*a03ca8b9SKrzysztof Kosiński // Reads a text header to check for the magic string "ZTxt" at the start
385*a03ca8b9SKrzysztof Kosiński // indicating the file should be treated as a Zucchini text file.
ReadZtfHeader(ConstBufferView image)386*a03ca8b9SKrzysztof Kosiński bool ReadZtfHeader(ConstBufferView image) {
387*a03ca8b9SKrzysztof Kosiński   BufferSource source(image);
388*a03ca8b9SKrzysztof Kosiński   // Reject empty images and "ZTxtxTZ\n" (missing 't').
389*a03ca8b9SKrzysztof Kosiński   if (source.size() < kTotalMagicSize)
390*a03ca8b9SKrzysztof Kosiński     return false;
391*a03ca8b9SKrzysztof Kosiński   if (source.size() > std::numeric_limits<offset_t>::max())
392*a03ca8b9SKrzysztof Kosiński     return false;
393*a03ca8b9SKrzysztof Kosiński   return source.CheckNextBytes({'Z', 'T', 'x', 't'});
394*a03ca8b9SKrzysztof Kosiński }
395*a03ca8b9SKrzysztof Kosiński 
396*a03ca8b9SKrzysztof Kosiński }  // namespace
397*a03ca8b9SKrzysztof Kosiński 
398*a03ca8b9SKrzysztof Kosiński /******** ZtfTranslator ********/
399*a03ca8b9SKrzysztof Kosiński 
ZtfTranslator()400*a03ca8b9SKrzysztof Kosiński ZtfTranslator::ZtfTranslator() {}
401*a03ca8b9SKrzysztof Kosiński 
402*a03ca8b9SKrzysztof Kosiński ZtfTranslator::~ZtfTranslator() = default;
403*a03ca8b9SKrzysztof Kosiński 
Init(ConstBufferView image)404*a03ca8b9SKrzysztof Kosiński bool ZtfTranslator::Init(ConstBufferView image) {
405*a03ca8b9SKrzysztof Kosiński   line_starts_.clear();
406*a03ca8b9SKrzysztof Kosiński   // Record the starting offset of every line in |image_| into |line_start_|.
407*a03ca8b9SKrzysztof Kosiński   line_starts_.push_back(0);
408*a03ca8b9SKrzysztof Kosiński   for (size_t i = 0; i < image.size(); ++i) {
409*a03ca8b9SKrzysztof Kosiński     if (image.read<uint8_t>(i) == '\n') {
410*a03ca8b9SKrzysztof Kosiński       // Maximum number of entries is |ztf::kMaxDimValue|, including the end
411*a03ca8b9SKrzysztof Kosiński       // sentinel.
412*a03ca8b9SKrzysztof Kosiński       if (line_starts_.size() >= ztf::kMaxDimValue)
413*a03ca8b9SKrzysztof Kosiński         return false;
414*a03ca8b9SKrzysztof Kosiński       line_starts_.push_back(base::checked_cast<offset_t>(i + 1));
415*a03ca8b9SKrzysztof Kosiński       // Check that the line length is reachable from an absolute reference.
416*a03ca8b9SKrzysztof Kosiński       if (line_starts_.back() - *std::next(line_starts_.rbegin()) >=
417*a03ca8b9SKrzysztof Kosiński           ztf::kMaxDimValue) {
418*a03ca8b9SKrzysztof Kosiński         return false;
419*a03ca8b9SKrzysztof Kosiński       }
420*a03ca8b9SKrzysztof Kosiński     }
421*a03ca8b9SKrzysztof Kosiński   }
422*a03ca8b9SKrzysztof Kosiński   // Since the last character of ZTF file is always '\n', |line_starts_| will
423*a03ca8b9SKrzysztof Kosiński   // always contain the file length as the last element, which serves as a
424*a03ca8b9SKrzysztof Kosiński   // sentinel.
425*a03ca8b9SKrzysztof Kosiński   CHECK_EQ(image.size(), static_cast<size_t>(line_starts_.back()));
426*a03ca8b9SKrzysztof Kosiński   return true;
427*a03ca8b9SKrzysztof Kosiński }
428*a03ca8b9SKrzysztof Kosiński 
IsValid(ztf::LineCol lc) const429*a03ca8b9SKrzysztof Kosiński bool ZtfTranslator::IsValid(ztf::LineCol lc) const {
430*a03ca8b9SKrzysztof Kosiński   DCHECK(!line_starts_.empty());
431*a03ca8b9SKrzysztof Kosiński   return lc.line >= 1 && lc.col >= 1 &&
432*a03ca8b9SKrzysztof Kosiński          static_cast<offset_t>(lc.line) <= NumLines() &&
433*a03ca8b9SKrzysztof Kosiński          static_cast<offset_t>(lc.col) <= LineLength(lc.line);
434*a03ca8b9SKrzysztof Kosiński }
435*a03ca8b9SKrzysztof Kosiński 
IsValid(offset_t offset,ztf::DeltaLineCol dlc) const436*a03ca8b9SKrzysztof Kosiński bool ZtfTranslator::IsValid(offset_t offset, ztf::DeltaLineCol dlc) const {
437*a03ca8b9SKrzysztof Kosiński   DCHECK(!line_starts_.empty());
438*a03ca8b9SKrzysztof Kosiński   auto abs_lc = OffsetToLineCol(offset);
439*a03ca8b9SKrzysztof Kosiński   if (!abs_lc.has_value())
440*a03ca8b9SKrzysztof Kosiński     return false;
441*a03ca8b9SKrzysztof Kosiński 
442*a03ca8b9SKrzysztof Kosiński   if (!base::CheckAdd(abs_lc->line, dlc.line).IsValid() ||
443*a03ca8b9SKrzysztof Kosiński       !base::CheckAdd(abs_lc->col, dlc.col).IsValid()) {
444*a03ca8b9SKrzysztof Kosiński     return false;
445*a03ca8b9SKrzysztof Kosiński   }
446*a03ca8b9SKrzysztof Kosiński   return IsValid(abs_lc.value() + dlc);
447*a03ca8b9SKrzysztof Kosiński }
448*a03ca8b9SKrzysztof Kosiński 
LineColToOffset(ztf::LineCol lc) const449*a03ca8b9SKrzysztof Kosiński offset_t ZtfTranslator::LineColToOffset(ztf::LineCol lc) const {
450*a03ca8b9SKrzysztof Kosiński   // Guard against out of bounds access to |line_starts_| and ensure the
451*a03ca8b9SKrzysztof Kosiński   // |lc| falls within the file.
452*a03ca8b9SKrzysztof Kosiński   DCHECK(!line_starts_.empty());
453*a03ca8b9SKrzysztof Kosiński   if (!IsValid(lc))
454*a03ca8b9SKrzysztof Kosiński     return kInvalidOffset;
455*a03ca8b9SKrzysztof Kosiński 
456*a03ca8b9SKrzysztof Kosiński   offset_t target = line_starts_[lc.line - 1] + lc.col - 1;
457*a03ca8b9SKrzysztof Kosiński   DCHECK_LT(target, line_starts_.back());
458*a03ca8b9SKrzysztof Kosiński   return target;
459*a03ca8b9SKrzysztof Kosiński }
460*a03ca8b9SKrzysztof Kosiński 
OffsetToLineCol(offset_t offset) const461*a03ca8b9SKrzysztof Kosiński std::optional<ztf::LineCol> ZtfTranslator::OffsetToLineCol(
462*a03ca8b9SKrzysztof Kosiński     offset_t offset) const {
463*a03ca8b9SKrzysztof Kosiński   DCHECK(!line_starts_.empty());
464*a03ca8b9SKrzysztof Kosiński   // Don't place a target outside the image.
465*a03ca8b9SKrzysztof Kosiński   if (offset >= line_starts_.back())
466*a03ca8b9SKrzysztof Kosiński     return std::nullopt;
467*a03ca8b9SKrzysztof Kosiński   auto it = SearchForRange(offset);
468*a03ca8b9SKrzysztof Kosiński   ztf::LineCol lc;
469*a03ca8b9SKrzysztof Kosiński   lc.line = std::distance(line_starts_.cbegin(), it) + 1;
470*a03ca8b9SKrzysztof Kosiński   lc.col = offset - line_starts_[lc.line - 1] + 1;
471*a03ca8b9SKrzysztof Kosiński   DCHECK_LE(static_cast<offset_t>(lc.col), LineLength(lc.line));
472*a03ca8b9SKrzysztof Kosiński   return lc;
473*a03ca8b9SKrzysztof Kosiński }
474*a03ca8b9SKrzysztof Kosiński 
SearchForRange(offset_t offset) const475*a03ca8b9SKrzysztof Kosiński std::vector<offset_t>::const_iterator ZtfTranslator::SearchForRange(
476*a03ca8b9SKrzysztof Kosiński     offset_t offset) const {
477*a03ca8b9SKrzysztof Kosiński   DCHECK(!line_starts_.empty());
478*a03ca8b9SKrzysztof Kosiński   auto it =
479*a03ca8b9SKrzysztof Kosiński       std::upper_bound(line_starts_.cbegin(), line_starts_.cend(), offset);
480*a03ca8b9SKrzysztof Kosiński   DCHECK(it != line_starts_.cbegin());
481*a03ca8b9SKrzysztof Kosiński   return --it;
482*a03ca8b9SKrzysztof Kosiński }
483*a03ca8b9SKrzysztof Kosiński 
LineLength(uint16_t line) const484*a03ca8b9SKrzysztof Kosiński offset_t ZtfTranslator::LineLength(uint16_t line) const {
485*a03ca8b9SKrzysztof Kosiński   DCHECK_GE(line, 1);
486*a03ca8b9SKrzysztof Kosiński   DCHECK_LE(line, NumLines());
487*a03ca8b9SKrzysztof Kosiński   return line_starts_[line] - line_starts_[line - 1];
488*a03ca8b9SKrzysztof Kosiński }
489*a03ca8b9SKrzysztof Kosiński 
490*a03ca8b9SKrzysztof Kosiński /******** DisassemblerZtf ********/
491*a03ca8b9SKrzysztof Kosiński 
492*a03ca8b9SKrzysztof Kosiński // Use 2 even though reference "chaining" isn't present in ZTF as it is the
493*a03ca8b9SKrzysztof Kosiński // usual case for other Disassemblers and this is meant to mimic that as closely
494*a03ca8b9SKrzysztof Kosiński // as possible.
DisassemblerZtf()495*a03ca8b9SKrzysztof Kosiński DisassemblerZtf::DisassemblerZtf() : Disassembler(2) {}
496*a03ca8b9SKrzysztof Kosiński 
497*a03ca8b9SKrzysztof Kosiński DisassemblerZtf::~DisassemblerZtf() = default;
498*a03ca8b9SKrzysztof Kosiński 
499*a03ca8b9SKrzysztof Kosiński // static.
QuickDetect(ConstBufferView image)500*a03ca8b9SKrzysztof Kosiński bool DisassemblerZtf::QuickDetect(ConstBufferView image) {
501*a03ca8b9SKrzysztof Kosiński   return ReadZtfHeader(image);
502*a03ca8b9SKrzysztof Kosiński }
503*a03ca8b9SKrzysztof Kosiński 
GetExeType() const504*a03ca8b9SKrzysztof Kosiński ExecutableType DisassemblerZtf::GetExeType() const {
505*a03ca8b9SKrzysztof Kosiński   return kExeTypeZtf;
506*a03ca8b9SKrzysztof Kosiński }
507*a03ca8b9SKrzysztof Kosiński 
GetExeTypeString() const508*a03ca8b9SKrzysztof Kosiński std::string DisassemblerZtf::GetExeTypeString() const {
509*a03ca8b9SKrzysztof Kosiński   return "Zucchini Text Format";
510*a03ca8b9SKrzysztof Kosiński }
511*a03ca8b9SKrzysztof Kosiński 
MakeReferenceGroups() const512*a03ca8b9SKrzysztof Kosiński std::vector<ReferenceGroup> DisassemblerZtf::MakeReferenceGroups() const {
513*a03ca8b9SKrzysztof Kosiński   return {
514*a03ca8b9SKrzysztof Kosiński       {{5, TypeTag(kAnglesAbs1), PoolTag(kAngles)},
515*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<1, kAngles>,
516*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<1, kAngles>},
517*a03ca8b9SKrzysztof Kosiński       {{7, TypeTag(kAnglesAbs2), PoolTag(kAngles)},
518*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<2, kAngles>,
519*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<2, kAngles>},
520*a03ca8b9SKrzysztof Kosiński       {{9, TypeTag(kAnglesAbs3), PoolTag(kAngles)},
521*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<3, kAngles>,
522*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<3, kAngles>},
523*a03ca8b9SKrzysztof Kosiński       {{7, TypeTag(kAnglesRel1), PoolTag(kAngles)},
524*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<1, kAngles>,
525*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<1, kAngles>},
526*a03ca8b9SKrzysztof Kosiński       {{9, TypeTag(kAnglesRel2), PoolTag(kAngles)},
527*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<2, kAngles>,
528*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<2, kAngles>},
529*a03ca8b9SKrzysztof Kosiński       {{11, TypeTag(kAnglesRel3), PoolTag(kAngles)},
530*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<3, kAngles>,
531*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<3, kAngles>},
532*a03ca8b9SKrzysztof Kosiński       {{5, TypeTag(kBracesAbs1), PoolTag(kBraces)},
533*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<1, kBraces>,
534*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<1, kBraces>},
535*a03ca8b9SKrzysztof Kosiński       {{7, TypeTag(kBracesAbs2), PoolTag(kBraces)},
536*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<2, kBraces>,
537*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<2, kBraces>},
538*a03ca8b9SKrzysztof Kosiński       {{9, TypeTag(kBracesAbs3), PoolTag(kBraces)},
539*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<3, kBraces>,
540*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<3, kBraces>},
541*a03ca8b9SKrzysztof Kosiński       {{7, TypeTag(kBracesRel1), PoolTag(kBraces)},
542*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<1, kBraces>,
543*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<1, kBraces>},
544*a03ca8b9SKrzysztof Kosiński       {{9, TypeTag(kBracesRel2), PoolTag(kBraces)},
545*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<2, kBraces>,
546*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<2, kBraces>},
547*a03ca8b9SKrzysztof Kosiński       {{11, TypeTag(kBracesRel3), PoolTag(kBraces)},
548*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<3, kBraces>,
549*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<3, kBraces>},
550*a03ca8b9SKrzysztof Kosiński       {{5, TypeTag(kBracketsAbs1), PoolTag(kBrackets)},
551*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<1, kBrackets>,
552*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<1, kBrackets>},
553*a03ca8b9SKrzysztof Kosiński       {{7, TypeTag(kBracketsAbs2), PoolTag(kBrackets)},
554*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<2, kBrackets>,
555*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<2, kBrackets>},
556*a03ca8b9SKrzysztof Kosiński       {{9, TypeTag(kBracketsAbs3), PoolTag(kBrackets)},
557*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<3, kBrackets>,
558*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<3, kBrackets>},
559*a03ca8b9SKrzysztof Kosiński       {{7, TypeTag(kBracketsRel1), PoolTag(kBrackets)},
560*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<1, kBrackets>,
561*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<1, kBrackets>},
562*a03ca8b9SKrzysztof Kosiński       {{9, TypeTag(kBracketsRel2), PoolTag(kBrackets)},
563*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<2, kBrackets>,
564*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<2, kBrackets>},
565*a03ca8b9SKrzysztof Kosiński       {{11, TypeTag(kBracketsRel3), PoolTag(kBrackets)},
566*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<3, kBrackets>,
567*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<3, kBrackets>},
568*a03ca8b9SKrzysztof Kosiński       {{5, TypeTag(kParenthesesAbs1), PoolTag(kParentheses)},
569*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<1, kParentheses>,
570*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<1, kParentheses>},
571*a03ca8b9SKrzysztof Kosiński       {{7, TypeTag(kParenthesesAbs2), PoolTag(kParentheses)},
572*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<2, kParentheses>,
573*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<2, kParentheses>},
574*a03ca8b9SKrzysztof Kosiński       {{9, TypeTag(kParenthesesAbs3), PoolTag(kParentheses)},
575*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadAbs<3, kParentheses>,
576*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteAbs<3, kParentheses>},
577*a03ca8b9SKrzysztof Kosiński       {{7, TypeTag(kParenthesesRel1), PoolTag(kParentheses)},
578*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<1, kParentheses>,
579*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<1, kParentheses>},
580*a03ca8b9SKrzysztof Kosiński       {{9, TypeTag(kParenthesesRel2), PoolTag(kParentheses)},
581*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<2, kParentheses>,
582*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<2, kParentheses>},
583*a03ca8b9SKrzysztof Kosiński       {{11, TypeTag(kParenthesesRel3), PoolTag(kParentheses)},
584*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeReadRel<3, kParentheses>,
585*a03ca8b9SKrzysztof Kosiński        &DisassemblerZtf::MakeWriteRel<3, kParentheses>},
586*a03ca8b9SKrzysztof Kosiński   };
587*a03ca8b9SKrzysztof Kosiński }
588*a03ca8b9SKrzysztof Kosiński 
589*a03ca8b9SKrzysztof Kosiński template <uint8_t digits, DisassemblerZtf::ReferencePool pool>
MakeReadAbs(offset_t lo,offset_t hi)590*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerZtf::MakeReadAbs(offset_t lo,
591*a03ca8b9SKrzysztof Kosiński                                                               offset_t hi) {
592*a03ca8b9SKrzysztof Kosiński   static_assert(digits >= 1 && digits <= kMaxDigitCount,
593*a03ca8b9SKrzysztof Kosiński                 "|digits| must be in range [1, 3]");
594*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ZtfReferenceReader<ztf::LineCol>>(
595*a03ca8b9SKrzysztof Kosiński       lo, hi, image_, translator_, MakeZtfConfig<pool>(digits));
596*a03ca8b9SKrzysztof Kosiński }
597*a03ca8b9SKrzysztof Kosiński 
598*a03ca8b9SKrzysztof Kosiński template <uint8_t digits, DisassemblerZtf::ReferencePool pool>
MakeReadRel(offset_t lo,offset_t hi)599*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceReader> DisassemblerZtf::MakeReadRel(offset_t lo,
600*a03ca8b9SKrzysztof Kosiński                                                               offset_t hi) {
601*a03ca8b9SKrzysztof Kosiński   static_assert(digits >= 1 && digits <= kMaxDigitCount,
602*a03ca8b9SKrzysztof Kosiński                 "|digits| must be in range [1, 3]");
603*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ZtfReferenceReader<ztf::DeltaLineCol>>(
604*a03ca8b9SKrzysztof Kosiński       lo, hi, image_, translator_, MakeZtfConfig<pool>(digits));
605*a03ca8b9SKrzysztof Kosiński }
606*a03ca8b9SKrzysztof Kosiński 
607*a03ca8b9SKrzysztof Kosiński template <uint8_t digits, DisassemblerZtf::ReferencePool pool>
MakeWriteAbs(MutableBufferView image)608*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerZtf::MakeWriteAbs(
609*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
610*a03ca8b9SKrzysztof Kosiński   static_assert(digits >= 1 && digits <= kMaxDigitCount,
611*a03ca8b9SKrzysztof Kosiński                 "|digits| must be in range [1, 3]");
612*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ZtfReferenceWriter<ztf::LineCol>>(
613*a03ca8b9SKrzysztof Kosiński       image, translator_, MakeZtfConfig<pool>(digits));
614*a03ca8b9SKrzysztof Kosiński }
615*a03ca8b9SKrzysztof Kosiński 
616*a03ca8b9SKrzysztof Kosiński template <uint8_t digits, DisassemblerZtf::ReferencePool pool>
MakeWriteRel(MutableBufferView image)617*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceWriter> DisassemblerZtf::MakeWriteRel(
618*a03ca8b9SKrzysztof Kosiński     MutableBufferView image) {
619*a03ca8b9SKrzysztof Kosiński   static_assert(digits >= 1 && digits <= kMaxDigitCount,
620*a03ca8b9SKrzysztof Kosiński                 "|digits| must be in range [1, 3]");
621*a03ca8b9SKrzysztof Kosiński   return std::make_unique<ZtfReferenceWriter<ztf::DeltaLineCol>>(
622*a03ca8b9SKrzysztof Kosiński       image, translator_, MakeZtfConfig<pool>(digits));
623*a03ca8b9SKrzysztof Kosiński }
624*a03ca8b9SKrzysztof Kosiński 
Parse(ConstBufferView image)625*a03ca8b9SKrzysztof Kosiński bool DisassemblerZtf::Parse(ConstBufferView image) {
626*a03ca8b9SKrzysztof Kosiński   image_ = image;
627*a03ca8b9SKrzysztof Kosiński   if (!ReadZtfHeader(image_))
628*a03ca8b9SKrzysztof Kosiński     return false;
629*a03ca8b9SKrzysztof Kosiński 
630*a03ca8b9SKrzysztof Kosiński   CHECK_GE(image_.size(),
631*a03ca8b9SKrzysztof Kosiński            static_cast<size_t>(kTotalMagicSize));  // Needs header and footer.
632*a03ca8b9SKrzysztof Kosiński 
633*a03ca8b9SKrzysztof Kosiński   // Find the terminating footer "txTZ\n" that indicates the end of the image.
634*a03ca8b9SKrzysztof Kosiński   offset_t offset = 0;
635*a03ca8b9SKrzysztof Kosiński   for (; offset <= image_.size() - kFooterMagicSize; offset++) {
636*a03ca8b9SKrzysztof Kosiński     if (image_.read<uint8_t>(offset) == 't' &&
637*a03ca8b9SKrzysztof Kosiński         image_.read<uint8_t>(offset + 1) == 'x' &&
638*a03ca8b9SKrzysztof Kosiński         image_.read<uint8_t>(offset + 2) == 'T' &&
639*a03ca8b9SKrzysztof Kosiński         image_.read<uint8_t>(offset + 3) == 'Z' &&
640*a03ca8b9SKrzysztof Kosiński         image_.read<uint8_t>(offset + 4) == '\n') {
641*a03ca8b9SKrzysztof Kosiński       break;
642*a03ca8b9SKrzysztof Kosiński     }
643*a03ca8b9SKrzysztof Kosiński   }
644*a03ca8b9SKrzysztof Kosiński 
645*a03ca8b9SKrzysztof Kosiński   // If no footer is found before the end of the image then the parsing failed.
646*a03ca8b9SKrzysztof Kosiński   if (offset > image_.size() - kFooterMagicSize)
647*a03ca8b9SKrzysztof Kosiński     return false;
648*a03ca8b9SKrzysztof Kosiński   image_.shrink(offset + kFooterMagicSize);
649*a03ca8b9SKrzysztof Kosiński 
650*a03ca8b9SKrzysztof Kosiński   return translator_.Init(image_);
651*a03ca8b9SKrzysztof Kosiński }
652*a03ca8b9SKrzysztof Kosiński 
653*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
654