github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/internal/auxv_test.go (about)

     1  package internal
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"testing"
     9  	"unsafe"
    10  
    11  	"github.com/cilium/ebpf/internal/unix"
    12  )
    13  
    14  type auxvFileReader struct {
    15  	file            *os.File
    16  	order           binary.ByteOrder
    17  	uintptrIs32bits bool
    18  }
    19  
    20  func (r *auxvFileReader) Close() error {
    21  	return r.file.Close()
    22  }
    23  
    24  type auxvPair32 struct {
    25  	Tag, Value uint32
    26  }
    27  
    28  type auxvPair64 struct {
    29  	Tag, Value uint64
    30  }
    31  
    32  func (r *auxvFileReader) ReadAuxvPair() (tag, value uint64, _ error) {
    33  	if r.uintptrIs32bits {
    34  		var aux auxvPair32
    35  		if err := binary.Read(r.file, r.order, &aux); err != nil {
    36  			return 0, 0, fmt.Errorf("reading auxv entry: %w", err)
    37  		}
    38  		return uint64(aux.Tag), uint64(aux.Value), nil
    39  	}
    40  
    41  	var aux auxvPair64
    42  	if err := binary.Read(r.file, r.order, &aux); err != nil {
    43  		return 0, 0, fmt.Errorf("reading auxv entry: %w", err)
    44  	}
    45  	return aux.Tag, aux.Value, nil
    46  }
    47  
    48  func newAuxFileReader(path string, order binary.ByteOrder, uintptrIs32bits bool) (auxvPairReader, error) {
    49  	// Read data from the auxiliary vector, which is normally passed directly
    50  	// to the process. Go does not expose that data before go 1.21, so we must read it from procfs.
    51  	// https://man7.org/linux/man-pages/man3/getauxval.3.html
    52  	av, err := os.Open(path)
    53  	if errors.Is(err, unix.EACCES) {
    54  		return nil, fmt.Errorf("opening auxv: %w (process may not be dumpable due to file capabilities)", err)
    55  	}
    56  	if err != nil {
    57  		return nil, fmt.Errorf("opening auxv: %w", err)
    58  	}
    59  
    60  	return &auxvFileReader{
    61  		file:            av,
    62  		order:           order,
    63  		uintptrIs32bits: uintptrIs32bits,
    64  	}, nil
    65  }
    66  
    67  func newDefaultAuxvFileReader() (auxvPairReader, error) {
    68  	const uintptrIs32bits = unsafe.Sizeof((uintptr)(0)) == 4
    69  	return newAuxFileReader("/proc/self/auxv", NativeEndian, uintptrIs32bits)
    70  }
    71  
    72  func TestAuxvBothSourcesEqual(t *testing.T) {
    73  	runtimeBased, err := newAuxvRuntimeReader()
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	fileBased, err := newDefaultAuxvFileReader()
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  
    82  	for {
    83  		runtimeTag, runtimeValue, err := runtimeBased.ReadAuxvPair()
    84  		if err != nil {
    85  			t.Fatal(err)
    86  		}
    87  
    88  		fileTag, fileValue, err := fileBased.ReadAuxvPair()
    89  		if err != nil {
    90  			t.Fatal(err)
    91  		}
    92  
    93  		if runtimeTag != fileTag {
    94  			t.Errorf("mismatching tags: runtime=%v, file=%v", runtimeTag, fileTag)
    95  		}
    96  
    97  		if runtimeValue != fileValue {
    98  			t.Errorf("mismatching values: runtime=%v, file=%v", runtimeValue, fileValue)
    99  		}
   100  
   101  		if runtimeTag == _AT_NULL {
   102  			break
   103  		}
   104  	}
   105  }