File: example_test.go

package info (click to toggle)
golang-golang-x-arch 0.13.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 6,932 kB
  • sloc: ansic: 1,975; makefile: 59
file content (180 lines) | stat: -rw-r--r-- 5,363 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xeddata_test

import (
	"fmt"
	"log"
	"strings"

	"golang.org/x/arch/x86/xeddata"
)

// The "testdata/xedpath" directory contains XED metadata files
// that are supposed to be used for Database initialization.

// Note that XED objects in this file are not real,
// instructions they describe are fictional.

// This example shows how to print raw XED objects using Reader.
// Objects are called "raw" because some of their fields may
// require additional transformations like macro (states) expansion.
func ExampleReader() {
	const xedPath = "testdata/xedpath"

	input := strings.NewReader(`
{
ICLASS: VEXADD
EXCEPTIONS: avx-type-zero
CPL: 2000
CATEGORY: AVX-Q
EXTENSION: AVX-Q
ATTRIBUTES: A B C
PATTERN: VV1 0x07 VL128 V66 V0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()
OPERANDS: REG0=XMM_R():w:width_dq:fword64 REG1=XMM_N():r:width_dq:fword64 MEM0:r:width_dq:fword64
}

{
ICLASS: COND_MOV_Z
CPL: 210
CATEGORY: MOV_IF_COND_MET
EXTENSION: BASE
ISA_SET: COND_MOV
FLAGS: READONLY [ zf-tst ]

PATTERN: 0x0F 0x4F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()
OPERANDS: REG0=GPRv_R():cw MEM0:r:width_v
PATTERN: 0x0F 0x4F MOD[0b11] MOD=3 REG[rrr] RM[nnn]
OPERANDS: REG0=GPRv_R():cw REG1=GPRv_B():r
}`)

	objects, err := xeddata.NewReader(input).ReadAll()
	if err != nil {
		log.Fatal(err)
	}

	for _, o := range objects {
		fmt.Printf("%s (%s):\n", o.Opcode(), o.Extension)
		for _, inst := range o.Insts {
			fmt.Printf("\t[%d] %s\n", inst.Index, inst.Operands)
		}
	}

	//Output:
	// VEXADD (AVX-Q):
	// 	[0] REG0=XMM_R():w:width_dq:fword64 REG1=XMM_N():r:width_dq:fword64 MEM0:r:width_dq:fword64
	// COND_MOV_Z (BASE):
	// 	[0] REG0=GPRv_R():cw MEM0:r:width_v
	// 	[1] REG0=GPRv_R():cw REG1=GPRv_B():r
}

// This example shows how to use ExpandStates and its effects.
func ExampleExpandStates() {
	const xedPath = "testdata/xedpath"

	input := strings.NewReader(`
{
ICLASS: VEXADD
CPL: 3
CATEGORY: ?
EXTENSION: ?
ATTRIBUTES: AT_A AT_B

PATTERN: _M_VV_TRUE 0x58  _M_VEX_P_66 _M_VLEN_128 _M_MAP_0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()
OPERANDS: REG0=XMM_R():w:width_dq:fword64 REG1=XMM_N():r:width_dq:fword64 MEM0:r:width_dq:fword64

PATTERN: _M_VV_TRUE 0x58  _M_VEX_P_66 _M_VLEN_128 _M_MAP_0F MOD[0b11] MOD=3 REG[rrr] RM[nnn]
OPERANDS: REG0=XMM_R():w:width_dq:fword64 REG1=XMM_N():r:width_dq:fword64 REG2=XMM_B():r:width_dq:fword64

PATTERN: _M_VV_TRUE 0x58  _M_VEX_P_66 _M_VLEN_256 _M_MAP_0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()
OPERANDS: REG0=YMM_R():w:qq:fword64 REG1=YMM_N():r:qq:fword64 MEM0:r:qq:fword64

PATTERN: _M_VV_TRUE 0x58  _M_VEX_P_66 _M_VLEN_256 _M_MAP_0F MOD[0b11] MOD=3 REG[rrr] RM[nnn]
OPERANDS: REG0=YMM_R():w:qq:fword64 REG1=YMM_N():r:qq:fword64 REG2=YMM_B():r:qq:fword64
}`)

	objects, err := xeddata.NewReader(input).ReadAll()
	if err != nil {
		log.Fatal(err)
	}
	db, err := xeddata.NewDatabase(xedPath)
	if err != nil {
		log.Fatal(err)
	}

	for _, o := range objects {
		for _, inst := range o.Insts {
			fmt.Printf("old: %q\n", inst.Pattern)
			fmt.Printf("new: %q\n", xeddata.ExpandStates(db, inst.Pattern))
		}
	}

	//Output:
	// old: "_M_VV_TRUE 0x58  _M_VEX_P_66 _M_VLEN_128 _M_MAP_0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()"
	// new: "VEXVALID=1 0x58 VEX_PREFIX=1 VL=0 MAP=1 MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()"
	// old: "_M_VV_TRUE 0x58  _M_VEX_P_66 _M_VLEN_128 _M_MAP_0F MOD[0b11] MOD=3 REG[rrr] RM[nnn]"
	// new: "VEXVALID=1 0x58 VEX_PREFIX=1 VL=0 MAP=1 MOD[0b11] MOD=3 REG[rrr] RM[nnn]"
	// old: "_M_VV_TRUE 0x58  _M_VEX_P_66 _M_VLEN_256 _M_MAP_0F MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()"
	// new: "VEXVALID=1 0x58 VEX_PREFIX=1 VL=1 MAP=1 MOD[mm] MOD!=3 REG[rrr] RM[nnn] MODRM()"
	// old: "_M_VV_TRUE 0x58  _M_VEX_P_66 _M_VLEN_256 _M_MAP_0F MOD[0b11] MOD=3 REG[rrr] RM[nnn]"
	// new: "VEXVALID=1 0x58 VEX_PREFIX=1 VL=1 MAP=1 MOD[0b11] MOD=3 REG[rrr] RM[nnn]"
}

// This example shows how to handle Inst "OPERANDS" field.
func ExampleOperand() {
	const xedPath = "testdata/xedpath"

	input := strings.NewReader(`
{
ICLASS: ADD_N_TIMES # Like IMUL
CPL: 3
CATEGORY: BINARY
EXTENSION: BASE
ISA_SET: I86
FLAGS: MUST [ of-mod sf-u zf-u af-u pf-u cf-mod ]

PATTERN: 0xAA MOD[mm] MOD!=3 REG[0b101] RM[nnn] MODRM()
OPERANDS: MEM0:r:width_v REG0=AX:rw:SUPP REG1=DX:w:SUPP
}`)

	objects, err := xeddata.NewReader(input).ReadAll()
	if err != nil {
		log.Fatal(err)
	}
	db, err := xeddata.NewDatabase(xedPath)
	if err != nil {
		log.Fatal(err)
	}

	inst := objects[0].Insts[0] // Single instruction is enough for this example
	for i, rawOperand := range strings.Fields(inst.Operands) {
		operand, err := xeddata.NewOperand(db, rawOperand)
		if err != nil {
			log.Fatalf("parse operand #%d: %+v", i, err)
		}

		visibility := "implicit"
		if operand.IsVisible() {
			visibility = "explicit"
		}
		fmt.Printf("(%s) %s:\n", visibility, rawOperand)

		fmt.Printf("\tname: %q\n", operand.Name)
		if operand.IsVisible() {
			fmt.Printf("\t32/64bit width: %s/%s bytes\n",
				db.WidthSize(operand.Width, xeddata.OpSize32),
				db.WidthSize(operand.Width, xeddata.OpSize64))
		}
	}

	//Output:
	// (explicit) MEM0:r:width_v:
	// 	name: "MEM0"
	// 	32/64bit width: 4/8 bytes
	// (implicit) REG0=AX:rw:SUPP:
	// 	name: "REG0=AX"
	// (implicit) REG1=DX:w:SUPP:
	// 	name: "REG1=DX"
}