disassembler_ztf.cc 23 KB

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