x86/xeddata: add Pos to Object and Inst
Change-Id: Ib9ad5e2c4bbd005b7fad15b7d0dc8943f2747689
Reviewed-on: https://go-review.googlesource.com/c/arch/+/656239
Auto-Submit: Austin Clements <austin@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/x86/xeddata/object.go b/x86/xeddata/object.go
index 4a73973..662aa69 100644
--- a/x86/xeddata/object.go
+++ b/x86/xeddata/object.go
@@ -21,6 +21,9 @@
// Object contains multiple Inst elements that represent concrete
// instruction with encoding pattern and operands description.
type Object struct {
+ // Pos is the file position of the start of this object.
+ Pos Pos
+
// Iclass is instruction class name (opcode).
// Iclass alone is not enough to uniquely identify machine instructions.
// Example: "PSRLW".
@@ -128,6 +131,9 @@
// Inst objects.
*Object
+ // Pos is the file position of this Inst's PATTERN.
+ Pos Pos
+
// Index is the position inside XED object.
// Object.Insts[Index] returns this inst.
Index int
diff --git a/x86/xeddata/reader.go b/x86/xeddata/reader.go
index c1a0aa7..02fd9c8 100644
--- a/x86/xeddata/reader.go
+++ b/x86/xeddata/reader.go
@@ -70,7 +70,9 @@
func readObjects(r io.Reader) iter.Seq2[*Object, error] {
iterLines := readLines(r)
return func(yield func(*Object, error) bool) {
+ var blockPos Pos
var block []string // Reused on each iteration
+ var linePos []Pos
inBlock := false
for line, err := range iterLines {
if err != nil {
@@ -79,15 +81,17 @@
}
if !inBlock {
inBlock = line.data[0] == '{'
+ blockPos = line.Pos
} else if line.data[0] == '}' {
inBlock = false
- obj, err := parseObjectLines(block)
+ obj, err := parseObjectLines(blockPos, block, linePos)
if !yield(obj, err) {
return
}
- block = block[:0]
+ block, linePos = block[:0], linePos[:0]
} else {
block = append(block, string(line.data))
+ linePos = append(linePos, line.Pos)
}
}
if inBlock {
@@ -107,8 +111,9 @@
var instLineRE = regexp.MustCompile(`^([A-Z_]+)\s*:\s*(.*)`)
// parseLines turns collected object lines into Object.
-func parseObjectLines(lines []string) (*Object, error) {
+func parseObjectLines(blockPos Pos, lines []string, linePos []Pos) (*Object, error) {
o := &Object{}
+ o.Pos = blockPos
// Repeatable tokens.
// We can not assign them eagerly, because these fields
@@ -117,9 +122,10 @@
operands []string
iforms []string
patterns []string
+ poses []Pos
)
- for _, l := range lines {
+ for i, l := range lines {
l = strings.TrimLeft(l, " ")
if l[0] == '#' { // Skip comment lines.
continue
@@ -167,6 +173,7 @@
operands = append(operands, val)
case "PATTERN":
patterns = append(patterns, val)
+ poses = append(poses, linePos[i])
case "IFORM":
iforms = append(iforms, val)
@@ -188,6 +195,7 @@
Object: o,
Index: i,
Pattern: patterns[i],
+ Pos: poses[i],
Operands: operands[i],
}
// There can be less IFORMs than insts.
diff --git a/x86/xeddata/xeddata_test.go b/x86/xeddata/xeddata_test.go
index fc98d86..8b64be4 100644
--- a/x86/xeddata/xeddata_test.go
+++ b/x86/xeddata/xeddata_test.go
@@ -470,6 +470,42 @@
}
}
+func TestReaderPos(t *testing.T) {
+ const data = `# Comment
+{
+ICLASS: iclass1
+DISASM: disasm1
+
+PATTERN: pat1 pat1
+OPERANDS: ops1 ops1
+}`
+ r := NewReader(namedReader{strings.NewReader(data), "test"})
+ objects, err := r.ReadAll()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if want := "test:2"; objects[0].Pos.String() != want {
+ t.Errorf("object Pos: got %q, want %q", objects[0].Pos, want)
+ }
+ if want := "test:6"; objects[0].Insts[0].Pos.String() != want {
+ t.Errorf("inst Pos: got %q, want %q", objects[0].Insts[0].Pos, want)
+ }
+}
+
+type namedReader struct {
+ r io.Reader
+ name string
+}
+
+func (n namedReader) Read(p []byte) (int, error) {
+ return n.r.Read(p)
+}
+
+func (n namedReader) Name() string {
+ return n.name
+}
+
func TestMacroExpand(t *testing.T) {
tests := [...]struct {
input string