Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions asm/amd/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ func (i *Interpreter) Step() (x86asm.Inst, error) {
switch inst.Op {
case x86asm.ADD:
if dst, ok := inst.Args[0].(x86asm.Reg); ok {
left := i.Regs.getX86asm(dst)
left := i.Regs.GetX86(dst)
switch src := inst.Args[1].(type) {
case x86asm.Imm:
right := expression.Imm(uint64(src))
i.Regs.setX86asm(dst, expression.Add(left, right))
case x86asm.Reg:
right := i.Regs.getX86asm(src)
right := i.Regs.GetX86(src)
i.Regs.setX86asm(dst, expression.Add(left, right))
case x86asm.Mem:
right := i.MemArg(src)
Expand All @@ -98,7 +98,7 @@ func (i *Interpreter) Step() (x86asm.Inst, error) {
if dst, ok := inst.Args[0].(x86asm.Reg); ok {
if src, imm := inst.Args[1].(x86asm.Imm); imm {
v := expression.Multiply(
i.Regs.getX86asm(dst),
i.Regs.GetX86(dst),
expression.Imm(uint64(math.Pow(2, float64(src)))),
)
i.Regs.setX86asm(dst, v)
Expand All @@ -110,7 +110,7 @@ func (i *Interpreter) Step() (x86asm.Inst, error) {
case x86asm.Imm:
i.Regs.setX86asm(dst, expression.Imm(uint64(src)))
case x86asm.Reg:
i.Regs.setX86asm(dst, i.Regs.getX86asm(src))
i.Regs.setX86asm(dst, i.Regs.GetX86(src))
case x86asm.Mem:
v := i.MemArg(src)

Expand All @@ -137,7 +137,7 @@ func (i *Interpreter) Step() (x86asm.Inst, error) {
if dst, ok := inst.Args[0].(x86asm.Reg); ok {
if src, imm := inst.Args[1].(x86asm.Imm); imm {
if src == 3 { // todo other cases
i.Regs.setX86asm(dst, expression.ZeroExtend(i.Regs.getX86asm(dst), 2))
i.Regs.setX86asm(dst, expression.ZeroExtend(i.Regs.GetX86(dst), 2))
}
}
}
Expand All @@ -159,11 +159,11 @@ func (i *Interpreter) MemArg(src x86asm.Mem) expression.Expression {
vs = append(vs, expression.Imm(uint64(src.Disp)))
}
if src.Base != 0 {
vs = append(vs, i.Regs.getX86asm(src.Base))
vs = append(vs, i.Regs.GetX86(src.Base))
}
if src.Index != 0 {
v := expression.Multiply(
i.Regs.getX86asm(src.Index),
i.Regs.GetX86(src.Index),
expression.Imm(uint64(src.Scale)),
)
vs = append(vs, v)
Expand Down
5 changes: 4 additions & 1 deletion asm/amd/regs_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,9 @@ func (r *Registers) setX86asm(reg x86asm.Reg, v expression.Expression) {
r.regs[e.idx] = v
}

func (r *Registers) getX86asm(reg x86asm.Reg) expression.Expression {
// GetX86 returns the expression.Expression value associated with the given x86asm.Reg, with
// appropriate zero-extension if necessary.
func (r *Registers) GetX86(reg x86asm.Reg) expression.Expression {
e := regMappingFor(reg)
res := r.regs[e.idx]
if e.bits != 64 {
Expand All @@ -224,6 +226,7 @@ func (r *Registers) getX86asm(reg x86asm.Reg) expression.Expression {
return res
}

// Get returns the expression.Expression value associated with the given Reg register
func (r *Registers) Get(reg Reg) expression.Expression {
if int(reg) >= len(r.regs) {
return r.regs[0]
Expand Down
4 changes: 2 additions & 2 deletions asm/expression/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ func cmpOrder(u Expression) int {
return 1
case *op:
return 2
case *ImmediateCapture:
return 3
case *named:
return 3
case *ImmediateCapture:
return 4
case *immediate:
return 5
Expand Down
2 changes: 1 addition & 1 deletion tpbase/assembly_decode_aarch64.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
aa "golang.org/x/arch/arm64/arm64asm"
)

func arm64GetAnalyzers() []Analyzer {
func getAnalyzersARM() []Analyzer {
return []Analyzer{
{"tls_set", analyzeTLSSetARM},
}
Expand Down
10 changes: 0 additions & 10 deletions tpbase/assembly_decode_arm64.go

This file was deleted.

6 changes: 2 additions & 4 deletions tpbase/assembly_decode_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build amd64

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -257,9 +255,9 @@ func TestFSBase(t *testing.T) {
var analyzers []Analyzer
switch test.machine {
case elf.EM_X86_64:
analyzers = x86GetAnalyzers()
analyzers = getAnalyzersX86()
case elf.EM_AARCH64:
analyzers = arm64GetAnalyzers()
analyzers = getAnalyzersARM()
}
if analyzers == nil {
t.Skip("tests not available on this platform")
Expand Down
69 changes: 38 additions & 31 deletions tpbase/assembly_decode_amd64.go → tpbase/assembly_decode_x86.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build amd64

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -9,51 +7,60 @@ import (
"bytes"
"encoding/binary"
"errors"
"unsafe"

_ "go.opentelemetry.io/ebpf-profiler/zydis" // links Zydis
"go.opentelemetry.io/ebpf-profiler/asm/amd"
e "go.opentelemetry.io/ebpf-profiler/asm/expression"
"golang.org/x/arch/x86/x86asm"
)

// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "fsbase_decode_amd64.h"
import "C"

func x86GetAnalyzers() []Analyzer {
func getAnalyzersX86() []Analyzer {
return []Analyzer{
{"x86_fsbase_write_task", AnalyzeX86fsbaseWriteTask},
{"aout_dump_debugregs", AnalyzeAoutDumpDebugregs},
{"x86_fsbase_write_task", analyzefsbaseWriteTaskX86},
{"aout_dump_debugregs", analyzeAoutDumpDebugregsX86},
}
}

func GetAnalyzers() []Analyzer {
return x86GetAnalyzers()
}

// AnalyzeAoutDumpDebugregs looks at the assembly of the `aout_dump_debugregs` function in the
// analyzeAoutDumpDebugregsX86 looks at the assembly of the `aout_dump_debugregs` function in the
// kernel in order to compute the offset of `fsbase` into `task_struct`.
func AnalyzeAoutDumpDebugregs(code []byte) (uint32, error) {
func analyzeAoutDumpDebugregsX86(code []byte) (uint32, error) {
if len(code) == 0 {
return 0, errors.New("empty code blob passed to getFSBaseOffset")
}

// Because different compilers generate code that looks different enough, we disassemble the
// function in order to properly analyze the code and deduce the fsbase offset.
// The underlying logic uses the zydis library, hence the cgo call.
offset := uint32(C.decode_fsbase_aout_dump_debugregs(
(*C.uint8_t)(unsafe.Pointer(&code[0])), C.size_t(len(code))))

if offset == 0 {
return 0, errors.New("unable to determine fsbase offset")
it := amd.NewInterpreterWithCode(code)
for {
op, err := it.Step()
if err != nil {
return 0, err
}
if op.Op != x86asm.MOV {
continue
}
dst, ok := op.Args[0].(x86asm.Reg)
if !ok {
continue
}
actual := it.Regs.GetX86(dst)
offset := e.NewImmediateCapture("offset")
expected := e.Mem8(
e.Add(
e.MemWithSegment8(x86asm.GS, e.NewImmediateCapture("")),
offset,
),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Same as the other comment: move offset and expected outside the for block to reduce GC pressure by creating new variable instances for each step. Obviously the actual and Match call cannot move.

But is there any reason why expected definition could not be moved and reused for each step?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, now I understand. will do

if actual.Match(expected) {
res := int64(offset.CapturedValue()) - 2*8
if res < 0 || res > 256*1024 {
return 0, errors.New("failed to determine offset of fsbase")
}
return uint32(res), nil
}
}

return offset, nil
}

// AnalyzeX86fsbaseWriteTask looks at the assembly of the function x86_fsbase_write_task which
// analyzefsbaseWriteTaskX86 looks at the assembly of the function x86_fsbase_write_task which
// is ideal because it only writes the argument to the fsbase function. We can get the fsbase
// offset directly from the assembly here. Available since kernel version 4.20.
func AnalyzeX86fsbaseWriteTask(code []byte) (uint32, error) {
func analyzefsbaseWriteTaskX86(code []byte) (uint32, error) {
// Supported sequences (might be surrounded be additional code for the WARN_ONCE):
//
// 1) Alpine Linux (kernel 5.10+)
Expand Down
130 changes: 0 additions & 130 deletions tpbase/fsbase_decode_amd64.c

This file was deleted.

13 changes: 0 additions & 13 deletions tpbase/fsbase_decode_amd64.h

This file was deleted.

Loading