github.com/apache/beam/sdks/v2@v2.48.2/go/cmd/symtab/main.go (about)

     1  // Licensed to the Apache Software Foundation (ASF) under one or more
     2  // contributor license agreements.  See the NOTICE file distributed with
     3  // this work for additional information regarding copyright ownership.
     4  // The ASF licenses this file to You under the Apache License, Version 2.0
     5  // (the "License"); you may not use this file except in compliance with
     6  // the License.  You may obtain a copy of the License at
     7  //
     8  //    http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  // Package verifies that functions sym2addr and addr2sym work correctly.
    17  package main
    18  
    19  import (
    20  	"log"
    21  	"os"
    22  	"reflect"
    23  
    24  	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/funcx"
    25  	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/util/reflectx"
    26  	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/util/symtab"
    27  )
    28  
    29  const (
    30  	name = "main.Increment"
    31  	arg  = "calling increment function"
    32  )
    33  
    34  var symbolTable *symtab.SymbolTable
    35  var counter int64
    36  var t reflect.Type
    37  
    38  // Increment is the function that will be executed by its address.
    39  // It increments a global var so we can check that it was indeed called.
    40  func Increment(str string) {
    41  	log.Printf(str)
    42  	counter++
    43  }
    44  
    45  func init() {
    46  	// Registers function in symbol table.
    47  	Increment("adding increment function to symbol table")
    48  	t = reflect.FuncOf([]reflect.Type{reflect.TypeOf(arg)}, []reflect.Type{}, false)
    49  
    50  	var err error
    51  	// First try the Linux location, since it's the most reliable.
    52  	symbolTable, err = symtab.New("/proc/self/exe")
    53  	if err == nil {
    54  		return
    55  	}
    56  	// For other OS's this works in most cases we need. If it doesn't, log
    57  	// an error and keep going.
    58  	symbolTable, err = symtab.New(os.Args[0])
    59  	if err == nil {
    60  		return
    61  	}
    62  	panic("Can't initialize symbol resolver.")
    63  }
    64  
    65  func main() {
    66  	// Translates function symbol to address.
    67  	addr, err := symbolTable.Sym2Addr(name)
    68  	if err != nil {
    69  		log.Fatalf("error translating function name to address: %v", err)
    70  		return
    71  	}
    72  
    73  	// Restarts counter and calls increment function by its address.
    74  	counter = 0
    75  	ret, err := funcx.New(reflectx.MakeFunc(reflectx.LoadFunction(addr, t)))
    76  	if err != nil {
    77  		log.Fatalf("error creating function out of address")
    78  		return
    79  	}
    80  	ret.Fn.Call([]any{arg})
    81  
    82  	// Checks that function was executed.
    83  	if counter != 1 {
    84  		log.Fatalf("error running function 'increment' through its address")
    85  		return
    86  	}
    87  
    88  	// Translates address back to function symbol.
    89  	symbol, err := symbolTable.Addr2Sym(addr)
    90  	if err != nil {
    91  		log.Fatalf("error translating address to function name")
    92  		return
    93  	}
    94  
    95  	// Checks that function name is correct.
    96  	if symbol != name {
    97  		log.Fatalf("error verifying translation from address to name")
    98  		return
    99  	}
   100  	log.Printf("success!")
   101  }