/*
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