feat: V2 microservices stack — backend services, gateway, JWT auth
Add full V2 architecture: identity, content, studio (.NET 10) and file, render, notification, gateway (Go) services with vendored deps, plus DB migrations, event/API contracts, and an init-db script. Wire the Next.js frontend to the gateway: server-side JWT auth routes (login/register/refresh/logout/me), gateway fetch helper, and session/ cookie/jwt helpers under src/lib. Containerize the stack via docker-compose.v2.yml and per-service Dockerfiles. Base images resolve through a Nexus mirror (Docker Hub) and MCR directly; npm/NuGet pull from Nexus groups. Self-host fonts via next/font/local to avoid Google Fonts (geo-blocked). Add CI workflow and ignore .env.v2, *.stackdump, and .NET bin/obj. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+27
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+716
@@ -0,0 +1,716 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package arch defines architecture-specific information and support functions.
|
||||
package arch
|
||||
|
||||
import (
|
||||
"github.com/twitchyliquid64/golang-asm/obj"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/arm"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/arm64"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/mips"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/ppc64"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/riscv"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/s390x"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/wasm"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/x86"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Pseudo-registers whose names are the constant name without the leading R.
|
||||
const (
|
||||
RFP = -(iota + 1)
|
||||
RSB
|
||||
RSP
|
||||
RPC
|
||||
)
|
||||
|
||||
// Arch wraps the link architecture object with more architecture-specific information.
|
||||
type Arch struct {
|
||||
*obj.LinkArch
|
||||
// Map of instruction names to enumeration.
|
||||
Instructions map[string]obj.As
|
||||
// Map of register names to enumeration.
|
||||
Register map[string]int16
|
||||
// Table of register prefix names. These are things like R for R(0) and SPR for SPR(268).
|
||||
RegisterPrefix map[string]bool
|
||||
// RegisterNumber converts R(10) into arm.REG_R10.
|
||||
RegisterNumber func(string, int16) (int16, bool)
|
||||
// Instruction is a jump.
|
||||
IsJump func(word string) bool
|
||||
}
|
||||
|
||||
// nilRegisterNumber is the register number function for architectures
|
||||
// that do not accept the R(N) notation. It always returns failure.
|
||||
func nilRegisterNumber(name string, n int16) (int16, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Set configures the architecture specified by GOARCH and returns its representation.
|
||||
// It returns nil if GOARCH is not recognized.
|
||||
func Set(GOARCH string) *Arch {
|
||||
switch GOARCH {
|
||||
case "386":
|
||||
return archX86(&x86.Link386)
|
||||
case "amd64":
|
||||
return archX86(&x86.Linkamd64)
|
||||
case "arm":
|
||||
return archArm()
|
||||
case "arm64":
|
||||
return archArm64()
|
||||
case "mips":
|
||||
return archMips(&mips.Linkmips)
|
||||
case "mipsle":
|
||||
return archMips(&mips.Linkmipsle)
|
||||
case "mips64":
|
||||
return archMips64(&mips.Linkmips64)
|
||||
case "mips64le":
|
||||
return archMips64(&mips.Linkmips64le)
|
||||
case "ppc64":
|
||||
return archPPC64(&ppc64.Linkppc64)
|
||||
case "ppc64le":
|
||||
return archPPC64(&ppc64.Linkppc64le)
|
||||
case "riscv64":
|
||||
return archRISCV64()
|
||||
case "s390x":
|
||||
return archS390x()
|
||||
case "wasm":
|
||||
return archWasm()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func jumpX86(word string) bool {
|
||||
return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP") || word == "XBEGIN"
|
||||
}
|
||||
|
||||
func jumpRISCV(word string) bool {
|
||||
switch word {
|
||||
case "BEQ", "BEQZ", "BGE", "BGEU", "BGEZ", "BGT", "BGTU", "BGTZ", "BLE", "BLEU", "BLEZ",
|
||||
"BLT", "BLTU", "BLTZ", "BNE", "BNEZ", "CALL", "JAL", "JALR", "JMP":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func jumpWasm(word string) bool {
|
||||
return word == "JMP" || word == "CALL" || word == "Call" || word == "Br" || word == "BrIf"
|
||||
}
|
||||
|
||||
func archX86(linkArch *obj.LinkArch) *Arch {
|
||||
register := make(map[string]int16)
|
||||
// Create maps for easy lookup of instruction names etc.
|
||||
for i, s := range x86.Register {
|
||||
register[s] = int16(i + x86.REG_AL)
|
||||
}
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
register["PC"] = RPC
|
||||
// Register prefix not used on this architecture.
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range x86.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABaseAMD64
|
||||
}
|
||||
}
|
||||
// Annoying aliases.
|
||||
instructions["JA"] = x86.AJHI /* alternate */
|
||||
instructions["JAE"] = x86.AJCC /* alternate */
|
||||
instructions["JB"] = x86.AJCS /* alternate */
|
||||
instructions["JBE"] = x86.AJLS /* alternate */
|
||||
instructions["JC"] = x86.AJCS /* alternate */
|
||||
instructions["JCC"] = x86.AJCC /* carry clear (CF = 0) */
|
||||
instructions["JCS"] = x86.AJCS /* carry set (CF = 1) */
|
||||
instructions["JE"] = x86.AJEQ /* alternate */
|
||||
instructions["JEQ"] = x86.AJEQ /* equal (ZF = 1) */
|
||||
instructions["JG"] = x86.AJGT /* alternate */
|
||||
instructions["JGE"] = x86.AJGE /* greater than or equal (signed) (SF = OF) */
|
||||
instructions["JGT"] = x86.AJGT /* greater than (signed) (ZF = 0 && SF = OF) */
|
||||
instructions["JHI"] = x86.AJHI /* higher (unsigned) (CF = 0 && ZF = 0) */
|
||||
instructions["JHS"] = x86.AJCC /* alternate */
|
||||
instructions["JL"] = x86.AJLT /* alternate */
|
||||
instructions["JLE"] = x86.AJLE /* less than or equal (signed) (ZF = 1 || SF != OF) */
|
||||
instructions["JLO"] = x86.AJCS /* alternate */
|
||||
instructions["JLS"] = x86.AJLS /* lower or same (unsigned) (CF = 1 || ZF = 1) */
|
||||
instructions["JLT"] = x86.AJLT /* less than (signed) (SF != OF) */
|
||||
instructions["JMI"] = x86.AJMI /* negative (minus) (SF = 1) */
|
||||
instructions["JNA"] = x86.AJLS /* alternate */
|
||||
instructions["JNAE"] = x86.AJCS /* alternate */
|
||||
instructions["JNB"] = x86.AJCC /* alternate */
|
||||
instructions["JNBE"] = x86.AJHI /* alternate */
|
||||
instructions["JNC"] = x86.AJCC /* alternate */
|
||||
instructions["JNE"] = x86.AJNE /* not equal (ZF = 0) */
|
||||
instructions["JNG"] = x86.AJLE /* alternate */
|
||||
instructions["JNGE"] = x86.AJLT /* alternate */
|
||||
instructions["JNL"] = x86.AJGE /* alternate */
|
||||
instructions["JNLE"] = x86.AJGT /* alternate */
|
||||
instructions["JNO"] = x86.AJOC /* alternate */
|
||||
instructions["JNP"] = x86.AJPC /* alternate */
|
||||
instructions["JNS"] = x86.AJPL /* alternate */
|
||||
instructions["JNZ"] = x86.AJNE /* alternate */
|
||||
instructions["JO"] = x86.AJOS /* alternate */
|
||||
instructions["JOC"] = x86.AJOC /* overflow clear (OF = 0) */
|
||||
instructions["JOS"] = x86.AJOS /* overflow set (OF = 1) */
|
||||
instructions["JP"] = x86.AJPS /* alternate */
|
||||
instructions["JPC"] = x86.AJPC /* parity clear (PF = 0) */
|
||||
instructions["JPE"] = x86.AJPS /* alternate */
|
||||
instructions["JPL"] = x86.AJPL /* non-negative (plus) (SF = 0) */
|
||||
instructions["JPO"] = x86.AJPC /* alternate */
|
||||
instructions["JPS"] = x86.AJPS /* parity set (PF = 1) */
|
||||
instructions["JS"] = x86.AJMI /* alternate */
|
||||
instructions["JZ"] = x86.AJEQ /* alternate */
|
||||
instructions["MASKMOVDQU"] = x86.AMASKMOVOU
|
||||
instructions["MOVD"] = x86.AMOVQ
|
||||
instructions["MOVDQ2Q"] = x86.AMOVQ
|
||||
instructions["MOVNTDQ"] = x86.AMOVNTO
|
||||
instructions["MOVOA"] = x86.AMOVO
|
||||
instructions["PSLLDQ"] = x86.APSLLO
|
||||
instructions["PSRLDQ"] = x86.APSRLO
|
||||
instructions["PADDD"] = x86.APADDL
|
||||
|
||||
return &Arch{
|
||||
LinkArch: linkArch,
|
||||
Instructions: instructions,
|
||||
Register: register,
|
||||
RegisterPrefix: nil,
|
||||
RegisterNumber: nilRegisterNumber,
|
||||
IsJump: jumpX86,
|
||||
}
|
||||
}
|
||||
|
||||
func archArm() *Arch {
|
||||
register := make(map[string]int16)
|
||||
// Create maps for easy lookup of instruction names etc.
|
||||
// Note that there is no list of names as there is for x86.
|
||||
for i := arm.REG_R0; i < arm.REG_SPSR; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
// Avoid unintentionally clobbering g using R10.
|
||||
delete(register, "R10")
|
||||
register["g"] = arm.REG_R10
|
||||
for i := 0; i < 16; i++ {
|
||||
register[fmt.Sprintf("C%d", i)] = int16(i)
|
||||
}
|
||||
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
register["PC"] = RPC
|
||||
register["SP"] = RSP
|
||||
registerPrefix := map[string]bool{
|
||||
"F": true,
|
||||
"R": true,
|
||||
}
|
||||
|
||||
// special operands for DMB/DSB instructions
|
||||
register["MB_SY"] = arm.REG_MB_SY
|
||||
register["MB_ST"] = arm.REG_MB_ST
|
||||
register["MB_ISH"] = arm.REG_MB_ISH
|
||||
register["MB_ISHST"] = arm.REG_MB_ISHST
|
||||
register["MB_NSH"] = arm.REG_MB_NSH
|
||||
register["MB_NSHST"] = arm.REG_MB_NSHST
|
||||
register["MB_OSH"] = arm.REG_MB_OSH
|
||||
register["MB_OSHST"] = arm.REG_MB_OSHST
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range arm.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABaseARM
|
||||
}
|
||||
}
|
||||
// Annoying aliases.
|
||||
instructions["B"] = obj.AJMP
|
||||
instructions["BL"] = obj.ACALL
|
||||
// MCR differs from MRC by the way fields of the word are encoded.
|
||||
// (Details in arm.go). Here we add the instruction so parse will find
|
||||
// it, but give it an opcode number known only to us.
|
||||
instructions["MCR"] = aMCR
|
||||
|
||||
return &Arch{
|
||||
LinkArch: &arm.Linkarm,
|
||||
Instructions: instructions,
|
||||
Register: register,
|
||||
RegisterPrefix: registerPrefix,
|
||||
RegisterNumber: armRegisterNumber,
|
||||
IsJump: jumpArm,
|
||||
}
|
||||
}
|
||||
|
||||
func archArm64() *Arch {
|
||||
register := make(map[string]int16)
|
||||
// Create maps for easy lookup of instruction names etc.
|
||||
// Note that there is no list of names as there is for 386 and amd64.
|
||||
register[obj.Rconv(arm64.REGSP)] = int16(arm64.REGSP)
|
||||
for i := arm64.REG_R0; i <= arm64.REG_R31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
// Rename R18 to R18_PLATFORM to avoid accidental use.
|
||||
register["R18_PLATFORM"] = register["R18"]
|
||||
delete(register, "R18")
|
||||
for i := arm64.REG_F0; i <= arm64.REG_F31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := arm64.REG_V0; i <= arm64.REG_V31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
|
||||
// System registers.
|
||||
for i := 0; i < len(arm64.SystemReg); i++ {
|
||||
register[arm64.SystemReg[i].Name] = arm64.SystemReg[i].Reg
|
||||
}
|
||||
|
||||
register["LR"] = arm64.REGLINK
|
||||
register["DAIFSet"] = arm64.REG_DAIFSet
|
||||
register["DAIFClr"] = arm64.REG_DAIFClr
|
||||
register["PLDL1KEEP"] = arm64.REG_PLDL1KEEP
|
||||
register["PLDL1STRM"] = arm64.REG_PLDL1STRM
|
||||
register["PLDL2KEEP"] = arm64.REG_PLDL2KEEP
|
||||
register["PLDL2STRM"] = arm64.REG_PLDL2STRM
|
||||
register["PLDL3KEEP"] = arm64.REG_PLDL3KEEP
|
||||
register["PLDL3STRM"] = arm64.REG_PLDL3STRM
|
||||
register["PLIL1KEEP"] = arm64.REG_PLIL1KEEP
|
||||
register["PLIL1STRM"] = arm64.REG_PLIL1STRM
|
||||
register["PLIL2KEEP"] = arm64.REG_PLIL2KEEP
|
||||
register["PLIL2STRM"] = arm64.REG_PLIL2STRM
|
||||
register["PLIL3KEEP"] = arm64.REG_PLIL3KEEP
|
||||
register["PLIL3STRM"] = arm64.REG_PLIL3STRM
|
||||
register["PSTL1KEEP"] = arm64.REG_PSTL1KEEP
|
||||
register["PSTL1STRM"] = arm64.REG_PSTL1STRM
|
||||
register["PSTL2KEEP"] = arm64.REG_PSTL2KEEP
|
||||
register["PSTL2STRM"] = arm64.REG_PSTL2STRM
|
||||
register["PSTL3KEEP"] = arm64.REG_PSTL3KEEP
|
||||
register["PSTL3STRM"] = arm64.REG_PSTL3STRM
|
||||
|
||||
// Conditional operators, like EQ, NE, etc.
|
||||
register["EQ"] = arm64.COND_EQ
|
||||
register["NE"] = arm64.COND_NE
|
||||
register["HS"] = arm64.COND_HS
|
||||
register["CS"] = arm64.COND_HS
|
||||
register["LO"] = arm64.COND_LO
|
||||
register["CC"] = arm64.COND_LO
|
||||
register["MI"] = arm64.COND_MI
|
||||
register["PL"] = arm64.COND_PL
|
||||
register["VS"] = arm64.COND_VS
|
||||
register["VC"] = arm64.COND_VC
|
||||
register["HI"] = arm64.COND_HI
|
||||
register["LS"] = arm64.COND_LS
|
||||
register["GE"] = arm64.COND_GE
|
||||
register["LT"] = arm64.COND_LT
|
||||
register["GT"] = arm64.COND_GT
|
||||
register["LE"] = arm64.COND_LE
|
||||
register["AL"] = arm64.COND_AL
|
||||
register["NV"] = arm64.COND_NV
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
register["PC"] = RPC
|
||||
register["SP"] = RSP
|
||||
// Avoid unintentionally clobbering g using R28.
|
||||
delete(register, "R28")
|
||||
register["g"] = arm64.REG_R28
|
||||
registerPrefix := map[string]bool{
|
||||
"F": true,
|
||||
"R": true,
|
||||
"V": true,
|
||||
}
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range arm64.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABaseARM64
|
||||
}
|
||||
}
|
||||
// Annoying aliases.
|
||||
instructions["B"] = arm64.AB
|
||||
instructions["BL"] = arm64.ABL
|
||||
|
||||
return &Arch{
|
||||
LinkArch: &arm64.Linkarm64,
|
||||
Instructions: instructions,
|
||||
Register: register,
|
||||
RegisterPrefix: registerPrefix,
|
||||
RegisterNumber: arm64RegisterNumber,
|
||||
IsJump: jumpArm64,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func archPPC64(linkArch *obj.LinkArch) *Arch {
|
||||
register := make(map[string]int16)
|
||||
// Create maps for easy lookup of instruction names etc.
|
||||
// Note that there is no list of names as there is for x86.
|
||||
for i := ppc64.REG_R0; i <= ppc64.REG_R31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := ppc64.REG_F0; i <= ppc64.REG_F31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := ppc64.REG_V0; i <= ppc64.REG_V31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := ppc64.REG_VS0; i <= ppc64.REG_VS63; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := ppc64.REG_CR0; i <= ppc64.REG_CR7; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := ppc64.REG_MSR; i <= ppc64.REG_CR; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
register["CR"] = ppc64.REG_CR
|
||||
register["XER"] = ppc64.REG_XER
|
||||
register["LR"] = ppc64.REG_LR
|
||||
register["CTR"] = ppc64.REG_CTR
|
||||
register["FPSCR"] = ppc64.REG_FPSCR
|
||||
register["MSR"] = ppc64.REG_MSR
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
register["PC"] = RPC
|
||||
// Avoid unintentionally clobbering g using R30.
|
||||
delete(register, "R30")
|
||||
register["g"] = ppc64.REG_R30
|
||||
registerPrefix := map[string]bool{
|
||||
"CR": true,
|
||||
"F": true,
|
||||
"R": true,
|
||||
"SPR": true,
|
||||
}
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range ppc64.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABasePPC64
|
||||
}
|
||||
}
|
||||
// Annoying aliases.
|
||||
instructions["BR"] = ppc64.ABR
|
||||
instructions["BL"] = ppc64.ABL
|
||||
|
||||
return &Arch{
|
||||
LinkArch: linkArch,
|
||||
Instructions: instructions,
|
||||
Register: register,
|
||||
RegisterPrefix: registerPrefix,
|
||||
RegisterNumber: ppc64RegisterNumber,
|
||||
IsJump: jumpPPC64,
|
||||
}
|
||||
}
|
||||
|
||||
func archMips(linkArch *obj.LinkArch) *Arch {
|
||||
register := make(map[string]int16)
|
||||
// Create maps for easy lookup of instruction names etc.
|
||||
// Note that there is no list of names as there is for x86.
|
||||
for i := mips.REG_R0; i <= mips.REG_R31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
|
||||
for i := mips.REG_F0; i <= mips.REG_F31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := mips.REG_M0; i <= mips.REG_M31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
register["HI"] = mips.REG_HI
|
||||
register["LO"] = mips.REG_LO
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
register["PC"] = RPC
|
||||
// Avoid unintentionally clobbering g using R30.
|
||||
delete(register, "R30")
|
||||
register["g"] = mips.REG_R30
|
||||
|
||||
registerPrefix := map[string]bool{
|
||||
"F": true,
|
||||
"FCR": true,
|
||||
"M": true,
|
||||
"R": true,
|
||||
}
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range mips.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABaseMIPS
|
||||
}
|
||||
}
|
||||
// Annoying alias.
|
||||
instructions["JAL"] = mips.AJAL
|
||||
|
||||
return &Arch{
|
||||
LinkArch: linkArch,
|
||||
Instructions: instructions,
|
||||
Register: register,
|
||||
RegisterPrefix: registerPrefix,
|
||||
RegisterNumber: mipsRegisterNumber,
|
||||
IsJump: jumpMIPS,
|
||||
}
|
||||
}
|
||||
|
||||
func archMips64(linkArch *obj.LinkArch) *Arch {
|
||||
register := make(map[string]int16)
|
||||
// Create maps for easy lookup of instruction names etc.
|
||||
// Note that there is no list of names as there is for x86.
|
||||
for i := mips.REG_R0; i <= mips.REG_R31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := mips.REG_F0; i <= mips.REG_F31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := mips.REG_M0; i <= mips.REG_M31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := mips.REG_W0; i <= mips.REG_W31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
register["HI"] = mips.REG_HI
|
||||
register["LO"] = mips.REG_LO
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
register["PC"] = RPC
|
||||
// Avoid unintentionally clobbering g using R30.
|
||||
delete(register, "R30")
|
||||
register["g"] = mips.REG_R30
|
||||
// Avoid unintentionally clobbering RSB using R28.
|
||||
delete(register, "R28")
|
||||
register["RSB"] = mips.REG_R28
|
||||
registerPrefix := map[string]bool{
|
||||
"F": true,
|
||||
"FCR": true,
|
||||
"M": true,
|
||||
"R": true,
|
||||
"W": true,
|
||||
}
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range mips.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABaseMIPS
|
||||
}
|
||||
}
|
||||
// Annoying alias.
|
||||
instructions["JAL"] = mips.AJAL
|
||||
|
||||
return &Arch{
|
||||
LinkArch: linkArch,
|
||||
Instructions: instructions,
|
||||
Register: register,
|
||||
RegisterPrefix: registerPrefix,
|
||||
RegisterNumber: mipsRegisterNumber,
|
||||
IsJump: jumpMIPS,
|
||||
}
|
||||
}
|
||||
|
||||
func archRISCV64() *Arch {
|
||||
register := make(map[string]int16)
|
||||
|
||||
// Standard register names.
|
||||
for i := riscv.REG_X0; i <= riscv.REG_X31; i++ {
|
||||
name := fmt.Sprintf("X%d", i-riscv.REG_X0)
|
||||
register[name] = int16(i)
|
||||
}
|
||||
for i := riscv.REG_F0; i <= riscv.REG_F31; i++ {
|
||||
name := fmt.Sprintf("F%d", i-riscv.REG_F0)
|
||||
register[name] = int16(i)
|
||||
}
|
||||
|
||||
// General registers with ABI names.
|
||||
register["ZERO"] = riscv.REG_ZERO
|
||||
register["RA"] = riscv.REG_RA
|
||||
register["SP"] = riscv.REG_SP
|
||||
register["GP"] = riscv.REG_GP
|
||||
register["TP"] = riscv.REG_TP
|
||||
register["T0"] = riscv.REG_T0
|
||||
register["T1"] = riscv.REG_T1
|
||||
register["T2"] = riscv.REG_T2
|
||||
register["S0"] = riscv.REG_S0
|
||||
register["S1"] = riscv.REG_S1
|
||||
register["A0"] = riscv.REG_A0
|
||||
register["A1"] = riscv.REG_A1
|
||||
register["A2"] = riscv.REG_A2
|
||||
register["A3"] = riscv.REG_A3
|
||||
register["A4"] = riscv.REG_A4
|
||||
register["A5"] = riscv.REG_A5
|
||||
register["A6"] = riscv.REG_A6
|
||||
register["A7"] = riscv.REG_A7
|
||||
register["S2"] = riscv.REG_S2
|
||||
register["S3"] = riscv.REG_S3
|
||||
register["S4"] = riscv.REG_S4
|
||||
register["S5"] = riscv.REG_S5
|
||||
register["S6"] = riscv.REG_S6
|
||||
register["S7"] = riscv.REG_S7
|
||||
register["S8"] = riscv.REG_S8
|
||||
register["S9"] = riscv.REG_S9
|
||||
register["S10"] = riscv.REG_S10
|
||||
register["S11"] = riscv.REG_S11
|
||||
register["T3"] = riscv.REG_T3
|
||||
register["T4"] = riscv.REG_T4
|
||||
register["T5"] = riscv.REG_T5
|
||||
register["T6"] = riscv.REG_T6
|
||||
|
||||
// Go runtime register names.
|
||||
register["g"] = riscv.REG_G
|
||||
register["CTXT"] = riscv.REG_CTXT
|
||||
register["TMP"] = riscv.REG_TMP
|
||||
|
||||
// ABI names for floating point register.
|
||||
register["FT0"] = riscv.REG_FT0
|
||||
register["FT1"] = riscv.REG_FT1
|
||||
register["FT2"] = riscv.REG_FT2
|
||||
register["FT3"] = riscv.REG_FT3
|
||||
register["FT4"] = riscv.REG_FT4
|
||||
register["FT5"] = riscv.REG_FT5
|
||||
register["FT6"] = riscv.REG_FT6
|
||||
register["FT7"] = riscv.REG_FT7
|
||||
register["FS0"] = riscv.REG_FS0
|
||||
register["FS1"] = riscv.REG_FS1
|
||||
register["FA0"] = riscv.REG_FA0
|
||||
register["FA1"] = riscv.REG_FA1
|
||||
register["FA2"] = riscv.REG_FA2
|
||||
register["FA3"] = riscv.REG_FA3
|
||||
register["FA4"] = riscv.REG_FA4
|
||||
register["FA5"] = riscv.REG_FA5
|
||||
register["FA6"] = riscv.REG_FA6
|
||||
register["FA7"] = riscv.REG_FA7
|
||||
register["FS2"] = riscv.REG_FS2
|
||||
register["FS3"] = riscv.REG_FS3
|
||||
register["FS4"] = riscv.REG_FS4
|
||||
register["FS5"] = riscv.REG_FS5
|
||||
register["FS6"] = riscv.REG_FS6
|
||||
register["FS7"] = riscv.REG_FS7
|
||||
register["FS8"] = riscv.REG_FS8
|
||||
register["FS9"] = riscv.REG_FS9
|
||||
register["FS10"] = riscv.REG_FS10
|
||||
register["FS11"] = riscv.REG_FS11
|
||||
register["FT8"] = riscv.REG_FT8
|
||||
register["FT9"] = riscv.REG_FT9
|
||||
register["FT10"] = riscv.REG_FT10
|
||||
register["FT11"] = riscv.REG_FT11
|
||||
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
register["PC"] = RPC
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range riscv.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABaseRISCV
|
||||
}
|
||||
}
|
||||
|
||||
return &Arch{
|
||||
LinkArch: &riscv.LinkRISCV64,
|
||||
Instructions: instructions,
|
||||
Register: register,
|
||||
RegisterPrefix: nil,
|
||||
RegisterNumber: nilRegisterNumber,
|
||||
IsJump: jumpRISCV,
|
||||
}
|
||||
}
|
||||
|
||||
func archS390x() *Arch {
|
||||
register := make(map[string]int16)
|
||||
// Create maps for easy lookup of instruction names etc.
|
||||
// Note that there is no list of names as there is for x86.
|
||||
for i := s390x.REG_R0; i <= s390x.REG_R15; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := s390x.REG_F0; i <= s390x.REG_F15; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := s390x.REG_V0; i <= s390x.REG_V31; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
for i := s390x.REG_AR0; i <= s390x.REG_AR15; i++ {
|
||||
register[obj.Rconv(i)] = int16(i)
|
||||
}
|
||||
register["LR"] = s390x.REG_LR
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
register["PC"] = RPC
|
||||
// Avoid unintentionally clobbering g using R13.
|
||||
delete(register, "R13")
|
||||
register["g"] = s390x.REG_R13
|
||||
registerPrefix := map[string]bool{
|
||||
"AR": true,
|
||||
"F": true,
|
||||
"R": true,
|
||||
}
|
||||
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range s390x.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABaseS390X
|
||||
}
|
||||
}
|
||||
// Annoying aliases.
|
||||
instructions["BR"] = s390x.ABR
|
||||
instructions["BL"] = s390x.ABL
|
||||
|
||||
return &Arch{
|
||||
LinkArch: &s390x.Links390x,
|
||||
Instructions: instructions,
|
||||
Register: register,
|
||||
RegisterPrefix: registerPrefix,
|
||||
RegisterNumber: s390xRegisterNumber,
|
||||
IsJump: jumpS390x,
|
||||
}
|
||||
}
|
||||
|
||||
func archWasm() *Arch {
|
||||
instructions := make(map[string]obj.As)
|
||||
for i, s := range obj.Anames {
|
||||
instructions[s] = obj.As(i)
|
||||
}
|
||||
for i, s := range wasm.Anames {
|
||||
if obj.As(i) >= obj.A_ARCHSPECIFIC {
|
||||
instructions[s] = obj.As(i) + obj.ABaseWasm
|
||||
}
|
||||
}
|
||||
|
||||
return &Arch{
|
||||
LinkArch: &wasm.Linkwasm,
|
||||
Instructions: instructions,
|
||||
Register: wasm.Register,
|
||||
RegisterPrefix: nil,
|
||||
RegisterNumber: nilRegisterNumber,
|
||||
IsJump: jumpWasm,
|
||||
}
|
||||
}
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file encapsulates some of the odd characteristics of the ARM
|
||||
// instruction set, to minimize its interaction with the core of the
|
||||
// assembler.
|
||||
|
||||
package arch
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/twitchyliquid64/golang-asm/obj"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/arm"
|
||||
)
|
||||
|
||||
var armLS = map[string]uint8{
|
||||
"U": arm.C_UBIT,
|
||||
"S": arm.C_SBIT,
|
||||
"W": arm.C_WBIT,
|
||||
"P": arm.C_PBIT,
|
||||
"PW": arm.C_WBIT | arm.C_PBIT,
|
||||
"WP": arm.C_WBIT | arm.C_PBIT,
|
||||
}
|
||||
|
||||
var armSCOND = map[string]uint8{
|
||||
"EQ": arm.C_SCOND_EQ,
|
||||
"NE": arm.C_SCOND_NE,
|
||||
"CS": arm.C_SCOND_HS,
|
||||
"HS": arm.C_SCOND_HS,
|
||||
"CC": arm.C_SCOND_LO,
|
||||
"LO": arm.C_SCOND_LO,
|
||||
"MI": arm.C_SCOND_MI,
|
||||
"PL": arm.C_SCOND_PL,
|
||||
"VS": arm.C_SCOND_VS,
|
||||
"VC": arm.C_SCOND_VC,
|
||||
"HI": arm.C_SCOND_HI,
|
||||
"LS": arm.C_SCOND_LS,
|
||||
"GE": arm.C_SCOND_GE,
|
||||
"LT": arm.C_SCOND_LT,
|
||||
"GT": arm.C_SCOND_GT,
|
||||
"LE": arm.C_SCOND_LE,
|
||||
"AL": arm.C_SCOND_NONE,
|
||||
"U": arm.C_UBIT,
|
||||
"S": arm.C_SBIT,
|
||||
"W": arm.C_WBIT,
|
||||
"P": arm.C_PBIT,
|
||||
"PW": arm.C_WBIT | arm.C_PBIT,
|
||||
"WP": arm.C_WBIT | arm.C_PBIT,
|
||||
"F": arm.C_FBIT,
|
||||
"IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT,
|
||||
"IAW": arm.C_WBIT | arm.C_UBIT,
|
||||
"DBW": arm.C_WBIT | arm.C_PBIT,
|
||||
"DAW": arm.C_WBIT,
|
||||
"IB": arm.C_PBIT | arm.C_UBIT,
|
||||
"IA": arm.C_UBIT,
|
||||
"DB": arm.C_PBIT,
|
||||
"DA": 0,
|
||||
}
|
||||
|
||||
var armJump = map[string]bool{
|
||||
"B": true,
|
||||
"BL": true,
|
||||
"BX": true,
|
||||
"BEQ": true,
|
||||
"BNE": true,
|
||||
"BCS": true,
|
||||
"BHS": true,
|
||||
"BCC": true,
|
||||
"BLO": true,
|
||||
"BMI": true,
|
||||
"BPL": true,
|
||||
"BVS": true,
|
||||
"BVC": true,
|
||||
"BHI": true,
|
||||
"BLS": true,
|
||||
"BGE": true,
|
||||
"BLT": true,
|
||||
"BGT": true,
|
||||
"BLE": true,
|
||||
"CALL": true,
|
||||
"JMP": true,
|
||||
}
|
||||
|
||||
func jumpArm(word string) bool {
|
||||
return armJump[word]
|
||||
}
|
||||
|
||||
// IsARMCMP reports whether the op (as defined by an arm.A* constant) is
|
||||
// one of the comparison instructions that require special handling.
|
||||
func IsARMCMP(op obj.As) bool {
|
||||
switch op {
|
||||
case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
|
||||
// one of the STREX-like instructions that require special handling.
|
||||
func IsARMSTREX(op obj.As) bool {
|
||||
switch op {
|
||||
case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MCR is not defined by the obj/arm; instead we define it privately here.
|
||||
// It is encoded as an MRC with a bit inside the instruction word,
|
||||
// passed to arch.ARMMRCOffset.
|
||||
const aMCR = arm.ALAST + 1
|
||||
|
||||
// IsARMMRC reports whether the op (as defined by an arm.A* constant) is
|
||||
// MRC or MCR
|
||||
func IsARMMRC(op obj.As) bool {
|
||||
switch op {
|
||||
case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsARMBFX reports whether the op (as defined by an arm.A* constant) is one the
|
||||
// BFX-like instructions which are in the form of "op $width, $LSB, (Reg,) Reg".
|
||||
func IsARMBFX(op obj.As) bool {
|
||||
switch op {
|
||||
case arm.ABFX, arm.ABFXU, arm.ABFC, arm.ABFI:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsARMFloatCmp reports whether the op is a floating comparison instruction.
|
||||
func IsARMFloatCmp(op obj.As) bool {
|
||||
switch op {
|
||||
case arm.ACMPF, arm.ACMPD:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
|
||||
// The difference between MRC and MCR is represented by a bit high in the word, not
|
||||
// in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
|
||||
// we return the opcode for MRC so that asm doesn't need to import obj/arm.
|
||||
func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) {
|
||||
op1 := int64(0)
|
||||
if op == arm.AMRC {
|
||||
op1 = 1
|
||||
}
|
||||
bits, ok := ParseARMCondition(cond)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
offset = (0xe << 24) | // opcode
|
||||
(op1 << 20) | // MCR/MRC
|
||||
((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
|
||||
((x0 & 15) << 8) | //coprocessor number
|
||||
((x1 & 7) << 21) | // coprocessor operation
|
||||
((x2 & 15) << 12) | // ARM register
|
||||
((x3 & 15) << 16) | // Crn
|
||||
((x4 & 15) << 0) | // Crm
|
||||
((x5 & 7) << 5) | // coprocessor information
|
||||
(1 << 4) /* must be set */
|
||||
return offset, arm.AMRC, true
|
||||
}
|
||||
|
||||
// IsARMMULA reports whether the op (as defined by an arm.A* constant) is
|
||||
// MULA, MULS, MMULA, MMULS, MULABB, MULAWB or MULAWT, the 4-operand instructions.
|
||||
func IsARMMULA(op obj.As) bool {
|
||||
switch op {
|
||||
case arm.AMULA, arm.AMULS, arm.AMMULA, arm.AMMULS, arm.AMULABB, arm.AMULAWB, arm.AMULAWT:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var bcode = []obj.As{
|
||||
arm.ABEQ,
|
||||
arm.ABNE,
|
||||
arm.ABCS,
|
||||
arm.ABCC,
|
||||
arm.ABMI,
|
||||
arm.ABPL,
|
||||
arm.ABVS,
|
||||
arm.ABVC,
|
||||
arm.ABHI,
|
||||
arm.ABLS,
|
||||
arm.ABGE,
|
||||
arm.ABLT,
|
||||
arm.ABGT,
|
||||
arm.ABLE,
|
||||
arm.AB,
|
||||
obj.ANOP,
|
||||
}
|
||||
|
||||
// ARMConditionCodes handles the special condition code situation for the ARM.
|
||||
// It returns a boolean to indicate success; failure means cond was unrecognized.
|
||||
func ARMConditionCodes(prog *obj.Prog, cond string) bool {
|
||||
if cond == "" {
|
||||
return true
|
||||
}
|
||||
bits, ok := ParseARMCondition(cond)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
/* hack to make B.NE etc. work: turn it into the corresponding conditional */
|
||||
if prog.As == arm.AB {
|
||||
prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf]
|
||||
bits = (bits &^ 0xf) | arm.C_SCOND_NONE
|
||||
}
|
||||
prog.Scond = bits
|
||||
return true
|
||||
}
|
||||
|
||||
// ParseARMCondition parses the conditions attached to an ARM instruction.
|
||||
// The input is a single string consisting of period-separated condition
|
||||
// codes, such as ".P.W". An initial period is ignored.
|
||||
func ParseARMCondition(cond string) (uint8, bool) {
|
||||
return parseARMCondition(cond, armLS, armSCOND)
|
||||
}
|
||||
|
||||
func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
|
||||
cond = strings.TrimPrefix(cond, ".")
|
||||
if cond == "" {
|
||||
return arm.C_SCOND_NONE, true
|
||||
}
|
||||
names := strings.Split(cond, ".")
|
||||
bits := uint8(0)
|
||||
for _, name := range names {
|
||||
if b, present := ls[name]; present {
|
||||
bits |= b
|
||||
continue
|
||||
}
|
||||
if b, present := scond[name]; present {
|
||||
bits = (bits &^ arm.C_SCOND) | b
|
||||
continue
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
return bits, true
|
||||
}
|
||||
|
||||
func armRegisterNumber(name string, n int16) (int16, bool) {
|
||||
if n < 0 || 15 < n {
|
||||
return 0, false
|
||||
}
|
||||
switch name {
|
||||
case "R":
|
||||
return arm.REG_R0 + n, true
|
||||
case "F":
|
||||
return arm.REG_F0 + n, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file encapsulates some of the odd characteristics of the ARM64
|
||||
// instruction set, to minimize its interaction with the core of the
|
||||
// assembler.
|
||||
|
||||
package arch
|
||||
|
||||
import (
|
||||
"github.com/twitchyliquid64/golang-asm/obj"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/arm64"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var arm64LS = map[string]uint8{
|
||||
"P": arm64.C_XPOST,
|
||||
"W": arm64.C_XPRE,
|
||||
}
|
||||
|
||||
var arm64Jump = map[string]bool{
|
||||
"B": true,
|
||||
"BL": true,
|
||||
"BEQ": true,
|
||||
"BNE": true,
|
||||
"BCS": true,
|
||||
"BHS": true,
|
||||
"BCC": true,
|
||||
"BLO": true,
|
||||
"BMI": true,
|
||||
"BPL": true,
|
||||
"BVS": true,
|
||||
"BVC": true,
|
||||
"BHI": true,
|
||||
"BLS": true,
|
||||
"BGE": true,
|
||||
"BLT": true,
|
||||
"BGT": true,
|
||||
"BLE": true,
|
||||
"CALL": true,
|
||||
"CBZ": true,
|
||||
"CBZW": true,
|
||||
"CBNZ": true,
|
||||
"CBNZW": true,
|
||||
"JMP": true,
|
||||
"TBNZ": true,
|
||||
"TBZ": true,
|
||||
}
|
||||
|
||||
func jumpArm64(word string) bool {
|
||||
return arm64Jump[word]
|
||||
}
|
||||
|
||||
// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is
|
||||
// one of the comparison instructions that require special handling.
|
||||
func IsARM64CMP(op obj.As) bool {
|
||||
switch op {
|
||||
case arm64.ACMN, arm64.ACMP, arm64.ATST,
|
||||
arm64.ACMNW, arm64.ACMPW, arm64.ATSTW,
|
||||
arm64.AFCMPS, arm64.AFCMPD,
|
||||
arm64.AFCMPES, arm64.AFCMPED:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsARM64STLXR reports whether the op (as defined by an arm64.A*
|
||||
// constant) is one of the STLXR-like instructions that require special
|
||||
// handling.
|
||||
func IsARM64STLXR(op obj.As) bool {
|
||||
switch op {
|
||||
case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR,
|
||||
arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR,
|
||||
arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
|
||||
return true
|
||||
}
|
||||
// atomic instructions
|
||||
if arm64.IsAtomicInstruction(op) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ARM64Suffix handles the special suffix for the ARM64.
|
||||
// It returns a boolean to indicate success; failure means
|
||||
// cond was unrecognized.
|
||||
func ARM64Suffix(prog *obj.Prog, cond string) bool {
|
||||
if cond == "" {
|
||||
return true
|
||||
}
|
||||
bits, ok := parseARM64Suffix(cond)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
prog.Scond = bits
|
||||
return true
|
||||
}
|
||||
|
||||
// parseARM64Suffix parses the suffix attached to an ARM64 instruction.
|
||||
// The input is a single string consisting of period-separated condition
|
||||
// codes, such as ".P.W". An initial period is ignored.
|
||||
func parseARM64Suffix(cond string) (uint8, bool) {
|
||||
if cond == "" {
|
||||
return 0, true
|
||||
}
|
||||
return parseARMCondition(cond, arm64LS, nil)
|
||||
}
|
||||
|
||||
func arm64RegisterNumber(name string, n int16) (int16, bool) {
|
||||
switch name {
|
||||
case "F":
|
||||
if 0 <= n && n <= 31 {
|
||||
return arm64.REG_F0 + n, true
|
||||
}
|
||||
case "R":
|
||||
if 0 <= n && n <= 30 { // not 31
|
||||
return arm64.REG_R0 + n, true
|
||||
}
|
||||
case "V":
|
||||
if 0 <= n && n <= 31 {
|
||||
return arm64.REG_V0 + n, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// IsARM64TBL reports whether the op (as defined by an arm64.A*
|
||||
// constant) is one of the table lookup instructions that require special
|
||||
// handling.
|
||||
func IsARM64TBL(op obj.As) bool {
|
||||
return op == arm64.AVTBL
|
||||
}
|
||||
|
||||
// ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
|
||||
func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
|
||||
Rnum := (reg & 31) + int16(num<<5)
|
||||
if isAmount {
|
||||
if num < 0 || num > 7 {
|
||||
return errors.New("index shift amount is out of range")
|
||||
}
|
||||
}
|
||||
switch ext {
|
||||
case "UXTB":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
if a.Type == obj.TYPE_MEM {
|
||||
return errors.New("invalid shift for the register offset addressing mode")
|
||||
}
|
||||
a.Reg = arm64.REG_UXTB + Rnum
|
||||
case "UXTH":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
if a.Type == obj.TYPE_MEM {
|
||||
return errors.New("invalid shift for the register offset addressing mode")
|
||||
}
|
||||
a.Reg = arm64.REG_UXTH + Rnum
|
||||
case "UXTW":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
// effective address of memory is a base register value and an offset register value.
|
||||
if a.Type == obj.TYPE_MEM {
|
||||
a.Index = arm64.REG_UXTW + Rnum
|
||||
} else {
|
||||
a.Reg = arm64.REG_UXTW + Rnum
|
||||
}
|
||||
case "UXTX":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
if a.Type == obj.TYPE_MEM {
|
||||
return errors.New("invalid shift for the register offset addressing mode")
|
||||
}
|
||||
a.Reg = arm64.REG_UXTX + Rnum
|
||||
case "SXTB":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_SXTB + Rnum
|
||||
case "SXTH":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
if a.Type == obj.TYPE_MEM {
|
||||
return errors.New("invalid shift for the register offset addressing mode")
|
||||
}
|
||||
a.Reg = arm64.REG_SXTH + Rnum
|
||||
case "SXTW":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
if a.Type == obj.TYPE_MEM {
|
||||
a.Index = arm64.REG_SXTW + Rnum
|
||||
} else {
|
||||
a.Reg = arm64.REG_SXTW + Rnum
|
||||
}
|
||||
case "SXTX":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
if a.Type == obj.TYPE_MEM {
|
||||
a.Index = arm64.REG_SXTX + Rnum
|
||||
} else {
|
||||
a.Reg = arm64.REG_SXTX + Rnum
|
||||
}
|
||||
case "LSL":
|
||||
if !isAmount {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Index = arm64.REG_LSL + Rnum
|
||||
case "B8":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5)
|
||||
case "B16":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5)
|
||||
case "H4":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5)
|
||||
case "H8":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5)
|
||||
case "S2":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5)
|
||||
case "S4":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5)
|
||||
case "D1":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5)
|
||||
case "D2":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5)
|
||||
case "Q1":
|
||||
if isIndex {
|
||||
return errors.New("invalid register extension")
|
||||
}
|
||||
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5)
|
||||
case "B":
|
||||
if !isIndex {
|
||||
return nil
|
||||
}
|
||||
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5)
|
||||
a.Index = num
|
||||
case "H":
|
||||
if !isIndex {
|
||||
return nil
|
||||
}
|
||||
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5)
|
||||
a.Index = num
|
||||
case "S":
|
||||
if !isIndex {
|
||||
return nil
|
||||
}
|
||||
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5)
|
||||
a.Index = num
|
||||
case "D":
|
||||
if !isIndex {
|
||||
return nil
|
||||
}
|
||||
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5)
|
||||
a.Index = num
|
||||
default:
|
||||
return errors.New("unsupported register extension type: " + ext)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ARM64RegisterArrangement parses an ARM64 vector register arrangement.
|
||||
func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) {
|
||||
var curQ, curSize uint16
|
||||
if name[0] != 'V' {
|
||||
return 0, errors.New("expect V0 through V31; found: " + name)
|
||||
}
|
||||
if reg < 0 {
|
||||
return 0, errors.New("invalid register number: " + name)
|
||||
}
|
||||
switch arng {
|
||||
case "B8":
|
||||
curSize = 0
|
||||
curQ = 0
|
||||
case "B16":
|
||||
curSize = 0
|
||||
curQ = 1
|
||||
case "H4":
|
||||
curSize = 1
|
||||
curQ = 0
|
||||
case "H8":
|
||||
curSize = 1
|
||||
curQ = 1
|
||||
case "S2":
|
||||
curSize = 2
|
||||
curQ = 0
|
||||
case "S4":
|
||||
curSize = 2
|
||||
curQ = 1
|
||||
case "D1":
|
||||
curSize = 3
|
||||
curQ = 0
|
||||
case "D2":
|
||||
curSize = 3
|
||||
curQ = 1
|
||||
default:
|
||||
return 0, errors.New("invalid arrangement in ARM64 register list")
|
||||
}
|
||||
return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil
|
||||
}
|
||||
|
||||
// ARM64RegisterListOffset generates offset encoding according to AArch64 specification.
|
||||
func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) {
|
||||
offset := int64(firstReg)
|
||||
switch regCnt {
|
||||
case 1:
|
||||
offset |= 0x7 << 12
|
||||
case 2:
|
||||
offset |= 0xa << 12
|
||||
case 3:
|
||||
offset |= 0x6 << 12
|
||||
case 4:
|
||||
offset |= 0x2 << 12
|
||||
default:
|
||||
return 0, errors.New("invalid register numbers in ARM64 register list")
|
||||
}
|
||||
offset |= arrangement
|
||||
// arm64 uses the 60th bit to differentiate from other archs
|
||||
// For more details, refer to: obj/arm64/list7.go
|
||||
offset |= 1 << 60
|
||||
return offset, nil
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file encapsulates some of the odd characteristics of the
|
||||
// MIPS (MIPS64) instruction set, to minimize its interaction
|
||||
// with the core of the assembler.
|
||||
|
||||
package arch
|
||||
|
||||
import (
|
||||
"github.com/twitchyliquid64/golang-asm/obj"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/mips"
|
||||
)
|
||||
|
||||
func jumpMIPS(word string) bool {
|
||||
switch word {
|
||||
case "BEQ", "BFPF", "BFPT", "BGEZ", "BGEZAL", "BGTZ", "BLEZ", "BLTZ", "BLTZAL", "BNE", "JMP", "JAL", "CALL":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsMIPSCMP reports whether the op (as defined by an mips.A* constant) is
|
||||
// one of the CMP instructions that require special handling.
|
||||
func IsMIPSCMP(op obj.As) bool {
|
||||
switch op {
|
||||
case mips.ACMPEQF, mips.ACMPEQD, mips.ACMPGEF, mips.ACMPGED,
|
||||
mips.ACMPGTF, mips.ACMPGTD:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsMIPSMUL reports whether the op (as defined by an mips.A* constant) is
|
||||
// one of the MUL/DIV/REM/MADD/MSUB instructions that require special handling.
|
||||
func IsMIPSMUL(op obj.As) bool {
|
||||
switch op {
|
||||
case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU,
|
||||
mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU,
|
||||
mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU,
|
||||
mips.AMADD, mips.AMSUB:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func mipsRegisterNumber(name string, n int16) (int16, bool) {
|
||||
switch name {
|
||||
case "F":
|
||||
if 0 <= n && n <= 31 {
|
||||
return mips.REG_F0 + n, true
|
||||
}
|
||||
case "FCR":
|
||||
if 0 <= n && n <= 31 {
|
||||
return mips.REG_FCR0 + n, true
|
||||
}
|
||||
case "M":
|
||||
if 0 <= n && n <= 31 {
|
||||
return mips.REG_M0 + n, true
|
||||
}
|
||||
case "R":
|
||||
if 0 <= n && n <= 31 {
|
||||
return mips.REG_R0 + n, true
|
||||
}
|
||||
case "W":
|
||||
if 0 <= n && n <= 31 {
|
||||
return mips.REG_W0 + n, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file encapsulates some of the odd characteristics of the
|
||||
// 64-bit PowerPC (PPC64) instruction set, to minimize its interaction
|
||||
// with the core of the assembler.
|
||||
|
||||
package arch
|
||||
|
||||
import (
|
||||
"github.com/twitchyliquid64/golang-asm/obj"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/ppc64"
|
||||
)
|
||||
|
||||
func jumpPPC64(word string) bool {
|
||||
switch word {
|
||||
case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "CALL", "JMP":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsPPC64RLD reports whether the op (as defined by an ppc64.A* constant) is
|
||||
// one of the RLD-like instructions that require special handling.
|
||||
// The FMADD-like instructions behave similarly.
|
||||
func IsPPC64RLD(op obj.As) bool {
|
||||
switch op {
|
||||
case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC,
|
||||
ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC,
|
||||
ppc64.ARLWMI, ppc64.ARLWMICC, ppc64.ARLWNM, ppc64.ARLWNMCC:
|
||||
return true
|
||||
case ppc64.AFMADD, ppc64.AFMADDCC, ppc64.AFMADDS, ppc64.AFMADDSCC,
|
||||
ppc64.AFMSUB, ppc64.AFMSUBCC, ppc64.AFMSUBS, ppc64.AFMSUBSCC,
|
||||
ppc64.AFNMADD, ppc64.AFNMADDCC, ppc64.AFNMADDS, ppc64.AFNMADDSCC,
|
||||
ppc64.AFNMSUB, ppc64.AFNMSUBCC, ppc64.AFNMSUBS, ppc64.AFNMSUBSCC:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsPPC64ISEL(op obj.As) bool {
|
||||
return op == ppc64.AISEL
|
||||
}
|
||||
|
||||
// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is
|
||||
// one of the CMP instructions that require special handling.
|
||||
func IsPPC64CMP(op obj.As) bool {
|
||||
switch op {
|
||||
case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU, ppc64.AFCMPU:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsPPC64NEG reports whether the op (as defined by an ppc64.A* constant) is
|
||||
// one of the NEG-like instructions that require special handling.
|
||||
func IsPPC64NEG(op obj.As) bool {
|
||||
switch op {
|
||||
case ppc64.AADDMECC, ppc64.AADDMEVCC, ppc64.AADDMEV, ppc64.AADDME,
|
||||
ppc64.AADDZECC, ppc64.AADDZEVCC, ppc64.AADDZEV, ppc64.AADDZE,
|
||||
ppc64.ACNTLZDCC, ppc64.ACNTLZD, ppc64.ACNTLZWCC, ppc64.ACNTLZW,
|
||||
ppc64.AEXTSBCC, ppc64.AEXTSB, ppc64.AEXTSHCC, ppc64.AEXTSH,
|
||||
ppc64.AEXTSWCC, ppc64.AEXTSW, ppc64.ANEGCC, ppc64.ANEGVCC,
|
||||
ppc64.ANEGV, ppc64.ANEG, ppc64.ASLBMFEE, ppc64.ASLBMFEV,
|
||||
ppc64.ASLBMTE, ppc64.ASUBMECC, ppc64.ASUBMEVCC, ppc64.ASUBMEV,
|
||||
ppc64.ASUBME, ppc64.ASUBZECC, ppc64.ASUBZEVCC, ppc64.ASUBZEV,
|
||||
ppc64.ASUBZE:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ppc64RegisterNumber(name string, n int16) (int16, bool) {
|
||||
switch name {
|
||||
case "CR":
|
||||
if 0 <= n && n <= 7 {
|
||||
return ppc64.REG_CR0 + n, true
|
||||
}
|
||||
case "VS":
|
||||
if 0 <= n && n <= 63 {
|
||||
return ppc64.REG_VS0 + n, true
|
||||
}
|
||||
case "V":
|
||||
if 0 <= n && n <= 31 {
|
||||
return ppc64.REG_V0 + n, true
|
||||
}
|
||||
case "F":
|
||||
if 0 <= n && n <= 31 {
|
||||
return ppc64.REG_F0 + n, true
|
||||
}
|
||||
case "R":
|
||||
if 0 <= n && n <= 31 {
|
||||
return ppc64.REG_R0 + n, true
|
||||
}
|
||||
case "SPR":
|
||||
if 0 <= n && n <= 1024 {
|
||||
return ppc64.REG_SPR0 + n, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
Generated
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file encapsulates some of the odd characteristics of the RISCV64
|
||||
// instruction set, to minimize its interaction with the core of the
|
||||
// assembler.
|
||||
|
||||
package arch
|
||||
|
||||
import (
|
||||
"github.com/twitchyliquid64/golang-asm/obj"
|
||||
"github.com/twitchyliquid64/golang-asm/obj/riscv"
|
||||
)
|
||||
|
||||
// IsRISCV64AMO reports whether the op (as defined by a riscv.A*
|
||||
// constant) is one of the AMO instructions that requires special
|
||||
// handling.
|
||||
func IsRISCV64AMO(op obj.As) bool {
|
||||
switch op {
|
||||
case riscv.ASCW, riscv.ASCD, riscv.AAMOSWAPW, riscv.AAMOSWAPD, riscv.AAMOADDW, riscv.AAMOADDD,
|
||||
riscv.AAMOANDW, riscv.AAMOANDD, riscv.AAMOORW, riscv.AAMOORD, riscv.AAMOXORW, riscv.AAMOXORD,
|
||||
riscv.AAMOMINW, riscv.AAMOMIND, riscv.AAMOMINUW, riscv.AAMOMINUD,
|
||||
riscv.AAMOMAXW, riscv.AAMOMAXD, riscv.AAMOMAXUW, riscv.AAMOMAXUD:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file encapsulates some of the odd characteristics of the
|
||||
// s390x instruction set, to minimize its interaction
|
||||
// with the core of the assembler.
|
||||
|
||||
package arch
|
||||
|
||||
import (
|
||||
"github.com/twitchyliquid64/golang-asm/obj/s390x"
|
||||
)
|
||||
|
||||
func jumpS390x(word string) bool {
|
||||
switch word {
|
||||
case "BRC",
|
||||
"BC",
|
||||
"BCL",
|
||||
"BEQ",
|
||||
"BGE",
|
||||
"BGT",
|
||||
"BL",
|
||||
"BLE",
|
||||
"BLEU",
|
||||
"BLT",
|
||||
"BLTU",
|
||||
"BNE",
|
||||
"BR",
|
||||
"BVC",
|
||||
"BVS",
|
||||
"BRCT",
|
||||
"BRCTG",
|
||||
"CMPBEQ",
|
||||
"CMPBGE",
|
||||
"CMPBGT",
|
||||
"CMPBLE",
|
||||
"CMPBLT",
|
||||
"CMPBNE",
|
||||
"CMPUBEQ",
|
||||
"CMPUBGE",
|
||||
"CMPUBGT",
|
||||
"CMPUBLE",
|
||||
"CMPUBLT",
|
||||
"CMPUBNE",
|
||||
"CRJ",
|
||||
"CGRJ",
|
||||
"CLRJ",
|
||||
"CLGRJ",
|
||||
"CIJ",
|
||||
"CGIJ",
|
||||
"CLIJ",
|
||||
"CLGIJ",
|
||||
"CALL",
|
||||
"JMP":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func s390xRegisterNumber(name string, n int16) (int16, bool) {
|
||||
switch name {
|
||||
case "AR":
|
||||
if 0 <= n && n <= 15 {
|
||||
return s390x.REG_AR0 + n, true
|
||||
}
|
||||
case "F":
|
||||
if 0 <= n && n <= 15 {
|
||||
return s390x.REG_F0 + n, true
|
||||
}
|
||||
case "R":
|
||||
if 0 <= n && n <= 15 {
|
||||
return s390x.REG_R0 + n, true
|
||||
}
|
||||
case "V":
|
||||
if 0 <= n && n <= 31 {
|
||||
return s390x.REG_V0 + n, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package bio implements common I/O abstractions used within the Go toolchain.
|
||||
package bio
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Reader implements a seekable buffered io.Reader.
|
||||
type Reader struct {
|
||||
f *os.File
|
||||
*bufio.Reader
|
||||
}
|
||||
|
||||
// Writer implements a seekable buffered io.Writer.
|
||||
type Writer struct {
|
||||
f *os.File
|
||||
*bufio.Writer
|
||||
}
|
||||
|
||||
// Create creates the file named name and returns a Writer
|
||||
// for that file.
|
||||
func Create(name string) (*Writer, error) {
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Writer{f: f, Writer: bufio.NewWriter(f)}, nil
|
||||
}
|
||||
|
||||
// Open returns a Reader for the file named name.
|
||||
func Open(name string) (*Reader, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewReader(f), nil
|
||||
}
|
||||
|
||||
// NewReader returns a Reader from an open file.
|
||||
func NewReader(f *os.File) *Reader {
|
||||
return &Reader{f: f, Reader: bufio.NewReader(f)}
|
||||
}
|
||||
|
||||
func (r *Reader) MustSeek(offset int64, whence int) int64 {
|
||||
if whence == 1 {
|
||||
offset -= int64(r.Buffered())
|
||||
}
|
||||
off, err := r.f.Seek(offset, whence)
|
||||
if err != nil {
|
||||
log.Fatalf("seeking in output: %v", err)
|
||||
}
|
||||
r.Reset(r.f)
|
||||
return off
|
||||
}
|
||||
|
||||
func (w *Writer) MustSeek(offset int64, whence int) int64 {
|
||||
if err := w.Flush(); err != nil {
|
||||
log.Fatalf("writing output: %v", err)
|
||||
}
|
||||
off, err := w.f.Seek(offset, whence)
|
||||
if err != nil {
|
||||
log.Fatalf("seeking in output: %v", err)
|
||||
}
|
||||
return off
|
||||
}
|
||||
|
||||
func (r *Reader) Offset() int64 {
|
||||
off, err := r.f.Seek(0, 1)
|
||||
if err != nil {
|
||||
log.Fatalf("seeking in output [0, 1]: %v", err)
|
||||
}
|
||||
off -= int64(r.Buffered())
|
||||
return off
|
||||
}
|
||||
|
||||
func (w *Writer) Offset() int64 {
|
||||
if err := w.Flush(); err != nil {
|
||||
log.Fatalf("writing output: %v", err)
|
||||
}
|
||||
off, err := w.f.Seek(0, 1)
|
||||
if err != nil {
|
||||
log.Fatalf("seeking in output [0, 1]: %v", err)
|
||||
}
|
||||
return off
|
||||
}
|
||||
|
||||
func (r *Reader) Close() error {
|
||||
return r.f.Close()
|
||||
}
|
||||
|
||||
func (w *Writer) Close() error {
|
||||
err := w.Flush()
|
||||
err1 := w.f.Close()
|
||||
if err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Reader) File() *os.File {
|
||||
return r.f
|
||||
}
|
||||
|
||||
func (w *Writer) File() *os.File {
|
||||
return w.f
|
||||
}
|
||||
|
||||
// Slice reads the next length bytes of r into a slice.
|
||||
//
|
||||
// This slice may be backed by mmap'ed memory. Currently, this memory
|
||||
// will never be unmapped. The second result reports whether the
|
||||
// backing memory is read-only.
|
||||
func (r *Reader) Slice(length uint64) ([]byte, bool, error) {
|
||||
if length == 0 {
|
||||
return []byte{}, false, nil
|
||||
}
|
||||
|
||||
data, ok := r.sliceOS(length)
|
||||
if ok {
|
||||
return data, true, nil
|
||||
}
|
||||
|
||||
data = make([]byte, length)
|
||||
_, err := io.ReadFull(r, data)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return data, false, nil
|
||||
}
|
||||
|
||||
// SliceRO returns a slice containing the next length bytes of r
|
||||
// backed by a read-only mmap'd data. If the mmap cannot be
|
||||
// established (limit exceeded, region too small, etc) a nil slice
|
||||
// will be returned. If mmap succeeds, it will never be unmapped.
|
||||
func (r *Reader) SliceRO(length uint64) []byte {
|
||||
data, ok := r.sliceOS(length)
|
||||
if ok {
|
||||
return data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd
|
||||
|
||||
package bio
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// mmapLimit is the maximum number of mmaped regions to create before
|
||||
// falling back to reading into a heap-allocated slice. This exists
|
||||
// because some operating systems place a limit on the number of
|
||||
// distinct mapped regions per process. As of this writing:
|
||||
//
|
||||
// Darwin unlimited
|
||||
// DragonFly 1000000 (vm.max_proc_mmap)
|
||||
// FreeBSD unlimited
|
||||
// Linux 65530 (vm.max_map_count) // TODO: query /proc/sys/vm/max_map_count?
|
||||
// NetBSD unlimited
|
||||
// OpenBSD unlimited
|
||||
var mmapLimit int32 = 1<<31 - 1
|
||||
|
||||
func init() {
|
||||
// Linux is the only practically concerning OS.
|
||||
if runtime.GOOS == "linux" {
|
||||
mmapLimit = 30000
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Reader) sliceOS(length uint64) ([]byte, bool) {
|
||||
// For small slices, don't bother with the overhead of a
|
||||
// mapping, especially since we have no way to unmap it.
|
||||
const threshold = 16 << 10
|
||||
if length < threshold {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Have we reached the mmap limit?
|
||||
if atomic.AddInt32(&mmapLimit, -1) < 0 {
|
||||
atomic.AddInt32(&mmapLimit, 1)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Page-align the offset.
|
||||
off := r.Offset()
|
||||
align := syscall.Getpagesize()
|
||||
aoff := off &^ int64(align-1)
|
||||
|
||||
data, err := syscall.Mmap(int(r.f.Fd()), aoff, int(length+uint64(off-aoff)), syscall.PROT_READ, syscall.MAP_SHARED|syscall.MAP_FILE)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
data = data[off-aoff:]
|
||||
r.MustSeek(int64(length), 1)
|
||||
return data, true
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
|
||||
|
||||
package bio
|
||||
|
||||
func (r *Reader) sliceOS(length uint64) ([]byte, bool) {
|
||||
return nil, false
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bio
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
)
|
||||
|
||||
// MustClose closes Closer c and calls log.Fatal if it returns a non-nil error.
|
||||
func MustClose(c io.Closer) {
|
||||
if err := c.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustWriter returns a Writer that wraps the provided Writer,
|
||||
// except that it calls log.Fatal instead of returning a non-nil error.
|
||||
func MustWriter(w io.Writer) io.Writer {
|
||||
return mustWriter{w}
|
||||
}
|
||||
|
||||
type mustWriter struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (w mustWriter) Write(b []byte) (int, error) {
|
||||
n, err := w.w.Write(b)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (w mustWriter) WriteString(s string) (int, error) {
|
||||
n, err := io.WriteString(w.w, s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
+1650
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+493
@@ -0,0 +1,493 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dwarf
|
||||
|
||||
// Cut, pasted, tr-and-awk'ed from tables in
|
||||
// http://dwarfstd.org/doc/Dwarf3.pdf
|
||||
|
||||
// Table 18
|
||||
const (
|
||||
DW_TAG_array_type = 0x01
|
||||
DW_TAG_class_type = 0x02
|
||||
DW_TAG_entry_point = 0x03
|
||||
DW_TAG_enumeration_type = 0x04
|
||||
DW_TAG_formal_parameter = 0x05
|
||||
DW_TAG_imported_declaration = 0x08
|
||||
DW_TAG_label = 0x0a
|
||||
DW_TAG_lexical_block = 0x0b
|
||||
DW_TAG_member = 0x0d
|
||||
DW_TAG_pointer_type = 0x0f
|
||||
DW_TAG_reference_type = 0x10
|
||||
DW_TAG_compile_unit = 0x11
|
||||
DW_TAG_string_type = 0x12
|
||||
DW_TAG_structure_type = 0x13
|
||||
DW_TAG_subroutine_type = 0x15
|
||||
DW_TAG_typedef = 0x16
|
||||
DW_TAG_union_type = 0x17
|
||||
DW_TAG_unspecified_parameters = 0x18
|
||||
DW_TAG_variant = 0x19
|
||||
DW_TAG_common_block = 0x1a
|
||||
DW_TAG_common_inclusion = 0x1b
|
||||
DW_TAG_inheritance = 0x1c
|
||||
DW_TAG_inlined_subroutine = 0x1d
|
||||
DW_TAG_module = 0x1e
|
||||
DW_TAG_ptr_to_member_type = 0x1f
|
||||
DW_TAG_set_type = 0x20
|
||||
DW_TAG_subrange_type = 0x21
|
||||
DW_TAG_with_stmt = 0x22
|
||||
DW_TAG_access_declaration = 0x23
|
||||
DW_TAG_base_type = 0x24
|
||||
DW_TAG_catch_block = 0x25
|
||||
DW_TAG_const_type = 0x26
|
||||
DW_TAG_constant = 0x27
|
||||
DW_TAG_enumerator = 0x28
|
||||
DW_TAG_file_type = 0x29
|
||||
DW_TAG_friend = 0x2a
|
||||
DW_TAG_namelist = 0x2b
|
||||
DW_TAG_namelist_item = 0x2c
|
||||
DW_TAG_packed_type = 0x2d
|
||||
DW_TAG_subprogram = 0x2e
|
||||
DW_TAG_template_type_parameter = 0x2f
|
||||
DW_TAG_template_value_parameter = 0x30
|
||||
DW_TAG_thrown_type = 0x31
|
||||
DW_TAG_try_block = 0x32
|
||||
DW_TAG_variant_part = 0x33
|
||||
DW_TAG_variable = 0x34
|
||||
DW_TAG_volatile_type = 0x35
|
||||
// Dwarf3
|
||||
DW_TAG_dwarf_procedure = 0x36
|
||||
DW_TAG_restrict_type = 0x37
|
||||
DW_TAG_interface_type = 0x38
|
||||
DW_TAG_namespace = 0x39
|
||||
DW_TAG_imported_module = 0x3a
|
||||
DW_TAG_unspecified_type = 0x3b
|
||||
DW_TAG_partial_unit = 0x3c
|
||||
DW_TAG_imported_unit = 0x3d
|
||||
DW_TAG_condition = 0x3f
|
||||
DW_TAG_shared_type = 0x40
|
||||
// Dwarf4
|
||||
DW_TAG_type_unit = 0x41
|
||||
DW_TAG_rvalue_reference_type = 0x42
|
||||
DW_TAG_template_alias = 0x43
|
||||
|
||||
// User defined
|
||||
DW_TAG_lo_user = 0x4080
|
||||
DW_TAG_hi_user = 0xffff
|
||||
)
|
||||
|
||||
// Table 19
|
||||
const (
|
||||
DW_CHILDREN_no = 0x00
|
||||
DW_CHILDREN_yes = 0x01
|
||||
)
|
||||
|
||||
// Not from the spec, but logically belongs here
|
||||
const (
|
||||
DW_CLS_ADDRESS = 0x01 + iota
|
||||
DW_CLS_BLOCK
|
||||
DW_CLS_CONSTANT
|
||||
DW_CLS_FLAG
|
||||
DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr
|
||||
DW_CLS_REFERENCE
|
||||
DW_CLS_ADDRLOC
|
||||
DW_CLS_STRING
|
||||
|
||||
// Go-specific internal hackery.
|
||||
DW_CLS_GO_TYPEREF
|
||||
)
|
||||
|
||||
// Table 20
|
||||
const (
|
||||
DW_AT_sibling = 0x01 // reference
|
||||
DW_AT_location = 0x02 // block, loclistptr
|
||||
DW_AT_name = 0x03 // string
|
||||
DW_AT_ordering = 0x09 // constant
|
||||
DW_AT_byte_size = 0x0b // block, constant, reference
|
||||
DW_AT_bit_offset = 0x0c // block, constant, reference
|
||||
DW_AT_bit_size = 0x0d // block, constant, reference
|
||||
DW_AT_stmt_list = 0x10 // lineptr
|
||||
DW_AT_low_pc = 0x11 // address
|
||||
DW_AT_high_pc = 0x12 // address
|
||||
DW_AT_language = 0x13 // constant
|
||||
DW_AT_discr = 0x15 // reference
|
||||
DW_AT_discr_value = 0x16 // constant
|
||||
DW_AT_visibility = 0x17 // constant
|
||||
DW_AT_import = 0x18 // reference
|
||||
DW_AT_string_length = 0x19 // block, loclistptr
|
||||
DW_AT_common_reference = 0x1a // reference
|
||||
DW_AT_comp_dir = 0x1b // string
|
||||
DW_AT_const_value = 0x1c // block, constant, string
|
||||
DW_AT_containing_type = 0x1d // reference
|
||||
DW_AT_default_value = 0x1e // reference
|
||||
DW_AT_inline = 0x20 // constant
|
||||
DW_AT_is_optional = 0x21 // flag
|
||||
DW_AT_lower_bound = 0x22 // block, constant, reference
|
||||
DW_AT_producer = 0x25 // string
|
||||
DW_AT_prototyped = 0x27 // flag
|
||||
DW_AT_return_addr = 0x2a // block, loclistptr
|
||||
DW_AT_start_scope = 0x2c // constant
|
||||
DW_AT_bit_stride = 0x2e // constant
|
||||
DW_AT_upper_bound = 0x2f // block, constant, reference
|
||||
DW_AT_abstract_origin = 0x31 // reference
|
||||
DW_AT_accessibility = 0x32 // constant
|
||||
DW_AT_address_class = 0x33 // constant
|
||||
DW_AT_artificial = 0x34 // flag
|
||||
DW_AT_base_types = 0x35 // reference
|
||||
DW_AT_calling_convention = 0x36 // constant
|
||||
DW_AT_count = 0x37 // block, constant, reference
|
||||
DW_AT_data_member_location = 0x38 // block, constant, loclistptr
|
||||
DW_AT_decl_column = 0x39 // constant
|
||||
DW_AT_decl_file = 0x3a // constant
|
||||
DW_AT_decl_line = 0x3b // constant
|
||||
DW_AT_declaration = 0x3c // flag
|
||||
DW_AT_discr_list = 0x3d // block
|
||||
DW_AT_encoding = 0x3e // constant
|
||||
DW_AT_external = 0x3f // flag
|
||||
DW_AT_frame_base = 0x40 // block, loclistptr
|
||||
DW_AT_friend = 0x41 // reference
|
||||
DW_AT_identifier_case = 0x42 // constant
|
||||
DW_AT_macro_info = 0x43 // macptr
|
||||
DW_AT_namelist_item = 0x44 // block
|
||||
DW_AT_priority = 0x45 // reference
|
||||
DW_AT_segment = 0x46 // block, loclistptr
|
||||
DW_AT_specification = 0x47 // reference
|
||||
DW_AT_static_link = 0x48 // block, loclistptr
|
||||
DW_AT_type = 0x49 // reference
|
||||
DW_AT_use_location = 0x4a // block, loclistptr
|
||||
DW_AT_variable_parameter = 0x4b // flag
|
||||
DW_AT_virtuality = 0x4c // constant
|
||||
DW_AT_vtable_elem_location = 0x4d // block, loclistptr
|
||||
// Dwarf3
|
||||
DW_AT_allocated = 0x4e // block, constant, reference
|
||||
DW_AT_associated = 0x4f // block, constant, reference
|
||||
DW_AT_data_location = 0x50 // block
|
||||
DW_AT_byte_stride = 0x51 // block, constant, reference
|
||||
DW_AT_entry_pc = 0x52 // address
|
||||
DW_AT_use_UTF8 = 0x53 // flag
|
||||
DW_AT_extension = 0x54 // reference
|
||||
DW_AT_ranges = 0x55 // rangelistptr
|
||||
DW_AT_trampoline = 0x56 // address, flag, reference, string
|
||||
DW_AT_call_column = 0x57 // constant
|
||||
DW_AT_call_file = 0x58 // constant
|
||||
DW_AT_call_line = 0x59 // constant
|
||||
DW_AT_description = 0x5a // string
|
||||
DW_AT_binary_scale = 0x5b // constant
|
||||
DW_AT_decimal_scale = 0x5c // constant
|
||||
DW_AT_small = 0x5d // reference
|
||||
DW_AT_decimal_sign = 0x5e // constant
|
||||
DW_AT_digit_count = 0x5f // constant
|
||||
DW_AT_picture_string = 0x60 // string
|
||||
DW_AT_mutable = 0x61 // flag
|
||||
DW_AT_threads_scaled = 0x62 // flag
|
||||
DW_AT_explicit = 0x63 // flag
|
||||
DW_AT_object_pointer = 0x64 // reference
|
||||
DW_AT_endianity = 0x65 // constant
|
||||
DW_AT_elemental = 0x66 // flag
|
||||
DW_AT_pure = 0x67 // flag
|
||||
DW_AT_recursive = 0x68 // flag
|
||||
|
||||
DW_AT_lo_user = 0x2000 // ---
|
||||
DW_AT_hi_user = 0x3fff // ---
|
||||
)
|
||||
|
||||
// Table 21
|
||||
const (
|
||||
DW_FORM_addr = 0x01 // address
|
||||
DW_FORM_block2 = 0x03 // block
|
||||
DW_FORM_block4 = 0x04 // block
|
||||
DW_FORM_data2 = 0x05 // constant
|
||||
DW_FORM_data4 = 0x06 // constant, lineptr, loclistptr, macptr, rangelistptr
|
||||
DW_FORM_data8 = 0x07 // constant, lineptr, loclistptr, macptr, rangelistptr
|
||||
DW_FORM_string = 0x08 // string
|
||||
DW_FORM_block = 0x09 // block
|
||||
DW_FORM_block1 = 0x0a // block
|
||||
DW_FORM_data1 = 0x0b // constant
|
||||
DW_FORM_flag = 0x0c // flag
|
||||
DW_FORM_sdata = 0x0d // constant
|
||||
DW_FORM_strp = 0x0e // string
|
||||
DW_FORM_udata = 0x0f // constant
|
||||
DW_FORM_ref_addr = 0x10 // reference
|
||||
DW_FORM_ref1 = 0x11 // reference
|
||||
DW_FORM_ref2 = 0x12 // reference
|
||||
DW_FORM_ref4 = 0x13 // reference
|
||||
DW_FORM_ref8 = 0x14 // reference
|
||||
DW_FORM_ref_udata = 0x15 // reference
|
||||
DW_FORM_indirect = 0x16 // (see Section 7.5.3)
|
||||
// Dwarf4
|
||||
DW_FORM_sec_offset = 0x17 // lineptr, loclistptr, macptr, rangelistptr
|
||||
DW_FORM_exprloc = 0x18 // exprloc
|
||||
DW_FORM_flag_present = 0x19 // flag
|
||||
DW_FORM_ref_sig8 = 0x20 // reference
|
||||
// Pseudo-form: expanded to data4 on IOS, udata elsewhere.
|
||||
DW_FORM_udata_pseudo = 0x99
|
||||
)
|
||||
|
||||
// Table 24 (#operands, notes)
|
||||
const (
|
||||
DW_OP_addr = 0x03 // 1 constant address (size target specific)
|
||||
DW_OP_deref = 0x06 // 0
|
||||
DW_OP_const1u = 0x08 // 1 1-byte constant
|
||||
DW_OP_const1s = 0x09 // 1 1-byte constant
|
||||
DW_OP_const2u = 0x0a // 1 2-byte constant
|
||||
DW_OP_const2s = 0x0b // 1 2-byte constant
|
||||
DW_OP_const4u = 0x0c // 1 4-byte constant
|
||||
DW_OP_const4s = 0x0d // 1 4-byte constant
|
||||
DW_OP_const8u = 0x0e // 1 8-byte constant
|
||||
DW_OP_const8s = 0x0f // 1 8-byte constant
|
||||
DW_OP_constu = 0x10 // 1 ULEB128 constant
|
||||
DW_OP_consts = 0x11 // 1 SLEB128 constant
|
||||
DW_OP_dup = 0x12 // 0
|
||||
DW_OP_drop = 0x13 // 0
|
||||
DW_OP_over = 0x14 // 0
|
||||
DW_OP_pick = 0x15 // 1 1-byte stack index
|
||||
DW_OP_swap = 0x16 // 0
|
||||
DW_OP_rot = 0x17 // 0
|
||||
DW_OP_xderef = 0x18 // 0
|
||||
DW_OP_abs = 0x19 // 0
|
||||
DW_OP_and = 0x1a // 0
|
||||
DW_OP_div = 0x1b // 0
|
||||
DW_OP_minus = 0x1c // 0
|
||||
DW_OP_mod = 0x1d // 0
|
||||
DW_OP_mul = 0x1e // 0
|
||||
DW_OP_neg = 0x1f // 0
|
||||
DW_OP_not = 0x20 // 0
|
||||
DW_OP_or = 0x21 // 0
|
||||
DW_OP_plus = 0x22 // 0
|
||||
DW_OP_plus_uconst = 0x23 // 1 ULEB128 addend
|
||||
DW_OP_shl = 0x24 // 0
|
||||
DW_OP_shr = 0x25 // 0
|
||||
DW_OP_shra = 0x26 // 0
|
||||
DW_OP_xor = 0x27 // 0
|
||||
DW_OP_skip = 0x2f // 1 signed 2-byte constant
|
||||
DW_OP_bra = 0x28 // 1 signed 2-byte constant
|
||||
DW_OP_eq = 0x29 // 0
|
||||
DW_OP_ge = 0x2a // 0
|
||||
DW_OP_gt = 0x2b // 0
|
||||
DW_OP_le = 0x2c // 0
|
||||
DW_OP_lt = 0x2d // 0
|
||||
DW_OP_ne = 0x2e // 0
|
||||
DW_OP_lit0 = 0x30 // 0 ...
|
||||
DW_OP_lit31 = 0x4f // 0 literals 0..31 = (DW_OP_lit0 + literal)
|
||||
DW_OP_reg0 = 0x50 // 0 ..
|
||||
DW_OP_reg31 = 0x6f // 0 reg 0..31 = (DW_OP_reg0 + regnum)
|
||||
DW_OP_breg0 = 0x70 // 1 ...
|
||||
DW_OP_breg31 = 0x8f // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
|
||||
DW_OP_regx = 0x90 // 1 ULEB128 register
|
||||
DW_OP_fbreg = 0x91 // 1 SLEB128 offset
|
||||
DW_OP_bregx = 0x92 // 2 ULEB128 register followed by SLEB128 offset
|
||||
DW_OP_piece = 0x93 // 1 ULEB128 size of piece addressed
|
||||
DW_OP_deref_size = 0x94 // 1 1-byte size of data retrieved
|
||||
DW_OP_xderef_size = 0x95 // 1 1-byte size of data retrieved
|
||||
DW_OP_nop = 0x96 // 0
|
||||
DW_OP_push_object_address = 0x97 // 0
|
||||
DW_OP_call2 = 0x98 // 1 2-byte offset of DIE
|
||||
DW_OP_call4 = 0x99 // 1 4-byte offset of DIE
|
||||
DW_OP_call_ref = 0x9a // 1 4- or 8-byte offset of DIE
|
||||
DW_OP_form_tls_address = 0x9b // 0
|
||||
DW_OP_call_frame_cfa = 0x9c // 0
|
||||
DW_OP_bit_piece = 0x9d // 2
|
||||
DW_OP_lo_user = 0xe0
|
||||
DW_OP_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 25
|
||||
const (
|
||||
DW_ATE_address = 0x01
|
||||
DW_ATE_boolean = 0x02
|
||||
DW_ATE_complex_float = 0x03
|
||||
DW_ATE_float = 0x04
|
||||
DW_ATE_signed = 0x05
|
||||
DW_ATE_signed_char = 0x06
|
||||
DW_ATE_unsigned = 0x07
|
||||
DW_ATE_unsigned_char = 0x08
|
||||
DW_ATE_imaginary_float = 0x09
|
||||
DW_ATE_packed_decimal = 0x0a
|
||||
DW_ATE_numeric_string = 0x0b
|
||||
DW_ATE_edited = 0x0c
|
||||
DW_ATE_signed_fixed = 0x0d
|
||||
DW_ATE_unsigned_fixed = 0x0e
|
||||
DW_ATE_decimal_float = 0x0f
|
||||
DW_ATE_lo_user = 0x80
|
||||
DW_ATE_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 26
|
||||
const (
|
||||
DW_DS_unsigned = 0x01
|
||||
DW_DS_leading_overpunch = 0x02
|
||||
DW_DS_trailing_overpunch = 0x03
|
||||
DW_DS_leading_separate = 0x04
|
||||
DW_DS_trailing_separate = 0x05
|
||||
)
|
||||
|
||||
// Table 27
|
||||
const (
|
||||
DW_END_default = 0x00
|
||||
DW_END_big = 0x01
|
||||
DW_END_little = 0x02
|
||||
DW_END_lo_user = 0x40
|
||||
DW_END_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 28
|
||||
const (
|
||||
DW_ACCESS_public = 0x01
|
||||
DW_ACCESS_protected = 0x02
|
||||
DW_ACCESS_private = 0x03
|
||||
)
|
||||
|
||||
// Table 29
|
||||
const (
|
||||
DW_VIS_local = 0x01
|
||||
DW_VIS_exported = 0x02
|
||||
DW_VIS_qualified = 0x03
|
||||
)
|
||||
|
||||
// Table 30
|
||||
const (
|
||||
DW_VIRTUALITY_none = 0x00
|
||||
DW_VIRTUALITY_virtual = 0x01
|
||||
DW_VIRTUALITY_pure_virtual = 0x02
|
||||
)
|
||||
|
||||
// Table 31
|
||||
const (
|
||||
DW_LANG_C89 = 0x0001
|
||||
DW_LANG_C = 0x0002
|
||||
DW_LANG_Ada83 = 0x0003
|
||||
DW_LANG_C_plus_plus = 0x0004
|
||||
DW_LANG_Cobol74 = 0x0005
|
||||
DW_LANG_Cobol85 = 0x0006
|
||||
DW_LANG_Fortran77 = 0x0007
|
||||
DW_LANG_Fortran90 = 0x0008
|
||||
DW_LANG_Pascal83 = 0x0009
|
||||
DW_LANG_Modula2 = 0x000a
|
||||
// Dwarf3
|
||||
DW_LANG_Java = 0x000b
|
||||
DW_LANG_C99 = 0x000c
|
||||
DW_LANG_Ada95 = 0x000d
|
||||
DW_LANG_Fortran95 = 0x000e
|
||||
DW_LANG_PLI = 0x000f
|
||||
DW_LANG_ObjC = 0x0010
|
||||
DW_LANG_ObjC_plus_plus = 0x0011
|
||||
DW_LANG_UPC = 0x0012
|
||||
DW_LANG_D = 0x0013
|
||||
// Dwarf4
|
||||
DW_LANG_Python = 0x0014
|
||||
// Dwarf5
|
||||
DW_LANG_Go = 0x0016
|
||||
|
||||
DW_LANG_lo_user = 0x8000
|
||||
DW_LANG_hi_user = 0xffff
|
||||
)
|
||||
|
||||
// Table 32
|
||||
const (
|
||||
DW_ID_case_sensitive = 0x00
|
||||
DW_ID_up_case = 0x01
|
||||
DW_ID_down_case = 0x02
|
||||
DW_ID_case_insensitive = 0x03
|
||||
)
|
||||
|
||||
// Table 33
|
||||
const (
|
||||
DW_CC_normal = 0x01
|
||||
DW_CC_program = 0x02
|
||||
DW_CC_nocall = 0x03
|
||||
DW_CC_lo_user = 0x40
|
||||
DW_CC_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 34
|
||||
const (
|
||||
DW_INL_not_inlined = 0x00
|
||||
DW_INL_inlined = 0x01
|
||||
DW_INL_declared_not_inlined = 0x02
|
||||
DW_INL_declared_inlined = 0x03
|
||||
)
|
||||
|
||||
// Table 35
|
||||
const (
|
||||
DW_ORD_row_major = 0x00
|
||||
DW_ORD_col_major = 0x01
|
||||
)
|
||||
|
||||
// Table 36
|
||||
const (
|
||||
DW_DSC_label = 0x00
|
||||
DW_DSC_range = 0x01
|
||||
)
|
||||
|
||||
// Table 37
|
||||
const (
|
||||
DW_LNS_copy = 0x01
|
||||
DW_LNS_advance_pc = 0x02
|
||||
DW_LNS_advance_line = 0x03
|
||||
DW_LNS_set_file = 0x04
|
||||
DW_LNS_set_column = 0x05
|
||||
DW_LNS_negate_stmt = 0x06
|
||||
DW_LNS_set_basic_block = 0x07
|
||||
DW_LNS_const_add_pc = 0x08
|
||||
DW_LNS_fixed_advance_pc = 0x09
|
||||
// Dwarf3
|
||||
DW_LNS_set_prologue_end = 0x0a
|
||||
DW_LNS_set_epilogue_begin = 0x0b
|
||||
DW_LNS_set_isa = 0x0c
|
||||
)
|
||||
|
||||
// Table 38
|
||||
const (
|
||||
DW_LNE_end_sequence = 0x01
|
||||
DW_LNE_set_address = 0x02
|
||||
DW_LNE_define_file = 0x03
|
||||
DW_LNE_lo_user = 0x80
|
||||
DW_LNE_hi_user = 0xff
|
||||
)
|
||||
|
||||
// Table 39
|
||||
const (
|
||||
DW_MACINFO_define = 0x01
|
||||
DW_MACINFO_undef = 0x02
|
||||
DW_MACINFO_start_file = 0x03
|
||||
DW_MACINFO_end_file = 0x04
|
||||
DW_MACINFO_vendor_ext = 0xff
|
||||
)
|
||||
|
||||
// Table 40.
|
||||
const (
|
||||
// operand,...
|
||||
DW_CFA_nop = 0x00
|
||||
DW_CFA_set_loc = 0x01 // address
|
||||
DW_CFA_advance_loc1 = 0x02 // 1-byte delta
|
||||
DW_CFA_advance_loc2 = 0x03 // 2-byte delta
|
||||
DW_CFA_advance_loc4 = 0x04 // 4-byte delta
|
||||
DW_CFA_offset_extended = 0x05 // ULEB128 register, ULEB128 offset
|
||||
DW_CFA_restore_extended = 0x06 // ULEB128 register
|
||||
DW_CFA_undefined = 0x07 // ULEB128 register
|
||||
DW_CFA_same_value = 0x08 // ULEB128 register
|
||||
DW_CFA_register = 0x09 // ULEB128 register, ULEB128 register
|
||||
DW_CFA_remember_state = 0x0a
|
||||
DW_CFA_restore_state = 0x0b
|
||||
|
||||
DW_CFA_def_cfa = 0x0c // ULEB128 register, ULEB128 offset
|
||||
DW_CFA_def_cfa_register = 0x0d // ULEB128 register
|
||||
DW_CFA_def_cfa_offset = 0x0e // ULEB128 offset
|
||||
DW_CFA_def_cfa_expression = 0x0f // BLOCK
|
||||
DW_CFA_expression = 0x10 // ULEB128 register, BLOCK
|
||||
DW_CFA_offset_extended_sf = 0x11 // ULEB128 register, SLEB128 offset
|
||||
DW_CFA_def_cfa_sf = 0x12 // ULEB128 register, SLEB128 offset
|
||||
DW_CFA_def_cfa_offset_sf = 0x13 // SLEB128 offset
|
||||
DW_CFA_val_offset = 0x14 // ULEB128, ULEB128
|
||||
DW_CFA_val_offset_sf = 0x15 // ULEB128, SLEB128
|
||||
DW_CFA_val_expression = 0x16 // ULEB128, BLOCK
|
||||
|
||||
DW_CFA_lo_user = 0x1c
|
||||
DW_CFA_hi_user = 0x3f
|
||||
|
||||
// Opcodes that take an addend operand.
|
||||
DW_CFA_advance_loc = 0x1 << 6 // +delta
|
||||
DW_CFA_offset = 0x2 << 6 // +register (ULEB128 offset)
|
||||
DW_CFA_restore = 0x3 << 6 // +register
|
||||
)
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package goobj
|
||||
|
||||
// Builtin (compiler-generated) function references appear
|
||||
// frequently. We assign special indices for them, so they
|
||||
// don't need to be referenced by name.
|
||||
|
||||
// NBuiltin returns the number of listed builtin
|
||||
// symbols.
|
||||
func NBuiltin() int {
|
||||
return len(builtins)
|
||||
}
|
||||
|
||||
// BuiltinName returns the name and ABI of the i-th
|
||||
// builtin symbol.
|
||||
func BuiltinName(i int) (string, int) {
|
||||
return builtins[i].name, builtins[i].abi
|
||||
}
|
||||
|
||||
// BuiltinIdx returns the index of the builtin with the
|
||||
// given name and abi, or -1 if it is not a builtin.
|
||||
func BuiltinIdx(name string, abi int) int {
|
||||
i, ok := builtinMap[name]
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
if builtins[i].abi != abi {
|
||||
return -1
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
//go:generate go run mkbuiltin.go
|
||||
|
||||
var builtinMap map[string]int
|
||||
|
||||
func init() {
|
||||
builtinMap = make(map[string]int, len(builtins))
|
||||
for i, b := range builtins {
|
||||
builtinMap[b.name] = i
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+245
@@ -0,0 +1,245 @@
|
||||
// Code generated by mkbuiltin.go. DO NOT EDIT.
|
||||
|
||||
package goobj
|
||||
|
||||
var builtins = [...]struct {
|
||||
name string
|
||||
abi int
|
||||
}{
|
||||
{"runtime.newobject", 1},
|
||||
{"runtime.mallocgc", 1},
|
||||
{"runtime.panicdivide", 1},
|
||||
{"runtime.panicshift", 1},
|
||||
{"runtime.panicmakeslicelen", 1},
|
||||
{"runtime.panicmakeslicecap", 1},
|
||||
{"runtime.throwinit", 1},
|
||||
{"runtime.panicwrap", 1},
|
||||
{"runtime.gopanic", 1},
|
||||
{"runtime.gorecover", 1},
|
||||
{"runtime.goschedguarded", 1},
|
||||
{"runtime.goPanicIndex", 1},
|
||||
{"runtime.goPanicIndexU", 1},
|
||||
{"runtime.goPanicSliceAlen", 1},
|
||||
{"runtime.goPanicSliceAlenU", 1},
|
||||
{"runtime.goPanicSliceAcap", 1},
|
||||
{"runtime.goPanicSliceAcapU", 1},
|
||||
{"runtime.goPanicSliceB", 1},
|
||||
{"runtime.goPanicSliceBU", 1},
|
||||
{"runtime.goPanicSlice3Alen", 1},
|
||||
{"runtime.goPanicSlice3AlenU", 1},
|
||||
{"runtime.goPanicSlice3Acap", 1},
|
||||
{"runtime.goPanicSlice3AcapU", 1},
|
||||
{"runtime.goPanicSlice3B", 1},
|
||||
{"runtime.goPanicSlice3BU", 1},
|
||||
{"runtime.goPanicSlice3C", 1},
|
||||
{"runtime.goPanicSlice3CU", 1},
|
||||
{"runtime.printbool", 1},
|
||||
{"runtime.printfloat", 1},
|
||||
{"runtime.printint", 1},
|
||||
{"runtime.printhex", 1},
|
||||
{"runtime.printuint", 1},
|
||||
{"runtime.printcomplex", 1},
|
||||
{"runtime.printstring", 1},
|
||||
{"runtime.printpointer", 1},
|
||||
{"runtime.printiface", 1},
|
||||
{"runtime.printeface", 1},
|
||||
{"runtime.printslice", 1},
|
||||
{"runtime.printnl", 1},
|
||||
{"runtime.printsp", 1},
|
||||
{"runtime.printlock", 1},
|
||||
{"runtime.printunlock", 1},
|
||||
{"runtime.concatstring2", 1},
|
||||
{"runtime.concatstring3", 1},
|
||||
{"runtime.concatstring4", 1},
|
||||
{"runtime.concatstring5", 1},
|
||||
{"runtime.concatstrings", 1},
|
||||
{"runtime.cmpstring", 1},
|
||||
{"runtime.intstring", 1},
|
||||
{"runtime.slicebytetostring", 1},
|
||||
{"runtime.slicebytetostringtmp", 1},
|
||||
{"runtime.slicerunetostring", 1},
|
||||
{"runtime.stringtoslicebyte", 1},
|
||||
{"runtime.stringtoslicerune", 1},
|
||||
{"runtime.slicecopy", 1},
|
||||
{"runtime.slicestringcopy", 1},
|
||||
{"runtime.decoderune", 1},
|
||||
{"runtime.countrunes", 1},
|
||||
{"runtime.convI2I", 1},
|
||||
{"runtime.convT16", 1},
|
||||
{"runtime.convT32", 1},
|
||||
{"runtime.convT64", 1},
|
||||
{"runtime.convTstring", 1},
|
||||
{"runtime.convTslice", 1},
|
||||
{"runtime.convT2E", 1},
|
||||
{"runtime.convT2Enoptr", 1},
|
||||
{"runtime.convT2I", 1},
|
||||
{"runtime.convT2Inoptr", 1},
|
||||
{"runtime.assertE2I", 1},
|
||||
{"runtime.assertE2I2", 1},
|
||||
{"runtime.assertI2I", 1},
|
||||
{"runtime.assertI2I2", 1},
|
||||
{"runtime.panicdottypeE", 1},
|
||||
{"runtime.panicdottypeI", 1},
|
||||
{"runtime.panicnildottype", 1},
|
||||
{"runtime.ifaceeq", 1},
|
||||
{"runtime.efaceeq", 1},
|
||||
{"runtime.fastrand", 1},
|
||||
{"runtime.makemap64", 1},
|
||||
{"runtime.makemap", 1},
|
||||
{"runtime.makemap_small", 1},
|
||||
{"runtime.mapaccess1", 1},
|
||||
{"runtime.mapaccess1_fast32", 1},
|
||||
{"runtime.mapaccess1_fast64", 1},
|
||||
{"runtime.mapaccess1_faststr", 1},
|
||||
{"runtime.mapaccess1_fat", 1},
|
||||
{"runtime.mapaccess2", 1},
|
||||
{"runtime.mapaccess2_fast32", 1},
|
||||
{"runtime.mapaccess2_fast64", 1},
|
||||
{"runtime.mapaccess2_faststr", 1},
|
||||
{"runtime.mapaccess2_fat", 1},
|
||||
{"runtime.mapassign", 1},
|
||||
{"runtime.mapassign_fast32", 1},
|
||||
{"runtime.mapassign_fast32ptr", 1},
|
||||
{"runtime.mapassign_fast64", 1},
|
||||
{"runtime.mapassign_fast64ptr", 1},
|
||||
{"runtime.mapassign_faststr", 1},
|
||||
{"runtime.mapiterinit", 1},
|
||||
{"runtime.mapdelete", 1},
|
||||
{"runtime.mapdelete_fast32", 1},
|
||||
{"runtime.mapdelete_fast64", 1},
|
||||
{"runtime.mapdelete_faststr", 1},
|
||||
{"runtime.mapiternext", 1},
|
||||
{"runtime.mapclear", 1},
|
||||
{"runtime.makechan64", 1},
|
||||
{"runtime.makechan", 1},
|
||||
{"runtime.chanrecv1", 1},
|
||||
{"runtime.chanrecv2", 1},
|
||||
{"runtime.chansend1", 1},
|
||||
{"runtime.closechan", 1},
|
||||
{"runtime.writeBarrier", 0},
|
||||
{"runtime.typedmemmove", 1},
|
||||
{"runtime.typedmemclr", 1},
|
||||
{"runtime.typedslicecopy", 1},
|
||||
{"runtime.selectnbsend", 1},
|
||||
{"runtime.selectnbrecv", 1},
|
||||
{"runtime.selectnbrecv2", 1},
|
||||
{"runtime.selectsetpc", 1},
|
||||
{"runtime.selectgo", 1},
|
||||
{"runtime.block", 1},
|
||||
{"runtime.makeslice", 1},
|
||||
{"runtime.makeslice64", 1},
|
||||
{"runtime.makeslicecopy", 1},
|
||||
{"runtime.growslice", 1},
|
||||
{"runtime.memmove", 1},
|
||||
{"runtime.memclrNoHeapPointers", 1},
|
||||
{"runtime.memclrHasPointers", 1},
|
||||
{"runtime.memequal", 1},
|
||||
{"runtime.memequal0", 1},
|
||||
{"runtime.memequal8", 1},
|
||||
{"runtime.memequal16", 1},
|
||||
{"runtime.memequal32", 1},
|
||||
{"runtime.memequal64", 1},
|
||||
{"runtime.memequal128", 1},
|
||||
{"runtime.f32equal", 1},
|
||||
{"runtime.f64equal", 1},
|
||||
{"runtime.c64equal", 1},
|
||||
{"runtime.c128equal", 1},
|
||||
{"runtime.strequal", 1},
|
||||
{"runtime.interequal", 1},
|
||||
{"runtime.nilinterequal", 1},
|
||||
{"runtime.memhash", 1},
|
||||
{"runtime.memhash0", 1},
|
||||
{"runtime.memhash8", 1},
|
||||
{"runtime.memhash16", 1},
|
||||
{"runtime.memhash32", 1},
|
||||
{"runtime.memhash64", 1},
|
||||
{"runtime.memhash128", 1},
|
||||
{"runtime.f32hash", 1},
|
||||
{"runtime.f64hash", 1},
|
||||
{"runtime.c64hash", 1},
|
||||
{"runtime.c128hash", 1},
|
||||
{"runtime.strhash", 1},
|
||||
{"runtime.interhash", 1},
|
||||
{"runtime.nilinterhash", 1},
|
||||
{"runtime.int64div", 1},
|
||||
{"runtime.uint64div", 1},
|
||||
{"runtime.int64mod", 1},
|
||||
{"runtime.uint64mod", 1},
|
||||
{"runtime.float64toint64", 1},
|
||||
{"runtime.float64touint64", 1},
|
||||
{"runtime.float64touint32", 1},
|
||||
{"runtime.int64tofloat64", 1},
|
||||
{"runtime.uint64tofloat64", 1},
|
||||
{"runtime.uint32tofloat64", 1},
|
||||
{"runtime.complex128div", 1},
|
||||
{"runtime.racefuncenter", 1},
|
||||
{"runtime.racefuncenterfp", 1},
|
||||
{"runtime.racefuncexit", 1},
|
||||
{"runtime.raceread", 1},
|
||||
{"runtime.racewrite", 1},
|
||||
{"runtime.racereadrange", 1},
|
||||
{"runtime.racewriterange", 1},
|
||||
{"runtime.msanread", 1},
|
||||
{"runtime.msanwrite", 1},
|
||||
{"runtime.checkptrAlignment", 1},
|
||||
{"runtime.checkptrArithmetic", 1},
|
||||
{"runtime.libfuzzerTraceCmp1", 1},
|
||||
{"runtime.libfuzzerTraceCmp2", 1},
|
||||
{"runtime.libfuzzerTraceCmp4", 1},
|
||||
{"runtime.libfuzzerTraceCmp8", 1},
|
||||
{"runtime.libfuzzerTraceConstCmp1", 1},
|
||||
{"runtime.libfuzzerTraceConstCmp2", 1},
|
||||
{"runtime.libfuzzerTraceConstCmp4", 1},
|
||||
{"runtime.libfuzzerTraceConstCmp8", 1},
|
||||
{"runtime.x86HasPOPCNT", 0},
|
||||
{"runtime.x86HasSSE41", 0},
|
||||
{"runtime.x86HasFMA", 0},
|
||||
{"runtime.armHasVFPv4", 0},
|
||||
{"runtime.arm64HasATOMICS", 0},
|
||||
{"runtime.deferproc", 1},
|
||||
{"runtime.deferprocStack", 1},
|
||||
{"runtime.deferreturn", 1},
|
||||
{"runtime.newproc", 1},
|
||||
{"runtime.panicoverflow", 1},
|
||||
{"runtime.sigpanic", 1},
|
||||
{"runtime.gcWriteBarrier", 0},
|
||||
{"runtime.morestack", 0},
|
||||
{"runtime.morestackc", 0},
|
||||
{"runtime.morestack_noctxt", 0},
|
||||
{"type.int8", 0},
|
||||
{"type.*int8", 0},
|
||||
{"type.uint8", 0},
|
||||
{"type.*uint8", 0},
|
||||
{"type.int16", 0},
|
||||
{"type.*int16", 0},
|
||||
{"type.uint16", 0},
|
||||
{"type.*uint16", 0},
|
||||
{"type.int32", 0},
|
||||
{"type.*int32", 0},
|
||||
{"type.uint32", 0},
|
||||
{"type.*uint32", 0},
|
||||
{"type.int64", 0},
|
||||
{"type.*int64", 0},
|
||||
{"type.uint64", 0},
|
||||
{"type.*uint64", 0},
|
||||
{"type.float32", 0},
|
||||
{"type.*float32", 0},
|
||||
{"type.float64", 0},
|
||||
{"type.*float64", 0},
|
||||
{"type.complex64", 0},
|
||||
{"type.*complex64", 0},
|
||||
{"type.complex128", 0},
|
||||
{"type.*complex128", 0},
|
||||
{"type.unsafe.Pointer", 0},
|
||||
{"type.*unsafe.Pointer", 0},
|
||||
{"type.uintptr", 0},
|
||||
{"type.*uintptr", 0},
|
||||
{"type.bool", 0},
|
||||
{"type.*bool", 0},
|
||||
{"type.string", 0},
|
||||
{"type.*string", 0},
|
||||
{"type.error", 0},
|
||||
{"type.*error", 0},
|
||||
{"type.func(error) string", 0},
|
||||
{"type.*func(error) string", 0},
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package goobj
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/twitchyliquid64/golang-asm/objabi"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// CUFileIndex is used to index the filenames that are stored in the
|
||||
// per-package/per-CU FileList.
|
||||
type CUFileIndex uint32
|
||||
|
||||
// FuncInfo is serialized as a symbol (aux symbol). The symbol data is
|
||||
// the binary encoding of the struct below.
|
||||
//
|
||||
// TODO: make each pcdata a separate symbol?
|
||||
type FuncInfo struct {
|
||||
Args uint32
|
||||
Locals uint32
|
||||
FuncID objabi.FuncID
|
||||
|
||||
Pcsp uint32
|
||||
Pcfile uint32
|
||||
Pcline uint32
|
||||
Pcinline uint32
|
||||
Pcdata []uint32
|
||||
PcdataEnd uint32
|
||||
Funcdataoff []uint32
|
||||
File []CUFileIndex
|
||||
|
||||
InlTree []InlTreeNode
|
||||
}
|
||||
|
||||
func (a *FuncInfo) Write(w *bytes.Buffer) {
|
||||
var b [4]byte
|
||||
writeUint32 := func(x uint32) {
|
||||
binary.LittleEndian.PutUint32(b[:], x)
|
||||
w.Write(b[:])
|
||||
}
|
||||
|
||||
writeUint32(a.Args)
|
||||
writeUint32(a.Locals)
|
||||
writeUint32(uint32(a.FuncID))
|
||||
|
||||
writeUint32(a.Pcsp)
|
||||
writeUint32(a.Pcfile)
|
||||
writeUint32(a.Pcline)
|
||||
writeUint32(a.Pcinline)
|
||||
writeUint32(uint32(len(a.Pcdata)))
|
||||
for _, x := range a.Pcdata {
|
||||
writeUint32(x)
|
||||
}
|
||||
writeUint32(a.PcdataEnd)
|
||||
writeUint32(uint32(len(a.Funcdataoff)))
|
||||
for _, x := range a.Funcdataoff {
|
||||
writeUint32(x)
|
||||
}
|
||||
writeUint32(uint32(len(a.File)))
|
||||
for _, f := range a.File {
|
||||
writeUint32(uint32(f))
|
||||
}
|
||||
writeUint32(uint32(len(a.InlTree)))
|
||||
for i := range a.InlTree {
|
||||
a.InlTree[i].Write(w)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *FuncInfo) Read(b []byte) {
|
||||
readUint32 := func() uint32 {
|
||||
x := binary.LittleEndian.Uint32(b)
|
||||
b = b[4:]
|
||||
return x
|
||||
}
|
||||
|
||||
a.Args = readUint32()
|
||||
a.Locals = readUint32()
|
||||
a.FuncID = objabi.FuncID(readUint32())
|
||||
|
||||
a.Pcsp = readUint32()
|
||||
a.Pcfile = readUint32()
|
||||
a.Pcline = readUint32()
|
||||
a.Pcinline = readUint32()
|
||||
pcdatalen := readUint32()
|
||||
a.Pcdata = make([]uint32, pcdatalen)
|
||||
for i := range a.Pcdata {
|
||||
a.Pcdata[i] = readUint32()
|
||||
}
|
||||
a.PcdataEnd = readUint32()
|
||||
funcdataofflen := readUint32()
|
||||
a.Funcdataoff = make([]uint32, funcdataofflen)
|
||||
for i := range a.Funcdataoff {
|
||||
a.Funcdataoff[i] = readUint32()
|
||||
}
|
||||
filelen := readUint32()
|
||||
a.File = make([]CUFileIndex, filelen)
|
||||
for i := range a.File {
|
||||
a.File[i] = CUFileIndex(readUint32())
|
||||
}
|
||||
inltreelen := readUint32()
|
||||
a.InlTree = make([]InlTreeNode, inltreelen)
|
||||
for i := range a.InlTree {
|
||||
b = a.InlTree[i].Read(b)
|
||||
}
|
||||
}
|
||||
|
||||
// FuncInfoLengths is a cache containing a roadmap of offsets and
|
||||
// lengths for things within a serialized FuncInfo. Each length field
|
||||
// stores the number of items (e.g. files, inltree nodes, etc), and the
|
||||
// corresponding "off" field stores the byte offset of the start of
|
||||
// the items in question.
|
||||
type FuncInfoLengths struct {
|
||||
NumPcdata uint32
|
||||
PcdataOff uint32
|
||||
NumFuncdataoff uint32
|
||||
FuncdataoffOff uint32
|
||||
NumFile uint32
|
||||
FileOff uint32
|
||||
NumInlTree uint32
|
||||
InlTreeOff uint32
|
||||
Initialized bool
|
||||
}
|
||||
|
||||
func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
|
||||
var result FuncInfoLengths
|
||||
|
||||
const numpcdataOff = 28
|
||||
result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
|
||||
result.PcdataOff = numpcdataOff + 4
|
||||
|
||||
numfuncdataoffOff := result.PcdataOff + 4*(result.NumPcdata+1)
|
||||
result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
|
||||
result.FuncdataoffOff = numfuncdataoffOff + 4
|
||||
|
||||
numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff
|
||||
result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:])
|
||||
result.FileOff = numfileOff + 4
|
||||
|
||||
numinltreeOff := result.FileOff + 4*result.NumFile
|
||||
result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:])
|
||||
result.InlTreeOff = numinltreeOff + 4
|
||||
|
||||
result.Initialized = true
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
|
||||
|
||||
func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) }
|
||||
|
||||
func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) }
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])
|
||||
}
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:])
|
||||
}
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])
|
||||
}
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[24:]), binary.LittleEndian.Uint32(b[pcdataoffset:])
|
||||
}
|
||||
|
||||
// return start and end offsets.
|
||||
func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) {
|
||||
return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:])
|
||||
}
|
||||
|
||||
func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
|
||||
return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:]))
|
||||
}
|
||||
|
||||
func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex {
|
||||
return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:]))
|
||||
}
|
||||
|
||||
func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode {
|
||||
const inlTreeNodeSize = 4 * 6
|
||||
var result InlTreeNode
|
||||
result.Read(b[inltreeoff+k*inlTreeNodeSize:])
|
||||
return result
|
||||
}
|
||||
|
||||
// InlTreeNode is the serialized form of FileInfo.InlTree.
|
||||
type InlTreeNode struct {
|
||||
Parent int32
|
||||
File CUFileIndex
|
||||
Line int32
|
||||
Func SymRef
|
||||
ParentPC int32
|
||||
}
|
||||
|
||||
func (inl *InlTreeNode) Write(w *bytes.Buffer) {
|
||||
var b [4]byte
|
||||
writeUint32 := func(x uint32) {
|
||||
binary.LittleEndian.PutUint32(b[:], x)
|
||||
w.Write(b[:])
|
||||
}
|
||||
writeUint32(uint32(inl.Parent))
|
||||
writeUint32(uint32(inl.File))
|
||||
writeUint32(uint32(inl.Line))
|
||||
writeUint32(inl.Func.PkgIdx)
|
||||
writeUint32(inl.Func.SymIdx)
|
||||
writeUint32(uint32(inl.ParentPC))
|
||||
}
|
||||
|
||||
// Read an InlTreeNode from b, return the remaining bytes.
|
||||
func (inl *InlTreeNode) Read(b []byte) []byte {
|
||||
readUint32 := func() uint32 {
|
||||
x := binary.LittleEndian.Uint32(b)
|
||||
b = b[4:]
|
||||
return x
|
||||
}
|
||||
inl.Parent = int32(readUint32())
|
||||
inl.File = CUFileIndex(readUint32())
|
||||
inl.Line = int32(readUint32())
|
||||
inl.Func = SymRef{readUint32(), readUint32()}
|
||||
inl.ParentPC = int32(readUint32())
|
||||
return b
|
||||
}
|
||||
+871
@@ -0,0 +1,871 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This package defines the Go object file format, and provide "low-level" functions
|
||||
// for reading and writing object files.
|
||||
|
||||
// The object file is understood by the compiler, assembler, linker, and tools. They
|
||||
// have "high level" code that operates on object files, handling application-specific
|
||||
// logics, and use this package for the actual reading and writing. Specifically, the
|
||||
// code below:
|
||||
//
|
||||
// - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile)
|
||||
// - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump)
|
||||
// - cmd/link/internal/loader package (used by cmd/link)
|
||||
//
|
||||
// If the object file format changes, they may (or may not) need to change.
|
||||
|
||||
package goobj
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/twitchyliquid64/golang-asm/bio"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/twitchyliquid64/golang-asm/unsafeheader"
|
||||
"io"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// New object file format.
|
||||
//
|
||||
// Header struct {
|
||||
// Magic [...]byte // "\x00go116ld"
|
||||
// Fingerprint [8]byte
|
||||
// Flags uint32
|
||||
// Offsets [...]uint32 // byte offset of each block below
|
||||
// }
|
||||
//
|
||||
// Strings [...]struct {
|
||||
// Data [...]byte
|
||||
// }
|
||||
//
|
||||
// Autolib [...]struct { // imported packages (for file loading)
|
||||
// Pkg string
|
||||
// Fingerprint [8]byte
|
||||
// }
|
||||
//
|
||||
// PkgIndex [...]string // referenced packages by index
|
||||
//
|
||||
// Files [...]string
|
||||
//
|
||||
// SymbolDefs [...]struct {
|
||||
// Name string
|
||||
// ABI uint16
|
||||
// Type uint8
|
||||
// Flag uint8
|
||||
// Flag2 uint8
|
||||
// Size uint32
|
||||
// }
|
||||
// Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions
|
||||
// ... // same as SymbolDefs
|
||||
// }
|
||||
// HashedDefs [...]struct { // hashed (content-addressable) symbol definitions
|
||||
// ... // same as SymbolDefs
|
||||
// }
|
||||
// NonPkgDefs [...]struct { // non-pkg symbol definitions
|
||||
// ... // same as SymbolDefs
|
||||
// }
|
||||
// NonPkgRefs [...]struct { // non-pkg symbol references
|
||||
// ... // same as SymbolDefs
|
||||
// }
|
||||
//
|
||||
// RefFlags [...]struct { // referenced symbol flags
|
||||
// Sym symRef
|
||||
// Flag uint8
|
||||
// Flag2 uint8
|
||||
// }
|
||||
//
|
||||
// Hash64 [...][8]byte
|
||||
// Hash [...][N]byte
|
||||
//
|
||||
// RelocIndex [...]uint32 // index to Relocs
|
||||
// AuxIndex [...]uint32 // index to Aux
|
||||
// DataIndex [...]uint32 // offset to Data
|
||||
//
|
||||
// Relocs [...]struct {
|
||||
// Off int32
|
||||
// Size uint8
|
||||
// Type uint8
|
||||
// Add int64
|
||||
// Sym symRef
|
||||
// }
|
||||
//
|
||||
// Aux [...]struct {
|
||||
// Type uint8
|
||||
// Sym symRef
|
||||
// }
|
||||
//
|
||||
// Data [...]byte
|
||||
// Pcdata [...]byte
|
||||
//
|
||||
// // blocks only used by tools (objdump, nm)
|
||||
//
|
||||
// RefNames [...]struct { // referenced symbol names
|
||||
// Sym symRef
|
||||
// Name string
|
||||
// // TODO: include ABI version as well?
|
||||
// }
|
||||
//
|
||||
// string is encoded as is a uint32 length followed by a uint32 offset
|
||||
// that points to the corresponding string bytes.
|
||||
//
|
||||
// symRef is struct { PkgIdx, SymIdx uint32 }.
|
||||
//
|
||||
// Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
|
||||
// followed by that number of elements.
|
||||
//
|
||||
// The types below correspond to the encoded data structure in the
|
||||
// object file.
|
||||
|
||||
// Symbol indexing.
|
||||
//
|
||||
// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
|
||||
// as the symRef struct above.
|
||||
//
|
||||
// PkgIdx is either a predeclared index (see PkgIdxNone below) or
|
||||
// an index of an imported package. For the latter case, PkgIdx is the
|
||||
// index of the package in the PkgIndex array. 0 is an invalid index.
|
||||
//
|
||||
// SymIdx is the index of the symbol in the given package.
|
||||
// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
|
||||
// SymbolDefs array.
|
||||
// - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the
|
||||
// Hashed64Defs array.
|
||||
// - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the
|
||||
// HashedDefs array.
|
||||
// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
|
||||
// NonPkgDefs array (could natually overflow to NonPkgRefs array).
|
||||
// - Otherwise, SymIdx is the index of the symbol in some other package's
|
||||
// SymbolDefs array.
|
||||
//
|
||||
// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
|
||||
//
|
||||
// Hash contains the content hashes of content-addressable symbols, of
|
||||
// which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array.
|
||||
// Hash64 is similar, for PkgIdxHashed64 symbols.
|
||||
//
|
||||
// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
|
||||
// Relocs/Aux/Data blocks, one element per symbol, first for all the
|
||||
// defined symbols, then all the defined hashed and non-package symbols,
|
||||
// in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs
|
||||
// arrays. For N total defined symbols, the array is of length N+1. The
|
||||
// last element is the total number of relocations (aux symbols, data
|
||||
// blocks, etc.).
|
||||
//
|
||||
// They can be accessed by index. For the i-th symbol, its relocations
|
||||
// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
|
||||
// elements in the Relocs array. Aux/Data are likewise. (The index is
|
||||
// 0-based.)
|
||||
|
||||
// Auxiliary symbols.
|
||||
//
|
||||
// Each symbol may (or may not) be associated with a number of auxiliary
|
||||
// symbols. They are described in the Aux block. See Aux struct below.
|
||||
// Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols
|
||||
// are auxiliary symbols.
|
||||
|
||||
const stringRefSize = 8 // two uint32s
|
||||
|
||||
type FingerprintType [8]byte
|
||||
|
||||
func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
|
||||
|
||||
// Package Index.
|
||||
const (
|
||||
PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols
|
||||
PkgIdxHashed64 // Short hashed (content-addressable) symbols
|
||||
PkgIdxHashed // Hashed (content-addressable) symbols
|
||||
PkgIdxBuiltin // Predefined runtime symbols (ex: runtime.newobject)
|
||||
PkgIdxSelf // Symbols defined in the current package
|
||||
PkgIdxInvalid = 0
|
||||
// The index of other referenced packages starts from 1.
|
||||
)
|
||||
|
||||
// Blocks
|
||||
const (
|
||||
BlkAutolib = iota
|
||||
BlkPkgIdx
|
||||
BlkFile
|
||||
BlkSymdef
|
||||
BlkHashed64def
|
||||
BlkHasheddef
|
||||
BlkNonpkgdef
|
||||
BlkNonpkgref
|
||||
BlkRefFlags
|
||||
BlkHash64
|
||||
BlkHash
|
||||
BlkRelocIdx
|
||||
BlkAuxIdx
|
||||
BlkDataIdx
|
||||
BlkReloc
|
||||
BlkAux
|
||||
BlkData
|
||||
BlkPcdata
|
||||
BlkRefName
|
||||
BlkEnd
|
||||
NBlk
|
||||
)
|
||||
|
||||
// File header.
|
||||
// TODO: probably no need to export this.
|
||||
type Header struct {
|
||||
Magic string
|
||||
Fingerprint FingerprintType
|
||||
Flags uint32
|
||||
Offsets [NBlk]uint32
|
||||
}
|
||||
|
||||
const Magic = "\x00go116ld"
|
||||
|
||||
func (h *Header) Write(w *Writer) {
|
||||
w.RawString(h.Magic)
|
||||
w.Bytes(h.Fingerprint[:])
|
||||
w.Uint32(h.Flags)
|
||||
for _, x := range h.Offsets {
|
||||
w.Uint32(x)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Header) Read(r *Reader) error {
|
||||
b := r.BytesAt(0, len(Magic))
|
||||
h.Magic = string(b)
|
||||
if h.Magic != Magic {
|
||||
return errors.New("wrong magic, not a Go object file")
|
||||
}
|
||||
off := uint32(len(h.Magic))
|
||||
copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
|
||||
off += 8
|
||||
h.Flags = r.uint32At(off)
|
||||
off += 4
|
||||
for i := range h.Offsets {
|
||||
h.Offsets[i] = r.uint32At(off)
|
||||
off += 4
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Header) Size() int {
|
||||
return len(h.Magic) + 4 + 4*len(h.Offsets)
|
||||
}
|
||||
|
||||
// Autolib
|
||||
type ImportedPkg struct {
|
||||
Pkg string
|
||||
Fingerprint FingerprintType
|
||||
}
|
||||
|
||||
const importedPkgSize = stringRefSize + 8
|
||||
|
||||
func (p *ImportedPkg) Write(w *Writer) {
|
||||
w.StringRef(p.Pkg)
|
||||
w.Bytes(p.Fingerprint[:])
|
||||
}
|
||||
|
||||
// Symbol definition.
|
||||
//
|
||||
// Serialized format:
|
||||
// Sym struct {
|
||||
// Name string
|
||||
// ABI uint16
|
||||
// Type uint8
|
||||
// Flag uint8
|
||||
// Flag2 uint8
|
||||
// Siz uint32
|
||||
// Align uint32
|
||||
// }
|
||||
type Sym [SymSize]byte
|
||||
|
||||
const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4
|
||||
|
||||
const SymABIstatic = ^uint16(0)
|
||||
|
||||
const (
|
||||
ObjFlagShared = 1 << iota // this object is built with -shared
|
||||
ObjFlagNeedNameExpansion // the linker needs to expand `"".` to package path in symbol names
|
||||
ObjFlagFromAssembly // object is from asm src, not go
|
||||
)
|
||||
|
||||
// Sym.Flag
|
||||
const (
|
||||
SymFlagDupok = 1 << iota
|
||||
SymFlagLocal
|
||||
SymFlagTypelink
|
||||
SymFlagLeaf
|
||||
SymFlagNoSplit
|
||||
SymFlagReflectMethod
|
||||
SymFlagGoType
|
||||
SymFlagTopFrame
|
||||
)
|
||||
|
||||
// Sym.Flag2
|
||||
const (
|
||||
SymFlagUsedInIface = 1 << iota
|
||||
SymFlagItab
|
||||
)
|
||||
|
||||
// Returns the length of the name of the symbol.
|
||||
func (s *Sym) NameLen(r *Reader) int {
|
||||
return int(binary.LittleEndian.Uint32(s[:]))
|
||||
}
|
||||
|
||||
func (s *Sym) Name(r *Reader) string {
|
||||
len := binary.LittleEndian.Uint32(s[:])
|
||||
off := binary.LittleEndian.Uint32(s[4:])
|
||||
return r.StringAt(off, len)
|
||||
}
|
||||
|
||||
func (s *Sym) ABI() uint16 { return binary.LittleEndian.Uint16(s[8:]) }
|
||||
func (s *Sym) Type() uint8 { return s[10] }
|
||||
func (s *Sym) Flag() uint8 { return s[11] }
|
||||
func (s *Sym) Flag2() uint8 { return s[12] }
|
||||
func (s *Sym) Siz() uint32 { return binary.LittleEndian.Uint32(s[13:]) }
|
||||
func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
|
||||
|
||||
func (s *Sym) Dupok() bool { return s.Flag()&SymFlagDupok != 0 }
|
||||
func (s *Sym) Local() bool { return s.Flag()&SymFlagLocal != 0 }
|
||||
func (s *Sym) Typelink() bool { return s.Flag()&SymFlagTypelink != 0 }
|
||||
func (s *Sym) Leaf() bool { return s.Flag()&SymFlagLeaf != 0 }
|
||||
func (s *Sym) NoSplit() bool { return s.Flag()&SymFlagNoSplit != 0 }
|
||||
func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
|
||||
func (s *Sym) IsGoType() bool { return s.Flag()&SymFlagGoType != 0 }
|
||||
func (s *Sym) TopFrame() bool { return s.Flag()&SymFlagTopFrame != 0 }
|
||||
func (s *Sym) UsedInIface() bool { return s.Flag2()&SymFlagUsedInIface != 0 }
|
||||
func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 }
|
||||
|
||||
func (s *Sym) SetName(x string, w *Writer) {
|
||||
binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
|
||||
binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
|
||||
}
|
||||
|
||||
func (s *Sym) SetABI(x uint16) { binary.LittleEndian.PutUint16(s[8:], x) }
|
||||
func (s *Sym) SetType(x uint8) { s[10] = x }
|
||||
func (s *Sym) SetFlag(x uint8) { s[11] = x }
|
||||
func (s *Sym) SetFlag2(x uint8) { s[12] = x }
|
||||
func (s *Sym) SetSiz(x uint32) { binary.LittleEndian.PutUint32(s[13:], x) }
|
||||
func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
|
||||
|
||||
func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
|
||||
|
||||
// for testing
|
||||
func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
|
||||
|
||||
// Symbol reference.
|
||||
type SymRef struct {
|
||||
PkgIdx uint32
|
||||
SymIdx uint32
|
||||
}
|
||||
|
||||
// Hash64
|
||||
type Hash64Type [Hash64Size]byte
|
||||
|
||||
const Hash64Size = 8
|
||||
|
||||
// Hash
|
||||
type HashType [HashSize]byte
|
||||
|
||||
const HashSize = sha1.Size
|
||||
|
||||
// Relocation.
|
||||
//
|
||||
// Serialized format:
|
||||
// Reloc struct {
|
||||
// Off int32
|
||||
// Siz uint8
|
||||
// Type uint8
|
||||
// Add int64
|
||||
// Sym SymRef
|
||||
// }
|
||||
type Reloc [RelocSize]byte
|
||||
|
||||
const RelocSize = 4 + 1 + 1 + 8 + 8
|
||||
|
||||
func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) }
|
||||
func (r *Reloc) Siz() uint8 { return r[4] }
|
||||
func (r *Reloc) Type() uint8 { return r[5] }
|
||||
func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[6:])) }
|
||||
func (r *Reloc) Sym() SymRef {
|
||||
return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])}
|
||||
}
|
||||
|
||||
func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
|
||||
func (r *Reloc) SetSiz(x uint8) { r[4] = x }
|
||||
func (r *Reloc) SetType(x uint8) { r[5] = x }
|
||||
func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[6:], uint64(x)) }
|
||||
func (r *Reloc) SetSym(x SymRef) {
|
||||
binary.LittleEndian.PutUint32(r[14:], x.PkgIdx)
|
||||
binary.LittleEndian.PutUint32(r[18:], x.SymIdx)
|
||||
}
|
||||
|
||||
func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) {
|
||||
r.SetOff(off)
|
||||
r.SetSiz(size)
|
||||
r.SetType(typ)
|
||||
r.SetAdd(add)
|
||||
r.SetSym(sym)
|
||||
}
|
||||
|
||||
func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
|
||||
|
||||
// for testing
|
||||
func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) }
|
||||
|
||||
// Aux symbol info.
|
||||
//
|
||||
// Serialized format:
|
||||
// Aux struct {
|
||||
// Type uint8
|
||||
// Sym SymRef
|
||||
// }
|
||||
type Aux [AuxSize]byte
|
||||
|
||||
const AuxSize = 1 + 8
|
||||
|
||||
// Aux Type
|
||||
const (
|
||||
AuxGotype = iota
|
||||
AuxFuncInfo
|
||||
AuxFuncdata
|
||||
AuxDwarfInfo
|
||||
AuxDwarfLoc
|
||||
AuxDwarfRanges
|
||||
AuxDwarfLines
|
||||
|
||||
// TODO: more. Pcdata?
|
||||
)
|
||||
|
||||
func (a *Aux) Type() uint8 { return a[0] }
|
||||
func (a *Aux) Sym() SymRef {
|
||||
return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
|
||||
}
|
||||
|
||||
func (a *Aux) SetType(x uint8) { a[0] = x }
|
||||
func (a *Aux) SetSym(x SymRef) {
|
||||
binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
|
||||
binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
|
||||
}
|
||||
|
||||
func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
|
||||
|
||||
// for testing
|
||||
func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
|
||||
|
||||
// Referenced symbol flags.
|
||||
//
|
||||
// Serialized format:
|
||||
// RefFlags struct {
|
||||
// Sym symRef
|
||||
// Flag uint8
|
||||
// Flag2 uint8
|
||||
// }
|
||||
type RefFlags [RefFlagsSize]byte
|
||||
|
||||
const RefFlagsSize = 8 + 1 + 1
|
||||
|
||||
func (r *RefFlags) Sym() SymRef {
|
||||
return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
|
||||
}
|
||||
func (r *RefFlags) Flag() uint8 { return r[8] }
|
||||
func (r *RefFlags) Flag2() uint8 { return r[9] }
|
||||
|
||||
func (r *RefFlags) SetSym(x SymRef) {
|
||||
binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
|
||||
binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
|
||||
}
|
||||
func (r *RefFlags) SetFlag(x uint8) { r[8] = x }
|
||||
func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
|
||||
|
||||
func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
|
||||
|
||||
// Referenced symbol name.
|
||||
//
|
||||
// Serialized format:
|
||||
// RefName struct {
|
||||
// Sym symRef
|
||||
// Name string
|
||||
// }
|
||||
type RefName [RefNameSize]byte
|
||||
|
||||
const RefNameSize = 8 + stringRefSize
|
||||
|
||||
func (n *RefName) Sym() SymRef {
|
||||
return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
|
||||
}
|
||||
func (n *RefName) Name(r *Reader) string {
|
||||
len := binary.LittleEndian.Uint32(n[8:])
|
||||
off := binary.LittleEndian.Uint32(n[12:])
|
||||
return r.StringAt(off, len)
|
||||
}
|
||||
|
||||
func (n *RefName) SetSym(x SymRef) {
|
||||
binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
|
||||
binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
|
||||
}
|
||||
func (n *RefName) SetName(x string, w *Writer) {
|
||||
binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
|
||||
binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
|
||||
}
|
||||
|
||||
func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
|
||||
|
||||
type Writer struct {
|
||||
wr *bio.Writer
|
||||
stringMap map[string]uint32
|
||||
off uint32 // running offset
|
||||
}
|
||||
|
||||
func NewWriter(wr *bio.Writer) *Writer {
|
||||
return &Writer{wr: wr, stringMap: make(map[string]uint32)}
|
||||
}
|
||||
|
||||
func (w *Writer) AddString(s string) {
|
||||
if _, ok := w.stringMap[s]; ok {
|
||||
return
|
||||
}
|
||||
w.stringMap[s] = w.off
|
||||
w.RawString(s)
|
||||
}
|
||||
|
||||
func (w *Writer) stringOff(s string) uint32 {
|
||||
off, ok := w.stringMap[s]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
|
||||
}
|
||||
return off
|
||||
}
|
||||
|
||||
func (w *Writer) StringRef(s string) {
|
||||
w.Uint32(uint32(len(s)))
|
||||
w.Uint32(w.stringOff(s))
|
||||
}
|
||||
|
||||
func (w *Writer) RawString(s string) {
|
||||
w.wr.WriteString(s)
|
||||
w.off += uint32(len(s))
|
||||
}
|
||||
|
||||
func (w *Writer) Bytes(s []byte) {
|
||||
w.wr.Write(s)
|
||||
w.off += uint32(len(s))
|
||||
}
|
||||
|
||||
func (w *Writer) Uint64(x uint64) {
|
||||
var b [8]byte
|
||||
binary.LittleEndian.PutUint64(b[:], x)
|
||||
w.wr.Write(b[:])
|
||||
w.off += 8
|
||||
}
|
||||
|
||||
func (w *Writer) Uint32(x uint32) {
|
||||
var b [4]byte
|
||||
binary.LittleEndian.PutUint32(b[:], x)
|
||||
w.wr.Write(b[:])
|
||||
w.off += 4
|
||||
}
|
||||
|
||||
func (w *Writer) Uint16(x uint16) {
|
||||
var b [2]byte
|
||||
binary.LittleEndian.PutUint16(b[:], x)
|
||||
w.wr.Write(b[:])
|
||||
w.off += 2
|
||||
}
|
||||
|
||||
func (w *Writer) Uint8(x uint8) {
|
||||
w.wr.WriteByte(x)
|
||||
w.off++
|
||||
}
|
||||
|
||||
func (w *Writer) Offset() uint32 {
|
||||
return w.off
|
||||
}
|
||||
|
||||
type Reader struct {
|
||||
b []byte // mmapped bytes, if not nil
|
||||
readonly bool // whether b is backed with read-only memory
|
||||
|
||||
rd io.ReaderAt
|
||||
start uint32
|
||||
h Header // keep block offsets
|
||||
}
|
||||
|
||||
func NewReaderFromBytes(b []byte, readonly bool) *Reader {
|
||||
r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0}
|
||||
err := r.h.Read(r)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Reader) BytesAt(off uint32, len int) []byte {
|
||||
if len == 0 {
|
||||
return nil
|
||||
}
|
||||
end := int(off) + len
|
||||
return r.b[int(off):end:end]
|
||||
}
|
||||
|
||||
func (r *Reader) uint64At(off uint32) uint64 {
|
||||
b := r.BytesAt(off, 8)
|
||||
return binary.LittleEndian.Uint64(b)
|
||||
}
|
||||
|
||||
func (r *Reader) int64At(off uint32) int64 {
|
||||
return int64(r.uint64At(off))
|
||||
}
|
||||
|
||||
func (r *Reader) uint32At(off uint32) uint32 {
|
||||
b := r.BytesAt(off, 4)
|
||||
return binary.LittleEndian.Uint32(b)
|
||||
}
|
||||
|
||||
func (r *Reader) int32At(off uint32) int32 {
|
||||
return int32(r.uint32At(off))
|
||||
}
|
||||
|
||||
func (r *Reader) uint16At(off uint32) uint16 {
|
||||
b := r.BytesAt(off, 2)
|
||||
return binary.LittleEndian.Uint16(b)
|
||||
}
|
||||
|
||||
func (r *Reader) uint8At(off uint32) uint8 {
|
||||
b := r.BytesAt(off, 1)
|
||||
return b[0]
|
||||
}
|
||||
|
||||
func (r *Reader) StringAt(off uint32, len uint32) string {
|
||||
b := r.b[off : off+len]
|
||||
if r.readonly {
|
||||
return toString(b) // backed by RO memory, ok to make unsafe string
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func toString(b []byte) string {
|
||||
if len(b) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var s string
|
||||
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
||||
hdr.Data = unsafe.Pointer(&b[0])
|
||||
hdr.Len = len(b)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *Reader) StringRef(off uint32) string {
|
||||
l := r.uint32At(off)
|
||||
return r.StringAt(r.uint32At(off+4), l)
|
||||
}
|
||||
|
||||
func (r *Reader) Fingerprint() FingerprintType {
|
||||
return r.h.Fingerprint
|
||||
}
|
||||
|
||||
func (r *Reader) Autolib() []ImportedPkg {
|
||||
n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
|
||||
s := make([]ImportedPkg, n)
|
||||
off := r.h.Offsets[BlkAutolib]
|
||||
for i := range s {
|
||||
s[i].Pkg = r.StringRef(off)
|
||||
copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
|
||||
off += importedPkgSize
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *Reader) Pkglist() []string {
|
||||
n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
|
||||
s := make([]string, n)
|
||||
off := r.h.Offsets[BlkPkgIdx]
|
||||
for i := range s {
|
||||
s[i] = r.StringRef(off)
|
||||
off += stringRefSize
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *Reader) NPkg() int {
|
||||
return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
|
||||
}
|
||||
|
||||
func (r *Reader) Pkg(i int) string {
|
||||
off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
|
||||
return r.StringRef(off)
|
||||
}
|
||||
|
||||
func (r *Reader) NFile() int {
|
||||
return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
|
||||
}
|
||||
|
||||
func (r *Reader) File(i int) string {
|
||||
off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
|
||||
return r.StringRef(off)
|
||||
}
|
||||
|
||||
func (r *Reader) NSym() int {
|
||||
return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
|
||||
}
|
||||
|
||||
func (r *Reader) NHashed64def() int {
|
||||
return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
|
||||
}
|
||||
|
||||
func (r *Reader) NHasheddef() int {
|
||||
return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
|
||||
}
|
||||
|
||||
func (r *Reader) NNonpkgdef() int {
|
||||
return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
|
||||
}
|
||||
|
||||
func (r *Reader) NNonpkgref() int {
|
||||
return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
|
||||
}
|
||||
|
||||
// SymOff returns the offset of the i-th symbol.
|
||||
func (r *Reader) SymOff(i uint32) uint32 {
|
||||
return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
|
||||
}
|
||||
|
||||
// Sym returns a pointer to the i-th symbol.
|
||||
func (r *Reader) Sym(i uint32) *Sym {
|
||||
off := r.SymOff(i)
|
||||
return (*Sym)(unsafe.Pointer(&r.b[off]))
|
||||
}
|
||||
|
||||
// NRefFlags returns the number of referenced symbol flags.
|
||||
func (r *Reader) NRefFlags() int {
|
||||
return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
|
||||
}
|
||||
|
||||
// RefFlags returns a pointer to the i-th referenced symbol flags.
|
||||
// Note: here i is not a local symbol index, just a counter.
|
||||
func (r *Reader) RefFlags(i int) *RefFlags {
|
||||
off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
|
||||
return (*RefFlags)(unsafe.Pointer(&r.b[off]))
|
||||
}
|
||||
|
||||
// Hash64 returns the i-th short hashed symbol's hash.
|
||||
// Note: here i is the index of short hashed symbols, not all symbols
|
||||
// (unlike other accessors).
|
||||
func (r *Reader) Hash64(i uint32) uint64 {
|
||||
off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
|
||||
return r.uint64At(off)
|
||||
}
|
||||
|
||||
// Hash returns a pointer to the i-th hashed symbol's hash.
|
||||
// Note: here i is the index of hashed symbols, not all symbols
|
||||
// (unlike other accessors).
|
||||
func (r *Reader) Hash(i uint32) *HashType {
|
||||
off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
|
||||
return (*HashType)(unsafe.Pointer(&r.b[off]))
|
||||
}
|
||||
|
||||
// NReloc returns the number of relocations of the i-th symbol.
|
||||
func (r *Reader) NReloc(i uint32) int {
|
||||
relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
|
||||
return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
|
||||
}
|
||||
|
||||
// RelocOff returns the offset of the j-th relocation of the i-th symbol.
|
||||
func (r *Reader) RelocOff(i uint32, j int) uint32 {
|
||||
relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
|
||||
relocIdx := r.uint32At(relocIdxOff)
|
||||
return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize)
|
||||
}
|
||||
|
||||
// Reloc returns a pointer to the j-th relocation of the i-th symbol.
|
||||
func (r *Reader) Reloc(i uint32, j int) *Reloc {
|
||||
off := r.RelocOff(i, j)
|
||||
return (*Reloc)(unsafe.Pointer(&r.b[off]))
|
||||
}
|
||||
|
||||
// Relocs returns a pointer to the relocations of the i-th symbol.
|
||||
func (r *Reader) Relocs(i uint32) []Reloc {
|
||||
off := r.RelocOff(i, 0)
|
||||
n := r.NReloc(i)
|
||||
return (*[1 << 20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
|
||||
}
|
||||
|
||||
// NAux returns the number of aux symbols of the i-th symbol.
|
||||
func (r *Reader) NAux(i uint32) int {
|
||||
auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
|
||||
return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
|
||||
}
|
||||
|
||||
// AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
|
||||
func (r *Reader) AuxOff(i uint32, j int) uint32 {
|
||||
auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
|
||||
auxIdx := r.uint32At(auxIdxOff)
|
||||
return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize)
|
||||
}
|
||||
|
||||
// Aux returns a pointer to the j-th aux symbol of the i-th symbol.
|
||||
func (r *Reader) Aux(i uint32, j int) *Aux {
|
||||
off := r.AuxOff(i, j)
|
||||
return (*Aux)(unsafe.Pointer(&r.b[off]))
|
||||
}
|
||||
|
||||
// Auxs returns the aux symbols of the i-th symbol.
|
||||
func (r *Reader) Auxs(i uint32) []Aux {
|
||||
off := r.AuxOff(i, 0)
|
||||
n := r.NAux(i)
|
||||
return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
|
||||
}
|
||||
|
||||
// DataOff returns the offset of the i-th symbol's data.
|
||||
func (r *Reader) DataOff(i uint32) uint32 {
|
||||
dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
|
||||
return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
|
||||
}
|
||||
|
||||
// DataSize returns the size of the i-th symbol's data.
|
||||
func (r *Reader) DataSize(i uint32) int {
|
||||
dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
|
||||
return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
|
||||
}
|
||||
|
||||
// Data returns the i-th symbol's data.
|
||||
func (r *Reader) Data(i uint32) []byte {
|
||||
dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
|
||||
base := r.h.Offsets[BlkData]
|
||||
off := r.uint32At(dataIdxOff)
|
||||
end := r.uint32At(dataIdxOff + 4)
|
||||
return r.BytesAt(base+off, int(end-off))
|
||||
}
|
||||
|
||||
// AuxDataBase returns the base offset of the aux data block.
|
||||
func (r *Reader) PcdataBase() uint32 {
|
||||
return r.h.Offsets[BlkPcdata]
|
||||
}
|
||||
|
||||
// NRefName returns the number of referenced symbol names.
|
||||
func (r *Reader) NRefName() int {
|
||||
return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
|
||||
}
|
||||
|
||||
// RefName returns a pointer to the i-th referenced symbol name.
|
||||
// Note: here i is not a local symbol index, just a counter.
|
||||
func (r *Reader) RefName(i int) *RefName {
|
||||
off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
|
||||
return (*RefName)(unsafe.Pointer(&r.b[off]))
|
||||
}
|
||||
|
||||
// ReadOnly returns whether r.BytesAt returns read-only bytes.
|
||||
func (r *Reader) ReadOnly() bool {
|
||||
return r.readonly
|
||||
}
|
||||
|
||||
// Flags returns the flag bits read from the object file header.
|
||||
func (r *Reader) Flags() uint32 {
|
||||
return r.h.Flags
|
||||
}
|
||||
|
||||
func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 }
|
||||
func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 }
|
||||
func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// Derived from Inferno utils/6l/l.h and related files.
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package objabi
|
||||
|
||||
// Auto.name
|
||||
const (
|
||||
A_AUTO = 1 + iota
|
||||
A_PARAM
|
||||
A_DELETED_AUTO
|
||||
)
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Flagcount(name, usage string, val *int) {
|
||||
flag.Var((*count)(val), name, usage)
|
||||
}
|
||||
|
||||
func Flagfn1(name, usage string, f func(string)) {
|
||||
flag.Var(fn1(f), name, usage)
|
||||
}
|
||||
|
||||
func Flagprint(w io.Writer) {
|
||||
flag.CommandLine.SetOutput(w)
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
func Flagparse(usage func()) {
|
||||
flag.Usage = usage
|
||||
os.Args = expandArgs(os.Args)
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
// expandArgs expands "response files" arguments in the provided slice.
|
||||
//
|
||||
// A "response file" argument starts with '@' and the rest of that
|
||||
// argument is a filename with CR-or-CRLF-separated arguments. Each
|
||||
// argument in the named files can also contain response file
|
||||
// arguments. See Issue 18468.
|
||||
//
|
||||
// The returned slice 'out' aliases 'in' iff the input did not contain
|
||||
// any response file arguments.
|
||||
//
|
||||
// TODO: handle relative paths of recursive expansions in different directories?
|
||||
// Is there a spec for this? Are relative paths allowed?
|
||||
func expandArgs(in []string) (out []string) {
|
||||
// out is nil until we see a "@" argument.
|
||||
for i, s := range in {
|
||||
if strings.HasPrefix(s, "@") {
|
||||
if out == nil {
|
||||
out = make([]string, 0, len(in)*2)
|
||||
out = append(out, in[:i]...)
|
||||
}
|
||||
slurp, err := ioutil.ReadFile(s[1:])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n")
|
||||
out = append(out, expandArgs(args)...)
|
||||
} else if out != nil {
|
||||
out = append(out, s)
|
||||
}
|
||||
}
|
||||
if out == nil {
|
||||
return in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func AddVersionFlag() {
|
||||
flag.Var(versionFlag{}, "V", "print version and exit")
|
||||
}
|
||||
|
||||
var buildID string // filled in by linker
|
||||
|
||||
type versionFlag struct{}
|
||||
|
||||
func (versionFlag) IsBoolFlag() bool { return true }
|
||||
func (versionFlag) Get() interface{} { return nil }
|
||||
func (versionFlag) String() string { return "" }
|
||||
func (versionFlag) Set(s string) error {
|
||||
name := os.Args[0]
|
||||
name = name[strings.LastIndex(name, `/`)+1:]
|
||||
name = name[strings.LastIndex(name, `\`)+1:]
|
||||
name = strings.TrimSuffix(name, ".exe")
|
||||
|
||||
// If there's an active experiment, include that,
|
||||
// to distinguish go1.10.2 with an experiment
|
||||
// from go1.10.2 without an experiment.
|
||||
p := Expstring()
|
||||
if p == DefaultExpstring() {
|
||||
p = ""
|
||||
}
|
||||
sep := ""
|
||||
if p != "" {
|
||||
sep = " "
|
||||
}
|
||||
|
||||
// The go command invokes -V=full to get a unique identifier
|
||||
// for this tool. It is assumed that the release version is sufficient
|
||||
// for releases, but during development we include the full
|
||||
// build ID of the binary, so that if the compiler is changed and
|
||||
// rebuilt, we notice and rebuild all packages.
|
||||
if s == "full" {
|
||||
if strings.HasPrefix(Version, "devel") {
|
||||
p += " buildID=" + buildID
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%s version %s%s%s\n", name, Version, sep, p)
|
||||
os.Exit(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// count is a flag.Value that is like a flag.Bool and a flag.Int.
|
||||
// If used as -name, it increments the count, but -name=x sets the count.
|
||||
// Used for verbose flag -v.
|
||||
type count int
|
||||
|
||||
func (c *count) String() string {
|
||||
return fmt.Sprint(int(*c))
|
||||
}
|
||||
|
||||
func (c *count) Set(s string) error {
|
||||
switch s {
|
||||
case "true":
|
||||
*c++
|
||||
case "false":
|
||||
*c = 0
|
||||
default:
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid count %q", s)
|
||||
}
|
||||
*c = count(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *count) Get() interface{} {
|
||||
return int(*c)
|
||||
}
|
||||
|
||||
func (c *count) IsBoolFlag() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *count) IsCountFlag() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type fn1 func(string)
|
||||
|
||||
func (f fn1) Set(s string) error {
|
||||
f(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f fn1) String() string { return "" }
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
// This file defines the IDs for PCDATA and FUNCDATA instructions
|
||||
// in Go binaries.
|
||||
//
|
||||
// These must agree with ../../../runtime/funcdata.h and
|
||||
// ../../../runtime/symtab.go.
|
||||
|
||||
const (
|
||||
PCDATA_RegMapIndex = 0 // if !go115ReduceLiveness
|
||||
PCDATA_UnsafePoint = 0 // if go115ReduceLiveness
|
||||
PCDATA_StackMapIndex = 1
|
||||
PCDATA_InlTreeIndex = 2
|
||||
|
||||
FUNCDATA_ArgsPointerMaps = 0
|
||||
FUNCDATA_LocalsPointerMaps = 1
|
||||
FUNCDATA_RegPointerMaps = 2 // if !go115ReduceLiveness
|
||||
FUNCDATA_StackObjects = 3
|
||||
FUNCDATA_InlTree = 4
|
||||
FUNCDATA_OpenCodedDeferInfo = 5
|
||||
|
||||
// ArgsSizeUnknown is set in Func.argsize to mark all functions
|
||||
// whose argument size is unknown (C vararg functions, and
|
||||
// assembly code without an explicit specification).
|
||||
// This value is generated by the compiler, assembler, or linker.
|
||||
ArgsSizeUnknown = -0x80000000
|
||||
)
|
||||
|
||||
// Special PCDATA values.
|
||||
const (
|
||||
// PCDATA_RegMapIndex values.
|
||||
//
|
||||
// Only if !go115ReduceLiveness.
|
||||
PCDATA_RegMapUnsafe = PCDATA_UnsafePointUnsafe // Unsafe for async preemption
|
||||
|
||||
// PCDATA_UnsafePoint values.
|
||||
PCDATA_UnsafePointSafe = -1 // Safe for async preemption
|
||||
PCDATA_UnsafePointUnsafe = -2 // Unsafe for async preemption
|
||||
|
||||
// PCDATA_Restart1(2) apply on a sequence of instructions, within
|
||||
// which if an async preemption happens, we should back off the PC
|
||||
// to the start of the sequence when resuming.
|
||||
// We need two so we can distinguish the start/end of the sequence
|
||||
// in case that two sequences are next to each other.
|
||||
PCDATA_Restart1 = -3
|
||||
PCDATA_Restart2 = -4
|
||||
|
||||
// Like PCDATA_Restart1, but back to function entry if async preempted.
|
||||
PCDATA_RestartAtEntry = -5
|
||||
)
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
// A FuncID identifies particular functions that need to be treated
|
||||
// specially by the runtime.
|
||||
// Note that in some situations involving plugins, there may be multiple
|
||||
// copies of a particular special runtime function.
|
||||
// Note: this list must match the list in runtime/symtab.go.
|
||||
type FuncID uint8
|
||||
|
||||
const (
|
||||
FuncID_normal FuncID = iota // not a special function
|
||||
FuncID_runtime_main
|
||||
FuncID_goexit
|
||||
FuncID_jmpdefer
|
||||
FuncID_mcall
|
||||
FuncID_morestack
|
||||
FuncID_mstart
|
||||
FuncID_rt0_go
|
||||
FuncID_asmcgocall
|
||||
FuncID_sigpanic
|
||||
FuncID_runfinq
|
||||
FuncID_gcBgMarkWorker
|
||||
FuncID_systemstack_switch
|
||||
FuncID_systemstack
|
||||
FuncID_cgocallback_gofunc
|
||||
FuncID_gogo
|
||||
FuncID_externalthreadhandler
|
||||
FuncID_debugCallV1
|
||||
FuncID_gopanic
|
||||
FuncID_panicwrap
|
||||
FuncID_handleAsyncEvent
|
||||
FuncID_asyncPreempt
|
||||
FuncID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.)
|
||||
)
|
||||
|
||||
// Get the function ID for the named function in the named file.
|
||||
// The function should be package-qualified.
|
||||
func GetFuncID(name string, isWrapper bool) FuncID {
|
||||
if isWrapper {
|
||||
return FuncID_wrapper
|
||||
}
|
||||
switch name {
|
||||
case "runtime.main":
|
||||
return FuncID_runtime_main
|
||||
case "runtime.goexit":
|
||||
return FuncID_goexit
|
||||
case "runtime.jmpdefer":
|
||||
return FuncID_jmpdefer
|
||||
case "runtime.mcall":
|
||||
return FuncID_mcall
|
||||
case "runtime.morestack":
|
||||
return FuncID_morestack
|
||||
case "runtime.mstart":
|
||||
return FuncID_mstart
|
||||
case "runtime.rt0_go":
|
||||
return FuncID_rt0_go
|
||||
case "runtime.asmcgocall":
|
||||
return FuncID_asmcgocall
|
||||
case "runtime.sigpanic":
|
||||
return FuncID_sigpanic
|
||||
case "runtime.runfinq":
|
||||
return FuncID_runfinq
|
||||
case "runtime.gcBgMarkWorker":
|
||||
return FuncID_gcBgMarkWorker
|
||||
case "runtime.systemstack_switch":
|
||||
return FuncID_systemstack_switch
|
||||
case "runtime.systemstack":
|
||||
return FuncID_systemstack
|
||||
case "runtime.cgocallback_gofunc":
|
||||
return FuncID_cgocallback_gofunc
|
||||
case "runtime.gogo":
|
||||
return FuncID_gogo
|
||||
case "runtime.externalthreadhandler":
|
||||
return FuncID_externalthreadhandler
|
||||
case "runtime.debugCallV1":
|
||||
return FuncID_debugCallV1
|
||||
case "runtime.gopanic":
|
||||
return FuncID_gopanic
|
||||
case "runtime.panicwrap":
|
||||
return FuncID_panicwrap
|
||||
case "runtime.handleAsyncEvent":
|
||||
return FuncID_handleAsyncEvent
|
||||
case "runtime.asyncPreempt":
|
||||
return FuncID_asyncPreempt
|
||||
case "runtime.deferreturn":
|
||||
// Don't show in the call stack (used when invoking defer functions)
|
||||
return FuncID_wrapper
|
||||
case "runtime.runOpenDeferFrame":
|
||||
// Don't show in the call stack (used when invoking defer functions)
|
||||
return FuncID_wrapper
|
||||
case "runtime.reflectcallSave":
|
||||
// Don't show in the call stack (used when invoking defer functions)
|
||||
return FuncID_wrapper
|
||||
}
|
||||
return FuncID_normal
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
// Derived from Inferno utils/6l/l.h and related files.
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package objabi
|
||||
|
||||
import "fmt"
|
||||
|
||||
// HeadType is the executable header type.
|
||||
type HeadType uint8
|
||||
|
||||
const (
|
||||
Hunknown HeadType = iota
|
||||
Hdarwin
|
||||
Hdragonfly
|
||||
Hfreebsd
|
||||
Hjs
|
||||
Hlinux
|
||||
Hnetbsd
|
||||
Hopenbsd
|
||||
Hplan9
|
||||
Hsolaris
|
||||
Hwindows
|
||||
Haix
|
||||
)
|
||||
|
||||
func (h *HeadType) Set(s string) error {
|
||||
switch s {
|
||||
case "aix":
|
||||
*h = Haix
|
||||
case "darwin":
|
||||
*h = Hdarwin
|
||||
case "dragonfly":
|
||||
*h = Hdragonfly
|
||||
case "freebsd":
|
||||
*h = Hfreebsd
|
||||
case "js":
|
||||
*h = Hjs
|
||||
case "linux", "android":
|
||||
*h = Hlinux
|
||||
case "netbsd":
|
||||
*h = Hnetbsd
|
||||
case "openbsd":
|
||||
*h = Hopenbsd
|
||||
case "plan9":
|
||||
*h = Hplan9
|
||||
case "illumos", "solaris":
|
||||
*h = Hsolaris
|
||||
case "windows":
|
||||
*h = Hwindows
|
||||
default:
|
||||
return fmt.Errorf("invalid headtype: %q", s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HeadType) String() string {
|
||||
switch *h {
|
||||
case Haix:
|
||||
return "aix"
|
||||
case Hdarwin:
|
||||
return "darwin"
|
||||
case Hdragonfly:
|
||||
return "dragonfly"
|
||||
case Hfreebsd:
|
||||
return "freebsd"
|
||||
case Hjs:
|
||||
return "js"
|
||||
case Hlinux:
|
||||
return "linux"
|
||||
case Hnetbsd:
|
||||
return "netbsd"
|
||||
case Hopenbsd:
|
||||
return "openbsd"
|
||||
case Hplan9:
|
||||
return "plan9"
|
||||
case Hsolaris:
|
||||
return "solaris"
|
||||
case Hwindows:
|
||||
return "windows"
|
||||
}
|
||||
return fmt.Sprintf("HeadType(%d)", *h)
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// WorkingDir returns the current working directory
|
||||
// (or "/???" if the directory cannot be identified),
|
||||
// with "/" as separator.
|
||||
func WorkingDir() string {
|
||||
var path string
|
||||
path, _ = os.Getwd()
|
||||
if path == "" {
|
||||
path = "/???"
|
||||
}
|
||||
return filepath.ToSlash(path)
|
||||
}
|
||||
|
||||
// AbsFile returns the absolute filename for file in the given directory,
|
||||
// as rewritten by the rewrites argument.
|
||||
// For unrewritten paths, AbsFile rewrites a leading $GOROOT prefix to the literal "$GOROOT".
|
||||
// If the resulting path is the empty string, the result is "??".
|
||||
//
|
||||
// The rewrites argument is a ;-separated list of rewrites.
|
||||
// Each rewrite is of the form "prefix" or "prefix=>replace",
|
||||
// where prefix must match a leading sequence of path elements
|
||||
// and is either removed entirely or replaced by the replacement.
|
||||
func AbsFile(dir, file, rewrites string) string {
|
||||
abs := file
|
||||
if dir != "" && !filepath.IsAbs(file) {
|
||||
abs = filepath.Join(dir, file)
|
||||
}
|
||||
|
||||
start := 0
|
||||
for i := 0; i <= len(rewrites); i++ {
|
||||
if i == len(rewrites) || rewrites[i] == ';' {
|
||||
if new, ok := applyRewrite(abs, rewrites[start:i]); ok {
|
||||
abs = new
|
||||
goto Rewritten
|
||||
}
|
||||
start = i + 1
|
||||
}
|
||||
}
|
||||
if hasPathPrefix(abs, GOROOT) {
|
||||
abs = "$GOROOT" + abs[len(GOROOT):]
|
||||
}
|
||||
|
||||
Rewritten:
|
||||
if abs == "" {
|
||||
abs = "??"
|
||||
}
|
||||
return abs
|
||||
}
|
||||
|
||||
// applyRewrite applies the rewrite to the path,
|
||||
// returning the rewritten path and a boolean
|
||||
// indicating whether the rewrite applied at all.
|
||||
func applyRewrite(path, rewrite string) (string, bool) {
|
||||
prefix, replace := rewrite, ""
|
||||
if j := strings.LastIndex(rewrite, "=>"); j >= 0 {
|
||||
prefix, replace = rewrite[:j], rewrite[j+len("=>"):]
|
||||
}
|
||||
|
||||
if prefix == "" || !hasPathPrefix(path, prefix) {
|
||||
return path, false
|
||||
}
|
||||
if len(path) == len(prefix) {
|
||||
return replace, true
|
||||
}
|
||||
if replace == "" {
|
||||
return path[len(prefix)+1:], true
|
||||
}
|
||||
return replace + path[len(prefix):], true
|
||||
}
|
||||
|
||||
// Does s have t as a path prefix?
|
||||
// That is, does s == t or does s begin with t followed by a slash?
|
||||
// For portability, we allow ASCII case folding, so that hasPathPrefix("a/b/c", "A/B") is true.
|
||||
// Similarly, we allow slash folding, so that hasPathPrefix("a/b/c", "a\\b") is true.
|
||||
// We do not allow full Unicode case folding, for fear of causing more confusion
|
||||
// or harm than good. (For an example of the kinds of things that can go wrong,
|
||||
// see http://article.gmane.org/gmane.linux.kernel/1853266.)
|
||||
func hasPathPrefix(s string, t string) bool {
|
||||
if len(t) > len(s) {
|
||||
return false
|
||||
}
|
||||
var i int
|
||||
for i = 0; i < len(t); i++ {
|
||||
cs := int(s[i])
|
||||
ct := int(t[i])
|
||||
if 'A' <= cs && cs <= 'Z' {
|
||||
cs += 'a' - 'A'
|
||||
}
|
||||
if 'A' <= ct && ct <= 'Z' {
|
||||
ct += 'a' - 'A'
|
||||
}
|
||||
if cs == '\\' {
|
||||
cs = '/'
|
||||
}
|
||||
if ct == '\\' {
|
||||
ct = '/'
|
||||
}
|
||||
if cs != ct {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return i >= len(s) || s[i] == '/' || s[i] == '\\'
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
import "strings"
|
||||
|
||||
// PathToPrefix converts raw string to the prefix that will be used in the
|
||||
// symbol table. All control characters, space, '%' and '"', as well as
|
||||
// non-7-bit clean bytes turn into %xx. The period needs escaping only in the
|
||||
// last segment of the path, and it makes for happier users if we escape that as
|
||||
// little as possible.
|
||||
func PathToPrefix(s string) string {
|
||||
slash := strings.LastIndex(s, "/")
|
||||
// check for chars that need escaping
|
||||
n := 0
|
||||
for r := 0; r < len(s); r++ {
|
||||
if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
// quick exit
|
||||
if n == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
// escape
|
||||
const hex = "0123456789abcdef"
|
||||
p := make([]byte, 0, len(s)+2*n)
|
||||
for r := 0; r < len(s); r++ {
|
||||
if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
|
||||
p = append(p, '%', hex[c>>4], hex[c&0xF])
|
||||
} else {
|
||||
p = append(p, c)
|
||||
}
|
||||
}
|
||||
|
||||
return string(p)
|
||||
}
|
||||
Generated
Vendored
+269
@@ -0,0 +1,269 @@
|
||||
// Derived from Inferno utils/6l/l.h and related files.
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package objabi
|
||||
|
||||
type RelocType int16
|
||||
|
||||
//go:generate stringer -type=RelocType
|
||||
const (
|
||||
R_ADDR RelocType = 1 + iota
|
||||
// R_ADDRPOWER relocates a pair of "D-form" instructions (instructions with 16-bit
|
||||
// immediates in the low half of the instruction word), usually addis followed by
|
||||
// another add or a load, inserting the "high adjusted" 16 bits of the address of
|
||||
// the referenced symbol into the immediate field of the first instruction and the
|
||||
// low 16 bits into that of the second instruction.
|
||||
R_ADDRPOWER
|
||||
// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
|
||||
// referenced symbol.
|
||||
R_ADDRARM64
|
||||
// R_ADDRMIPS (only used on mips/mips64) resolves to the low 16 bits of an external
|
||||
// address, by encoding it into the instruction.
|
||||
R_ADDRMIPS
|
||||
// R_ADDROFF resolves to a 32-bit offset from the beginning of the section
|
||||
// holding the data being relocated to the referenced symbol.
|
||||
R_ADDROFF
|
||||
// R_WEAKADDROFF resolves just like R_ADDROFF but is a weak relocation.
|
||||
// A weak relocation does not make the symbol it refers to reachable,
|
||||
// and is only honored by the linker if the symbol is in some other way
|
||||
// reachable.
|
||||
R_WEAKADDROFF
|
||||
R_SIZE
|
||||
R_CALL
|
||||
R_CALLARM
|
||||
R_CALLARM64
|
||||
R_CALLIND
|
||||
R_CALLPOWER
|
||||
// R_CALLMIPS (only used on mips64) resolves to non-PC-relative target address
|
||||
// of a CALL (JAL) instruction, by encoding the address into the instruction.
|
||||
R_CALLMIPS
|
||||
// R_CALLRISCV marks RISC-V CALLs for stack checking.
|
||||
R_CALLRISCV
|
||||
R_CONST
|
||||
R_PCREL
|
||||
// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
|
||||
// thread-local symbol from the thread local base and is used to implement the
|
||||
// "local exec" model for tls access (r.Sym is not set on intel platforms but is
|
||||
// set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking).
|
||||
R_TLS_LE
|
||||
// R_TLS_IE, used 386, amd64, and ARM resolves to the PC-relative offset to a GOT
|
||||
// slot containing the offset from the thread-local symbol from the thread local
|
||||
// base and is used to implemented the "initial exec" model for tls access (r.Sym
|
||||
// is not set on intel platforms but is set to a TLS symbol -- runtime.tlsg -- in
|
||||
// the linker when externally linking).
|
||||
R_TLS_IE
|
||||
R_GOTOFF
|
||||
R_PLT0
|
||||
R_PLT1
|
||||
R_PLT2
|
||||
R_USEFIELD
|
||||
// R_USETYPE resolves to an *rtype, but no relocation is created. The
|
||||
// linker uses this as a signal that the pointed-to type information
|
||||
// should be linked into the final binary, even if there are no other
|
||||
// direct references. (This is used for types reachable by reflection.)
|
||||
R_USETYPE
|
||||
// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
|
||||
// holding the data being relocated to the referenced symbol.
|
||||
// It is a variant of R_ADDROFF used when linking from the uncommonType of a
|
||||
// *rtype, and may be set to zero by the linker if it determines the method
|
||||
// text is unreachable by the linked program.
|
||||
R_METHODOFF
|
||||
R_POWER_TOC
|
||||
R_GOTPCREL
|
||||
// R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address
|
||||
// of a JMP instruction, by encoding the address into the instruction.
|
||||
// The stack nosplit check ignores this since it is not a function call.
|
||||
R_JMPMIPS
|
||||
|
||||
// R_DWARFSECREF resolves to the offset of the symbol from its section.
|
||||
// Target of relocation must be size 4 (in current implementation).
|
||||
R_DWARFSECREF
|
||||
|
||||
// R_DWARFFILEREF resolves to an index into the DWARF .debug_line
|
||||
// file table for the specified file symbol. Must be applied to an
|
||||
// attribute of form DW_FORM_data4.
|
||||
R_DWARFFILEREF
|
||||
|
||||
// Platform dependent relocations. Architectures with fixed width instructions
|
||||
// have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be
|
||||
// stuffed into a 32-bit instruction, so an address needs to be spread across
|
||||
// several instructions, and in turn this requires a sequence of relocations, each
|
||||
// updating a part of an instruction. This leads to relocation codes that are
|
||||
// inherently processor specific.
|
||||
|
||||
// Arm64.
|
||||
|
||||
// Set a MOV[NZ] immediate field to bits [15:0] of the offset from the thread
|
||||
// local base to the thread local variable defined by the referenced (thread
|
||||
// local) symbol. Error if the offset does not fit into 16 bits.
|
||||
R_ARM64_TLS_LE
|
||||
|
||||
// Relocates an ADRP; LD64 instruction sequence to load the offset between
|
||||
// the thread local base and the thread local variable defined by the
|
||||
// referenced (thread local) symbol from the GOT.
|
||||
R_ARM64_TLS_IE
|
||||
|
||||
// R_ARM64_GOTPCREL relocates an adrp, ld64 pair to compute the address of the GOT
|
||||
// slot of the referenced symbol.
|
||||
R_ARM64_GOTPCREL
|
||||
|
||||
// R_ARM64_GOT resolves a GOT-relative instruction sequence, usually an adrp
|
||||
// followed by another ld instruction.
|
||||
R_ARM64_GOT
|
||||
|
||||
// R_ARM64_PCREL resolves a PC-relative addresses instruction sequence, usually an
|
||||
// adrp followed by another add instruction.
|
||||
R_ARM64_PCREL
|
||||
|
||||
// R_ARM64_LDST8 sets a LD/ST immediate value to bits [11:0] of a local address.
|
||||
R_ARM64_LDST8
|
||||
|
||||
// R_ARM64_LDST32 sets a LD/ST immediate value to bits [11:2] of a local address.
|
||||
R_ARM64_LDST32
|
||||
|
||||
// R_ARM64_LDST64 sets a LD/ST immediate value to bits [11:3] of a local address.
|
||||
R_ARM64_LDST64
|
||||
|
||||
// R_ARM64_LDST128 sets a LD/ST immediate value to bits [11:4] of a local address.
|
||||
R_ARM64_LDST128
|
||||
|
||||
// PPC64.
|
||||
|
||||
// R_POWER_TLS_LE is used to implement the "local exec" model for tls
|
||||
// access. It resolves to the offset of the thread-local symbol from the
|
||||
// thread pointer (R13) and inserts this value into the low 16 bits of an
|
||||
// instruction word.
|
||||
R_POWER_TLS_LE
|
||||
|
||||
// R_POWER_TLS_IE is used to implement the "initial exec" model for tls access. It
|
||||
// relocates a D-form, DS-form instruction sequence like R_ADDRPOWER_DS. It
|
||||
// inserts to the offset of GOT slot for the thread-local symbol from the TOC (the
|
||||
// GOT slot is filled by the dynamic linker with the offset of the thread-local
|
||||
// symbol from the thread pointer (R13)).
|
||||
R_POWER_TLS_IE
|
||||
|
||||
// R_POWER_TLS marks an X-form instruction such as "MOVD 0(R13)(R31*1), g" as
|
||||
// accessing a particular thread-local symbol. It does not affect code generation
|
||||
// but is used by the system linker when relaxing "initial exec" model code to
|
||||
// "local exec" model code.
|
||||
R_POWER_TLS
|
||||
|
||||
// R_ADDRPOWER_DS is similar to R_ADDRPOWER above, but assumes the second
|
||||
// instruction is a "DS-form" instruction, which has an immediate field occupying
|
||||
// bits [15:2] of the instruction word. Bits [15:2] of the address of the
|
||||
// relocated symbol are inserted into this field; it is an error if the last two
|
||||
// bits of the address are not 0.
|
||||
R_ADDRPOWER_DS
|
||||
|
||||
// R_ADDRPOWER_PCREL relocates a D-form, DS-form instruction sequence like
|
||||
// R_ADDRPOWER_DS but inserts the offset of the GOT slot for the referenced symbol
|
||||
// from the TOC rather than the symbol's address.
|
||||
R_ADDRPOWER_GOT
|
||||
|
||||
// R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but
|
||||
// inserts the displacement from the place being relocated to the address of the
|
||||
// relocated symbol instead of just its address.
|
||||
R_ADDRPOWER_PCREL
|
||||
|
||||
// R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but
|
||||
// inserts the offset from the TOC to the address of the relocated symbol
|
||||
// rather than the symbol's address.
|
||||
R_ADDRPOWER_TOCREL
|
||||
|
||||
// R_ADDRPOWER_TOCREL relocates a D-form, DS-form instruction sequence like
|
||||
// R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the
|
||||
// relocated symbol rather than the symbol's address.
|
||||
R_ADDRPOWER_TOCREL_DS
|
||||
|
||||
// RISC-V.
|
||||
|
||||
// R_RISCV_PCREL_ITYPE resolves a 32-bit PC-relative address using an
|
||||
// AUIPC + I-type instruction pair.
|
||||
R_RISCV_PCREL_ITYPE
|
||||
|
||||
// R_RISCV_PCREL_STYPE resolves a 32-bit PC-relative address using an
|
||||
// AUIPC + S-type instruction pair.
|
||||
R_RISCV_PCREL_STYPE
|
||||
|
||||
// R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses.
|
||||
// TODO(mundaym): remove once variants can be serialized - see issue 14218.
|
||||
R_PCRELDBL
|
||||
|
||||
// R_ADDRMIPSU (only used on mips/mips64) resolves to the sign-adjusted "upper" 16
|
||||
// bits (bit 16-31) of an external address, by encoding it into the instruction.
|
||||
R_ADDRMIPSU
|
||||
// R_ADDRMIPSTLS (only used on mips64) resolves to the low 16 bits of a TLS
|
||||
// address (offset from thread pointer), by encoding it into the instruction.
|
||||
R_ADDRMIPSTLS
|
||||
|
||||
// R_ADDRCUOFF resolves to a pointer-sized offset from the start of the
|
||||
// symbol's DWARF compile unit.
|
||||
R_ADDRCUOFF
|
||||
|
||||
// R_WASMIMPORT resolves to the index of the WebAssembly function import.
|
||||
R_WASMIMPORT
|
||||
|
||||
// R_XCOFFREF (only used on aix/ppc64) prevents garbage collection by ld
|
||||
// of a symbol. This isn't a real relocation, it can be placed in anywhere
|
||||
// in a symbol and target any symbols.
|
||||
R_XCOFFREF
|
||||
)
|
||||
|
||||
// IsDirectCall reports whether r is a relocation for a direct call.
|
||||
// A direct call is a CALL instruction that takes the target address
|
||||
// as an immediate. The address is embedded into the instruction, possibly
|
||||
// with limited width. An indirect call is a CALL instruction that takes
|
||||
// the target address in register or memory.
|
||||
func (r RelocType) IsDirectCall() bool {
|
||||
switch r {
|
||||
case R_CALL, R_CALLARM, R_CALLARM64, R_CALLMIPS, R_CALLPOWER, R_CALLRISCV:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsDirectJump reports whether r is a relocation for a direct jump.
|
||||
// A direct jump is a JMP instruction that takes the target address
|
||||
// as an immediate. The address is embedded into the instruction, possibly
|
||||
// with limited width. An indirect jump is a JMP instruction that takes
|
||||
// the target address in register or memory.
|
||||
func (r RelocType) IsDirectJump() bool {
|
||||
switch r {
|
||||
case R_JMPMIPS:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsDirectCallOrJump reports whether r is a relocation for a direct
|
||||
// call or a direct jump.
|
||||
func (r RelocType) IsDirectCallOrJump() bool {
|
||||
return r.IsDirectCall() || r.IsDirectJump()
|
||||
}
|
||||
Generated
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
// Code generated by "stringer -type=RelocType"; DO NOT EDIT.
|
||||
|
||||
package objabi
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
|
||||
|
||||
var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 219, 230, 240, 249, 262, 276, 290, 304, 320, 331, 344, 357, 371, 385, 400, 414, 428, 439, 453, 468, 485, 503, 524, 543, 562, 572, 583, 596, 607, 619, 629}
|
||||
|
||||
func (i RelocType) String() string {
|
||||
i -= 1
|
||||
if i < 0 || i >= RelocType(len(_RelocType_index)-1) {
|
||||
return "RelocType(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||
}
|
||||
return _RelocType_name[_RelocType_index[i]:_RelocType_index[i+1]]
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
// For the linkers. Must match Go definitions.
|
||||
|
||||
const (
|
||||
STACKSYSTEM = 0
|
||||
StackSystem = STACKSYSTEM
|
||||
StackBig = 4096
|
||||
StackSmall = 128
|
||||
)
|
||||
|
||||
const (
|
||||
StackPreempt = -1314 // 0xfff...fade
|
||||
)
|
||||
|
||||
// Initialize StackGuard and StackLimit according to target system.
|
||||
var StackGuard = 928*stackGuardMultiplier() + StackSystem
|
||||
var StackLimit = StackGuard - StackSystem - StackSmall
|
||||
|
||||
// stackGuardMultiplier returns a multiplier to apply to the default
|
||||
// stack guard size. Larger multipliers are used for non-optimized
|
||||
// builds that have larger stack frames or for specific targets.
|
||||
func stackGuardMultiplier() int {
|
||||
// On AIX, a larger stack is needed for syscalls.
|
||||
if GOOS == "aix" {
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
// Derived from Inferno utils/6l/l.h and related files.
|
||||
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package objabi
|
||||
|
||||
// A SymKind describes the kind of memory represented by a symbol.
|
||||
type SymKind uint8
|
||||
|
||||
// Defined SymKind values.
|
||||
// These are used to index into cmd/link/internal/sym/AbiSymKindToSymKind
|
||||
//
|
||||
// TODO(rsc): Give idiomatic Go names.
|
||||
//go:generate stringer -type=SymKind
|
||||
const (
|
||||
// An otherwise invalid zero value for the type
|
||||
Sxxx SymKind = iota
|
||||
// Executable instructions
|
||||
STEXT
|
||||
// Read only static data
|
||||
SRODATA
|
||||
// Static data that does not contain any pointers
|
||||
SNOPTRDATA
|
||||
// Static data
|
||||
SDATA
|
||||
// Statically data that is initially all 0s
|
||||
SBSS
|
||||
// Statically data that is initially all 0s and does not contain pointers
|
||||
SNOPTRBSS
|
||||
// Thread-local data that is initially all 0s
|
||||
STLSBSS
|
||||
// Debugging data
|
||||
SDWARFCUINFO
|
||||
SDWARFCONST
|
||||
SDWARFFCN
|
||||
SDWARFABSFCN
|
||||
SDWARFTYPE
|
||||
SDWARFVAR
|
||||
SDWARFRANGE
|
||||
SDWARFLOC
|
||||
SDWARFLINES
|
||||
// ABI alias. An ABI alias symbol is an empty symbol with a
|
||||
// single relocation with 0 size that references the native
|
||||
// function implementation symbol.
|
||||
//
|
||||
// TODO(austin): Remove this and all uses once the compiler
|
||||
// generates real ABI wrappers rather than symbol aliases.
|
||||
SABIALIAS
|
||||
// Coverage instrumentation counter for libfuzzer.
|
||||
SLIBFUZZER_EXTRA_COUNTER
|
||||
// Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.
|
||||
|
||||
)
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
// Code generated by "stringer -type=SymKind"; DO NOT EDIT.
|
||||
|
||||
package objabi
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Sxxx-0]
|
||||
_ = x[STEXT-1]
|
||||
_ = x[SRODATA-2]
|
||||
_ = x[SNOPTRDATA-3]
|
||||
_ = x[SDATA-4]
|
||||
_ = x[SBSS-5]
|
||||
_ = x[SNOPTRBSS-6]
|
||||
_ = x[STLSBSS-7]
|
||||
_ = x[SDWARFCUINFO-8]
|
||||
_ = x[SDWARFCONST-9]
|
||||
_ = x[SDWARFFCN-10]
|
||||
_ = x[SDWARFABSFCN-11]
|
||||
_ = x[SDWARFTYPE-12]
|
||||
_ = x[SDWARFVAR-13]
|
||||
_ = x[SDWARFRANGE-14]
|
||||
_ = x[SDWARFLOC-15]
|
||||
_ = x[SDWARFLINES-16]
|
||||
_ = x[SABIALIAS-17]
|
||||
_ = x[SLIBFUZZER_EXTRA_COUNTER-18]
|
||||
}
|
||||
|
||||
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSABIALIASSLIBFUZZER_EXTRA_COUNTER"
|
||||
|
||||
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 63, 74, 83, 95, 105, 114, 125, 134, 145, 154, 178}
|
||||
|
||||
func (i SymKind) String() string {
|
||||
if i >= SymKind(len(_SymKind_index)-1) {
|
||||
return "SymKind(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]]
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
// Must match runtime and reflect.
|
||||
// Included by cmd/gc.
|
||||
|
||||
const (
|
||||
KindBool = 1 + iota
|
||||
KindInt
|
||||
KindInt8
|
||||
KindInt16
|
||||
KindInt32
|
||||
KindInt64
|
||||
KindUint
|
||||
KindUint8
|
||||
KindUint16
|
||||
KindUint32
|
||||
KindUint64
|
||||
KindUintptr
|
||||
KindFloat32
|
||||
KindFloat64
|
||||
KindComplex64
|
||||
KindComplex128
|
||||
KindArray
|
||||
KindChan
|
||||
KindFunc
|
||||
KindInterface
|
||||
KindMap
|
||||
KindPtr
|
||||
KindSlice
|
||||
KindString
|
||||
KindStruct
|
||||
KindUnsafePointer
|
||||
KindDirectIface = 1 << 5
|
||||
KindGCProg = 1 << 6
|
||||
KindMask = (1 << 5) - 1
|
||||
)
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package objabi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func envOr(key, value string) string {
|
||||
if x := os.Getenv(key); x != "" {
|
||||
return x
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
var (
|
||||
defaultGOROOT string // set by linker
|
||||
|
||||
GOROOT = envOr("GOROOT", defaultGOROOT)
|
||||
GOARCH = envOr("GOARCH", "amd64")
|
||||
GOOS = envOr("GOOS", "linux")
|
||||
GO386 = envOr("GO386", "")
|
||||
GOAMD64 = goamd64()
|
||||
GOARM = goarm()
|
||||
GOMIPS = gomips()
|
||||
GOMIPS64 = gomips64()
|
||||
GOPPC64 = goppc64()
|
||||
GOWASM = gowasm()
|
||||
GO_LDSO = ""
|
||||
Version = ""
|
||||
)
|
||||
|
||||
const (
|
||||
ElfRelocOffset = 256
|
||||
MachoRelocOffset = 2048 // reserve enough space for ELF relocations
|
||||
Go115AMD64 = "alignedjumps" // Should be "alignedjumps" or "normaljumps"; this replaces environment variable introduced in CL 219357.
|
||||
)
|
||||
|
||||
// TODO(1.16): assuming no issues in 1.15 release, remove this and related constant.
|
||||
func goamd64() string {
|
||||
return Go115AMD64
|
||||
}
|
||||
|
||||
func goarm() int {
|
||||
switch v := envOr("GOARM", "7"); v {
|
||||
case "5":
|
||||
return 5
|
||||
case "6":
|
||||
return 6
|
||||
case "7":
|
||||
return 7
|
||||
}
|
||||
// Fail here, rather than validate at multiple call sites.
|
||||
log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func gomips() string {
|
||||
switch v := envOr("GOMIPS", "hardfloat"); v {
|
||||
case "hardfloat", "softfloat":
|
||||
return v
|
||||
}
|
||||
log.Fatalf("Invalid GOMIPS value. Must be hardfloat or softfloat.")
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func gomips64() string {
|
||||
switch v := envOr("GOMIPS64", "hardfloat"); v {
|
||||
case "hardfloat", "softfloat":
|
||||
return v
|
||||
}
|
||||
log.Fatalf("Invalid GOMIPS64 value. Must be hardfloat or softfloat.")
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func goppc64() int {
|
||||
switch v := envOr("GOPPC64", "power8"); v {
|
||||
case "power8":
|
||||
return 8
|
||||
case "power9":
|
||||
return 9
|
||||
}
|
||||
log.Fatalf("Invalid GOPPC64 value. Must be power8 or power9.")
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
type gowasmFeatures struct {
|
||||
SignExt bool
|
||||
SatConv bool
|
||||
}
|
||||
|
||||
func (f gowasmFeatures) String() string {
|
||||
var flags []string
|
||||
if f.SatConv {
|
||||
flags = append(flags, "satconv")
|
||||
}
|
||||
if f.SignExt {
|
||||
flags = append(flags, "signext")
|
||||
}
|
||||
return strings.Join(flags, ",")
|
||||
}
|
||||
|
||||
func gowasm() (f gowasmFeatures) {
|
||||
for _, opt := range strings.Split(envOr("GOWASM", ""), ",") {
|
||||
switch opt {
|
||||
case "satconv":
|
||||
f.SatConv = true
|
||||
case "signext":
|
||||
f.SignExt = true
|
||||
case "":
|
||||
// ignore
|
||||
default:
|
||||
log.Fatalf("Invalid GOWASM value. No such feature: " + opt)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Getgoextlinkenabled() string {
|
||||
return envOr("GO_EXTLINK_ENABLED", "")
|
||||
}
|
||||
|
||||
func init() {
|
||||
for _, f := range strings.Split("", ",") {
|
||||
if f != "" {
|
||||
addexp(f)
|
||||
}
|
||||
}
|
||||
|
||||
// regabi is only supported on amd64.
|
||||
if GOARCH != "amd64" {
|
||||
Regabi_enabled = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Note: must agree with runtime.framepointer_enabled.
|
||||
var Framepointer_enabled = GOARCH == "amd64" || GOARCH == "arm64" && (GOOS == "linux" || GOOS == "darwin")
|
||||
|
||||
func addexp(s string) {
|
||||
// Could do general integer parsing here, but the runtime copy doesn't yet.
|
||||
v := 1
|
||||
name := s
|
||||
if len(name) > 2 && name[:2] == "no" {
|
||||
v = 0
|
||||
name = name[2:]
|
||||
}
|
||||
for i := 0; i < len(exper); i++ {
|
||||
if exper[i].name == name {
|
||||
if exper[i].val != nil {
|
||||
*exper[i].val = v
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("unknown experiment %s\n", s)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
var (
|
||||
Fieldtrack_enabled int
|
||||
Preemptibleloops_enabled int
|
||||
Staticlockranking_enabled int
|
||||
Regabi_enabled int
|
||||
)
|
||||
|
||||
// Toolchain experiments.
|
||||
// These are controlled by the GOEXPERIMENT environment
|
||||
// variable recorded when the toolchain is built.
|
||||
// This list is also known to cmd/gc.
|
||||
var exper = []struct {
|
||||
name string
|
||||
val *int
|
||||
}{
|
||||
{"fieldtrack", &Fieldtrack_enabled},
|
||||
{"preemptibleloops", &Preemptibleloops_enabled},
|
||||
{"staticlockranking", &Staticlockranking_enabled},
|
||||
{"regabi", &Regabi_enabled},
|
||||
}
|
||||
|
||||
var defaultExpstring = Expstring()
|
||||
|
||||
func DefaultExpstring() string {
|
||||
return defaultExpstring
|
||||
}
|
||||
|
||||
func Expstring() string {
|
||||
buf := "X"
|
||||
for i := range exper {
|
||||
if *exper[i].val != 0 {
|
||||
buf += "," + exper[i].name
|
||||
}
|
||||
}
|
||||
if buf == "X" {
|
||||
buf += ",none"
|
||||
}
|
||||
return "X:" + buf[2:]
|
||||
}
|
||||
+470
@@ -0,0 +1,470 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file implements the encoding of source positions.
|
||||
|
||||
package src
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A Pos encodes a source position consisting of a (line, column) number pair
|
||||
// and a position base. A zero Pos is a ready to use "unknown" position (nil
|
||||
// position base and zero line number).
|
||||
//
|
||||
// The (line, column) values refer to a position in a file independent of any
|
||||
// position base ("absolute" file position).
|
||||
//
|
||||
// The position base is used to determine the "relative" position, that is the
|
||||
// filename and line number relative to the position base. If the base refers
|
||||
// to the current file, there is no difference between absolute and relative
|
||||
// positions. If it refers to a //line directive, a relative position is relative
|
||||
// to that directive. A position base in turn contains the position at which it
|
||||
// was introduced in the current file.
|
||||
type Pos struct {
|
||||
base *PosBase
|
||||
lico
|
||||
}
|
||||
|
||||
// NoPos is a valid unknown position.
|
||||
var NoPos Pos
|
||||
|
||||
// MakePos creates a new Pos value with the given base, and (file-absolute)
|
||||
// line and column.
|
||||
func MakePos(base *PosBase, line, col uint) Pos {
|
||||
return Pos{base, makeLico(line, col)}
|
||||
}
|
||||
|
||||
// IsKnown reports whether the position p is known.
|
||||
// A position is known if it either has a non-nil
|
||||
// position base, or a non-zero line number.
|
||||
func (p Pos) IsKnown() bool {
|
||||
return p.base != nil || p.Line() != 0
|
||||
}
|
||||
|
||||
// Before reports whether the position p comes before q in the source.
|
||||
// For positions in different files, ordering is by filename.
|
||||
func (p Pos) Before(q Pos) bool {
|
||||
n, m := p.Filename(), q.Filename()
|
||||
return n < m || n == m && p.lico < q.lico
|
||||
}
|
||||
|
||||
// After reports whether the position p comes after q in the source.
|
||||
// For positions in different files, ordering is by filename.
|
||||
func (p Pos) After(q Pos) bool {
|
||||
n, m := p.Filename(), q.Filename()
|
||||
return n > m || n == m && p.lico > q.lico
|
||||
}
|
||||
|
||||
func (p Pos) LineNumber() string {
|
||||
if !p.IsKnown() {
|
||||
return "?"
|
||||
}
|
||||
return p.lico.lineNumber()
|
||||
}
|
||||
|
||||
func (p Pos) LineNumberHTML() string {
|
||||
if !p.IsKnown() {
|
||||
return "?"
|
||||
}
|
||||
return p.lico.lineNumberHTML()
|
||||
}
|
||||
|
||||
// Filename returns the name of the actual file containing this position.
|
||||
func (p Pos) Filename() string { return p.base.Pos().RelFilename() }
|
||||
|
||||
// Base returns the position base.
|
||||
func (p Pos) Base() *PosBase { return p.base }
|
||||
|
||||
// SetBase sets the position base.
|
||||
func (p *Pos) SetBase(base *PosBase) { p.base = base }
|
||||
|
||||
// RelFilename returns the filename recorded with the position's base.
|
||||
func (p Pos) RelFilename() string { return p.base.Filename() }
|
||||
|
||||
// RelLine returns the line number relative to the position's base.
|
||||
func (p Pos) RelLine() uint {
|
||||
b := p.base
|
||||
if b.Line() == 0 {
|
||||
// base line is unknown => relative line is unknown
|
||||
return 0
|
||||
}
|
||||
return b.Line() + (p.Line() - b.Pos().Line())
|
||||
}
|
||||
|
||||
// RelCol returns the column number relative to the position's base.
|
||||
func (p Pos) RelCol() uint {
|
||||
b := p.base
|
||||
if b.Col() == 0 {
|
||||
// base column is unknown => relative column is unknown
|
||||
// (the current specification for line directives requires
|
||||
// this to apply until the next PosBase/line directive,
|
||||
// not just until the new newline)
|
||||
return 0
|
||||
}
|
||||
if p.Line() == b.Pos().Line() {
|
||||
// p on same line as p's base => column is relative to p's base
|
||||
return b.Col() + (p.Col() - b.Pos().Col())
|
||||
}
|
||||
return p.Col()
|
||||
}
|
||||
|
||||
// AbsFilename() returns the absolute filename recorded with the position's base.
|
||||
func (p Pos) AbsFilename() string { return p.base.AbsFilename() }
|
||||
|
||||
// SymFilename() returns the absolute filename recorded with the position's base,
|
||||
// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol.
|
||||
func (p Pos) SymFilename() string { return p.base.SymFilename() }
|
||||
|
||||
func (p Pos) String() string {
|
||||
return p.Format(true, true)
|
||||
}
|
||||
|
||||
// Format formats a position as "filename:line" or "filename:line:column",
|
||||
// controlled by the showCol flag and if the column is known (!= 0).
|
||||
// For positions relative to line directives, the original position is
|
||||
// shown as well, as in "filename:line[origfile:origline:origcolumn] if
|
||||
// showOrig is set.
|
||||
func (p Pos) Format(showCol, showOrig bool) string {
|
||||
buf := new(bytes.Buffer)
|
||||
p.WriteTo(buf, showCol, showOrig)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// WriteTo a position to w, formatted as Format does.
|
||||
func (p Pos) WriteTo(w io.Writer, showCol, showOrig bool) {
|
||||
if !p.IsKnown() {
|
||||
io.WriteString(w, "<unknown line number>")
|
||||
return
|
||||
}
|
||||
|
||||
if b := p.base; b == b.Pos().base {
|
||||
// base is file base (incl. nil)
|
||||
format(w, p.Filename(), p.Line(), p.Col(), showCol)
|
||||
return
|
||||
}
|
||||
|
||||
// base is relative
|
||||
// Print the column only for the original position since the
|
||||
// relative position's column information may be bogus (it's
|
||||
// typically generated code and we can't say much about the
|
||||
// original source at that point but for the file:line info
|
||||
// that's provided via a line directive).
|
||||
// TODO(gri) This may not be true if we have an inlining base.
|
||||
// We may want to differentiate at some point.
|
||||
format(w, p.RelFilename(), p.RelLine(), p.RelCol(), showCol)
|
||||
if showOrig {
|
||||
io.WriteString(w, "[")
|
||||
format(w, p.Filename(), p.Line(), p.Col(), showCol)
|
||||
io.WriteString(w, "]")
|
||||
}
|
||||
}
|
||||
|
||||
// format formats a (filename, line, col) tuple as "filename:line" (showCol
|
||||
// is false or col == 0) or "filename:line:column" (showCol is true and col != 0).
|
||||
func format(w io.Writer, filename string, line, col uint, showCol bool) {
|
||||
io.WriteString(w, filename)
|
||||
io.WriteString(w, ":")
|
||||
fmt.Fprint(w, line)
|
||||
// col == 0 and col == colMax are interpreted as unknown column values
|
||||
if showCol && 0 < col && col < colMax {
|
||||
io.WriteString(w, ":")
|
||||
fmt.Fprint(w, col)
|
||||
}
|
||||
}
|
||||
|
||||
// formatstr wraps format to return a string.
|
||||
func formatstr(filename string, line, col uint, showCol bool) string {
|
||||
buf := new(bytes.Buffer)
|
||||
format(buf, filename, line, col, showCol)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PosBase
|
||||
|
||||
// A PosBase encodes a filename and base position.
|
||||
// Typically, each file and line directive introduce a PosBase.
|
||||
type PosBase struct {
|
||||
pos Pos // position at which the relative position is (line, col)
|
||||
filename string // file name used to open source file, for error messages
|
||||
absFilename string // absolute file name, for PC-Line tables
|
||||
symFilename string // cached symbol file name, to avoid repeated string concatenation
|
||||
line, col uint // relative line, column number at pos
|
||||
inl int // inlining index (see cmd/internal/obj/inl.go)
|
||||
}
|
||||
|
||||
// NewFileBase returns a new *PosBase for a file with the given (relative and
|
||||
// absolute) filenames.
|
||||
func NewFileBase(filename, absFilename string) *PosBase {
|
||||
base := &PosBase{
|
||||
filename: filename,
|
||||
absFilename: absFilename,
|
||||
symFilename: FileSymPrefix + absFilename,
|
||||
line: 1,
|
||||
col: 1,
|
||||
inl: -1,
|
||||
}
|
||||
base.pos = MakePos(base, 1, 1)
|
||||
return base
|
||||
}
|
||||
|
||||
// NewLinePragmaBase returns a new *PosBase for a line directive of the form
|
||||
// //line filename:line:col
|
||||
// /*line filename:line:col*/
|
||||
// at position pos.
|
||||
func NewLinePragmaBase(pos Pos, filename, absFilename string, line, col uint) *PosBase {
|
||||
return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line, col, -1}
|
||||
}
|
||||
|
||||
// NewInliningBase returns a copy of the old PosBase with the given inlining
|
||||
// index. If old == nil, the resulting PosBase has no filename.
|
||||
func NewInliningBase(old *PosBase, inlTreeIndex int) *PosBase {
|
||||
if old == nil {
|
||||
base := &PosBase{line: 1, col: 1, inl: inlTreeIndex}
|
||||
base.pos = MakePos(base, 1, 1)
|
||||
return base
|
||||
}
|
||||
copy := *old
|
||||
base := ©
|
||||
base.inl = inlTreeIndex
|
||||
if old == old.pos.base {
|
||||
base.pos.base = base
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
var noPos Pos
|
||||
|
||||
// Pos returns the position at which base is located.
|
||||
// If b == nil, the result is the zero position.
|
||||
func (b *PosBase) Pos() *Pos {
|
||||
if b != nil {
|
||||
return &b.pos
|
||||
}
|
||||
return &noPos
|
||||
}
|
||||
|
||||
// Filename returns the filename recorded with the base.
|
||||
// If b == nil, the result is the empty string.
|
||||
func (b *PosBase) Filename() string {
|
||||
if b != nil {
|
||||
return b.filename
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// AbsFilename returns the absolute filename recorded with the base.
|
||||
// If b == nil, the result is the empty string.
|
||||
func (b *PosBase) AbsFilename() string {
|
||||
if b != nil {
|
||||
return b.absFilename
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
const FileSymPrefix = "gofile.."
|
||||
|
||||
// SymFilename returns the absolute filename recorded with the base,
|
||||
// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol.
|
||||
// If b is nil, SymFilename returns FileSymPrefix + "??".
|
||||
func (b *PosBase) SymFilename() string {
|
||||
if b != nil {
|
||||
return b.symFilename
|
||||
}
|
||||
return FileSymPrefix + "??"
|
||||
}
|
||||
|
||||
// Line returns the line number recorded with the base.
|
||||
// If b == nil, the result is 0.
|
||||
func (b *PosBase) Line() uint {
|
||||
if b != nil {
|
||||
return b.line
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Col returns the column number recorded with the base.
|
||||
// If b == nil, the result is 0.
|
||||
func (b *PosBase) Col() uint {
|
||||
if b != nil {
|
||||
return b.col
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// InliningIndex returns the index into the global inlining
|
||||
// tree recorded with the base. If b == nil or the base has
|
||||
// not been inlined, the result is < 0.
|
||||
func (b *PosBase) InliningIndex() int {
|
||||
if b != nil {
|
||||
return b.inl
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// lico
|
||||
|
||||
// A lico is a compact encoding of a LIne and COlumn number.
|
||||
type lico uint32
|
||||
|
||||
// Layout constants: 20 bits for line, 8 bits for column, 2 for isStmt, 2 for pro/epilogue
|
||||
// (If this is too tight, we can either make lico 64b wide,
|
||||
// or we can introduce a tiered encoding where we remove column
|
||||
// information as line numbers grow bigger; similar to what gcc
|
||||
// does.)
|
||||
// The bitfield order is chosen to make IsStmt be the least significant
|
||||
// part of a position; its use is to communicate statement edges through
|
||||
// instruction scrambling in code generation, not to impose an order.
|
||||
// TODO: Prologue and epilogue are perhaps better handled as pseudo-ops for the assembler,
|
||||
// because they have almost no interaction with other uses of the position.
|
||||
const (
|
||||
lineBits, lineMax = 20, 1<<lineBits - 2
|
||||
bogusLine = 1 // Used to disrupt infinite loops to prevent debugger looping
|
||||
isStmtBits, isStmtMax = 2, 1<<isStmtBits - 1
|
||||
xlogueBits, xlogueMax = 2, 1<<xlogueBits - 1
|
||||
colBits, colMax = 32 - lineBits - xlogueBits - isStmtBits, 1<<colBits - 1
|
||||
|
||||
isStmtShift = 0
|
||||
isStmtMask = isStmtMax << isStmtShift
|
||||
xlogueShift = isStmtBits + isStmtShift
|
||||
xlogueMask = xlogueMax << xlogueShift
|
||||
colShift = xlogueBits + xlogueShift
|
||||
lineShift = colBits + colShift
|
||||
)
|
||||
const (
|
||||
// It is expected that the front end or a phase in SSA will usually generate positions tagged with
|
||||
// PosDefaultStmt, but note statement boundaries with PosIsStmt. Simple statements will have a single
|
||||
// boundary; for loops with initialization may have one for their entry and one for their back edge
|
||||
// (this depends on exactly how the loop is compiled; the intent is to provide a good experience to a
|
||||
// user debugging a program; the goal is that a breakpoint set on the loop line fires both on entry
|
||||
// and on iteration). Proper treatment of non-gofmt input with multiple simple statements on a single
|
||||
// line is TBD.
|
||||
//
|
||||
// Optimizing compilation will move instructions around, and some of these will become known-bad as
|
||||
// step targets for debugging purposes (examples: register spills and reloads; code generated into
|
||||
// the entry block; invariant code hoisted out of loops) but those instructions will still have interesting
|
||||
// positions for profiling purposes. To reflect this these positions will be changed to PosNotStmt.
|
||||
//
|
||||
// When the optimizer removes an instruction marked PosIsStmt; it should attempt to find a nearby
|
||||
// instruction with the same line marked PosDefaultStmt to be the new statement boundary. I.e., the
|
||||
// optimizer should make a best-effort to conserve statement boundary positions, and might be enhanced
|
||||
// to note when a statement boundary is not conserved.
|
||||
//
|
||||
// Code cloning, e.g. loop unrolling or loop unswitching, is an exception to the conservation rule
|
||||
// because a user running a debugger would expect to see breakpoints active in the copies of the code.
|
||||
//
|
||||
// In non-optimizing compilation there is still a role for PosNotStmt because of code generation
|
||||
// into the entry block. PosIsStmt statement positions should be conserved.
|
||||
//
|
||||
// When code generation occurs any remaining default-marked positions are replaced with not-statement
|
||||
// positions.
|
||||
//
|
||||
PosDefaultStmt uint = iota // Default; position is not a statement boundary, but might be if optimization removes the designated statement boundary
|
||||
PosIsStmt // Position is a statement boundary; if optimization removes the corresponding instruction, it should attempt to find a new instruction to be the boundary.
|
||||
PosNotStmt // Position should not be a statement boundary, but line should be preserved for profiling and low-level debugging purposes.
|
||||
)
|
||||
|
||||
type PosXlogue uint
|
||||
|
||||
const (
|
||||
PosDefaultLogue PosXlogue = iota
|
||||
PosPrologueEnd
|
||||
PosEpilogueBegin
|
||||
)
|
||||
|
||||
func makeLicoRaw(line, col uint) lico {
|
||||
return lico(line<<lineShift | col<<colShift)
|
||||
}
|
||||
|
||||
// This is a not-position that will not be elided.
|
||||
// Depending on the debugger (gdb or delve) it may or may not be displayed.
|
||||
func makeBogusLico() lico {
|
||||
return makeLicoRaw(bogusLine, 0).withIsStmt()
|
||||
}
|
||||
|
||||
func makeLico(line, col uint) lico {
|
||||
if line > lineMax {
|
||||
// cannot represent line, use max. line so we have some information
|
||||
line = lineMax
|
||||
}
|
||||
if col > colMax {
|
||||
// cannot represent column, use max. column so we have some information
|
||||
col = colMax
|
||||
}
|
||||
// default is not-sure-if-statement
|
||||
return makeLicoRaw(line, col)
|
||||
}
|
||||
|
||||
func (x lico) Line() uint { return uint(x) >> lineShift }
|
||||
func (x lico) SameLine(y lico) bool { return 0 == (x^y)&^lico(1<<lineShift-1) }
|
||||
func (x lico) Col() uint { return uint(x) >> colShift & colMax }
|
||||
func (x lico) IsStmt() uint {
|
||||
if x == 0 {
|
||||
return PosNotStmt
|
||||
}
|
||||
return uint(x) >> isStmtShift & isStmtMax
|
||||
}
|
||||
func (x lico) Xlogue() PosXlogue {
|
||||
return PosXlogue(uint(x) >> xlogueShift & xlogueMax)
|
||||
}
|
||||
|
||||
// withNotStmt returns a lico for the same location, but not a statement
|
||||
func (x lico) withNotStmt() lico {
|
||||
return x.withStmt(PosNotStmt)
|
||||
}
|
||||
|
||||
// withDefaultStmt returns a lico for the same location, with default isStmt
|
||||
func (x lico) withDefaultStmt() lico {
|
||||
return x.withStmt(PosDefaultStmt)
|
||||
}
|
||||
|
||||
// withIsStmt returns a lico for the same location, tagged as definitely a statement
|
||||
func (x lico) withIsStmt() lico {
|
||||
return x.withStmt(PosIsStmt)
|
||||
}
|
||||
|
||||
// withLogue attaches a prologue/epilogue attribute to a lico
|
||||
func (x lico) withXlogue(xlogue PosXlogue) lico {
|
||||
if x == 0 {
|
||||
if xlogue == 0 {
|
||||
return x
|
||||
}
|
||||
// Normalize 0 to "not a statement"
|
||||
x = lico(PosNotStmt << isStmtShift)
|
||||
}
|
||||
return lico(uint(x) & ^uint(xlogueMax<<xlogueShift) | (uint(xlogue) << xlogueShift))
|
||||
}
|
||||
|
||||
// withStmt returns a lico for the same location with specified is_stmt attribute
|
||||
func (x lico) withStmt(stmt uint) lico {
|
||||
if x == 0 {
|
||||
return lico(0)
|
||||
}
|
||||
return lico(uint(x) & ^uint(isStmtMax<<isStmtShift) | (stmt << isStmtShift))
|
||||
}
|
||||
|
||||
func (x lico) lineNumber() string {
|
||||
return fmt.Sprintf("%d", x.Line())
|
||||
}
|
||||
|
||||
func (x lico) lineNumberHTML() string {
|
||||
if x.IsStmt() == PosDefaultStmt {
|
||||
return fmt.Sprintf("%d", x.Line())
|
||||
}
|
||||
style, pfx := "b", "+"
|
||||
if x.IsStmt() == PosNotStmt {
|
||||
style = "s" // /strike not supported in HTML5
|
||||
pfx = ""
|
||||
}
|
||||
return fmt.Sprintf("<%s>%s%d</%s>", style, pfx, x.Line(), style)
|
||||
}
|
||||
|
||||
func (x lico) atColumn1() lico {
|
||||
return makeLico(x.Line(), 1).withIsStmt()
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file implements the compressed encoding of source
|
||||
// positions using a lookup table.
|
||||
|
||||
package src
|
||||
|
||||
// XPos is a more compact representation of Pos.
|
||||
type XPos struct {
|
||||
index int32
|
||||
lico
|
||||
}
|
||||
|
||||
// NoXPos is a valid unknown position.
|
||||
var NoXPos XPos
|
||||
|
||||
// IsKnown reports whether the position p is known.
|
||||
// XPos.IsKnown() matches Pos.IsKnown() for corresponding
|
||||
// positions.
|
||||
func (p XPos) IsKnown() bool {
|
||||
return p.index != 0 || p.Line() != 0
|
||||
}
|
||||
|
||||
// Before reports whether the position p comes before q in the source.
|
||||
// For positions with different bases, ordering is by base index.
|
||||
func (p XPos) Before(q XPos) bool {
|
||||
n, m := p.index, q.index
|
||||
return n < m || n == m && p.lico < q.lico
|
||||
}
|
||||
|
||||
// SameFile reports whether p and q are positions in the same file.
|
||||
func (p XPos) SameFile(q XPos) bool {
|
||||
return p.index == q.index
|
||||
}
|
||||
|
||||
// SameFileAndLine reports whether p and q are positions on the same line in the same file.
|
||||
func (p XPos) SameFileAndLine(q XPos) bool {
|
||||
return p.index == q.index && p.lico.SameLine(q.lico)
|
||||
}
|
||||
|
||||
// After reports whether the position p comes after q in the source.
|
||||
// For positions with different bases, ordering is by base index.
|
||||
func (p XPos) After(q XPos) bool {
|
||||
n, m := p.index, q.index
|
||||
return n > m || n == m && p.lico > q.lico
|
||||
}
|
||||
|
||||
// WithNotStmt returns the same location to be marked with DWARF is_stmt=0
|
||||
func (p XPos) WithNotStmt() XPos {
|
||||
p.lico = p.lico.withNotStmt()
|
||||
return p
|
||||
}
|
||||
|
||||
// WithDefaultStmt returns the same location with undetermined is_stmt
|
||||
func (p XPos) WithDefaultStmt() XPos {
|
||||
p.lico = p.lico.withDefaultStmt()
|
||||
return p
|
||||
}
|
||||
|
||||
// WithIsStmt returns the same location to be marked with DWARF is_stmt=1
|
||||
func (p XPos) WithIsStmt() XPos {
|
||||
p.lico = p.lico.withIsStmt()
|
||||
return p
|
||||
}
|
||||
|
||||
// WithBogusLine returns a bogus line that won't match any recorded for the source code.
|
||||
// Its use is to disrupt the statements within an infinite loop so that the debugger
|
||||
// will not itself loop infinitely waiting for the line number to change.
|
||||
// gdb chooses not to display the bogus line; delve shows it with a complaint, but the
|
||||
// alternative behavior is to hang.
|
||||
func (p XPos) WithBogusLine() XPos {
|
||||
if p.index == 0 {
|
||||
// See #35652
|
||||
panic("Assigning a bogus line to XPos with no file will cause mysterious downstream failures.")
|
||||
}
|
||||
p.lico = makeBogusLico()
|
||||
return p
|
||||
}
|
||||
|
||||
// WithXlogue returns the same location but marked with DWARF function prologue/epilogue
|
||||
func (p XPos) WithXlogue(x PosXlogue) XPos {
|
||||
p.lico = p.lico.withXlogue(x)
|
||||
return p
|
||||
}
|
||||
|
||||
// LineNumber returns a string for the line number, "?" if it is not known.
|
||||
func (p XPos) LineNumber() string {
|
||||
if !p.IsKnown() {
|
||||
return "?"
|
||||
}
|
||||
return p.lico.lineNumber()
|
||||
}
|
||||
|
||||
// FileIndex returns a smallish non-negative integer corresponding to the
|
||||
// file for this source position. Smallish is relative; it can be thousands
|
||||
// large, but not millions.
|
||||
func (p XPos) FileIndex() int32 {
|
||||
return p.index
|
||||
}
|
||||
|
||||
func (p XPos) LineNumberHTML() string {
|
||||
if !p.IsKnown() {
|
||||
return "?"
|
||||
}
|
||||
return p.lico.lineNumberHTML()
|
||||
}
|
||||
|
||||
// AtColumn1 returns the same location but shifted to column 1.
|
||||
func (p XPos) AtColumn1() XPos {
|
||||
p.lico = p.lico.atColumn1()
|
||||
return p
|
||||
}
|
||||
|
||||
// A PosTable tracks Pos -> XPos conversions and vice versa.
|
||||
// Its zero value is a ready-to-use PosTable.
|
||||
type PosTable struct {
|
||||
baseList []*PosBase
|
||||
indexMap map[*PosBase]int
|
||||
nameMap map[string]int // Maps file symbol name to index for debug information.
|
||||
}
|
||||
|
||||
// XPos returns the corresponding XPos for the given pos,
|
||||
// adding pos to t if necessary.
|
||||
func (t *PosTable) XPos(pos Pos) XPos {
|
||||
m := t.indexMap
|
||||
if m == nil {
|
||||
// Create new list and map and populate with nil
|
||||
// base so that NoPos always gets index 0.
|
||||
t.baseList = append(t.baseList, nil)
|
||||
m = map[*PosBase]int{nil: 0}
|
||||
t.indexMap = m
|
||||
t.nameMap = make(map[string]int)
|
||||
}
|
||||
i, ok := m[pos.base]
|
||||
if !ok {
|
||||
i = len(t.baseList)
|
||||
t.baseList = append(t.baseList, pos.base)
|
||||
t.indexMap[pos.base] = i
|
||||
if _, ok := t.nameMap[pos.base.symFilename]; !ok {
|
||||
t.nameMap[pos.base.symFilename] = len(t.nameMap)
|
||||
}
|
||||
}
|
||||
return XPos{int32(i), pos.lico}
|
||||
}
|
||||
|
||||
// Pos returns the corresponding Pos for the given p.
|
||||
// If p cannot be translated via t, the function panics.
|
||||
func (t *PosTable) Pos(p XPos) Pos {
|
||||
var base *PosBase
|
||||
if p.index != 0 {
|
||||
base = t.baseList[p.index]
|
||||
}
|
||||
return Pos{base, p.lico}
|
||||
}
|
||||
|
||||
// FileIndex returns the index of the given filename(symbol) in the PosTable, or -1 if not found.
|
||||
func (t *PosTable) FileIndex(filename string) int {
|
||||
if v, ok := t.nameMap[filename]; ok {
|
||||
return v
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// FileTable returns a slice of all files used to build this package.
|
||||
func (t *PosTable) FileTable() []string {
|
||||
// Create a LUT of the global package level file indices. This table is what
|
||||
// is written in the debug_lines header, the file[N] will be referenced as
|
||||
// N+1 in the debug_lines table.
|
||||
fileLUT := make([]string, len(t.nameMap))
|
||||
for str, i := range t.nameMap {
|
||||
fileLUT[i] = str
|
||||
}
|
||||
return fileLUT
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sys
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// ArchFamily represents a family of one or more related architectures.
|
||||
// For example, ppc64 and ppc64le are both members of the PPC64 family.
|
||||
type ArchFamily byte
|
||||
|
||||
const (
|
||||
NoArch ArchFamily = iota
|
||||
AMD64
|
||||
ARM
|
||||
ARM64
|
||||
I386
|
||||
MIPS
|
||||
MIPS64
|
||||
PPC64
|
||||
RISCV64
|
||||
S390X
|
||||
Wasm
|
||||
)
|
||||
|
||||
// Arch represents an individual architecture.
|
||||
type Arch struct {
|
||||
Name string
|
||||
Family ArchFamily
|
||||
|
||||
ByteOrder binary.ByteOrder
|
||||
|
||||
// PtrSize is the size in bytes of pointers and the
|
||||
// predeclared "int", "uint", and "uintptr" types.
|
||||
PtrSize int
|
||||
|
||||
// RegSize is the size in bytes of general purpose registers.
|
||||
RegSize int
|
||||
|
||||
// MinLC is the minimum length of an instruction code.
|
||||
MinLC int
|
||||
}
|
||||
|
||||
// InFamily reports whether a is a member of any of the specified
|
||||
// architecture families.
|
||||
func (a *Arch) InFamily(xs ...ArchFamily) bool {
|
||||
for _, x := range xs {
|
||||
if a.Family == x {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var Arch386 = &Arch{
|
||||
Name: "386",
|
||||
Family: I386,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 4,
|
||||
RegSize: 4,
|
||||
MinLC: 1,
|
||||
}
|
||||
|
||||
var ArchAMD64 = &Arch{
|
||||
Name: "amd64",
|
||||
Family: AMD64,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 1,
|
||||
}
|
||||
|
||||
var ArchARM = &Arch{
|
||||
Name: "arm",
|
||||
Family: ARM,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 4,
|
||||
RegSize: 4,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchARM64 = &Arch{
|
||||
Name: "arm64",
|
||||
Family: ARM64,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchMIPS = &Arch{
|
||||
Name: "mips",
|
||||
Family: MIPS,
|
||||
ByteOrder: binary.BigEndian,
|
||||
PtrSize: 4,
|
||||
RegSize: 4,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchMIPSLE = &Arch{
|
||||
Name: "mipsle",
|
||||
Family: MIPS,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 4,
|
||||
RegSize: 4,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchMIPS64 = &Arch{
|
||||
Name: "mips64",
|
||||
Family: MIPS64,
|
||||
ByteOrder: binary.BigEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchMIPS64LE = &Arch{
|
||||
Name: "mips64le",
|
||||
Family: MIPS64,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchPPC64 = &Arch{
|
||||
Name: "ppc64",
|
||||
Family: PPC64,
|
||||
ByteOrder: binary.BigEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchPPC64LE = &Arch{
|
||||
Name: "ppc64le",
|
||||
Family: PPC64,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchRISCV64 = &Arch{
|
||||
Name: "riscv64",
|
||||
Family: RISCV64,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 4,
|
||||
}
|
||||
|
||||
var ArchS390X = &Arch{
|
||||
Name: "s390x",
|
||||
Family: S390X,
|
||||
ByteOrder: binary.BigEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 2,
|
||||
}
|
||||
|
||||
var ArchWasm = &Arch{
|
||||
Name: "wasm",
|
||||
Family: Wasm,
|
||||
ByteOrder: binary.LittleEndian,
|
||||
PtrSize: 8,
|
||||
RegSize: 8,
|
||||
MinLC: 1,
|
||||
}
|
||||
|
||||
var Archs = [...]*Arch{
|
||||
Arch386,
|
||||
ArchAMD64,
|
||||
ArchARM,
|
||||
ArchARM64,
|
||||
ArchMIPS,
|
||||
ArchMIPSLE,
|
||||
ArchMIPS64,
|
||||
ArchMIPS64LE,
|
||||
ArchPPC64,
|
||||
ArchPPC64LE,
|
||||
ArchRISCV64,
|
||||
ArchS390X,
|
||||
ArchWasm,
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sys
|
||||
|
||||
// RaceDetectorSupported reports whether goos/goarch supports the race
|
||||
// detector. There is a copy of this function in cmd/dist/test.go.
|
||||
// Race detector only supports 48-bit VMA on arm64. But it will always
|
||||
// return true for arm64, because we don't have VMA size information during
|
||||
// the compile time.
|
||||
func RaceDetectorSupported(goos, goarch string) bool {
|
||||
switch goos {
|
||||
case "linux":
|
||||
return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64"
|
||||
case "darwin", "freebsd", "netbsd", "windows":
|
||||
return goarch == "amd64"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MSanSupported reports whether goos/goarch supports the memory
|
||||
// sanitizer option. There is a copy of this function in cmd/dist/test.go.
|
||||
func MSanSupported(goos, goarch string) bool {
|
||||
switch goos {
|
||||
case "linux":
|
||||
return goarch == "amd64" || goarch == "arm64"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MustLinkExternal reports whether goos/goarch requires external linking.
|
||||
func MustLinkExternal(goos, goarch string) bool {
|
||||
switch goos {
|
||||
case "android":
|
||||
if goarch != "arm64" {
|
||||
return true
|
||||
}
|
||||
case "darwin":
|
||||
if goarch == "arm64" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// BuildModeSupported reports whether goos/goarch supports the given build mode
|
||||
// using the given compiler.
|
||||
func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
|
||||
if compiler == "gccgo" {
|
||||
return true
|
||||
}
|
||||
|
||||
platform := goos + "/" + goarch
|
||||
|
||||
switch buildmode {
|
||||
case "archive":
|
||||
return true
|
||||
|
||||
case "c-archive":
|
||||
// TODO(bcmills): This seems dubious.
|
||||
// Do we really support c-archive mode on js/wasm‽
|
||||
return platform != "linux/ppc64"
|
||||
|
||||
case "c-shared":
|
||||
switch platform {
|
||||
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x",
|
||||
"android/amd64", "android/arm", "android/arm64", "android/386",
|
||||
"freebsd/amd64",
|
||||
"darwin/amd64",
|
||||
"windows/amd64", "windows/386":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
case "default":
|
||||
return true
|
||||
|
||||
case "exe":
|
||||
return true
|
||||
|
||||
case "pie":
|
||||
switch platform {
|
||||
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
|
||||
"android/amd64", "android/arm", "android/arm64", "android/386",
|
||||
"freebsd/amd64",
|
||||
"darwin/amd64",
|
||||
"aix/ppc64",
|
||||
"windows/386", "windows/amd64", "windows/arm":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
case "shared":
|
||||
switch platform {
|
||||
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
case "plugin":
|
||||
switch platform {
|
||||
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le",
|
||||
"android/amd64", "android/arm", "android/arm64", "android/386",
|
||||
"darwin/amd64",
|
||||
"freebsd/amd64":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package unsafeheader contains header declarations for the Go runtime's slice
|
||||
// and string implementations.
|
||||
//
|
||||
// This package allows packages that cannot import "reflect" to use types that
|
||||
// are tested to be equivalent to reflect.SliceHeader and reflect.StringHeader.
|
||||
package unsafeheader
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Slice is the runtime representation of a slice.
|
||||
// It cannot be used safely or portably and its representation may
|
||||
// change in a later release.
|
||||
//
|
||||
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||
// data it references will not be garbage collected.
|
||||
type Slice struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
Cap int
|
||||
}
|
||||
|
||||
// String is the runtime representation of a string.
|
||||
// It cannot be used safely or portably and its representation may
|
||||
// change in a later release.
|
||||
//
|
||||
// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the
|
||||
// data it references will not be garbage collected.
|
||||
type String struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
}
|
||||
Reference in New Issue
Block a user