attr: generate code from textflag.h (#176)
This commit is contained in:
committed by
GitHub
parent
e5c9b4e5a6
commit
c5faaae583
59
attr/attr.go
59
attr/attr.go
@@ -10,50 +10,7 @@ import (
|
|||||||
// Attribute represents TEXT or DATA flags.
|
// Attribute represents TEXT or DATA flags.
|
||||||
type Attribute uint16
|
type Attribute uint16
|
||||||
|
|
||||||
// Reference: https://github.com/golang/go/blob/aafe257390cc9048e8b5df898fabd79a9e0d4c39/src/runtime/textflag.h#L11-L37
|
//go:generate go run make_textflag.go -output ztextflag.go
|
||||||
//
|
|
||||||
// // Don't profile the marked routine. This flag is deprecated.
|
|
||||||
// #define NOPROF 1
|
|
||||||
// // It is ok for the linker to get multiple of these symbols. It will
|
|
||||||
// // pick one of the duplicates to use.
|
|
||||||
// #define DUPOK 2
|
|
||||||
// // Don't insert stack check preamble.
|
|
||||||
// #define NOSPLIT 4
|
|
||||||
// // Put this data in a read-only section.
|
|
||||||
// #define RODATA 8
|
|
||||||
// // This data contains no pointers.
|
|
||||||
// #define NOPTR 16
|
|
||||||
// // This is a wrapper function and should not count as disabling 'recover'.
|
|
||||||
// #define WRAPPER 32
|
|
||||||
// // This function uses its incoming context register.
|
|
||||||
// #define NEEDCTXT 64
|
|
||||||
// // Allocate a word of thread local storage and store the offset from the
|
|
||||||
// // thread local base to the thread local storage in this variable.
|
|
||||||
// #define TLSBSS 256
|
|
||||||
// // Do not insert instructions to allocate a stack frame for this function.
|
|
||||||
// // Only valid on functions that declare a frame size of 0.
|
|
||||||
// // TODO(mwhudson): only implemented for ppc64x at present.
|
|
||||||
// #define NOFRAME 512
|
|
||||||
// // Function can call reflect.Type.Method or reflect.Type.MethodByName.
|
|
||||||
// #define REFLECTMETHOD 1024
|
|
||||||
// // Function is the top of the call stack. Call stack unwinders should stop
|
|
||||||
// // at this function.
|
|
||||||
// #define TOPFRAME 2048
|
|
||||||
//
|
|
||||||
const (
|
|
||||||
NOPROF Attribute = 1 << iota
|
|
||||||
DUPOK
|
|
||||||
NOSPLIT
|
|
||||||
RODATA
|
|
||||||
NOPTR
|
|
||||||
WRAPPER
|
|
||||||
NEEDCTXT
|
|
||||||
_
|
|
||||||
TLSBSS
|
|
||||||
NOFRAME
|
|
||||||
REFLECTMETHOD
|
|
||||||
TOPFRAME
|
|
||||||
)
|
|
||||||
|
|
||||||
// Asm returns a representation of the attributes in assembly syntax. This may use macros from "textflags.h"; see ContainsTextFlags() to determine if this header is required.
|
// Asm returns a representation of the attributes in assembly syntax. This may use macros from "textflags.h"; see ContainsTextFlags() to determine if this header is required.
|
||||||
func (a Attribute) Asm() string {
|
func (a Attribute) Asm() string {
|
||||||
@@ -86,17 +43,3 @@ func (a Attribute) split() ([]string, Attribute) {
|
|||||||
}
|
}
|
||||||
return flags, rest
|
return flags, rest
|
||||||
}
|
}
|
||||||
|
|
||||||
var attrname = map[Attribute]string{
|
|
||||||
NOPROF: "NOPROF",
|
|
||||||
DUPOK: "DUPOK",
|
|
||||||
NOSPLIT: "NOSPLIT",
|
|
||||||
RODATA: "RODATA",
|
|
||||||
NOPTR: "NOPTR",
|
|
||||||
WRAPPER: "WRAPPER",
|
|
||||||
NEEDCTXT: "NEEDCTXT",
|
|
||||||
TLSBSS: "TLSBSS",
|
|
||||||
NOFRAME: "NOFRAME",
|
|
||||||
REFLECTMETHOD: "REFLECTMETHOD",
|
|
||||||
TOPFRAME: "TOPFRAME",
|
|
||||||
}
|
|
||||||
|
|||||||
200
attr/make_textflag.go
Normal file
200
attr/make_textflag.go
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
TextFlagPath = "src/runtime/textflag.h"
|
||||||
|
TextFlagName = filepath.Base(TextFlagPath)
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
download = flag.Bool("download", false, "download new version of "+TextFlagName)
|
||||||
|
version = flag.String("version", runtime.Version(), "go version to download file from")
|
||||||
|
textflag = flag.String("textflag", TextFlagName, "path to "+TextFlagName)
|
||||||
|
output = flag.String("output", "", "path to output file")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := mainerr(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mainerr() error {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Download new version, if requested.
|
||||||
|
if *download {
|
||||||
|
if err := DownloadGoSourceFile(*textflag, *version, TextFlagPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("downloaded %q from version %s to %q", TextFlagPath, *version, *textflag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse text flags header.
|
||||||
|
fs, err := ParseFile(*textflag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine output.
|
||||||
|
w := os.Stdout
|
||||||
|
if *output != "" {
|
||||||
|
f, err := os.Create(*output)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
w = f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate code and format it.
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
PrintFlagAttributes(buf, fs)
|
||||||
|
|
||||||
|
src, err := format.Source(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write output.
|
||||||
|
_, err = w.Write(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadGoSourceFile downloads a Go source file from a specific version.
|
||||||
|
func DownloadGoSourceFile(outpath, v, srcpath string) (err error) {
|
||||||
|
// Download from github.
|
||||||
|
url := "https://github.com/golang/go/raw/" + v + "/" + srcpath
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if errc := res.Body.Close(); errc != nil && err == nil {
|
||||||
|
err = errc
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Write to file.
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
fmt.Fprintf(buf, "// Code generated by downloading from %s. DO NOT EDIT.\n\n", url)
|
||||||
|
|
||||||
|
if _, err := io.Copy(buf, res.Body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(outpath, buf.Bytes(), 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Flag struct {
|
||||||
|
Doc []string
|
||||||
|
Name string
|
||||||
|
Value int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse text flags header format.
|
||||||
|
func Parse(r io.Reader) ([]Flag, error) {
|
||||||
|
var fs []Flag
|
||||||
|
var doc []string
|
||||||
|
|
||||||
|
s := bufio.NewScanner(r)
|
||||||
|
for s.Scan() {
|
||||||
|
line := s.Text()
|
||||||
|
switch {
|
||||||
|
case strings.Contains(line, "TODO"):
|
||||||
|
// skip
|
||||||
|
|
||||||
|
case strings.HasPrefix(line, "// "):
|
||||||
|
doc = append(doc, strings.TrimPrefix(line, "// "))
|
||||||
|
|
||||||
|
case strings.HasPrefix(line, "#define"):
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
if len(fields) != 3 || fields[0] != "#define" {
|
||||||
|
return nil, fmt.Errorf("unexpected line format %q", line)
|
||||||
|
}
|
||||||
|
v, err := strconv.Atoi(fields[2])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = append(fs, Flag{
|
||||||
|
Doc: doc,
|
||||||
|
Name: fields[1],
|
||||||
|
Value: v,
|
||||||
|
})
|
||||||
|
doc = nil
|
||||||
|
|
||||||
|
case line == "" || line == "//":
|
||||||
|
doc = nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unexpected format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseFile parses text flags header file.
|
||||||
|
func ParseFile(filename string) ([]Flag, error) {
|
||||||
|
b, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Parse(bytes.NewReader(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintFlagAttributes(w io.Writer, fs []Flag) {
|
||||||
|
_, self, _, _ := runtime.Caller(0)
|
||||||
|
fmt.Fprintf(w, "// Code generated by %s. DO NOT EDIT.\n\n", filepath.Base(self))
|
||||||
|
fmt.Fprintf(w, "package attr\n")
|
||||||
|
|
||||||
|
// Attribute constants.
|
||||||
|
fmt.Fprintf(w, "\n// Attribute values defined in %s.\n", TextFlagName)
|
||||||
|
fmt.Fprintf(w, "const (\n")
|
||||||
|
for _, f := range fs {
|
||||||
|
for _, line := range f.Doc {
|
||||||
|
fmt.Fprintf(w, "\t// %s\n", line)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "\t%s Attribute = %d\n\n", f.Name, f.Value)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, ")\n")
|
||||||
|
|
||||||
|
// String map.
|
||||||
|
fmt.Fprintf(w, "\nvar attrname = map[Attribute]string{\n")
|
||||||
|
for _, f := range fs {
|
||||||
|
fmt.Fprintf(w, "\t%s: %q,\n", f.Name, f.Name)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "}\n")
|
||||||
|
}
|
||||||
39
attr/textflag.h
Normal file
39
attr/textflag.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Code generated by downloading from https://github.com/golang/go/raw/go1.16.2/src/runtime/textflag.h. DO NOT EDIT.
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// This file defines flags attached to various functions
|
||||||
|
// and data objects. The compilers, assemblers, and linker must
|
||||||
|
// all agree on these values.
|
||||||
|
//
|
||||||
|
// Keep in sync with src/cmd/internal/obj/textflag.go.
|
||||||
|
|
||||||
|
// Don't profile the marked routine. This flag is deprecated.
|
||||||
|
#define NOPROF 1
|
||||||
|
// It is ok for the linker to get multiple of these symbols. It will
|
||||||
|
// pick one of the duplicates to use.
|
||||||
|
#define DUPOK 2
|
||||||
|
// Don't insert stack check preamble.
|
||||||
|
#define NOSPLIT 4
|
||||||
|
// Put this data in a read-only section.
|
||||||
|
#define RODATA 8
|
||||||
|
// This data contains no pointers.
|
||||||
|
#define NOPTR 16
|
||||||
|
// This is a wrapper function and should not count as disabling 'recover'.
|
||||||
|
#define WRAPPER 32
|
||||||
|
// This function uses its incoming context register.
|
||||||
|
#define NEEDCTXT 64
|
||||||
|
// Allocate a word of thread local storage and store the offset from the
|
||||||
|
// thread local base to the thread local storage in this variable.
|
||||||
|
#define TLSBSS 256
|
||||||
|
// Do not insert instructions to allocate a stack frame for this function.
|
||||||
|
// Only valid on functions that declare a frame size of 0.
|
||||||
|
// TODO(mwhudson): only implemented for ppc64x at present.
|
||||||
|
#define NOFRAME 512
|
||||||
|
// Function can call reflect.Type.Method or reflect.Type.MethodByName.
|
||||||
|
#define REFLECTMETHOD 1024
|
||||||
|
// Function is the top of the call stack. Call stack unwinders should stop
|
||||||
|
// at this function.
|
||||||
|
#define TOPFRAME 2048
|
||||||
57
attr/ztextflag.go
Normal file
57
attr/ztextflag.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Code generated by make_textflag.go. DO NOT EDIT.
|
||||||
|
|
||||||
|
package attr
|
||||||
|
|
||||||
|
// Attribute values defined in textflag.h.
|
||||||
|
const (
|
||||||
|
// Don't profile the marked routine. This flag is deprecated.
|
||||||
|
NOPROF Attribute = 1
|
||||||
|
|
||||||
|
// It is ok for the linker to get multiple of these symbols. It will
|
||||||
|
// pick one of the duplicates to use.
|
||||||
|
DUPOK Attribute = 2
|
||||||
|
|
||||||
|
// Don't insert stack check preamble.
|
||||||
|
NOSPLIT Attribute = 4
|
||||||
|
|
||||||
|
// Put this data in a read-only section.
|
||||||
|
RODATA Attribute = 8
|
||||||
|
|
||||||
|
// This data contains no pointers.
|
||||||
|
NOPTR Attribute = 16
|
||||||
|
|
||||||
|
// This is a wrapper function and should not count as disabling 'recover'.
|
||||||
|
WRAPPER Attribute = 32
|
||||||
|
|
||||||
|
// This function uses its incoming context register.
|
||||||
|
NEEDCTXT Attribute = 64
|
||||||
|
|
||||||
|
// Allocate a word of thread local storage and store the offset from the
|
||||||
|
// thread local base to the thread local storage in this variable.
|
||||||
|
TLSBSS Attribute = 256
|
||||||
|
|
||||||
|
// Do not insert instructions to allocate a stack frame for this function.
|
||||||
|
// Only valid on functions that declare a frame size of 0.
|
||||||
|
NOFRAME Attribute = 512
|
||||||
|
|
||||||
|
// Function can call reflect.Type.Method or reflect.Type.MethodByName.
|
||||||
|
REFLECTMETHOD Attribute = 1024
|
||||||
|
|
||||||
|
// Function is the top of the call stack. Call stack unwinders should stop
|
||||||
|
// at this function.
|
||||||
|
TOPFRAME Attribute = 2048
|
||||||
|
)
|
||||||
|
|
||||||
|
var attrname = map[Attribute]string{
|
||||||
|
NOPROF: "NOPROF",
|
||||||
|
DUPOK: "DUPOK",
|
||||||
|
NOSPLIT: "NOSPLIT",
|
||||||
|
RODATA: "RODATA",
|
||||||
|
NOPTR: "NOPTR",
|
||||||
|
WRAPPER: "WRAPPER",
|
||||||
|
NEEDCTXT: "NEEDCTXT",
|
||||||
|
TLSBSS: "TLSBSS",
|
||||||
|
NOFRAME: "NOFRAME",
|
||||||
|
REFLECTMETHOD: "REFLECTMETHOD",
|
||||||
|
TOPFRAME: "TOPFRAME",
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user