/* Copyright (C) 2018 de4dot@gmail.com This file is part of Iced. Iced is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Iced is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Iced. If not, see . */ #if (!NO_GAS_FORMATTER || !NO_INTEL_FORMATTER || !NO_MASM_FORMATTER || !NO_NASM_FORMATTER) && !NO_FORMATTER using System; namespace Iced.Intel { /// /// Used by a to resolve symbols. It can also override number formatting options /// public abstract class SymbolResolver { /// /// This method is called if you don't override any of the other virtual methods. It should return true if /// was updated. If false is returned, can be updated to /// override the default number formatting options. /// /// Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. /// Instruction /// Address /// Size of in bytes /// Updated with symbol information if this method returns true /// Number formatting options if this method returns false /// protected virtual bool TryGetSymbol(int operand, ref Instruction instruction, ulong address, int addressSize, out SymbolResult symbol, ref NumberFormattingOptions options) { symbol = default; return false; } /// /// Updates with the symbol and returns true, else it returns false and can update /// to override the default number formatting options /// /// Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. /// Instruction /// Address /// Size of in bytes /// Updated with symbol information if this method returns true /// true if branch info (short, near ptr, far ptr) should be shown /// Number formatting options if this method returns false /// public virtual bool TryGetBranchSymbol(int operand, ref Instruction instruction, ulong address, int addressSize, out SymbolResult symbol, ref bool showBranchSize, ref NumberFormattingOptions options) => TryGetSymbol(operand, ref instruction, address, addressSize, out symbol, ref options); /// /// Returns true if was updated with a symbol. can be set to default value /// if it should be formatted as a number. is used if this method returns false or if /// has the default value. /// /// Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. /// Instruction /// Selector/segment /// Address /// Size of in bytes /// Updated with the selector symbol or with the default value if it should be formatted as a number /// Updated with symbol information if this method returns true /// true if branch info (short, near ptr, far ptr) should be shown /// Number formatting options if this method returns false or if has the default value /// public virtual bool TryGetFarBranchSymbol(int operand, ref Instruction instruction, ushort selector, uint address, int addressSize, out SymbolResult symbolSelector, out SymbolResult symbol, ref bool showBranchSize, ref NumberFormattingOptions options) { symbolSelector = default; return TryGetSymbol(operand, ref instruction, address, addressSize, out symbol, ref options); } /// /// Gets a symbol and returns true. If it returns false, can be updated to override /// the default number formatting options. /// /// Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. /// Instruction /// Immediate value /// Size of in bytes /// Updated with symbol information if this method returns true /// Number formatting options if this method returns false /// public virtual bool TryGetImmediateSymbol(int operand, ref Instruction instruction, ulong immediate, int immediateSize, out SymbolResult symbol, ref NumberFormattingOptions options) => TryGetSymbol(operand, ref instruction, immediate, immediateSize, out symbol, ref options); /// /// Gets a symbol and returns true. If it returns false, can be updated to override /// the default number formatting options. /// /// This method gets called even if the memory operand has no displacement, eg. [eax]. /// /// Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. /// Instruction /// Displacement. If it's RIP-relative addressing, this is the absolute address (rip/eip + displ) /// Size of in bytes /// true to use RIP relative addresses /// Updated with symbol information if this method returns true /// Number formatting options if this method returns false /// public virtual bool TryGetDisplSymbol(int operand, ref Instruction instruction, ulong displacement, int displacementSize, ref bool ripRelativeAddresses, out SymbolResult symbol, ref NumberFormattingOptions options) => TryGetSymbol(operand, ref instruction, displacement, displacementSize, out symbol, ref options); } /// /// Gets initialized with the default options and can be overridden by a /// public struct NumberFormattingOptions { /// /// Digit separator or null/empty string /// public string DigitSeparator; /// /// Number prefix or null/empty string /// public string Prefix; /// /// Number suffix or null/empty string /// public string Suffix; /// /// Size of a digit group /// public byte DigitGroupSize; /// /// Number base /// public NumberBase NumberBase { get => (NumberBase)numberBaseByteValue; set => numberBaseByteValue = (byte)value; } internal byte numberBaseByteValue; /// /// Use upper case hex digits /// public bool UpperCaseHex; /// /// Small hex numbers (-9 .. 9) are shown in decimal /// public bool SmallHexNumbersInDecimal; /// /// Add a leading zero to numbers if there's no prefix and the number begins with hex digits A-F, eg. Ah vs 0Ah /// public bool AddLeadingZeroToHexNumbers; /// /// If true, use short numbers, and if false, add leading zeroes, eg. '1h' vs '00000001h' /// public bool ShortNumbers; /// /// If true, the number is signed, and if false it's an unsigned number /// public bool SignedNumber; /// /// Sign extend the number to the real size (16-bit, 32-bit, 64-bit), eg. 'mov al,[eax+12h]' vs 'mov al,[eax+00000012h]' /// public bool SignExtendImmediate; /// /// Constructor /// /// Options /// If true, use short numbers, and if false, add leading zeroes, eg. '1h' vs '00000001h' /// Signed numbers if true, and unsigned numbers if false /// Sign extend the number to the real size (16-bit, 32-bit, 64-bit), eg. 'mov al,[eax+12h]' vs 'mov al,[eax+00000012h]' public NumberFormattingOptions(FormatterOptions options, bool shortNumbers, bool signedNumber, bool signExtendImmediate) { if (options == null) throw new ArgumentNullException(nameof(options)); ShortNumbers = shortNumbers; SignedNumber = signedNumber; SignExtendImmediate = signExtendImmediate; numberBaseByteValue = (byte)options.NumberBase; DigitSeparator = options.DigitSeparator; UpperCaseHex = options.UpperCaseHex; SmallHexNumbersInDecimal = options.SmallHexNumbersInDecimal; AddLeadingZeroToHexNumbers = options.AddLeadingZeroToHexNumbers; int digitGroupSize; switch (options.NumberBase) { case NumberBase.Hexadecimal: Prefix = options.HexPrefix; Suffix = options.HexSuffix; digitGroupSize = options.HexDigitGroupSize; break; case NumberBase.Decimal: Prefix = options.DecimalPrefix; Suffix = options.DecimalSuffix; digitGroupSize = options.DecimalDigitGroupSize; break; case NumberBase.Octal: Prefix = options.OctalPrefix; Suffix = options.OctalSuffix; digitGroupSize = options.OctalDigitGroupSize; break; case NumberBase.Binary: Prefix = options.BinaryPrefix; Suffix = options.BinarySuffix; digitGroupSize = options.BinaryDigitGroupSize; break; default: throw new ArgumentException(); } if (digitGroupSize < 0) DigitGroupSize = 0; else if (digitGroupSize > byte.MaxValue) DigitGroupSize = byte.MaxValue; else DigitGroupSize = (byte)digitGroupSize; } } /// /// Symbol flags /// [Flags] public enum SymbolFlags : uint { /// /// No bit is set /// None = 0, /// /// If set it's the address of a symbol, else it's a symbol relative to the base and index registers (eg. a struct field offset) /// Address = 0x00000001, /// /// It's a signed symbol and it should be displayed as '-symbol' or 'reg-symbol' instead of 'symbol' or 'reg+symbol' /// Signed = 0x00000002, } /// /// The result of resolving a symbol /// public readonly struct SymbolResult { /// /// Contains the symbol /// public readonly TextInfo Text; /// /// Symbol flags /// public readonly SymbolFlags Flags; /// /// Constructor /// /// Symbol public SymbolResult(string text) { Text = new TextInfo(text, FormatterOutputTextKind.Label); Flags = 0; } /// /// Constructor /// /// Symbol /// Color public SymbolResult(string text, FormatterOutputTextKind color) { Text = new TextInfo(text, color); Flags = 0; } /// /// Constructor /// /// Symbol /// Color /// Symbol flags public SymbolResult(string text, FormatterOutputTextKind color, SymbolFlags flags) { Text = new TextInfo(text, color); Flags = flags; } /// /// Constructor /// /// Symbol public SymbolResult(TextInfo text) { Text = text; Flags = 0; } /// /// Constructor /// /// Symbol /// Symbol flags public SymbolResult(TextInfo text, SymbolFlags flags) { Text = text; Flags = flags; } } /// /// Contains one or more s (text and color) /// public readonly struct TextInfo { /// /// true if this is the default instance /// public bool IsDefault => TextArray == null && Text.Text == null; /// /// The text and color unless is non-null /// public readonly TextPart Text; /// /// Text and color or null if should be used /// public readonly TextPart[] TextArray; /// /// Constructor /// /// Text /// Color public TextInfo(string text, FormatterOutputTextKind color) { Text = new TextPart(text, color); TextArray = null; } /// /// Constructor /// /// Text public TextInfo(TextPart text) { Text = text; TextArray = null; } /// /// Constructor /// /// All text parts public TextInfo(TextPart[] text) { Text = default; TextArray = text; } } /// /// Contains text and colors /// public readonly struct TextPart { /// /// Text /// public readonly string Text; /// /// Color /// public readonly FormatterOutputTextKind Color; /// /// Constructor /// /// Text /// Color public TextPart(string text, FormatterOutputTextKind color) { Text = text; Color = color; } } } #endif