Skip to content

Commit

Permalink
move (re-license) tracing package and introduce 'allowundefined' in k…
Browse files Browse the repository at this point in the history
…probe struct tag (#37602)

* fix: replace deprecated io/ioutil with os

* fix: rename local vars so they don't collide with built-in functions

* feat: introduce support for allowundefined tag

* fix: remove unnecessary named return variable

* feat: expose the option to set the wakeup_events for the perf channel

* feat: move tracing from x-pack/auditbeat to auditbeat

* legal: re-license tracing from Elastic License to Apache License Version 2.0

* fix: remove deprecated ioutil in events_test.go

* fix: replace naked return(s)

* fix: pre-allocate slices wherever the len is known

* fix: use errors.Is to check for a specific error

* fix: remove unused withTime struct field from PerfChannel

* fix: properly use make(chan struct{})

* fix: use raw string with regexp.MustCompile

* fix: replace missed naked return(s)

* fix: replace pre-allocating len of the slices with cap

* feat: modernise tracing endian.go to use binary.NativeEndian

* feat: refactor copyInt and readInt to use unsafe.Slice

* fix: revert pollAll in perfevent.go to named returns as these can be properly documented

* fix: remove redundant endian.go and utilise directly binary.NativeEndian

* fix: return explicitly the named returns in pollAll

* Revert "fix: remove redundant endian.go and utilise directly binary.NativeEndian"

This reverts commit 19d9c28.
  • Loading branch information
pkoutsovasilis authored Jan 25, 2024
1 parent 56e198b commit 685be2f
Show file tree
Hide file tree
Showing 39 changed files with 350 additions and 192 deletions.
40 changes: 28 additions & 12 deletions x-pack/auditbeat/tracing/cpu.go → auditbeat/tracing/cpu.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build linux

Expand All @@ -9,7 +22,7 @@ package tracing
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
)
Expand Down Expand Up @@ -72,7 +85,7 @@ func (s CPUSet) AsList() []int {

// NewCPUSetFromFile creates a new CPUSet from the contents of a file.
func NewCPUSetFromFile(path string) (cpus CPUSet, err error) {
contents, err := ioutil.ReadFile(path)
contents, err := os.ReadFile(path)
if err != nil {
return cpus, err
}
Expand All @@ -84,9 +97,12 @@ func NewCPUSetFromFile(path string) (cpus CPUSet, err error) {
// Where:
// RANGE := <NUMBER> | <NUMBER>-<NUMBER>
func NewCPUSetFromExpression(contents string) (CPUSet, error) {
var ranges [][]int
var max, count int
for _, expr := range strings.Split(contents, ",") {
expressions := strings.Split(contents, ",")

ranges := make([][]int, 0, len(expressions))

var maximum, count int
for _, expr := range expressions {
if len(expr) == 0 {
continue
}
Expand All @@ -99,16 +115,16 @@ func NewCPUSetFromExpression(contents string) (CPUSet, error) {
}
num := int(num16)
r = append(r, num)
if num+1 > max {
max = num + 1
if num+1 > maximum {
maximum = num + 1
}
}
ranges = append(ranges, r)
}
if max == 0 {
if maximum == 0 {
return CPUSet{}, nil
}
mask := make([]bool, max)
mask := make([]bool, maximum)
for _, r := range ranges {
from, to := -1, -1
switch len(r) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build linux

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build linux

Expand Down Expand Up @@ -183,9 +196,13 @@ func NewStructDecoder(desc ProbeFormat, allocFn AllocateFn) (Decoder, error) {
}

var name string
var allowUndefined bool
var greedy bool
for idx, param := range strings.Split(values, ",") {
switch param {
case "allowundefined":
// it is okay not to find it in the desc.Fields
allowUndefined = true
case "greedy":
greedy = true
default:
Expand Down Expand Up @@ -214,6 +231,9 @@ func NewStructDecoder(desc ProbeFormat, allocFn AllocateFn) (Decoder, error) {

inField, found := desc.Fields[name]
if !found {
if allowUndefined {
continue
}
return nil, fmt.Errorf("field '%s' not found in kprobe format description", name)
}

Expand Down Expand Up @@ -326,14 +346,14 @@ func (d *structDecoder) Decode(raw []byte, meta Metadata) (s interface{}, err er

case FieldTypeString:
offset := uintptr(MachineEndian.Uint16(raw[dec.src:]))
len := uintptr(MachineEndian.Uint16(raw[dec.src+2:]))
if offset+len > n {
length := uintptr(MachineEndian.Uint16(raw[dec.src+2:]))
if offset+length > n {
return nil, fmt.Errorf("perf event string data for field %s overflows message of size %d", dec.name, n)
}
if len > 0 && raw[offset+len-1] == 0 {
len--
if length > 0 && raw[offset+length-1] == 0 {
length--
}
*(*string)(unsafe.Add(destPtr, dec.dst)) = string(raw[offset : offset+len])
*(*string)(unsafe.Add(destPtr, dec.dst)) = string(raw[offset : offset+length])

case FieldTypeMeta:
*(*Metadata)(unsafe.Add(destPtr, dec.dst)) = meta
Expand All @@ -357,7 +377,8 @@ type dumpDecoder struct {
// - integer of 64bit (u64 / s64).
// - dump consecutive memory.
func NewDumpDecoder(format ProbeFormat) (Decoder, error) {
var fields []Field
fields := make([]Field, 0, len(format.Fields))

for name, field := range format.Fields {
if strings.Index(name, "arg") != 0 {
continue
Expand Down
22 changes: 22 additions & 0 deletions auditbeat/tracing/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

// Package tracing provides a set of tools built on top of
// golang.org/x/sys/unix/linux/perf that simplify working with KProbes and
// UProbes, using tracing perf channels to receive events from the kernel and
// decoding of this raw events into more useful types.
package tracing
28 changes: 28 additions & 0 deletions auditbeat/tracing/endian.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build linux

package tracing

import (
"encoding/binary"
)

// MachineEndian is either binary.BigEndian or binary.LittleEndian, depending
// on the current architecture.
var MachineEndian = binary.NativeEndian
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build linux

Expand All @@ -9,7 +22,6 @@ package tracing
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -301,7 +313,7 @@ func TestKProbeReal(t *testing.T) {

func TestKProbeEventsList(t *testing.T) {
// Make dir to monitor.
tmpDir, err := ioutil.TempDir("", "events_test")
tmpDir, err := os.MkdirTemp("", "events_test")
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -358,7 +370,7 @@ w:future feature

func TestKProbeEventsAddRemoveKProbe(t *testing.T) {
// Make dir to monitor.
tmpDir, err := ioutil.TempDir("", "events_test")
tmpDir, err := os.MkdirTemp("", "events_test")
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -397,7 +409,7 @@ w:future feature
off, err := file.Seek(int64(0), io.SeekStart)
assert.NoError(t, err)
assert.Equal(t, int64(0), off)
contents, err := ioutil.ReadAll(file)
contents, err := io.ReadAll(file)
assert.NoError(t, err)
expected := append([]byte(baseContents), []byte(
`p:kprobe/myprobe sys_open path=+0(%di):string mode=%si
Expand Down
71 changes: 71 additions & 0 deletions auditbeat/tracing/int_aligned.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//go:build linux && !386 && !amd64 && !amd64p32

// Alignment-safe integer reading and writing functions.

package tracing

import (
"errors"
"unsafe"
)

var errBadSize = errors.New("bad size for integer")

func copyInt(dst unsafe.Pointer, src unsafe.Pointer, len uint8) error {
copy(unsafe.Slice((*byte)(dst), len), unsafe.Slice((*byte)(src), len))
return nil
}

func readInt(ptr unsafe.Pointer, len uint8, signed bool) (any, error) {
var value any
asSlice := unsafe.Slice((*byte)(ptr), len)
switch len {
case 1:
if signed {
value = int8(asSlice[0])
} else {
value = asSlice[0]
}
case 2:
if signed {
value = int16(MachineEndian.Uint16(asSlice))
} else {
value = MachineEndian.Uint16(asSlice)
}

case 4:
if signed {
value = int32(MachineEndian.Uint32(asSlice))
} else {
value = MachineEndian.Uint32(asSlice)
}

case 8:
if signed {
value = int64(MachineEndian.Uint64(asSlice))
} else {
value = MachineEndian.Uint64(asSlice)
}

default:
return nil, errBadSize
}
return value, nil
}
Loading

0 comments on commit 685be2f

Please sign in to comment.