2018-09-05 23:38:53 +00:00
/ *
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 < https : //www.gnu.org/licenses/>.
* /
#if ( ! NO_GAS_FORMATTER | | ! NO_INTEL_FORMATTER | | ! NO_MASM_FORMATTER | | ! NO_NASM_FORMATTER ) & & ! NO_FORMATTER
using System ;
namespace Iced.Intel {
/// <summary>
/// Used by a <see cref="Formatter"/> to resolve symbols. It can also override number formatting options
/// </summary>
public abstract class SymbolResolver {
/// <summary>
/// This method is called if you don't override any of the other virtual methods. It should return true if
/// <paramref name="symbol"/> was updated. If false is returned, <paramref name="options"/> can be updated to
/// override the default number formatting options.
/// </summary>
/// <param name="operand">Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.</param>
2018-09-13 05:31:30 +00:00
/// <param name="instruction">Instruction</param>
2018-09-05 23:38:53 +00:00
/// <param name="address">Address</param>
2018-09-13 05:31:30 +00:00
/// <param name="addressSize">Size of <paramref name="address"/> in bytes</param>
2018-09-05 23:38:53 +00:00
/// <param name="symbol">Updated with symbol information if this method returns true</param>
/// <param name="options">Number formatting options if this method returns false</param>
/// <returns></returns>
2018-09-13 05:31:30 +00:00
protected virtual bool TryGetSymbol ( int operand , ref Instruction instruction , ulong address , int addressSize , out SymbolResult symbol , ref NumberFormattingOptions options ) {
2018-09-05 23:38:53 +00:00
symbol = default ;
return false ;
}
/// <summary>
/// Updates <paramref name="symbol"/> with the symbol and returns true, else it returns false and can update <paramref name="options"/>
/// to override the default number formatting options
/// </summary>
/// <param name="operand">Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.</param>
2018-09-13 05:31:30 +00:00
/// <param name="instruction">Instruction</param>
2018-09-05 23:38:53 +00:00
/// <param name="address">Address</param>
2018-09-13 05:31:30 +00:00
/// <param name="addressSize">Size of <paramref name="address"/> in bytes</param>
2018-09-05 23:38:53 +00:00
/// <param name="symbol">Updated with symbol information if this method returns true</param>
/// <param name="showBranchSize">true if branch info (short, near ptr, far ptr) should be shown</param>
/// <param name="options">Number formatting options if this method returns false</param>
/// <returns></returns>
2018-09-13 05:31:30 +00:00
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 ) ;
2018-09-05 23:38:53 +00:00
/// <summary>
/// Returns true if <paramref name="symbol"/> was updated with a symbol. <paramref name="symbolSelector"/> can be set to default value
/// if it should be formatted as a number. <paramref name="options"/> is used if this method returns false or if <paramref name="symbolSelector"/>
/// has the default value.
/// </summary>
/// <param name="operand">Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.</param>
2018-09-13 05:31:30 +00:00
/// <param name="instruction">Instruction</param>
2018-09-05 23:38:53 +00:00
/// <param name="selector">Selector/segment</param>
/// <param name="address">Address</param>
2018-09-13 05:31:30 +00:00
/// <param name="addressSize">Size of <paramref name="address"/> in bytes</param>
2018-09-05 23:38:53 +00:00
/// <param name="symbolSelector">Updated with the selector symbol or with the default value if it should be formatted as a number</param>
/// <param name="symbol">Updated with symbol information if this method returns true</param>
/// <param name="showBranchSize">true if branch info (short, near ptr, far ptr) should be shown</param>
/// <param name="options">Number formatting options if this method returns false or if <paramref name="symbolSelector"/> has the default value</param>
/// <returns></returns>
2018-09-13 05:31:30 +00:00
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 ) {
2018-09-05 23:38:53 +00:00
symbolSelector = default ;
2018-09-13 05:31:30 +00:00
return TryGetSymbol ( operand , ref instruction , address , addressSize , out symbol , ref options ) ;
2018-09-05 23:38:53 +00:00
}
/// <summary>
/// Gets a symbol and returns true. If it returns false, <paramref name="options"/> can be updated to override
/// the default number formatting options.
/// </summary>
/// <param name="operand">Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.</param>
2018-09-13 05:31:30 +00:00
/// <param name="instruction">Instruction</param>
2018-09-05 23:38:53 +00:00
/// <param name="immediate">Immediate value</param>
2018-09-13 05:31:30 +00:00
/// <param name="immediateSize">Size of <paramref name="immediate"/> in bytes</param>
2018-09-05 23:38:53 +00:00
/// <param name="symbol">Updated with symbol information if this method returns true</param>
/// <param name="options">Number formatting options if this method returns false</param>
/// <returns></returns>
2018-09-13 05:31:30 +00:00
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 ) ;
2018-09-05 23:38:53 +00:00
/// <summary>
/// Gets a symbol and returns true. If it returns false, <paramref name="options"/> can be updated to override
/// the default number formatting options.
///
/// This method gets called even if the memory operand has no displacement, eg. [eax].
/// </summary>
/// <param name="operand">Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.</param>
2018-09-13 05:31:30 +00:00
/// <param name="instruction">Instruction</param>
2018-09-05 23:38:53 +00:00
/// <param name="displacement">Displacement. If it's RIP-relative addressing, this is the absolute address (rip/eip + displ)</param>
2018-09-13 05:31:30 +00:00
/// <param name="displacementSize">Size of <paramref name="displacement"/> in bytes</param>
2018-09-05 23:38:53 +00:00
/// <param name="ripRelativeAddresses">true to use RIP relative addresses</param>
/// <param name="symbol">Updated with symbol information if this method returns true</param>
/// <param name="options">Number formatting options if this method returns false</param>
/// <returns></returns>
2018-09-13 05:31:30 +00:00
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 ) ;
2018-09-05 23:38:53 +00:00
}
/// <summary>
/// Gets initialized with the default options and can be overridden by a <see cref="SymbolResolver"/>
/// </summary>
public struct NumberFormattingOptions {
/// <summary>
/// Digit separator or null/empty string
/// </summary>
public string DigitSeparator ;
/// <summary>
/// Number prefix or null/empty string
/// </summary>
public string Prefix ;
/// <summary>
/// Number suffix or null/empty string
/// </summary>
public string Suffix ;
/// <summary>
2018-10-09 20:43:22 +00:00
/// Size of a digit group
2018-09-05 23:38:53 +00:00
/// </summary>
public byte DigitGroupSize ;
/// <summary>
/// Number base
/// </summary>
public NumberBase NumberBase {
get = > ( NumberBase ) numberBaseByteValue ;
set = > numberBaseByteValue = ( byte ) value ;
}
internal byte numberBaseByteValue ;
/// <summary>
/// Use upper case hex digits
/// </summary>
public bool UpperCaseHex ;
/// <summary>
/// Small hex numbers (-9 .. 9) are shown in decimal
/// </summary>
public bool SmallHexNumbersInDecimal ;
/// <summary>
/// Add a leading zero to numbers if there's no prefix and the number begins with hex digits A-F, eg. Ah vs 0Ah
/// </summary>
public bool AddLeadingZeroToHexNumbers ;
/// <summary>
/// If true, use short numbers, and if false, add leading zeroes, eg. '1h' vs '00000001h'
/// </summary>
public bool ShortNumbers ;
/// <summary>
/// If true, the number is signed, and if false it's an unsigned number
/// </summary>
public bool SignedNumber ;
/// <summary>
/// Sign extend the number to the real size (16-bit, 32-bit, 64-bit), eg. 'mov al,[eax+12h]' vs 'mov al,[eax+00000012h]'
/// </summary>
public bool SignExtendImmediate ;
/// <summary>
/// Constructor
/// </summary>
/// <param name="options">Options</param>
/// <param name="shortNumbers">If true, use short numbers, and if false, add leading zeroes, eg. '1h' vs '00000001h'</param>
/// <param name="signedNumber">Signed numbers if true, and unsigned numbers if false</param>
/// <param name="signExtendImmediate">Sign extend the number to the real size (16-bit, 32-bit, 64-bit), eg. 'mov al,[eax+12h]' vs 'mov al,[eax+00000012h]'</param>
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 ;
}
}
/// <summary>
/// Symbol flags
/// </summary>
[Flags]
public enum SymbolFlags : uint {
/// <summary>
/// No bit is set
/// </summary>
None = 0 ,
/// <summary>
/// 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)
/// </summary>
Address = 0x00000001 ,
/// <summary>
/// It's a signed symbol and it should be displayed as '-symbol' or 'reg-symbol' instead of 'symbol' or 'reg+symbol'
/// </summary>
Signed = 0x00000002 ,
}
/// <summary>
/// The result of resolving a symbol
/// </summary>
public readonly struct SymbolResult {
/// <summary>
/// Contains the symbol
/// </summary>
public readonly TextInfo Text ;
/// <summary>
/// Symbol flags
/// </summary>
public readonly SymbolFlags Flags ;
2018-10-11 15:22:59 +00:00
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Symbol</param>
public SymbolResult ( string text ) {
Text = new TextInfo ( text , FormatterOutputTextKind . Label ) ;
Flags = 0 ;
}
2018-09-05 23:38:53 +00:00
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Symbol</param>
/// <param name="color">Color</param>
public SymbolResult ( string text , FormatterOutputTextKind color ) {
Text = new TextInfo ( text , color ) ;
Flags = 0 ;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Symbol</param>
/// <param name="color">Color</param>
/// <param name="flags">Symbol flags</param>
public SymbolResult ( string text , FormatterOutputTextKind color , SymbolFlags flags ) {
Text = new TextInfo ( text , color ) ;
Flags = flags ;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Symbol</param>
public SymbolResult ( TextInfo text ) {
Text = text ;
Flags = 0 ;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Symbol</param>
/// <param name="flags">Symbol flags</param>
public SymbolResult ( TextInfo text , SymbolFlags flags ) {
Text = text ;
Flags = flags ;
}
}
/// <summary>
/// Contains one or more <see cref="TextPart"/>s (text and color)
/// </summary>
public readonly struct TextInfo {
/// <summary>
/// true if this is the default instance
/// </summary>
public bool IsDefault = > TextArray = = null & & Text . Text = = null ;
/// <summary>
/// The text and color unless <see cref="TextArray"/> is non-null
/// </summary>
public readonly TextPart Text ;
/// <summary>
/// Text and color or null if <see cref="Text"/> should be used
/// </summary>
public readonly TextPart [ ] TextArray ;
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Text</param>
/// <param name="color">Color</param>
public TextInfo ( string text , FormatterOutputTextKind color ) {
Text = new TextPart ( text , color ) ;
TextArray = null ;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Text</param>
public TextInfo ( TextPart text ) {
Text = text ;
TextArray = null ;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">All text parts</param>
public TextInfo ( TextPart [ ] text ) {
Text = default ;
TextArray = text ;
}
}
/// <summary>
/// Contains text and colors
/// </summary>
public readonly struct TextPart {
/// <summary>
/// Text
/// </summary>
public readonly string Text ;
/// <summary>
/// Color
/// </summary>
public readonly FormatterOutputTextKind Color ;
/// <summary>
/// Constructor
/// </summary>
/// <param name="text">Text</param>
/// <param name="color">Color</param>
public TextPart ( string text , FormatterOutputTextKind color ) {
Text = text ;
Color = color ;
}
}
}
#endif