golang.org/x/arch@v0.17.0/x86/xeddata/object.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package xeddata
     6  
     7  import (
     8  	"encoding/json"
     9  	"strings"
    10  )
    11  
    12  // An Object is a single "dec/enc-instruction" XED object from datafiles.
    13  //
    14  // Field names and their comments are borrowed from Intel XED
    15  // engineering notes (see "$XED/misc/engineering-notes.txt").
    16  //
    17  // Field values are always trimmed (i.e. no leading/trailing whitespace).
    18  //
    19  // Missing optional members are expressed with an empty string.
    20  //
    21  // Object contains multiple Inst elements that represent concrete
    22  // instruction with encoding pattern and operands description.
    23  type Object struct {
    24  	// Pos is the file position of the start of this object.
    25  	Pos Pos
    26  
    27  	// Iclass is instruction class name (opcode).
    28  	// Iclass alone is not enough to uniquely identify machine instructions.
    29  	// Example: "PSRLW".
    30  	Iclass string
    31  
    32  	// Disasm is substituted name when a simple conversion
    33  	// from iclass is inappropriate.
    34  	// Never combined with DisasmIntel or DisasmATTSV.
    35  	// Example: "syscall".
    36  	//
    37  	// Optional.
    38  	Disasm string
    39  
    40  	// DisasmIntel is like Disasm, but with Intel syntax.
    41  	// If present, usually comes with DisasmATTSV.
    42  	// Example: "jmp far".
    43  	//
    44  	// Optional.
    45  	DisasmIntel string
    46  
    47  	// DisasmATTSV is like Disasm, but with AT&T/SysV syntax.
    48  	// If present, usually comes with DisasmIntel.
    49  	// Example: "ljmp".
    50  	//
    51  	// Optional.
    52  	DisasmATTSV string
    53  
    54  	// Attributes describes name set for bits in the binary attributes field.
    55  	// Example: "NOP X87_CONTROL NOTSX".
    56  	//
    57  	// Optional. If not present, zero attribute set is implied.
    58  	Attributes string
    59  
    60  	// Uname is unique name used for deleting / replacing instructions.
    61  	//
    62  	// Optional. Provided for completeness, mostly useful for XED internal usage.
    63  	Uname string
    64  
    65  	// CPL is instruction current privilege level restriction.
    66  	// Can have value of "0" or "3".
    67  	CPL string
    68  
    69  	// Category is an ad-hoc categorization of instructions.
    70  	// Example: "SEMAPHORE".
    71  	Category string
    72  
    73  	// Extension is an ad-hoc grouping of instructions.
    74  	// If no ISASet is specified, this is used instead.
    75  	// Example: "3DNOW"
    76  	Extension string
    77  
    78  	// Exceptions is an exception set name.
    79  	// Example: "SSE_TYPE_7".
    80  	//
    81  	// Optional. Empty exception category generally means that
    82  	// instruction generates no exceptions.
    83  	Exceptions string
    84  
    85  	// ISASet is a name for the group of instructions that
    86  	// introduced this feature.
    87  	// Example: "I286PROTECTED".
    88  	//
    89  	// Older objects only defined Extension field.
    90  	// Newer objects may contain both Extension and ISASet fields.
    91  	// For some objects Extension==ISASet.
    92  	// Both fields are required to do precise CPUID-like decisions.
    93  	//
    94  	// Optional.
    95  	ISASet string
    96  
    97  	// Flags describes read/written flag bit values.
    98  	// Example: "MUST [ of-u sf-u af-u pf-u cf-mod ]".
    99  	//
   100  	// Optional. If not present, no flags are neither read nor written.
   101  	Flags string
   102  
   103  	// A hopefully useful comment.
   104  	//
   105  	// Optional.
   106  	Comment string
   107  
   108  	// The object revision.
   109  	//
   110  	// Optional.
   111  	Version string
   112  
   113  	// RealOpcode marks unstable (not in SDM yet) instructions with "N".
   114  	// Normally, always "Y" or not present at all.
   115  	//
   116  	// Optional.
   117  	RealOpcode string
   118  
   119  	// Insts are concrete instruction templates that are derived from containing Object.
   120  	// Inst contains fields PATTERN, OPERANDS, IFORM in enc/dec instruction.
   121  	Insts []*Inst
   122  }
   123  
   124  // Inst represents a single instruction template.
   125  //
   126  // Some templates contain expandable (macro) pattern and operands
   127  // which tells that there are more than one real instructions
   128  // that are expressed by the template.
   129  type Inst struct {
   130  	// Object that contains properties that are shared with multiple
   131  	// Inst objects.
   132  	*Object
   133  
   134  	// Pos is the file position of this Inst's PATTERN.
   135  	Pos Pos
   136  
   137  	// Index is the position inside XED object.
   138  	// Object.Insts[Index] returns this inst.
   139  	Index int
   140  
   141  	// Pattern is the sequence of bits and nonterminals used to
   142  	// decode/encode an instruction.
   143  	// Example: "0x0F 0x28 no_refining_prefix MOD[0b11] MOD=3 REG[rrr] RM[nnn]".
   144  	Pattern string
   145  
   146  	// Operands are instruction arguments, typicall registers,
   147  	// memory operands and pseudo-resources. Separated by space.
   148  	// Example: "MEM0:rcw:b REG0=GPR8_R():r REG1=XED_REG_AL:rcw:SUPP".
   149  	Operands string
   150  
   151  	// Iform is a name for the pattern that starts with the
   152  	// iclass and bakes in the operands. If omitted, XED
   153  	// tries to generate one. We often add custom suffixes
   154  	// to these to disambiguate certain combinations.
   155  	// Example: "MOVAPS_XMMps_XMMps_0F28".
   156  	//
   157  	// Optional.
   158  	Iform string
   159  }
   160  
   161  // Opcode returns instruction name or empty string,
   162  // if appropriate Object fields are not initialized.
   163  func (o *Object) Opcode() string {
   164  	switch {
   165  	case o.Iclass != "":
   166  		return o.Iclass
   167  	case o.Disasm != "":
   168  		return o.Disasm
   169  	case o.DisasmIntel != "":
   170  		return o.DisasmIntel
   171  	case o.DisasmATTSV != "":
   172  		return o.DisasmATTSV
   173  	case o.Uname != "":
   174  		return o.Uname
   175  	}
   176  	return ""
   177  }
   178  
   179  // HasAttribute checks that o has attribute with specified name.
   180  // Note that check is done at "word" level, substring names will not match.
   181  func (o *Object) HasAttribute(name string) bool {
   182  	return containsWord(o.Attributes, name)
   183  }
   184  
   185  // String returns pretty-printed inst representation.
   186  //
   187  // Outputs valid JSON string. This property is
   188  // not guaranteed to be preserved.
   189  func (inst *Inst) String() string {
   190  	// Do not use direct inst marshalling to achieve
   191  	// flat object printed representation.
   192  	// Map is avoided to ensure consistent props order.
   193  	type flatObject struct {
   194  		Iclass      string
   195  		Disasm      string `json:",omitempty"`
   196  		DisasmIntel string `json:",omitempty"`
   197  		DisasmATTSV string `json:",omitempty"`
   198  		Attributes  string `json:",omitempty"`
   199  		Uname       string `json:",omitempty"`
   200  		CPL         string
   201  		Category    string
   202  		Extension   string
   203  		Exceptions  string `json:",omitempty"`
   204  		ISASet      string `json:",omitempty"`
   205  		Flags       string `json:",omitempty"`
   206  		Comment     string `json:",omitempty"`
   207  		Version     string `json:",omitempty"`
   208  		RealOpcode  string `json:",omitempty"`
   209  		Pattern     string
   210  		Operands    string
   211  		Iform       string `json:",omitempty"`
   212  	}
   213  
   214  	flat := flatObject{
   215  		Iclass:      inst.Iclass,
   216  		Disasm:      inst.Disasm,
   217  		DisasmIntel: inst.DisasmIntel,
   218  		DisasmATTSV: inst.DisasmATTSV,
   219  		Attributes:  inst.Attributes,
   220  		Uname:       inst.Uname,
   221  		CPL:         inst.CPL,
   222  		Category:    inst.Category,
   223  		Extension:   inst.Extension,
   224  		Exceptions:  inst.Exceptions,
   225  		ISASet:      inst.ISASet,
   226  		Flags:       inst.Flags,
   227  		Comment:     inst.Comment,
   228  		Version:     inst.Version,
   229  		RealOpcode:  inst.RealOpcode,
   230  		Pattern:     inst.Pattern,
   231  		Operands:    inst.Operands,
   232  		Iform:       inst.Iform,
   233  	}
   234  
   235  	b, err := json.MarshalIndent(flat, "", "  ")
   236  	if err != nil {
   237  		panic(err)
   238  	}
   239  	return string(b)
   240  }
   241  
   242  // ExpandStates returns a copy of s where all state macros
   243  // are expanded.
   244  // This requires db "states" to be loaded.
   245  func ExpandStates(db *Database, s string) string {
   246  	substs := db.states
   247  	parts := strings.Fields(s)
   248  	for i := range parts {
   249  		if repl := substs[parts[i]]; repl != "" {
   250  			parts[i] = repl
   251  		}
   252  	}
   253  	return strings.Join(parts, " ")
   254  }
   255  
   256  // containsWord searches for whole word match in s.
   257  func containsWord(s, word string) bool {
   258  	i := strings.Index(s, word)
   259  	if i == -1 {
   260  		return false
   261  	}
   262  	leftOK := i == 0 ||
   263  		(s[i-1] == ' ')
   264  	rigthOK := i+len(word) == len(s) ||
   265  		(s[i+len(word)] == ' ')
   266  	return leftOK && rigthOK
   267  }