Skip to content

currently mksyscall_zos_s390x.go generate empty string for funcName #85

@github-actions

Description

@github-actions

have correct funcName pass to the funcptrtest function

Is function descriptor f a valid function?

// TODO: currently mksyscall_zos_s390x.go generate empty string for funcName

	"unsafe"
)

//go:noescape
func initZosLibVec()

//go:noescape
func GetZosLibVec() uintptr

func init() {
	initZosLibVec()
	r0, _, _ := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS_____GETENV_A<<4, uintptr(unsafe.Pointer(&([]byte("__ZOS_XSYSTRACE\x00"))[0])))
	if r0 != 0 {
		n, _, _ := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS___ATOI_A<<4, r0)
		ZosTraceLevel = int(n)
		r0, _, _ := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS_____GETENV_A<<4, uintptr(unsafe.Pointer(&([]byte("__ZOS_XSYSTRACEFD\x00"))[0])))
		if r0 != 0 {
			fd, _, _ := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS___ATOI_A<<4, r0)
			f := os.NewFile(fd, "zostracefile")
			if f != nil {
				ZosTracefile = f
			}
		}

	}
}

//go:noescape
func CallLeFuncWithErr(funcdesc uintptr, parms ...uintptr) (ret, errno2 uintptr, err Errno)

//go:noescape
func CallLeFuncWithPtrReturn(funcdesc uintptr, parms ...uintptr) (ret, errno2 uintptr, err Errno)

// -------------------------------
// pointer validity test
// good pointer returns 0
// bad pointer returns 1
//
//go:nosplit
func ptrtest(uintptr) uint64

// Load memory at ptr location with error handling if the location is invalid
//
//go:noescape
func safeload(ptr uintptr) (value uintptr, error uintptr)

const (
	entrypointLocationOffset = 8 // From function descriptor

	xplinkEyecatcher   = 0x00c300c500c500f1 // ".C.E.E.1"
	eyecatcherOffset   = 16                 // From function entrypoint (negative)
	ppa1LocationOffset = 8                  // From function entrypoint (negative)

	nameLenOffset = 0x14 // From PPA1 start
	nameOffset    = 0x16 // From PPA1 start
)

func getPpaOffset(funcptr uintptr) int64 {
	entrypoint, err := safeload(funcptr + entrypointLocationOffset)
	if err != 0 {
		return -1
	}

	// XPLink functions have ".C.E.E.1" as the first 8 bytes (EBCDIC)
	val, err := safeload(entrypoint - eyecatcherOffset)
	if err != 0 {
		return -1
	}
	if val != xplinkEyecatcher {
		return -1
	}

	ppaoff, err := safeload(entrypoint - ppa1LocationOffset)
	if err != 0 {
		return -1
	}

	ppaoff >>= 32
	return int64(ppaoff)
}

//-------------------------------
// function descriptor pointer validity test
// good pointer returns 0
// bad pointer returns 1

// TODO: currently mksyscall_zos_s390x.go generate empty string for funcName
// have correct funcName pass to the funcptrtest function
func funcptrtest(funcptr uintptr, funcName string) uint64 {
	entrypoint, err := safeload(funcptr + entrypointLocationOffset)
	if err != 0 {
		return 1
	}

	ppaoff := getPpaOffset(funcptr)
	if ppaoff == -1 {
		return 1
	}

	// PPA1 offset value is from the start of the entire function block, not the entrypoint
	ppa1 := (entrypoint - eyecatcherOffset) + uintptr(ppaoff)

	nameLen, err := safeload(ppa1 + nameLenOffset)
	if err != 0 {
		return 1
	}

	nameLen >>= 48
	if nameLen > 128 {
		return 1
	}

	// no function name input to argument end here
	if funcName == "" {
		return 0
	}

	var funcname [128]byte
	for i := 0; i < int(nameLen); i += 8 {
		v, err := safeload(ppa1 + nameOffset + uintptr(i))
		if err != 0 {
			return 1
		}
		funcname[i] = byte(v >> 56)
		funcname[i+1] = byte(v >> 48)
		funcname[i+2] = byte(v >> 40)
		funcname[i+3] = byte(v >> 32)
		funcname[i+4] = byte(v >> 24)
		funcname[i+5] = byte(v >> 16)
		funcname[i+6] = byte(v >> 8)
		funcname[i+7] = byte(v)
	}

	runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___E2A_L<<4, // __e2a_l
		[]uintptr{uintptr(unsafe.Pointer(&funcname[0])), nameLen})

	name := string(funcname[:nameLen])
	if name != funcName {
		return 1
	}

	return 0
}

// For detection of capabilities on a system.
// Is function descriptor f a valid function?
func isValidLeFunc(f uintptr) error {
	ret := funcptrtest(f, "")
	if ret != 0 {
		return fmt.Errorf("Bad pointer, not an LE function ")
	}
	return nil
}

// Retrieve function name from descriptor
func getLeFuncName(f uintptr) (string, error) {
	// assume it has been checked, only check ppa1 validity here
	entry := ((*[2]uintptr)(unsafe.Pointer(f)))[1]
	preamp := ((*[4]uint32)(unsafe.Pointer(entry - eyecatcherOffset)))

	offsetPpa1 := preamp[2]
	if offsetPpa1 > 0x0ffff {
		return "", fmt.Errorf("PPA1 offset seems too big 0x%x\n", offsetPpa1)
	}

	ppa1 := uintptr(unsafe.Pointer(preamp)) + uintptr(offsetPpa1)
	res := ptrtest(ppa1)
	if res != 0 {
		return "", fmt.Errorf("PPA1 address not valid")
	}

	size := *(*uint16)(unsafe.Pointer(ppa1 + nameLenOffset))
	if size > 128 {
		return "", fmt.Errorf("Function name seems too long, length=%d\n", size)
	}

	var name [128]byte
	funcname := (*[128]byte)(unsafe.Pointer(ppa1 + nameOffset))
	copy(name[0:size], funcname[0:size])

	runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___E2A_L<<4, // __e2a_l
		[]uintptr{uintptr(unsafe.Pointer(&name[0])), uintptr(size)})

	return string(name[:size]), nil
}

// Check z/OS version
func zosLeVersion() (version, release uint32) {
	p1 := (*(*uintptr)(unsafe.Pointer(uintptr(1208)))) >> 32
	p1 = *(*uintptr)(unsafe.Pointer(uintptr(p1 + 88)))
	p1 = *(*uintptr)(unsafe.Pointer(uintptr(p1 + 8)))
	p1 = *(*uintptr)(unsafe.Pointer(uintptr(p1 + 984)))
	vrm := *(*uint32)(unsafe.Pointer(p1 + 80))
	version = (vrm & 0x00ff0000) >> 16
	release = (vrm & 0x0000ff00) >> 8
	return
}

// returns a zos C FILE * for stdio fd 0, 1, 2
func ZosStdioFilep(fd int32) uintptr {
	return uintptr(*(*uint64)(unsafe.Pointer(uintptr(*(*uint64)(unsafe.Pointer(uintptr(*(*uint64)(unsafe.Pointer(uintptr(uint64(*(*uint32)(unsafe.Pointer(uintptr(1208)))) + 80))) + uint64((fd+2)<<3))))))))
}

func copyStat(stat *Stat_t, statLE *Stat_LE_t) {
	stat.Dev = uint64(statLE.Dev)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions