I want set a process to a CPU using Go in win7, the below code:
package main
import (
"fmt"
"math"
"runtime"
"syscall"
"unsafe"
)
func SetAffinity(pid int, mask *int64) {
syscall.Syscall(syscall.SYS_SCHED_SETAFFINITY,
uintptr(pid), 8, uintptr(unsafe.Pointer(mask)))
}
func GetAffinity(pid int, mask *int64) {
syscall.Syscall(syscall.SYS_SCHED_GETAFFINITY,
uintptr(pid), 8, uintptr(unsafe.Pointer(mask)))
}
var cpuNum = float64(runtime.NumCPU())
var setx = []struct {
args int
expected int64
}{
{0, int64(math.Pow(2, cpuNum)) - 2},
}
func main() {
for _, ca := range setx {
var cpuSet int64
GetAffinity(ca.args, &cpuSet)
cpuSet = cpuSet & 0XFFFFFFE
SetAffinity(ca.args, &cpuSet)
fmt.Println(cpuSet)
GetAffinity(ca.args, &cpuSet)
fmt.Println(cpuSet)
}
}
When I use go run affinity.go, get the follow info:
# command-line-arguments
.\affinity.go:12: undefined: syscall.SYS_SCHED_SETAFFINITY
.\affinity.go:13: not enough arguments in call to syscall.Syscall
.\affinity.go:17: undefined: syscall.SYS_SCHED_GETAFFINITY
.\affinity.go:18: not enough arguments in call to syscall.Syscall
I find SYS_SCHED_SETAFFINITY that it only used in linux.
So, I want to set a process to a cpu using Go in Windows(Win7), what can I do?
You'll have to invoke the WinAPI SetProcessAffinityMask.
Something like this should work:
func setProcessAffinityMask(h syscall.Handle, mask uintptr) (err error) {
r1, _, e1 := syscall.Syscall(syscall.NewLazyDLL("kernel32.dll").NewProc("SetProcessAffinityMask").Addr(), 2, uintptr(h), mask, 0)
if r1 == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = syscall.EINVAL
}
}
return
}
h being the process handle, and mask being the desired affinity mask, of course.
This is taken from Go benchmarks, under the BSD license.
Related
document of DnsQueryConfig here:
https://learn.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsqueryconfig
add file dnsapi.go in project: github.com/kbinani/win, the content of the file is:
// +build windows
package win
import "unsafe"
var (
// Library
libdnsapi uintptr
// function
dnsQueryConfig uintptr
)
type DNS_CONFIG_TYPE uint32
type IP4_ARRAY struct {
AddrCount DWORD
IP4_ADDRESS [1]IP_ADDRESS_STRING
}
type PIP4_ARRAY *IP4_ARRAY
func init(){
// Library
libdnsapi = doLoadLibrary("Dnsapi.dll")
// Functions
dnsQueryConfig = doGetProcAddress(libdnsapi, "DnsQueryConfig")
}
// https://learn.microsoft.com/en-us/windows/win32/api/windns/nf-windns-dnsqueryconfig
func DnsQueryConfig(config DNS_CONFIG_TYPE, flag DWORD, pwsAdapterName PCWSTR, pReserved PVOID, pBuffer PVOID, pBufLen DWORD_PTR) int32 {
ret1 := syscall6(dnsQueryConfig,
6,
uintptr(unsafe.Pointer(&config)),
uintptr(unsafe.Pointer(&flag)),
uintptr(unsafe.Pointer(pwsAdapterName)),
uintptr(pReserved),
uintptr(pBuffer),
uintptr(unsafe.Pointer(pBufLen)),
)
return int32(ret1)
}
code in my project:
package main
import (
"fmt"
"github.com/kbinani/win"
"unsafe"
)
func main(){
// func DnsQueryConfig(config DNS_CONFIG_TYPE, flag DWORD, pwsAdapterName PCWSTR, pReserved PVOID, pBuffer PVOID, pBufLen DWORD_PTR) int32 {
config := win.DNS_CONFIG_TYPE(6)
flag := win.DWORD(0)
pwsAdapterName := win.PCWSTR(nil)
pReserved := win.PVOID(unsafe.Pointer(nil))
buffer := win.IP4_ARRAY{}
a := win.PVOID(unsafe.Pointer(&buffer))
l := uint32(unsafe.Sizeof(buffer))
pBufLen := win.DWORD_PTR(unsafe.Pointer(&l))
r := win.DnsQueryConfig(config, flag, pwsAdapterName, pReserved, a, pBufLen)
fmt.Println(r, buffer)
}
it always return code 87, can you give me some suggestions, thanks a lot.
solve the problem
package main
import (
"fmt"
"golang.org/x/sys/windows"
"net"
"strings"
"unsafe"
)
const (
DnsConfigDnsServerList int32 = 6
)
type char byte
type IpAddressString struct {
DNS [4 * 10]char
}
type Ip4Array struct {
AddrCount uint32
Ip4Address [1]IpAddressString
}
func main() {
fmt.Println(dns())
}
func dns() []string {
dns := []string{}
dnsapi := windows.NewLazyDLL("Dnsapi.dll")
dnsQuery := dnsapi.NewProc("DnsQueryConfig")
bufferBytes := make([]byte, 60)
loop:
buffer := (*Ip4Array)(unsafe.Pointer(&bufferBytes[0]))
blen := len(bufferBytes)
r1, _, _ := dnsQuery.Call(uintptr(DnsConfigDnsServerList), uintptr(0), uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&bufferBytes[0])), uintptr(unsafe.Pointer(&blen)))
if r1 == 234 {
bufferBytes = make([]byte, blen)
goto loop
} else if r1 == 0 {
} else {
return dns
}
for i := uint32(1); i <= buffer.AddrCount; i++ {
right := i * 4
left := right - 4
tmpChars := buffer.Ip4Address[0].DNS[left:right]
tmpStr := []string{}
for j := 0; j < len(tmpChars); j++ {
tmpStr = append(tmpStr, fmt.Sprint(tmpChars[j]))
}
tmpDNS := strings.Join(tmpStr, ".")
pDns := net.ParseIP(tmpDNS)
if pDns == nil {
continue
}
if !pDns.IsGlobalUnicast() {
continue
}
dns = append(dns, tmpDNS)
}
return dns
}
I was referring to spf13/cobra.
I downloaded the cobra package using go get github.com/spf13/cobra/cobra and imported "github.com/spf13/cobra" in my program and then installed it using go install github.com/spf13/cobra/cobra.
This is my program - It is a calculator which can be implemented of number of inputs , but for now only 2 are taken from the user. I wanted to use cobra in this program.
package main
import (
"fmt"
"github.com/spf13/cobra"
)
func add(m ...int) int {
sum := 0
for _, a := range m {
sum += a
}
return sum
}
func sub(m ...int) int {
sub := m[0]
for _, a := range m[1:] {
sub -= a
}
return sub
}
func mul(m ...float32) float32 {
pro := float32(1)
for _, a := range m {
pro *= a
}
return pro
}
func div(m ...float32) float32 {
quo := m[0]
for _, a := range m[1:] {
quo /= a
}
return quo
}
var i int
func display() {
fmt.Println("Choose the operation : 1:Addition 2:Subtration 3:Multiplication 4:Division ")
fmt.Scanln(&i)
}
func main() {
display()
var v1,v2 int
fmt.Println("Enter 2 numbers with enter")
fmt.Scanln(&v1)
fmt.Scanln(&v2)
switch i {
case 1:
fmt.Println(add(v1,v2))
case 2:
fmt.Println(sub(v1,v2))
case 3:
fmt.Println(mul(float32(v1),float32(v2)))
case 4:
fmt.Println(div(float32(v1),float32(v2)))
}
}
You need to run go get github.com/spf13/cobra/cobra first. go install can only install packages you've already downloaded, go get downloads and installs a package.
To help debug GO programs, I want to write two generic functions that will be called on entry and exit, which will print the values of input and output parameters respectively:
printInputParameters(input ...interface{})
printOutputParameters(output ...interface{})
Is there an equivalent of os.Args() for functions? I looked at runtime package and didn't find such functions.
For example lets say I have two functions with different input parameters and output parameters
func f1(int i, float f) (e error) {
... some code here
}
func f2(s string, b []byte) (u uint64, e error) {
.. some code here
}
I want to be able to do the following
func f1(int i, float f) (e error) {
printInputparameters( ? )
defer func() {
printOutputParameters( ? )
}()
... some code here
}
func f2(s string, b []byte) (u uint64, e error) {
printInputparameters( ? )
defer func() {
printOutputParameters( ? )
}()
... some code here
}
You cannot do this in Go since there is no way you can get the stack frame of the currently active function in the current goroutine. It is not impossible to do this as I'll show further below but the problem is that there is no public API to get this done reliably. That it can be done can be seen in the stack traces printed when a panic is raised: all values on the stack are dumped in that case.
Should you be interested in how the stack trace is actually generated then have a look at genstacktrace in the runtime package.
As for a solution to your problem, you can the source code parsing route as already suggested. If you feel adventurous, you can parse the stack trace provided by runtime.Stack. But beware, there are so many drawbacks that you will quickly realize that any solution is better than this one.
To parse the stack trace, just get the line of the previously called function (from the viewpoint of printInputParameters), get the name of that function and parse the parameter values according to the parameter types provided by reflection. Some examples of stack trace outputs of various function invocations:
main.Test1(0x2) // Test1(int64(2))
main.Test1(0xc820043ed5, 0x3, 0x3) // Test1([]byte{'A','B','C'})
main.Test1(0x513350, 0x4) // Test1("AAAA")
You can see that complex types (those which do not fit into a register) may use more than one 'parameter'. A string for example is a pointer to the data and the length. So you have to use the unsafe package to access these pointers and reflection to create values from this data.
If you want to try yourself, here's some example code:
import (
"fmt"
"math"
"reflect"
"runtime"
"strconv"
"strings"
"unsafe"
)
// Parses the second call's parameters in a stack trace of the form:
//
// goroutine 1 [running]:
// main.printInputs(0x4c4c60, 0x539038)
// /.../go/src/debug/main.go:16 +0xe0
// main.Test1(0x2)
// /.../go/src/debug/main.go:23
//
func parseParams(st string) (string, []uintptr) {
line := 1
start, stop := 0, 0
for i, c := range st {
if c == '\n' {
line++
}
if line == 4 && c == '\n' {
start = i + 1
}
if line == 5 && c == '\n' {
stop = i
}
}
call := st[start:stop]
fname := call[0:strings.IndexByte(call, '(')]
param := call[strings.IndexByte(call, '(')+1 : strings.IndexByte(call, ')')]
params := strings.Split(param, ", ")
parsedParams := make([]uintptr, len(params))
for i := range params {
iv, err := strconv.ParseInt(params[i], 0, 64)
if err != nil {
panic(err.Error())
}
parsedParams[i] = uintptr(iv)
}
return fname, parsedParams
}
func fromAddress(t reflect.Type, addr uintptr) reflect.Value {
return reflect.NewAt(t, unsafe.Pointer(&addr)).Elem()
}
func printInputs(fn interface{}) {
v := reflect.ValueOf(fn)
vt := v.Type()
b := make([]byte, 500)
if v.Kind() != reflect.Func {
return
}
runtime.Stack(b, false)
name, params := parseParams(string(b))
pidx := 0
fmt.Print(name + "(")
for i := 0; i < vt.NumIn(); i++ {
t := vt.In(i)
switch t.Kind() {
case reflect.Int64:
case reflect.Int:
// Just use the value from the stack
fmt.Print(params[pidx], ",")
pidx++
case reflect.Float64:
fmt.Print(math.Float64frombits(uint64(params[pidx])), ",")
pidx++
case reflect.Slice:
// create []T pointing to slice content
data := reflect.ArrayOf(int(params[pidx+2]), t.Elem())
svp := reflect.NewAt(data, unsafe.Pointer(params[pidx]))
fmt.Printf("%v,", svp.Elem())
pidx += 3
case reflect.String:
sv := fromAddress(t, params[pidx])
fmt.Printf("%v,", sv)
pidx += 2
case reflect.Map:
// points to hmap struct
mv := fromAddress(t,params[pidx])
fmt.Printf("%v,", mv)
pidx++
} /* switch */
}
fmt.Println(")")
}
Test:
func Test1(in int, b []byte, in2 int, m string) {
printInputs(Test1)
}
func main() {
b := []byte{'A', 'B', 'C'}
s := "AAAA"
Test1(2, b, 9, s)
}
Output:
main.Test1(2,[65 66 67],9,"AAAA",)
A slightly advanced version of this can be found on github:
go get github.com/githubnemo/pdump
To generically print your functions' arguments, you can do this:
func printInputParameters(input ...interface{}) {
fmt.Printf("Args: %v", input)
}
printInputParameters is a variadic function, and input is of type []interface{}.
I have my script "file.go" Built with "go build file.go" now I have "file.exe"
In the code I have "steamid := xxxxxxxxxxxxxxxx" Is there anyway when executing file.exe in cmd like "file.exe -steamid=xxxxxxxxxxxxxxxx"
code:
package main
import (
"crypto/md5"
"fmt"
)
func main() {
steamid := xxxxxxxxxxxxxxxx
h := md5.New()
h.Write([]byte("BE"))
for i := 0; i < 8; i++ {
h.Write([]byte{byte(steamid & 0xFF)})
steamid >>= 8
}
fmt.Printf("Battleye GUID: %x", h.Sum(nil))
}
I've gotten as far as here with new replys;
package main
import (
"crypto/md5"
"fmt"
"bufio"
"os"
"flag"
)
var SteamID string
func init() {
flag.StringVar(&SteamID, "steamid", "XXXXXXXXXXXXXXXXX", "17 Numbers SteamID")
}
func main() {
steamid := &SteamID
h := md5.New()
h.Write([]byte("BE"))
for i := 0; i < 8; i++ {
h.Write([]byte{byte(steamid & 0xFF)})
steamid >>= 8
}
fmt.Printf("Battleye GUID: %x", h.Sum(nil))
fmt.Print("\nPress 'Enter' to continue...")
bufio.NewReader(os.Stdin).ReadBytes('\n')
}
Error:
C:\Go\bin>go build file.go
# command-line-arguments
.\file.go:24: invalid operation: steamid & 255 (mismatched types *string and int)
.\file.go:25: invalid operation: steamid >>= 8 (shift of type *string)
the flag package included in the standard library does just that.
what you need to add in your script:
var SteamID string
func init() {
flag.StringVar(&SteamID, "steamid", "<insert default value>", "<insert help text>")
}
(in case you need to get it as an integer, use Int64Var instead)
then in your main function add:
flag.Parse()
This will initialise the value of SteamID
It's all in the error message. You can't do bitwise operations with strings, pointers to strings or anything that is not an integer, you need to convert or parse them into integers first. Use strconv.ParseInt and its friends from the strconv package to parse strings.
parsedID, e := strconv.ParseInt(*steamID, 16, 64)
if e != nil { log.Fatal("couldn't parse the ID") }
// Use parsedID.
My apologies if this is a beginner question, but I simply can't seem to find any solution for this. I'm trying to take an argument that can be either a string or an int, depending on the context, and I need to determine which type, (then convert it to int if it is indeed that type.)
Thank you :)
For example,
package main
import (
"errors"
"fmt"
"strconv"
)
func IntConv(arg interface{}) (int, error) {
switch x := arg.(type) {
case int:
return x, nil
case string:
return strconv.Atoi(x)
}
return 0, errors.New("IntConv: invalid argument ")
}
func main() {
fmt.Println(IntConv(7))
fmt.Println(IntConv("42"))
}
http://golang.org/pkg/strconv/#Atoi
func Atoi
func Atoi(s string) (i int, err error)
Atoi is shorthand for ParseInt(s, 10, 0).
This is an update. To clarify, since Atoi accepts string, then trying to pass an int will cause a compile time error. If you need a check during runtime, then you can do something like this.
package main
import (
"fmt"
"strconv"
"errors"
)
func toInt(data interface{}) (n int, err error) {
switch t := data.(type) {
case int:
return t, nil
case string:
return strconv.Atoi(t)
default:
return 0, errors.New(fmt.Sprintf("Invalid type received: %T", t))
}
panic("unreachable!")
}
func main() {
var (
n int
err error
)
n, _ = toInt("1")
fmt.Println(n)
n, _ = toInt(2)
fmt.Println(n)
n, err = toInt(32.3)
fmt.Println(err)
}
I'm a bit late to the party, but you could also use fmt.Sprintf:
import "fmt"
func ConvertToString(x interface{}) string {
return fmt.Sprintf("%v", x)
}
Passing "%v" to Sprintf tells it to format it using the best format it knows, which essentially just means "convert x to a string". This is shorter (and perhaps easier to understand) than the other solutions, but has the disadvantage that it'll allow inputs that aren't ints or strings.