How to use a struct for golang fuction args in bpftrace - go

I have following go-code:
package main
import "fmt"
type foo struct {
bar string
some int
}
//go:noinline
func sum(a int, b int) {
fmt.Printf("Sum: %d\n", (a + b))
}
//go:noinline
func (f *foo) baz(value string) string {
return f.bar
}
//go:noinline
func (f *foo) nested(_f foo) foo {
fmt.Printf("Arg value: %s and %d\n", _f.bar, _f.some)
return _f
}
func main() {
f := foo{
bar: "hello world!",
some: 42,
}
fmt.Println(f.baz(f.bar))
sum(1, 2)
temp := f.nested(f)
fmt.Println(temp.bar)
}
Following script or I have problems to dereference the string struct correctly when using a struct definition:
struct args
{
uint64_t array;
uint64_t length;
uint64_t somevalue;
};
uprobe:/tmp/main:0x49aa00 {
$s = (struct args *)(reg("sp") + 16);
$length = *(reg("sp") + 24);
$array = reg("sp") + 16;
printf("length: %d\n", $s->length);
printf("array: %s\n", str(*($array), $length));
printf("somevalue: %d\n", $s->somevalue);
// this one will be empty
printf("array: %s\n", str($s->array, $s->length));
}
Output:
Attaching 1 probe...
length: 12
array: hello world!
somevalue: 42
array:
Removing $s->length prints 64 bytes (default) however:
hello world!host is downillegal seekinvalid slotlfstack.pushmad
Using reg("sp") works without any issues but when using a user-defined struct the array seems to be "empty". $s->length seems to be 12 but when assigning to an additional variable it becomes 2... Can someone help out here, please?

I have tested your code with bpftrace 0.9.4 in ubuntu 20.04, it seems the same issue.
After that I build bpftrace with latest version, all is ok.
You can have a try.
Attaching 1 probe...
length: 12
array: hello world!
somevalue: 42
array: hello world!

Related

go generics: processing different struct types with same data member types [duplicate]

This question already has answers here:
How can I access a struct field with generics (type T has no field or method)?
(1 answer)
Generic function to work on different structs with common members from external package?
(1 answer)
Closed 3 months ago.
There are two struct types, Foo and Bar, with an int data member val. I am trying to write a generic function that can handle both types. I tried the following and this did not work.
package main
import "fmt"
type Foo struct {
val int
}
type Bar struct {
val int
}
func Add[T any](slice []T) int {
var sum int
for _, elem := range slice {
sum += elem.val
}
return sum
}
func Test() {
f1 := Foo{val: 2}
f2 := Foo{val: 2}
fslice := []Foo{f1, f2}
fsum := Add(fslice)
fmt.Printf("fsum = %d\n", fsum)
b1 := Bar{val: 3}
b2 := Bar{val: 3}
bslice := []Bar{b1, b2}
bsum := Add(bslice)
fmt.Printf("bsum = %d\n", bsum)
}
func main() {
Test()
}
The compiler throws the following error.
$ go run generics1.go
# command-line-arguments
./generics1.go:16:15: elem.val undefined (type T has no field or method val)
Go playground link: https://go.dev/play/p/mdOMH3xuwu7
What could be a possible way to approach this?
Per golang 1.18 release note
The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type parameter's type set have a field f. We may remove this restriction in a future release.
You could define one GetVal() interface method to retrieve the val, and use this method as part of type constraint of generic.
Sample codes
type Foo struct {
val int
}
func (f Foo) GetVal() int {
return f.val
}
type Bar struct {
val int
}
func (b Bar) GetVal() int {
return b.val
}
type MyType interface {
Foo | Bar
GetVal() int
}
func Add[T MyType](slice []T) int {
var sum int
for _, elem := range slice {
sum += elem.GetVal()
}
return sum
}
https://go.dev/play/p/0eJZpqy7q8f

I can't mutate this struct I and I don't understand why

Consider the following gist linked here:
Code:
package main
import (
"fmt"
)
type StateTransition struct {
msg Message
}
type Message interface {
To() *string
}
type Transaction struct {
data txdata
}
type txdata struct {
Recipient *string
}
func (t Transaction) To() (*string) {
return t.data.Recipient
}
func UnMask(n **string, k string) {
*n = &k
}
func main() {
toField := "Bob"
toPtr := &toField
txd := txdata{toPtr}
tx := Transaction{txd}
st := StateTransition{tx}
n1 := st.msg.To()
fmt.Printf("Hello, %s \n", *n1)
UnMask(&n1, "Joe")
fmt.Printf("Hello, %s \n", *n1)
n2 := st.msg.To()
fmt.Printf("Hello, %s \n", *n2)
}
Output
Hello, Bob
Hello, Joe
Hello, Bob
Expected Output
Hello, Bob
Hello, Joe
Hello, Joe
The result is the sequence "Bob, Joe, Bob" is printed whereas my intuition says that it should be "Bob, Joe, Joe" (this is also what i want it to print). Can someone experienced in go please explain to me enough about combining pointers, structs, and interfaces as they relate to this problem to give me some understanding about why I'm wrong, and how to fix it?
Unmask takes a pointer to a pointer, let's say pointer X to pointer Y, pointer Y points to the string value. Unmask then changes the pointer to which X is pointing to, Y is unchanged and points still to the same old string.
You can do this:
func UnMask(n **string, k string) {
**n = k
}
or
func UnMask(n *string, k string) {
*n = k
}
// ....
UnMask(n1, "Joe") // drop the '&'

How do I assign embedded interface to object in golang [duplicate]

This question already has answers here:
Type converting slices of interfaces
(9 answers)
Closed 5 years ago.
I am attempting to assign an array of structs of type Baz to an array of interfaces of type Bar embedded in a second struct of type Foo. I have not been able to find the exact information here or elsewhere googling. I have provided a minimum working example.
I get the following error:
$ go run main.go
./main.go:38: cannot use baz (type []*Baz) as type []Bar in argument to NewFoo
My apologies if my code is not idiomatic go and also if I have not confirmed exactly to standards for posting questions, this is my first post.
package main
import (
"fmt"
)
type Foo struct {
b []Bar
}
type Baz struct {
a, b int
}
type Bar interface {
Multiply() int
}
func (baz *Baz) Multiply() int{
return baz.a * baz.b
}
func NewFoo(bar []Bar) *Foo{
return &Foo{b: bar}
}
func NewBaz() []*Baz {
bazes := make([]*Baz, 2)
bazes[0] = &Baz{a: 1, b: 2}
bazes[1] = &Baz{a: 3, b: 4}
return bazes
}
func main() {
baz := NewBaz()
foo := NewFoo(baz)
for _, f := range foo.b {
fmt.Println("Foo.Multiply ", f.Multiply())
}
}
UPDATE: I approved the duplicate vote after further reading and understanding the suggested related posts. Thank you to those who pointed me in that direction. For future interested readers, my final implementation consistent with my use case is as follows:
package main
import (
"fmt"
)
type Foo struct {
b []Bar
}
type Baz struct {
a, b int
}
type Bar interface { //
Multiply() int
}
func (baz *Baz) Multiply() int {
return baz.a * baz.b
}
func NewFoo(bar []*Baz) *Foo{
f := &Foo{}
f.b = make([]Bar, 2)
fmt.Println("len(bar) ", len(bar), "len(f.b)", len(f.b) )
for i, _ := range f.b {
f.b[i] = bar[i]
}
return f
}
func MakeBaz() []*Baz {
bazes := make([]*Baz, 2)
bazes[0] = NewBaz(1, 2)
bazes[1] = NewBaz(3, 4)
return bazes
}
func NewBaz(aa, bb int) *Baz {
return &Baz{a: aa, b: bb}
}
func main() {
baz := MakeBaz()
foo := NewFoo(baz)
fmt.Printf("%v\n", foo)
for _, f := range foo.b {
fmt.Println("Foo.Multiply ", f.Multiply())
}
}
There's a couple of different ways to do this, but the most straightforward is to embed type Baz with Bar. Baz can now multiply() and has two fields (a, b). Your code would look something like this:
package main
import (
"fmt"
)
type Foo struct {
b []*Baz
}
type Baz struct {
Bar
a, b int
}
type Bar interface {
Multiply() int
}
func (baz *Baz) Multiply() int {
return baz.a * baz.b
}
func NewFoo(bar []*Baz) *Foo {
return &Foo{b: bar}
}
func NewBaz() []*Baz {
bazes := make([]*Baz, 2)
bazes[0] = &Baz{a: 1, b: 2}
bazes[1] = &Baz{a: 3, b: 4}
return bazes
}
func main() {
baz := NewBaz()
foo := NewFoo(baz)
for _, f := range foo.b {
fmt.Println("Foo.Multiply ", f.Multiply())
}
}
GoPlay here:
https://play.golang.org/p/lia0ZS81TO
Great first question, by the way.
The error you are getting:
cannot use baz (type []*Baz) as type []Bar
Is because Go won't let you assign an array of Baz to an array of Bar, even when it'd let you assign a Baz to a Bar variable.
To see this in a more simple form, this works fine:
var oneBaz *Baz = &Baz{a: 1, b: 2}
var oneBar Bar = oneBaz
Because the type Baz satisfies the Bar interface and you can assign a Baz object to a Bar variable.
But this does not work (even if it'd looks like it could work):
var bazArray []*Baz = make([]*Baz, 2)
var barArray []Bar = bazArray
It will throw the same error you are seeing.
In order to make this work, you'd probably need to implement one of the solutions listed in this related question:
Type converting slices of interfaces in go

What's the difference between these functions in golang?

I'm new to Go programming and wondering what's the difference (if any) there between
a.
func DoSomething(a *A) {
b = a
}
b.
func DoSomething(a A) {
b = &a
}
If you are actually asking what the difference of those b's are, one is a pointer to the object passed as an argument to DoSomething, and the other is a pointer to a copy of the object passed as an argument to DoSomething.
https://play.golang.org/p/ush0hDZsdE
type A struct {
f string
}
func DoSomethingPtr(a *A) {
b := a
b.f = "hi"
}
func DoSomething(a A) {
b := &a
b.f = "hey"
}
func main() {
x := A{"hello"}
DoSomething(x)
fmt.Println(x)
DoSomethingPtr(&x)
fmt.Println(x)
}
The variable b would be assigned a different value in each function. The values are different because one is passing a copied value and the other is passing a pointer to the original value in memory.
package main
import "fmt"
type A string
func DoSomethingPtr(a *A) {
fmt.Println(a)
}
func DoSomething(a A) {
fmt.Println(&a)
}
func main() {
x := A("hello")
DoSomething(x)
DoSomethingPtr(&x)
}
Here is the executable proof.
In general, these two functions will assign different values to b. The second one makes a copy of the argument, and so the a inside the function generally has a different memory address than whatever input is passed into the function. See this playground example
package main
type A struct{
x int
}
var b *A
func d(a *A) {
b = a
}
func e(a A) {
b = &a
}
func main() {
var a = A{3}
println(&a)
d(&a)
println(b)
e(a)
println(b)
}
Interestingly, if you make the type A an empty struct instead, and initialize var a = A{}, you actually see the same value for b in the println statements.
That's because for the empty-struct type, there can only really only ever be 1 value, and its immutable, so all instances of it share the same memory address?

How do I declare a function pointer to a method in Go

I am trying to create function pointer to a function that has a method receiver. However, I can't figure out how to get it to work (if it is possible)?
Essentially, I have the following:
type Foo struct {...}
func (T Foo) Bar bool {
...
}
type BarFunc (Foo) func() bool // Does not work.
The last line of the code gives the error
syntax error: unexpected func, expecting semicolon or newline
If you want to create a function pointer to a method, you have two ways. The first is essentially turning a method with one argument into a function with two:
type Summable int
func (s Summable) Add(n int) int {
return s+n
}
var f func(s Summable, n int) int = (Summable).Add
// ...
fmt.Println(f(1, 2))
The second way will "bind" the value of s (at the time of evaluation) to the Summable receiver method Add, and then assign it to the variable f:
s := Summable(1)
var f func(n int) int = s.Add
fmt.Println(f(2))
Playground: http://play.golang.org/p/ctovxsFV2z.
Any changes to s after f is assigned will have no affect on the result: https://play.golang.org/p/UhPdYW5wUOP
And for an example more familiar to those of us used to a typedef in C for function pointers:
package main
import "fmt"
type DyadicMath func (int, int) int // your function pointer type
func doAdd(one int, two int) (ret int) {
ret = one + two;
return
}
func Work(input []int, addthis int, workfunc DyadicMath) {
for _, val := range input {
fmt.Println("--> ",workfunc(val, addthis))
}
}
func main() {
stuff := []int{ 1,2,3,4,5 }
Work(stuff,10,doAdd)
doMult := func (one int, two int) (ret int) {
ret = one * two;
return
}
Work(stuff,10,doMult)
}
https://play.golang.org/p/G5xzJXLexc
I am very likely off-target (just started on Golang) but what if you create a pointer then examine type:
pfun := Bar
fmt.Println("type of pfun is:", reflect.TypeOf(pfun))
then it seems that you can declare the type of pointer correctly:
https://play.golang.org/p/SV8W0J9JDuQ

Resources