4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-06-26 20:09:24 +00:00

Compare commits

...

83 Commits

Author SHA1 Message Date
Wim
3f79da84d5 Release v0.14.0 2017-06-15 01:44:46 +02:00
Wim
d540638223 Remove debug 2017-06-15 01:30:58 +02:00
Wim
4ec9b6dd4e Add 3.10.0 support (mattermost) 2017-06-15 01:30:05 +02:00
Wim
3bc219167a Remove need for channel when using api. Closes #195 2017-06-15 00:40:23 +02:00
Wim
8a55c97b4e Fix utf-8 issues #193 2017-06-15 00:07:12 +02:00
9e34162a09 remove second flag.Parse() (#196)
flag.Parse() is already being called on line 28 https://github.com/42wim/matterbridge/blob/master/matterbridge.go#L28
and there is no need for calling it again
2017-06-14 17:15:35 +02:00
Wim
860a371eeb Use cache for teamid 2017-06-12 20:30:30 +02:00
Wim
41a46526a1 Add note about file permissions 2017-06-08 23:42:00 +02:00
Wim
46b798ac1b Update documentation (api) 2017-06-08 00:03:06 +02:00
Wim
359d0f2910 Allow reuse of api in different gateways. See #189 2017-06-07 23:54:50 +02:00
Wim
ad3cb0386b Add token authentication (api) 2017-06-06 00:05:32 +02:00
Wim
3a183cb218 Update vendor 2017-06-06 00:04:18 +02:00
Wim
2eecaccd1c Change to lowercase JSON keys (api) 2017-06-05 23:18:13 +02:00
Wim
5f30a98bc1 Add gateway name to messages 2017-06-05 23:12:19 +02:00
Wim
b8a2fcbaff Post valid JSON (api). See #185 2017-06-05 23:08:36 +02:00
Wim
01496cd080 Fix panic (mattermost). Closes #186 2017-06-05 21:35:38 +02:00
Wim
6a968ab82a Bump version 2017-06-03 18:22:09 +02:00
Wim
c0c4890887 Add hashtag to channel (discord) 2017-06-03 18:21:47 +02:00
Wim
171a53592d Add note about lowercase channel (irc) 2017-06-01 21:00:58 +02:00
Wim
7811c330db Release v0.13.0 2017-05-31 23:32:38 +02:00
Wim
9bcd131e66 Reset variables each loop (telegram). Closes #181 2017-05-30 21:14:03 +02:00
Wim
c791423dd5 Add NOPINGNICK option. Closes #175 2017-05-30 00:11:53 +02:00
Wim
80bdf38388 Bump version 2017-05-29 23:54:43 +02:00
Wim
9d9cb32f4e Limit message length (irc). Closes #179 2017-05-29 21:54:34 +02:00
Wim
87229bab13 Fix sending to different channels on same account (slack). Closes #177 2017-05-24 22:10:21 +02:00
Wim
f065e9e4d5 Release v0.12.1 2017-05-23 22:48:05 +02:00
Wim
3812693111 Replace long ids in channel metions (discord). Fixes #174 2017-05-23 22:26:37 +02:00
Wim
dd3c572256 Fix possible crash on nil (discord) 2017-05-22 21:57:19 +02:00
Wim
c5dfe40326 Update documentation about encrypted rooms in matrix 2017-05-21 15:36:40 +02:00
ef278301e3 Fix JoinChannel argument to use IRC channel key (#172) 2017-05-21 15:23:56 +02:00
Wim
2888fd64b0 Add UseFirstName option (telegram). Closes #144 2017-05-15 23:23:10 +02:00
Wim
27c0f37e49 Update matterbridge.toml.sample about NoHomeServerSuffix 2017-05-15 23:11:27 +02:00
Wim
0774f6a5e7 Bump version 2017-05-12 23:20:22 +02:00
Wim
4036d4459b Add NoHomeServerSuffix. Option to disable homeserver on username (matrix). Closes #160. 2017-05-12 23:04:58 +02:00
ee643de5b6 Add Compatibility for Cisco Jabber (xmpp) (#166) 2017-05-11 20:10:53 +02:00
Wim
8c7549a09e Update changelog 2017-05-09 23:46:20 +02:00
Wim
7a16146304 Release v0.12.0 2017-05-09 23:31:26 +02:00
Wim
3d3809a21b Add 3.9.0 support (mattermost) 2017-05-09 23:30:53 +02:00
29465397dd Add support for HTTP{S}_PROXY env variables (#162) 2017-05-08 21:20:52 +02:00
Wim
d300bb1735 Relay messages starting with ! (irc). Closes #164 2017-05-08 21:15:01 +02:00
Wim
2e703472f1 Fix crash on reconnects when server is down. Closes #163 2017-05-08 20:44:36 +02:00
Wim
8fede90b9e Remove examples (vendor issues) 2017-05-05 20:45:11 +02:00
Wim
d128f157c4 Update doc 2017-04-19 21:57:40 +02:00
Wim
4fcedabfd0 Revert "Add support for edited messages (gitter)"
This reverts commit 17b8b86d68.
Reverted because of lingering file descriptors (memory leak)
2017-04-19 19:51:33 +02:00
Wim
246c8e4f74 Ignore error on private channel join (slack) Fixes #150 2017-04-17 18:01:24 +02:00
Wim
4d2207aba7 Add support for edited messages (slack) 2017-04-16 00:16:24 +02:00
Wim
17b8b86d68 Add support for edited messages (gitter) 2017-04-15 23:46:01 +02:00
Wim
fdb57230a3 Add support for edited messages (mattermost) 2017-04-15 20:21:57 +02:00
Wim
7469732bbc Add support for edited messages (telegram) 2017-04-15 19:07:35 +02:00
Wim
d1dd6c3440 Add support for edited messages (discord) 2017-04-15 19:00:15 +02:00
Wim
02612c0061 Add support for sending edited messages 2017-04-15 18:46:25 +02:00
Wim
a4db63a773 Bump version 2017-04-15 16:24:25 +02:00
Wim
035c2b906a Strip custom emoji metadata (discord). Closes #148 2017-04-15 16:23:34 +02:00
Wim
6ea8be5749 Release v0.11.0 2017-04-11 21:51:23 +02:00
Wim
36024d5439 Add 3.8.0 support (mattermost) 2017-04-09 23:15:11 +02:00
Wim
8d52c98373 Update README 2017-04-08 00:57:11 +02:00
Wim
b4a4eb0057 Update changelog 2017-04-08 00:50:17 +02:00
Wim
b469c8ddbd Rejoin channel when kicked (irc). Closes #146 2017-04-08 00:42:37 +02:00
Wim
eee0036c7f Modify iconurl correctly (mattermost). Closes #145 2017-04-08 00:16:46 +02:00
Wim
89c66b9430 Reconnect on session removal (mattermost) 2017-04-07 23:27:41 +02:00
Wim
bd38319d83 Add support for showing/hiding join/leave messages from mattermost. Closes #147 2017-04-07 22:27:36 +02:00
Wim
33dffd5ea8 Fix join/leave regression (irc) 2017-04-03 22:18:29 +02:00
Wim
57176dadd4 Support edited messages (telegram). See #141 2017-04-01 18:18:38 +02:00
Wim
dd449a8705 Remove debug info (irc) 2017-04-01 18:10:11 +02:00
Wim
587ad9f41d Remove space after nick (mattermost). Closes #142 2017-04-01 17:44:17 +02:00
Wim
a16ad8bf3b Reuse connection when using same bridge with another gateway. See #87 2017-04-01 17:24:19 +02:00
Wim
1e0490bd36 Merge branch 'channelinfo' 2017-03-28 23:58:22 +02:00
Wim
8afc641f0c Bump version 2017-03-28 23:58:07 +02:00
Wim
2e4d58cb92 Refactor 2017-03-28 23:56:58 +02:00
Wim
02d7e2db65 Release v0.10.3 2017-03-27 20:40:57 +02:00
Wim
f935c573e9 Allow bot tokens for now without warning (slack). Closes #140 2017-03-27 20:15:05 +02:00
Wim
4a25e66c00 Release v0.10.2 2017-03-25 21:35:13 +01:00
Wim
95f4e3448e Use API_URL_SUFFIX_V3 (mattermost) 2017-03-25 21:05:02 +01:00
Wim
eacb1c1771 Update vendor (mattermost) 2017-03-25 21:04:10 +01:00
Wim
07fd825349 Update vendor 2017-03-25 20:45:10 +01:00
Wim
be15cc8a36 Update vendored toml. Adds support for inline tables 2017-03-25 19:13:47 +01:00
Wim
2f68519b3c Add gops agent 2017-03-23 23:28:55 +01:00
Wim
efe641f202 Add link about token (slack) 2017-03-23 23:02:00 +01:00
Wim
9bd663046a Fix slack/discord example 2017-03-20 12:12:12 +01:00
Wim
11b07f01ba Add more startup messages 2017-03-19 19:41:57 +01:00
Wim
6c2f370e6b Add badges 2017-03-18 22:16:25 +01:00
Wim
936bccccd2 Release v0.10.1 2017-03-18 21:19:22 +01:00
Wim
c30ffeb81e Fix roomid bug (gitter) 2017-03-18 21:17:21 +01:00
518 changed files with 230679 additions and 2675 deletions

View File

@ -1,5 +1,6 @@
# matterbridge
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/42wim/matterbridge) [![Join the IRC chat at https://webchat.freenode.net/?channels=matterbridgechat](https://img.shields.io/badge/IRC-matterbridgechat-green.svg)](https://webchat.freenode.net/?channels=matterbridgechat)
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/42wim/matterbridge) [![Join the IRC chat at https://webchat.freenode.net/?channels=matterbridgechat](https://img.shields.io/badge/IRC-matterbridgechat-green.svg)](https://webchat.freenode.net/?channels=matterbridgechat) [![Discord](https://img.shields.io/badge/discord-matterbridge-green.svg)](https://discord.gg/AkKPtrQ) [![Matrix](https://img.shields.io/badge/matrix-matterbridge-green.svg)](https://riot.im/app/#/room/#matterbridge:matrix.org)
![matterbridge.gif](https://s15.postimg.org/qpjhp6y3f/matterbridge.gif)
Simple bridge between Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, Rocket.Chat, Hipchat(via xmpp) and Matrix with REST API.
@ -27,7 +28,7 @@ Simple bridge between Mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, R
# Requirements
Accounts to one of the supported bridges
* [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.7.x
* [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.10.x
* [IRC](http://www.mirc.com/servers.html)
* [XMPP](https://jabber.org)
* [Gitter](https://gitter.im)
@ -41,7 +42,7 @@ Accounts to one of the supported bridges
# Installing
## Binaries
Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/)
* Latest release [v0.10.0](https://github.com/42wim/matterbridge/releases/tag/v0.10.0)
* Latest stable release [v0.14.0](https://github.com/42wim/matterbridge/releases/latest)
## Building
Go 1.6+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH] (https://golang.org/doc/code.html#GOPATH)
@ -93,10 +94,13 @@ enable=true
### Bridge slack (#general) - discord (general)
```
[slack]
[slack.test]
useAPI=true
Token="yourslacktoken"
PrefixMessagesWithNick=true
[discord]
[discord.test]
Token="yourdiscordtoken"
Server="yourdiscordservername"
@ -118,9 +122,11 @@ RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
```
# Running
1) Copy the matterbridge.toml.sample to matterbridge.toml in the same directory as the matterbridge binary.
1) Copy the matterbridge.toml.sample to matterbridge.toml
2) Edit matterbridge.toml with the settings for your environment.
3) Now you can run matterbridge. (```./matterbridge```)
3) Now you can run matterbridge. (```./matterbridge```)
(Matterbridge will only look for the config file in your current directory, if it isn't there specify -conf "/path/toyour/matterbridge.toml")
```
Usage of ./matterbridge:
@ -128,6 +134,8 @@ Usage of ./matterbridge:
config file (default "matterbridge.toml")
-debug
enable debug
-gops
enable gops agent
-version
show version
```
@ -161,6 +169,7 @@ Matterbridge wouldn't exist without these libraries:
* discord - https://github.com/bwmarrin/discordgo
* echo - https://github.com/labstack/echo
* gitter - https://github.com/sromku/go-gitter
* gops - https://github.com/google/gops
* irc - https://github.com/thoj/go-ircevent
* mattermost - https://github.com/mattermost/platform
* matrix - https://github.com/matrix-org/gomatrix

View File

@ -4,6 +4,7 @@ import (
"github.com/42wim/matterbridge/bridge/config"
log "github.com/Sirupsen/logrus"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"github.com/zfjagann/golang-ring"
"net/http"
"sync"
@ -21,6 +22,7 @@ type ApiMessage struct {
Text string `json:"text"`
Username string `json:"username"`
Avatar string `json:"avatar"`
Gateway string `json:"gateway"`
}
var flog *log.Entry
@ -38,6 +40,11 @@ func New(cfg config.Protocol, account string, c chan config.Message) *Api {
b.Config = &cfg
b.Account = account
b.Remote = c
if b.Config.Token != "" {
e.Use(middleware.KeyAuth(func(key string, c echo.Context) (bool, error) {
return key == b.Config.Token, nil
}))
}
e.GET("/api/messages", b.handleMessages)
e.POST("/api/message", b.handlePostMessage)
go func() {
@ -70,12 +77,15 @@ func (b *Api) handlePostMessage(c echo.Context) error {
if err := c.Bind(message); err != nil {
return err
}
flog.Debugf("Sending message from %s on %s to gateway", message.Username, "api")
b.Remote <- config.Message{
Text: message.Text,
Username: message.Username,
Channel: "api",
Avatar: message.Avatar,
Account: b.Account,
Gateway: message.Gateway,
Protocol: "api",
}
return c.JSON(http.StatusOK, message)
}
@ -83,9 +93,7 @@ func (b *Api) handlePostMessage(c echo.Context) error {
func (b *Api) handleMessages(c echo.Context) error {
b.Lock()
defer b.Unlock()
for _, msg := range b.Messages.Values() {
c.JSONPretty(http.StatusOK, msg, " ")
}
c.JSONPretty(http.StatusOK, b.Messages.Values(), " ")
b.Messages = ring.Ring{}
return nil
}

View File

@ -27,23 +27,23 @@ type Bridger interface {
type Bridge struct {
Config config.Protocol
Bridger
Name string
Account string
Protocol string
ChannelsIn map[string]config.ChannelOptions
ChannelsOut map[string]config.ChannelOptions
Name string
Account string
Protocol string
Channels map[string]config.ChannelInfo
Joined map[string]bool
}
func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Bridge {
b := new(Bridge)
b.ChannelsIn = make(map[string]config.ChannelOptions)
b.ChannelsOut = make(map[string]config.ChannelOptions)
b.Channels = make(map[string]config.ChannelInfo)
accInfo := strings.Split(bridge.Account, ".")
protocol := accInfo[0]
name := accInfo[1]
b.Name = name
b.Protocol = protocol
b.Account = bridge.Account
b.Joined = make(map[string]bool)
// override config from environment
config.OverrideCfgFromEnv(cfg, protocol, name)
@ -83,33 +83,28 @@ func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Brid
}
func (b *Bridge) JoinChannels() error {
exists := make(map[string]bool)
err := b.joinChannels(b.ChannelsIn, exists)
if err != nil {
return err
}
err = b.joinChannels(b.ChannelsOut, exists)
err := b.joinChannels(b.Channels, b.Joined)
if err != nil {
return err
}
return nil
}
func (b *Bridge) joinChannels(cMap map[string]config.ChannelOptions, exists map[string]bool) error {
func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map[string]bool) error {
mychannel := ""
for channel, info := range cMap {
if !exists[channel] {
mychannel = channel
log.Infof("%s: joining %s", b.Account, channel)
if b.Protocol == "irc" && info.Key != "" {
log.Debugf("using key %s for channel %s", info.Key, channel)
mychannel = mychannel + " " + info.Key
for ID, channel := range channels {
if !exists[ID] {
mychannel = channel.Name
log.Infof("%s: joining %s (%s)", b.Account, channel.Name, ID)
if b.Protocol == "irc" && channel.Options.Key != "" {
log.Debugf("using key %s for channel %s", channel.Options.Key, channel.Name)
mychannel = mychannel + " " + channel.Options.Key
}
err := b.JoinChannel(mychannel)
if err != nil {
return err
}
exists[channel] = true
exists[ID] = true
}
}
return nil

View File

@ -10,24 +10,38 @@ import (
)
const (
EVENT_JOIN_LEAVE = "join_leave"
EVENT_FAILURE = "failure"
EVENT_JOIN_LEAVE = "join_leave"
EVENT_FAILURE = "failure"
EVENT_REJOIN_CHANNELS = "rejoin_channels"
)
type Message struct {
Text string
Channel string
Username string
Avatar string
Account string
Event string
Protocol string
Timestamp time.Time
Text string `json:"text"`
Channel string `json:"channel"`
Username string `json:"username"`
Avatar string `json:"avatar"`
Account string `json:"account"`
Event string `json:"event"`
Protocol string `json:"protocol"`
Gateway string `json:"gateway"`
Timestamp time.Time `json:"timestamp"`
}
type ChannelInfo struct {
Name string
Account string
Direction string
ID string
GID map[string]bool
SameChannel map[string]bool
Options ChannelOptions
}
type Protocol struct {
BindAddress string // mattermost, slack
Buffer int // api
EditSuffix string // mattermost, slack, discord, telegram, gitter
EditDisable bool // mattermost, slack, discord, telegram, gitter
IconURL string // mattermost, slack
IgnoreNicks string // all protocols
Jid string // xmpp
@ -39,23 +53,26 @@ type Protocol struct {
NickServNick string // IRC
NickServPassword string // IRC
NicksPerRow int // mattermost, slack
NoHomeServerSuffix bool // matrix
NoTLS bool // mattermost
Password string // IRC,mattermost,XMPP,matrix
PrefixMessagesWithNick bool // mattemost, slack
Protocol string //all protocols
MessageQueue int // IRC, size of message queue for flood control
MessageDelay int // IRC, time in millisecond to wait between messages
MessageLength int // IRC, max length of a message allowed
MessageFormat string // telegram
RemoteNickFormat string // all protocols
Server string // IRC,mattermost,XMPP,discord
ShowJoinPart bool // all protocols
SkipTLSVerify bool // IRC, mattermost
Team string // mattermost
Token string // gitter, slack, discord
Token string // gitter, slack, discord, api
URL string // mattermost, slack, matrix
UseAPI bool // mattermost, slack
UseSASL bool // IRC
UseTLS bool // IRC
UseFirstName bool // telegram
}
type ChannelOptions struct {
@ -63,9 +80,10 @@ type ChannelOptions struct {
}
type Bridge struct {
Account string
Channel string
Options ChannelOptions
Account string
Channel string
Options ChannelOptions
SameChannel bool
}
type Gateway struct {

View File

@ -4,6 +4,7 @@ import (
"github.com/42wim/matterbridge/bridge/config"
log "github.com/Sirupsen/logrus"
"github.com/bwmarrin/discordgo"
"regexp"
"strings"
"sync"
)
@ -51,6 +52,7 @@ func (b *bdiscord) Connect() error {
flog.Info("Connection succeeded")
b.c.AddHandler(b.messageCreate)
b.c.AddHandler(b.memberUpdate)
b.c.AddHandler(b.messageUpdate)
err = b.c.Open()
if err != nil {
flog.Debugf("%#v", err)
@ -103,6 +105,18 @@ func (b *bdiscord) Send(msg config.Message) error {
return nil
}
func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
if b.Config.EditDisable {
return
}
// only when message is actually edited
if m.Message.EditedTimestamp != "" {
flog.Debugf("Sending edit message")
m.Content = m.Content + b.Config.EditSuffix
b.messageCreate(s, (*discordgo.MessageCreate)(m))
}
}
func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
// not relay our own messages
if m.Author.Username == b.Nick {
@ -125,6 +139,8 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
if len(m.MentionRoles) > 0 {
m.Message.Content = b.replaceRoleMentions(m.Message.Content)
}
m.Message.Content = b.stripCustomoji(m.Message.Content)
m.Message.Content = b.replaceChannelMentions(m.Message.Content)
b.Remote <- config.Message{Username: username, Text: m.ContentWithMentionsReplaced(), Channel: channelName,
Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg"}
}
@ -143,12 +159,14 @@ func (b *bdiscord) getNick(user *discordgo.User) string {
b.Lock()
defer b.Unlock()
if _, ok := b.userMemberMap[user.ID]; ok {
if b.userMemberMap[user.ID].Nick != "" {
// only return if nick is set
return b.userMemberMap[user.ID].Nick
if b.userMemberMap[user.ID] != nil {
if b.userMemberMap[user.ID].Nick != "" {
// only return if nick is set
return b.userMemberMap[user.ID].Nick
}
// otherwise return username
return user.Username
}
// otherwise return username
return user.Username
}
// if we didn't find nick, search for it
b.userMemberMap[user.ID], err = b.c.GuildMember(b.guildID, user.ID)
@ -195,3 +213,28 @@ func (b *bdiscord) replaceRoleMentions(text string) string {
}
return text
}
func (b *bdiscord) replaceChannelMentions(text string) string {
var err error
re := regexp.MustCompile("<#[0-9]+>")
text = re.ReplaceAllStringFunc(text, func(m string) string {
channel := b.getChannelName(m[2 : len(m)-1])
// if at first don't succeed, try again
if channel == "" {
b.Channels, err = b.c.GuildChannels(b.guildID)
if err != nil {
return "#unknownchannel"
}
channel = b.getChannelName(m[2 : len(m)-1])
return "#" + channel
}
return "#" + channel
})
return text
}
func (b *bdiscord) stripCustomoji(text string) string {
// <:doge:302803592035958784>
re := regexp.MustCompile("<(:.*?:)[0-9]+>")
return re.ReplaceAllString(text, `$1`)
}

View File

@ -58,8 +58,9 @@ func (b *Bgitter) JoinChannel(channel string) error {
}
room, err := b.c.GetRoom(roomID)
if err != nil {
b.Rooms = append(b.Rooms, *room)
return err
}
b.Rooms = append(b.Rooms, *room)
user, err := b.c.GetUser()
if err != nil {
return err

View File

@ -46,6 +46,9 @@ func New(cfg config.Protocol, account string, c chan config.Message) *Birc {
if b.Config.MessageQueue == 0 {
b.Config.MessageQueue = 30
}
if b.Config.MessageLength == 0 {
b.Config.MessageLength = 400
}
return b
}
@ -92,7 +95,7 @@ func (b *Birc) Connect() error {
}
func (b *Birc) Disconnect() error {
b.i.Disconnect()
//b.i.Disconnect()
close(b.Local)
return nil
}
@ -109,9 +112,11 @@ func (b *Birc) Send(msg config.Message) error {
}
if strings.HasPrefix(msg.Text, "!") {
b.Command(&msg)
return nil
}
for _, text := range strings.Split(msg.Text, "\n") {
if len(text) > b.Config.MessageLength {
text = text[:b.Config.MessageLength] + " <message clipped>"
}
if len(b.Local) < b.Config.MessageQueue {
if len(b.Local) == b.Config.MessageQueue-1 {
text = text + " <message clipped>"
@ -167,14 +172,19 @@ func (b *Birc) handleNewConnection(event *irc.Event) {
i.AddCallback("JOIN", b.handleJoinPart)
i.AddCallback("PART", b.handleJoinPart)
i.AddCallback("QUIT", b.handleJoinPart)
i.AddCallback("KICK", b.handleJoinPart)
i.AddCallback("*", b.handleOther)
// we are now fully connected
b.connected <- struct{}{}
}
func (b *Birc) handleJoinPart(event *irc.Event) {
flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
channel := event.Arguments[0]
if event.Code == "KICK" {
flog.Infof("Got kicked from %s by %s", channel, event.Nick)
b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: channel, Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS}
return
}
if event.Code == "QUIT" {
if event.Nick == b.Nick && strings.Contains(event.Raw, "Ping timeout") {
flog.Infof("%s reconnecting ..", b.Account)
@ -182,6 +192,7 @@ func (b *Birc) handleJoinPart(event *irc.Event) {
return
}
}
flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
b.Remote <- config.Message{Username: "system", Text: event.Nick + " " + strings.ToLower(event.Code) + "s", Channel: channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE}
flog.Debugf("handle %#v", event)
}

View File

@ -1,10 +1,12 @@
package bmatrix
import (
"regexp"
"sync"
"github.com/42wim/matterbridge/bridge/config"
log "github.com/Sirupsen/logrus"
matrix "github.com/matrix-org/gomatrix"
"sync"
)
type Bmatrix struct {
@ -101,8 +103,13 @@ func (b *Bmatrix) handlematrix() error {
flog.Debugf("Unknown room %s", ev.RoomID)
return
}
username := ev.Sender[1:]
if b.Config.NoHomeServerSuffix {
re := regexp.MustCompile("(.*?):.*")
username = re.ReplaceAllString(username, `$1`)
}
flog.Debugf("Sending message from %s on %s to gateway", ev.Sender, b.Account)
b.Remote <- config.Message{Username: ev.Sender, Text: ev.Content["body"].(string), Channel: channel, Account: b.Account}
b.Remote <- config.Message{Username: username, Text: ev.Content["body"].(string), Channel: channel, Account: b.Account}
}
flog.Debugf("Received: %#v", ev)
})

View File

@ -72,6 +72,7 @@ func (b *Bmattermost) Connect() error {
flog.Info("Connection succeeded")
b.TeamId = b.mc.GetTeamId()
go b.mc.WsReceiver()
go b.mc.StatusLoop()
}
go b.handleMatter()
return nil
@ -96,15 +97,11 @@ func (b *Bmattermost) Send(msg config.Message) error {
channel := msg.Channel
if b.Config.PrefixMessagesWithNick {
/*if IsMarkup(message) {
message = nick + "\n\n" + message
} else {
*/
message = nick + " " + message
//}
message = nick + message
}
if !b.Config.UseAPI {
matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL}
matterMessage.IconURL = msg.Avatar
matterMessage.Channel = channel
matterMessage.UserName = nick
matterMessage.Type = ""
@ -136,14 +133,26 @@ func (b *Bmattermost) handleMatter() {
func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
for message := range b.mc.MessageChan {
flog.Debugf("%#v", message.Raw.Data)
if message.Type == "system_join_leave" ||
message.Type == "system_join_channel" ||
message.Type == "system_leave_channel" {
flog.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account)
b.Remote <- config.Message{Username: "system", Text: message.Text, Channel: message.Channel, Account: b.Account, Event: config.EVENT_JOIN_LEAVE}
continue
}
// do not post our own messages back to irc
// only listen to message from our team
if message.Raw.Event == "posted" && b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
if (message.Raw.Event == "posted" || message.Raw.Event == "post_edited") &&
b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
flog.Debugf("Receiving from matterclient %#v", message)
m := &MMMessage{}
m.Username = message.Username
m.Channel = message.Channel
m.Text = message.Text
if message.Raw.Event == "post_edited" && !b.Config.EditDisable {
m.Text = message.Text + b.Config.EditSuffix
}
if len(message.Post.FileIds) > 0 {
for _, link := range b.mc.GetPublicLinks(message.Post.FileIds) {
m.Text = m.Text + "\n" + link

View File

@ -73,9 +73,15 @@ func (b *Bslack) Disconnect() error {
func (b *Bslack) JoinChannel(channel string) error {
// we can only join channels using the API
if b.Config.UseAPI {
if strings.HasPrefix(b.Config.Token, "xoxb") {
// TODO check if bot has already joined channel
return nil
}
_, err := b.sc.JoinChannel(channel)
if err != nil {
return err
if err.Error() != "name_taken" {
return err
}
}
}
return nil
@ -83,9 +89,6 @@ func (b *Bslack) JoinChannel(channel string) error {
func (b *Bslack) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg)
if msg.Account == b.Account {
return nil
}
nick := msg.Username
message := msg.Text
channel := msg.Channel
@ -195,6 +198,11 @@ func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
// ignore first message
if count > 0 {
flog.Debugf("Receiving from slackclient %#v", ev)
if !b.Config.EditDisable && ev.SubMessage != nil {
flog.Debugf("SubMessage %#v", ev.SubMessage)
ev.User = ev.SubMessage.User
ev.Text = ev.SubMessage.Text + b.Config.EditSuffix
}
// use our own func because rtm.GetChannelInfo doesn't work for private channels
channel, err := b.getChannelByID(ev.Channel)
if err != nil {

View File

@ -76,32 +76,41 @@ func (b *Btelegram) Send(msg config.Message) error {
}
func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
username := ""
text := ""
channel := ""
for update := range updates {
var message *tgbotapi.Message
username := ""
channel := ""
text := ""
// handle channels
if update.ChannelPost != nil {
if update.ChannelPost.From != nil {
username = update.ChannelPost.From.FirstName
if username == "" {
username = update.ChannelPost.From.UserName
}
}
text = update.ChannelPost.Text
channel = strconv.FormatInt(update.ChannelPost.Chat.ID, 10)
message = update.ChannelPost
}
if update.EditedChannelPost != nil && !b.Config.EditDisable {
message = update.EditedChannelPost
message.Text = message.Text + b.Config.EditSuffix
}
// handle groups
if update.Message != nil {
if update.Message.From != nil {
username = update.Message.From.FirstName
message = update.Message
}
if update.EditedMessage != nil && !b.Config.EditDisable {
message = update.EditedMessage
message.Text = message.Text + b.Config.EditSuffix
}
if message.From != nil {
if b.Config.UseFirstName {
username = message.From.FirstName
}
if username == "" {
username = message.From.UserName
if username == "" {
username = update.Message.From.UserName
username = message.From.FirstName
}
}
text = update.Message.Text
channel = strconv.FormatInt(update.Message.Chat.ID, 10)
text = message.Text
channel = strconv.FormatInt(message.Chat.ID, 10)
}
if username == "" {
username = "unknown"
}

View File

@ -119,7 +119,7 @@ func (b *Bxmpp) handleXmpp() error {
var channel, nick string
if v.Type == "groupchat" {
s := strings.Split(v.Remote, "@")
if len(s) == 2 {
if len(s) >= 2 {
channel = s[0]
}
s = strings.Split(s[1], "/")

View File

@ -1,3 +1,97 @@
# v0.14.0
## New features
* api: add token authentication
* mattermost: add support for mattermost 3.10.0
## Changes
* api: gateway name is added in JSON messages
* api: lowercase JSON keys
* api: channel name isn't needed in config #195
## Bugfix
* discord: Add hashtag to channelname (when translating from id) (discord)
* mattermost: Fix a panic. #186
* mattermost: use teamid cache if possible. Fixes a panic
* api: post valid json. #185
* api: allow reuse of api in different gateways. #189
* general: Fix utf-8 issues for {NOPINGNICK}. #193
# v0.13.0
## New features
* irc: Limit message length. ```MessageLength=400```
Maximum length of message sent to irc server. If it exceeds <message clipped> will be add to the message.
* irc: Add NOPINGNICK option.
The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged.
See https://github.com/42wim/matterbridge/issues/175 for more information
## Bugfix
* slack: Fix sending to different channels on same account (slack). Closes #177
* telegram: Fix incorrect usernames being sent. Closes #181
# v0.12.1
## New features
* telegram: Add UseFirstName option (telegram). Closes #144
* matrix: Add NoHomeServerSuffix. Option to disable homeserver on username (matrix). Closes #160.
## Bugfix
* xmpp: Add Compatibility for Cisco Jabber (xmpp) (#166)
* irc: Fix JoinChannel argument to use IRC channel key (#172)
* discord: Fix possible crash on nil (discord)
* discord: Replace long ids in channel metions (discord). Fixes #174
# v0.12.0
## Changes
* general: edited messages are now being sent by default on discord/mattermost/telegram/slack. See "New Features"
## New features
* general: add support for edited messages.
Add new keyword EditDisable (false/true), default false. Which means by default edited messages will be sent to other bridges.
Add new keyword EditSuffix , default "". You can change this eg to "(edited)", this will be appended to every edit message.
* mattermost: support mattermost v3.9.x
* general: Add support for HTTP{S}_PROXY env variables (#162)
* discord: Strip custom emoji metadata (discord). Closes #148
## Bugfix
* slack: Ignore error on private channel join (slack) Fixes #150
* mattermost: fix crash on reconnects when server is down. Closes #163
* irc: Relay messages starting with ! (irc). Closes #164
# v0.11.0
## New features
* general: reusing the same account on multiple gateways now also reuses the connection.
This is particuarly useful for irc. See #87
* general: the Name is now REQUIRED and needs to be UNIQUE for each gateway configuration
* telegram: Support edited messages (telegram). See #141
* mattermost: Add support for showing/hiding join/leave messages from mattermost. Closes #147
* mattermost: Reconnect on session removal/timeout (mattermost)
* mattermost: Support mattermost v3.8.x
* irc: Rejoin channel when kicked (irc).
## Bugfix
* mattermost: Remove space after nick (mattermost). Closes #142
* mattermost: Modify iconurl correctly (mattermost).
* irc: Fix join/leave regression (irc)
# v0.10.3
## Bugfix
* slack: Allow bot tokens for now without warning (slack). Closes #140 (fixes user_is_bot message on channel join)
# v0.10.2
## New features
* general: gops agent added. Allows for more debugging. See #134
* general: toml inline table support added for config file
## Bugfix
* all: vendored libs updated
## Changes
* general: add more informative messages on startup
# v0.10.1
## Bugfix
* gitter: Fix sending messages on new channel join.
# v0.10.0
## New features
* matrix: New protocol support added (https://matrix.org)

View File

@ -5,7 +5,6 @@ import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
log "github.com/Sirupsen/logrus"
"reflect"
"strings"
"time"
)
@ -14,21 +13,21 @@ type Gateway struct {
*config.Config
MyConfig *config.Gateway
Bridges map[string]*bridge.Bridge
ChannelsOut map[string][]string
ChannelsIn map[string][]string
Channels map[string]*config.ChannelInfo
ChannelOptions map[string]config.ChannelOptions
Names map[string]bool
Name string
Message chan config.Message
DestChannelFunc func(msg *config.Message, dest string) []string
DestChannelFunc func(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo
}
func New(cfg *config.Config, gateway *config.Gateway) *Gateway {
func New(cfg *config.Config) *Gateway {
gw := &Gateway{}
gw.Name = gateway.Name
gw.Config = cfg
gw.MyConfig = gateway
gw.Channels = make(map[string]*config.ChannelInfo)
gw.Message = make(chan config.Message)
gw.Bridges = make(map[string]*bridge.Bridge)
gw.Names = make(map[string]bool)
gw.DestChannelFunc = gw.getDestChannel
return gw
}
@ -36,13 +35,17 @@ func New(cfg *config.Config, gateway *config.Gateway) *Gateway {
func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
for _, br := range gw.Bridges {
if br.Account == cfg.Account {
gw.mapChannelsToBridge(br)
err := br.JoinChannels()
if err != nil {
return fmt.Errorf("Bridge %s failed to join channel: %v", br.Account, err)
}
return nil
}
}
log.Infof("Starting bridge: %s ", cfg.Account)
br := bridge.New(gw.Config, cfg, gw.Message)
gw.mapChannelsToBridge(br, gw.ChannelsOut)
gw.mapChannelsToBridge(br, gw.ChannelsIn)
gw.mapChannelsToBridge(br)
gw.Bridges[cfg.Account] = br
err := br.Connect()
if err != nil {
@ -55,17 +58,17 @@ func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
return nil
}
func (gw *Gateway) mapChannelsToBridge(br *bridge.Bridge, cMap map[string][]string) {
for _, channel := range cMap[br.Account] {
if _, ok := gw.ChannelOptions[br.Account+channel]; ok {
br.ChannelsOut[channel] = gw.ChannelOptions[br.Account+channel]
} else {
br.ChannelsOut[channel] = config.ChannelOptions{}
}
func (gw *Gateway) AddConfig(cfg *config.Gateway) error {
if gw.Names[cfg.Name] {
return fmt.Errorf("Gateway with name %s already exists", cfg.Name)
}
}
func (gw *Gateway) Start() error {
if cfg.Name == "" {
return fmt.Errorf("%s", "Gateway without name found")
}
log.Infof("Starting gateway: %s", cfg.Name)
gw.Names[cfg.Name] = true
gw.Name = cfg.Name
gw.MyConfig = cfg
gw.mapChannels()
for _, br := range append(gw.MyConfig.In, append(gw.MyConfig.InOut, gw.MyConfig.Out...)...) {
err := gw.AddBridge(&br)
@ -73,6 +76,18 @@ func (gw *Gateway) Start() error {
return err
}
}
return nil
}
func (gw *Gateway) mapChannelsToBridge(br *bridge.Bridge) {
for ID, channel := range gw.Channels {
if br.Account == channel.Account {
br.Channels[ID] = *channel
}
}
}
func (gw *Gateway) Start() error {
go gw.handleReceive()
return nil
}
@ -88,6 +103,15 @@ func (gw *Gateway) handleReceive() {
}
}
}
if msg.Event == config.EVENT_REJOIN_CHANNELS {
for _, br := range gw.Bridges {
if msg.Account == br.Account {
br.Joined = make(map[string]bool)
br.JoinChannels()
}
}
continue
}
if !gw.ignoreMessage(&msg) {
msg.Timestamp = time.Now()
for _, br := range gw.Bridges {
@ -109,45 +133,58 @@ RECONNECT:
time.Sleep(time.Second * 60)
goto RECONNECT
}
br.Joined = make(map[string]bool)
br.JoinChannels()
}
func (gw *Gateway) mapChannels() error {
options := make(map[string]config.ChannelOptions)
m := make(map[string][]string)
for _, br := range gw.MyConfig.Out {
m[br.Account] = append(m[br.Account], br.Channel)
options[br.Account+br.Channel] = br.Options
for _, br := range append(gw.MyConfig.Out, gw.MyConfig.InOut...) {
if isApi(br.Account) {
br.Channel = "api"
}
ID := br.Channel + br.Account
_, ok := gw.Channels[ID]
if !ok {
channel := &config.ChannelInfo{Name: br.Channel, Direction: "out", ID: ID, Options: br.Options, Account: br.Account,
GID: make(map[string]bool), SameChannel: make(map[string]bool)}
channel.GID[gw.Name] = true
channel.SameChannel[gw.Name] = br.SameChannel
gw.Channels[channel.ID] = channel
}
gw.Channels[ID].GID[gw.Name] = true
gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
}
gw.ChannelsOut = m
m = nil
m = make(map[string][]string)
for _, br := range gw.MyConfig.In {
m[br.Account] = append(m[br.Account], br.Channel)
options[br.Account+br.Channel] = br.Options
for _, br := range append(gw.MyConfig.In, gw.MyConfig.InOut...) {
if isApi(br.Account) {
br.Channel = "api"
}
ID := br.Channel + br.Account
_, ok := gw.Channels[ID]
if !ok {
channel := &config.ChannelInfo{Name: br.Channel, Direction: "in", ID: ID, Options: br.Options, Account: br.Account,
GID: make(map[string]bool), SameChannel: make(map[string]bool)}
channel.GID[gw.Name] = true
channel.SameChannel[gw.Name] = br.SameChannel
gw.Channels[channel.ID] = channel
}
gw.Channels[ID].GID[gw.Name] = true
gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
}
gw.ChannelsIn = m
for _, br := range gw.MyConfig.InOut {
gw.ChannelsIn[br.Account] = append(gw.ChannelsIn[br.Account], br.Channel)
gw.ChannelsOut[br.Account] = append(gw.ChannelsOut[br.Account], br.Channel)
options[br.Account+br.Channel] = br.Options
}
gw.ChannelOptions = options
return nil
}
func (gw *Gateway) getDestChannel(msg *config.Message, dest string) []string {
channels := gw.ChannelsIn[msg.Account]
// broadcast to every out channel (irc QUIT)
if msg.Event == config.EVENT_JOIN_LEAVE && msg.Channel == "" {
return gw.ChannelsOut[dest]
}
for _, channel := range channels {
if channel == msg.Channel {
return gw.ChannelsOut[dest]
func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo {
var channels []config.ChannelInfo
for _, channel := range gw.Channels {
if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
continue
}
if channel.Direction == "out" && channel.Account == dest.Account && gw.validGatewayDest(msg, channel) {
channels = append(channels, *channel)
}
}
return []string{}
return channels
}
func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
@ -155,19 +192,21 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart {
return
}
// broadcast to every out channel (irc QUIT)
if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
log.Debug("empty channel")
return
}
originchannel := msg.Channel
channels := gw.DestChannelFunc(&msg, dest.Account)
for _, channel := range channels {
// do not send the message to the bridge we come from if also the channel is the same
if msg.Account == dest.Account && channel == originchannel {
origmsg := msg
for _, channel := range gw.DestChannelFunc(&msg, *dest) {
// do not send to ourself
if channel.ID == getChannelID(origmsg) {
continue
}
msg.Channel = channel
if msg.Channel == "" {
log.Debug("empty channel")
return
}
log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel)
log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
msg.Channel = channel.Name
gw.modifyAvatar(&msg, dest)
gw.modifyUsername(&msg, dest)
// for api we need originchannel as channel
if dest.Protocol == "api" {
@ -194,21 +233,6 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
return false
}
func (gw *Gateway) modifyMessage(msg *config.Message, dest *bridge.Bridge) {
val := reflect.ValueOf(gw.Config).Elem()
for i := 0; i < val.NumField(); i++ {
typeField := val.Type().Field(i)
// look for the protocol map (both lowercase)
if strings.ToLower(typeField.Name) == dest.Protocol {
// get the Protocol struct from the map
protoCfg := val.Field(i).MapIndex(reflect.ValueOf(dest.Name))
//config.SetNickFormat(msg, protoCfg.Interface().(config.Protocol))
val.Field(i).SetMapIndex(reflect.ValueOf(dest.Name), protoCfg)
break
}
}
}
func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
br := gw.Bridges[msg.Account]
msg.Protocol = br.Protocol
@ -216,8 +240,74 @@ func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
if nick == "" {
nick = dest.Config.RemoteNickFormat
}
if len(msg.Username) > 0 {
// fix utf-8 issue #193
i := 0
for index := range msg.Username {
if i == 1 {
i = index
break
}
i++
}
nick = strings.Replace(nick, "{NOPINGNICK}", msg.Username[:i]+""+msg.Username[i:], -1)
}
nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
msg.Username = nick
}
func (gw *Gateway) modifyAvatar(msg *config.Message, dest *bridge.Bridge) {
iconurl := gw.Config.General.IconURL
if iconurl == "" {
iconurl = dest.Config.IconURL
}
iconurl = strings.Replace(iconurl, "{NICK}", msg.Username, -1)
if msg.Avatar == "" {
msg.Avatar = iconurl
}
}
func getChannelID(msg config.Message) string {
return msg.Channel + msg.Account
}
func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.ChannelInfo) bool {
GIDmap := gw.Channels[getChannelID(*msg)].GID
// gateway is specified in message (probably from api)
if msg.Gateway != "" {
return channel.GID[msg.Gateway]
}
// check if we are running a samechannelgateway.
// if it is and the channel name matches it's ok, otherwise we shouldn't use this channel.
for k, _ := range GIDmap {
if channel.SameChannel[k] == true {
if msg.Channel == channel.Name {
// add the gateway to our message
msg.Gateway = k
return true
} else {
return false
}
}
}
// check if we are in the correct gateway
for k, _ := range GIDmap {
if channel.GID[k] == true {
// add the gateway to our message
msg.Gateway = k
return true
}
}
return false
}
func isApi(account string) bool {
if strings.HasPrefix(account, "api.") {
return true
}
return false
}

View File

@ -2,48 +2,27 @@ package samechannelgateway
import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/gateway"
)
type SameChannelGateway struct {
*config.Config
MyConfig *config.SameChannelGateway
Channels []string
Name string
}
func New(cfg *config.Config, gatewayCfg *config.SameChannelGateway) *SameChannelGateway {
return &SameChannelGateway{
MyConfig: gatewayCfg,
Channels: gatewayCfg.Channels,
Name: gatewayCfg.Name,
Config: cfg}
func New(cfg *config.Config) *SameChannelGateway {
return &SameChannelGateway{Config: cfg}
}
func (sgw *SameChannelGateway) Start() error {
gw := gateway.New(sgw.Config, &config.Gateway{Name: sgw.Name})
gw.DestChannelFunc = sgw.getDestChannel
for _, account := range sgw.MyConfig.Accounts {
for _, channel := range sgw.Channels {
br := config.Bridge{Account: account, Channel: channel}
gw.MyConfig.InOut = append(gw.MyConfig.InOut, br)
func (sgw *SameChannelGateway) GetConfig() []config.Gateway {
var gwconfigs []config.Gateway
cfg := sgw.Config
for _, gw := range cfg.SameChannelGateway {
gwconfig := config.Gateway{Name: gw.Name, Enable: gw.Enable}
for _, account := range gw.Accounts {
for _, channel := range gw.Channels {
gwconfig.InOut = append(gwconfig.InOut, config.Bridge{Account: account, Channel: channel, SameChannel: true})
}
}
gwconfigs = append(gwconfigs, gwconfig)
}
return gw.Start()
}
func (sgw *SameChannelGateway) validChannel(channel string) bool {
for _, c := range sgw.Channels {
if c == channel {
return true
}
}
return false
}
func (sgw *SameChannelGateway) getDestChannel(msg *config.Message, dest string) []string {
if sgw.validChannel(msg.Channel) {
return []string{msg.Channel}
}
return []string{}
return gwconfigs
}

View File

@ -7,10 +7,12 @@ import (
"github.com/42wim/matterbridge/gateway"
"github.com/42wim/matterbridge/gateway/samechannel"
log "github.com/Sirupsen/logrus"
"github.com/google/gops/agent"
"strings"
)
var (
version = "0.10.0"
version = "0.14.0"
githash string
)
@ -22,40 +24,42 @@ func main() {
flagConfig := flag.String("conf", "matterbridge.toml", "config file")
flagDebug := flag.Bool("debug", false, "enable debug")
flagVersion := flag.Bool("version", false, "show version")
flagGops := flag.Bool("gops", false, "enable gops agent")
flag.Parse()
if *flagGops {
agent.Listen(&agent.Options{})
defer agent.Close()
}
if *flagVersion {
fmt.Printf("version: %s %s\n", version, githash)
return
}
flag.Parse()
if *flagDebug {
log.Info("Enabling debug")
log.SetLevel(log.DebugLevel)
}
log.Printf("Running version %s %s", version, githash)
if strings.Contains(version, "-dev") {
log.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.")
}
cfg := config.NewConfig(*flagConfig)
for _, gw := range cfg.SameChannelGateway {
if !gw.Enable {
continue
}
log.Printf("Starting samechannel gateway %#v", gw.Name)
g := samechannelgateway.New(cfg, &gw)
err := g.Start()
if err != nil {
log.Fatalf("Starting gateway failed %#v", err)
}
}
for _, gw := range cfg.Gateway {
g := gateway.New(cfg)
sgw := samechannelgateway.New(cfg)
gwconfigs := sgw.GetConfig()
for _, gw := range append(gwconfigs, cfg.Gateway...) {
if !gw.Enable {
continue
}
log.Printf("Starting gateway %#v", gw.Name)
g := gateway.New(cfg, &gw)
err := g.Start()
err := g.AddConfig(&gw)
if err != nil {
log.Fatalf("Starting gateway failed %#v", err)
log.Fatalf("Starting gateway failed: %s", err)
}
}
err := g.Start()
if err != nil {
log.Fatalf("Starting gateway failed: %s", err)
}
log.Printf("Gateway(s) started succesfully. Now relaying messages")
select {}
}

View File

@ -1,4 +1,5 @@
#This is configuration for matterbridge.
#WARNING: as this file contains credentials, be sure to set correct file permissions
###################################################################
#IRC section
###################################################################
@ -48,10 +49,15 @@ MessageDelay=1300
#Maximum amount of messages to hold in queue. If queue is full
#messages will be dropped.
#<clipped> will be add to the message that fills the queue.
#<message clipped> will be add to the message that fills the queue.
#OPTIONAL (default 30)
MessageQueue=30
#Maximum length of message sent to irc server. If it exceeds
#<message clipped> will be add to the message.
#OPTIONAL (default 400)
MessageLength=400
#Nicks you want to ignore.
#Messages from those users will not be sent to other bridges.
#OPTIONAL
@ -61,10 +67,12 @@ IgnoreNicks="ircspammer1 ircspammer2"
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge
#The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged. See https://github.com/42wim/matterbridge/issues/175 for more information
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -114,7 +122,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -157,7 +166,8 @@ IgnoreNicks="spammer1 spammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -197,9 +207,9 @@ IconURL="http://youricon.png"
#OPTIONAL
useAPI=false
#The mattermost hostname.
#The mattermost hostname. (do not prefix it with http or https)
#REQUIRED (when useAPI=true)
Server="yourmattermostserver.domain"
Server="yourmattermostserver.domain"
#Your team on mattermost.
#REQUIRED (when useAPI=true)
@ -238,6 +248,14 @@ NicksPerRow=4
#OPTIONAL (default false)
PrefixMessagesWithNick=false
#Disable sending of edits to other bridges
#OPTIONAL (default false)
EditDisable=false
#Message to be appended to every edited message
#OPTIONAL (default empty)
EditSuffix=" (edited)"
#Nicks you want to ignore.
#Messages from those users will not be sent to other bridges.
#OPTIONAL
@ -250,7 +268,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -282,7 +301,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -321,6 +341,7 @@ useAPI=false
#Token to connect with the Slack API
#You'll have to use a test/api-token using a dedicated user and not a bot token.
#See https://github.com/42wim/matterbridge/issues/75 for more info.
#Use https://api.slack.com/custom-integrations/legacy-tokens
#REQUIRED (when useAPI=true)
Token="yourslacktoken"
@ -341,6 +362,14 @@ NickFormatter="plain"
#OPTIONAL (default 4)
NicksPerRow=4
#Disable sending of edits to other bridges
#OPTIONAL (default false)
EditDisable=true
#Message to be appended to every edited message
#OPTIONAL (default empty)
EditSuffix=" (edited)"
#Whether to prefix messages from other bridges to mattermost with RemoteNickFormat
#Useful if username overrides for incoming webhooks isn't enabled on the
#slack server. If you set PrefixMessagesWithNick to true, each message
@ -361,7 +390,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -384,6 +414,14 @@ Token="Yourtokenhere"
#REQUIRED
Server="yourservername"
#Disable sending of edits to other bridges
#OPTIONAL (default false)
EditDisable=false
#Message to be appended to every edited message
#OPTIONAL (default empty)
EditSuffix=" (edited)"
#Nicks you want to ignore.
#Messages from those users will not be sent to other bridges.
#OPTIONAL
@ -396,7 +434,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -419,6 +458,20 @@ Token="Yourtokenhere"
#See https://core.telegram.org/bots/api#html-style
MessageFormat=""
#If enabled use the "First Name" as username. If this is empty use the Username
#If disabled use the "Username" as username. If this is empty use the First Name
#If all names are empty, username will be "unknown"
#OPTIONAL (default false)
UseFirstName=false
#Disable sending of edits to other bridges
#OPTIONAL (default false)
EditDisable=false
#Message to be appended to every edited message
#OPTIONAL (default empty)
EditSuffix=" (edited)"
#Nicks you want to ignore.
#Messages from those users will not be sent to other bridges.
#OPTIONAL
@ -431,7 +484,8 @@ IgnoreNicks="spammer1 spammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -488,7 +542,8 @@ IgnoreNicks="ircspammer1 ircspammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -512,6 +567,11 @@ Server="https://matrix.org"
Login="yourlogin"
Password="yourpass"
#Whether to send the homeserver suffix. eg ":matrix.org" in @username:matrix.org
#to other bridges, or only send "username".(true only sends username)
#OPTIONAL (default false)
NoHomeServerSuffix=false
#Whether to prefix messages from other bridges to matrix with the sender's nick.
#Useful if username overrides for incoming webhooks isn't enabled on the
#matrix server. If you set PrefixMessagesWithNick to true, each message
@ -531,7 +591,8 @@ IgnoreNicks="spammer1 spammer2"
#OPTIONAL (default empty)
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#Enable to show users joins/parts from other bridges (only from irc-bridge at the moment)
#Enable to show users joins/parts from other bridges
#Only works hiding/show messages from irc and mattermost bridge for now
#OPTIONAL (default false)
ShowJoinPart=false
@ -552,6 +613,11 @@ BindAddress="127.0.0.1:4242"
#Amount of messages to keep in memory
Buffer=1000
#Bearer token used for authentication
#curl -H "Authorization: Bearer token" http://localhost:4242/api/messages
#OPTIONAL (no authorization if token is empty)
Token="mytoken"
#RemoteNickFormat defines how remote users appear on this bridge
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
@ -559,6 +625,8 @@ Buffer=1000
#OPTIONAL (default empty)
RemoteNickFormat="{NICK}"
###################################################################
#General configuration
###################################################################
@ -586,7 +654,7 @@ RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#
[[gateway]]
#OPTIONAL (not used for now)
#REQUIRED and UNIQUE
name="gateway1"
#Enable enables this gateway
##OPTIONAL (default false)
@ -602,7 +670,7 @@ enable=true
#channel to connect on that account
#How to specify them for the different bridges:
#
#irc - #channel (# is required)
#irc - #channel (# is required) (this needs to be lowercase!)
#mattermost - channel (the channel name as seen in the URL, not the displayname)
#gitter - username/room
#xmpp - channel
@ -614,7 +682,8 @@ enable=true
# see (https://www.linkedin.com/pulse/telegram-bots-beginners-marco-frau)
#hipchat - id_channel (see https://www.hipchat.com/account/xmpp for the correct channel)
#rocketchat - #channel (# is required)
#matrix - #channel:server (eg #yourchannel:matrix.org)
#matrix - #channel:server (eg #yourchannel:matrix.org)
# - encrypted rooms are not supported in matrix
#REQUIRED
channel="#testing"
@ -650,7 +719,9 @@ enable=true
#account="api.local"
#channel="api"
#To send data to the api:
#curl -XPOST -H 'Content-Type: application/json' -d '{"text":"test","username":"randomuser"}' http://localhost:4242/api/message
#curl -XPOST -H 'Content-Type: application/json' -d '{"text":"test","username":"randomuser","gateway":"gateway1"}' http://localhost:4242/api/message
#To read from the api:
#curl http://localhost:4242/api/messages
#If you want to do a 1:1 mapping between protocols where the channelnames are the same
#e.g. slack and mattermost you can use the samechannelgateway configuration
@ -658,6 +729,7 @@ enable=true
#channel testing on slack and vice versa. (and for the channel testing2 and testing3)
[[samechannelgateway]]
name="samechannel1"
enable = false
accounts = [ "mattermost.work","slack.hobby" ]
channels = [ "testing","testing2","testing3"]

View File

@ -1,3 +1,4 @@
#WARNING: as this file contains credentials, be sure to set correct file permissions
[irc]
[irc.freenode]
Server="irc.freenode.net:6667"
@ -6,7 +7,8 @@
[mattermost]
[mattermost.work]
useAPI=true
Server="yourmattermostserver.domain"
#do not prefix it wit http:// or https://
Server="yourmattermostserver.domain"
Team="yourteam"
Login="yourlogin"
Password="yourpass"
@ -15,18 +17,19 @@
[[gateway]]
name="gateway1"
enable=true
[[gateway.in]]
[[gateway.inout]]
account="irc.freenode"
channel="#testing"
[[gateway.out]]
account="irc.freenode"
channel="#testing"
[[gateway.in]]
[[gateway.inout]]
account="mattermost.work"
channel="off-topic"
[[gateway.out]]
account="mattermost.work"
channel="off-topic"
#simpler config possible since v0.10.2
#[[gateway]]
#name="gateway2"
#enable=true
#inout = [
# { account="irc.freenode", channel="#testing", options={key="channelkey"}},
# { account="mattermost.work", channel="off-topic" },
#]

View File

@ -4,9 +4,11 @@ import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/cookiejar"
"net/url"
"strconv"
"strings"
"sync"
"time"
@ -34,6 +36,7 @@ type Message struct {
Channel string
Username string
Text string
Type string
}
type Team struct {
@ -47,19 +50,20 @@ type Team struct {
type MMClient struct {
sync.RWMutex
*Credentials
Team *Team
OtherTeams []*Team
Client *model.Client
User *model.User
Users map[string]*model.User
MessageChan chan *Message
log *log.Entry
WsClient *websocket.Conn
WsQuit bool
WsAway bool
WsConnected bool
WsSequence int64
WsPingChan chan *model.WebSocketResponse
Team *Team
OtherTeams []*Team
Client *model.Client
User *model.User
Users map[string]*model.User
MessageChan chan *Message
log *log.Entry
WsClient *websocket.Conn
WsQuit bool
WsAway bool
WsConnected bool
WsSequence int64
WsPingChan chan *model.WebSocketResponse
ServerVersion string
}
func New(login, pass, team, server string) *MMClient {
@ -102,8 +106,27 @@ func (m *MMClient) Login() error {
}
// login to mattermost
m.Client = model.NewClient(uriScheme + m.Credentials.Server)
m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}}
m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}, Proxy: http.ProxyFromEnvironment}
m.Client.HttpClient.Timeout = time.Second * 10
for {
d := b.Duration()
// bogus call to get the serverversion
m.Client.GetClientProperties()
if firstConnection && !supportedVersion(m.Client.ServerVersion) {
return fmt.Errorf("unsupported mattermost version: %s", m.Client.ServerVersion)
}
m.ServerVersion = m.Client.ServerVersion
if m.ServerVersion == "" {
m.log.Debugf("Server not up yet, reconnecting in %s", d)
time.Sleep(d)
} else {
m.log.Infof("Found version %s", m.ServerVersion)
break
}
}
b.Reset()
var myinfo *model.Result
var appErr *model.AppError
var logmsg = "trying login"
@ -159,11 +182,11 @@ func (m *MMClient) Login() error {
m.Client.SetTeamId(m.Team.Id)
// setup websocket connection
wsurl := wsScheme + m.Credentials.Server + model.API_URL_SUFFIX + "/users/websocket"
wsurl := wsScheme + m.Credentials.Server + model.API_URL_SUFFIX_V3 + "/users/websocket"
header := http.Header{}
header.Set(model.HEADER_AUTH, "BEARER "+m.Client.AuthToken)
m.log.Debug("WsClient: making connection")
m.log.Debugf("WsClient: making connection: %s", wsurl)
for {
wsDialer := &websocket.Dialer{Proxy: http.ProxyFromEnvironment, TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}}
m.WsClient, _, err = wsDialer.Dial(wsurl, header)
@ -177,6 +200,7 @@ func (m *MMClient) Login() error {
}
b.Reset()
m.log.Debug("WsClient: connected")
m.WsSequence = 1
m.WsPingChan = make(chan *model.WebSocketResponse)
// only start to parse WS messages when login is completely done
@ -238,7 +262,7 @@ func (m *MMClient) WsReceiver() {
func (m *MMClient) parseMessage(rmsg *Message) {
switch rmsg.Raw.Event {
case model.WEBSOCKET_EVENT_POSTED:
case model.WEBSOCKET_EVENT_POSTED, model.WEBSOCKET_EVENT_POST_EDITED:
m.parseActionPost(rmsg)
/*
case model.ACTION_USER_REMOVED:
@ -264,9 +288,19 @@ func (m *MMClient) parseActionPost(rmsg *Message) {
if m.GetUser(data.UserId) == nil {
m.UpdateUsers()
}
rmsg.Username = m.GetUser(data.UserId).Username
rmsg.Username = m.GetUserName(data.UserId)
rmsg.Channel = m.GetChannelName(data.ChannelId)
rmsg.Team = m.GetTeamName(rmsg.Raw.Data["team_id"].(string))
rmsg.Type = data.Type
teamid, _ := rmsg.Raw.Data["team_id"].(string)
// edit messsages have no team_id for some reason
if teamid == "" {
// we can find the team_id from the channelid
teamid = m.GetChannelTeamId(data.ChannelId)
rmsg.Raw.Data["team_id"] = teamid
}
if teamid != "" {
rmsg.Team = m.GetTeamName(teamid)
}
// direct message
if rmsg.Raw.Data["channel_type"] == "D" {
rmsg.Channel = m.GetUser(data.UserId).Username
@ -292,7 +326,12 @@ func (m *MMClient) UpdateChannels() error {
if err != nil {
return errors.New(err.DetailedError)
}
mmchannels2, err := m.Client.GetMoreChannels("")
var mmchannels2 *model.Result
if m.mmVersion() >= 3.08 {
mmchannels2, err = m.Client.GetMoreChannelsPage(0, 5000)
} else {
mmchannels2, err = m.Client.GetMoreChannels("")
}
if err != nil {
return errors.New(err.DetailedError)
}
@ -334,6 +373,19 @@ func (m *MMClient) GetChannelId(name string, teamId string) string {
return ""
}
func (m *MMClient) GetChannelTeamId(id string) string {
m.RLock()
defer m.RUnlock()
for _, t := range append(m.OtherTeams, m.Team) {
for _, channel := range append(*t.Channels, *t.MoreChannels...) {
if channel.Id == id {
return channel.TeamId
}
}
}
return ""
}
func (m *MMClient) GetChannelHeader(channelId string) string {
m.RLock()
defer m.RUnlock()
@ -427,6 +479,14 @@ func (m *MMClient) UpdateChannelHeader(channelId string, header string) {
func (m *MMClient) UpdateLastViewed(channelId string) {
m.log.Debugf("posting lastview %#v", channelId)
if m.mmVersion() >= 3.08 {
view := model.ChannelView{ChannelId: channelId}
res, _ := m.Client.ViewChannel(view)
if res == false {
m.log.Errorf("ChannelView update for %s failed", channelId)
}
return
}
_, err := m.Client.UpdateLastViewedAt(channelId, true)
if err != nil {
m.log.Error(err)
@ -573,6 +633,14 @@ func (m *MMClient) GetUser(userId string) *model.User {
return m.Users[userId]
}
func (m *MMClient) GetUserName(userId string) string {
user := m.GetUser(userId)
if user != nil {
return user.Username
}
return ""
}
func (m *MMClient) GetStatus(userId string) string {
res, err := m.Client.GetStatuses()
if err != nil {
@ -628,6 +696,7 @@ func (m *MMClient) StatusLoop() {
m.Logout()
m.WsQuit = false
m.Login()
go m.WsReceiver()
}
}
time.Sleep(time.Second * 60)
@ -659,7 +728,11 @@ func (m *MMClient) initUser() error {
return errors.New(err.DetailedError)
}
t.Channels = mmchannels.Data.(*model.ChannelList)
mmchannels, err = m.Client.GetMoreChannels("")
if m.mmVersion() >= 3.08 {
mmchannels, err = m.Client.GetMoreChannelsPage(0, 5000)
} else {
mmchannels, err = m.Client.GetMoreChannels("")
}
if err != nil {
return errors.New(err.DetailedError)
}
@ -687,3 +760,23 @@ func (m *MMClient) sendWSRequest(action string, data map[string]interface{}) err
m.WsClient.WriteJSON(req)
return nil
}
func (m *MMClient) mmVersion() float64 {
v, _ := strconv.ParseFloat(string(m.ServerVersion[0:2])+"0"+string(m.ServerVersion[2]), 64)
if string(m.ServerVersion[4]) == "." {
v, _ = strconv.ParseFloat(m.ServerVersion[0:4], 64)
}
return v
}
func supportedVersion(version string) bool {
if strings.HasPrefix(version, "3.5.0") ||
strings.HasPrefix(version, "3.6.0") ||
strings.HasPrefix(version, "3.7.0") ||
strings.HasPrefix(version, "3.8.0") ||
strings.HasPrefix(version, "3.9.0") ||
strings.HasPrefix(version, "3.10.0") {
return true
}
return false
}

View File

@ -4,7 +4,7 @@ files via reflection. There is also support for delaying decoding with
the Primitive type, and querying the set of keys in a TOML document with the
MetaData type.
The specification implemented: https://github.com/mojombo/toml
The specification implemented: https://github.com/toml-lang/toml
The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
whether a file is a valid TOML document. It can also be used to print the

View File

@ -241,7 +241,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
func (enc *Encoder) eTable(key Key, rv reflect.Value) {
panicIfInvalidKey(key)
if len(key) == 1 {
// Output an extra new line between top-level tables.
// Output an extra newline between top-level tables.
// (The newline isn't written if nothing else has been written though.)
enc.newline()
}

View File

@ -30,24 +30,28 @@ const (
itemArrayTableEnd
itemKeyStart
itemCommentStart
itemInlineTableStart
itemInlineTableEnd
)
const (
eof = 0
tableStart = '['
tableEnd = ']'
arrayTableStart = '['
arrayTableEnd = ']'
tableSep = '.'
keySep = '='
arrayStart = '['
arrayEnd = ']'
arrayValTerm = ','
commentStart = '#'
stringStart = '"'
stringEnd = '"'
rawStringStart = '\''
rawStringEnd = '\''
eof = 0
comma = ','
tableStart = '['
tableEnd = ']'
arrayTableStart = '['
arrayTableEnd = ']'
tableSep = '.'
keySep = '='
arrayStart = '['
arrayEnd = ']'
commentStart = '#'
stringStart = '"'
stringEnd = '"'
rawStringStart = '\''
rawStringEnd = '\''
inlineTableStart = '{'
inlineTableEnd = '}'
)
type stateFn func(lx *lexer) stateFn
@ -56,11 +60,18 @@ type lexer struct {
input string
start int
pos int
width int
line int
state stateFn
items chan item
// Allow for backing up up to three runes.
// This is necessary because TOML contains 3-rune tokens (""" and ''').
prevWidths [3]int
nprev int // how many of prevWidths are in use
// If we emit an eof, we can still back up, but it is not OK to call
// next again.
atEOF bool
// A stack of state functions used to maintain context.
// The idea is to reuse parts of the state machine in various places.
// For example, values can appear at the top level or within arbitrarily
@ -88,7 +99,7 @@ func (lx *lexer) nextItem() item {
func lex(input string) *lexer {
lx := &lexer{
input: input + "\n",
input: input,
state: lexTop,
line: 1,
items: make(chan item, 10),
@ -103,7 +114,7 @@ func (lx *lexer) push(state stateFn) {
func (lx *lexer) pop() stateFn {
if len(lx.stack) == 0 {
return lx.errorf("BUG in lexer: no states to pop.")
return lx.errorf("BUG in lexer: no states to pop")
}
last := lx.stack[len(lx.stack)-1]
lx.stack = lx.stack[0 : len(lx.stack)-1]
@ -125,16 +136,25 @@ func (lx *lexer) emitTrim(typ itemType) {
}
func (lx *lexer) next() (r rune) {
if lx.atEOF {
panic("next called after EOF")
}
if lx.pos >= len(lx.input) {
lx.width = 0
lx.atEOF = true
return eof
}
if lx.input[lx.pos] == '\n' {
lx.line++
}
r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:])
lx.pos += lx.width
lx.prevWidths[2] = lx.prevWidths[1]
lx.prevWidths[1] = lx.prevWidths[0]
if lx.nprev < 3 {
lx.nprev++
}
r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
lx.prevWidths[0] = w
lx.pos += w
return r
}
@ -143,9 +163,20 @@ func (lx *lexer) ignore() {
lx.start = lx.pos
}
// backup steps back one rune. Can be called only once per call of next.
// backup steps back one rune. Can be called only twice between calls to next.
func (lx *lexer) backup() {
lx.pos -= lx.width
if lx.atEOF {
lx.atEOF = false
return
}
if lx.nprev < 1 {
panic("backed up too far")
}
w := lx.prevWidths[0]
lx.prevWidths[0] = lx.prevWidths[1]
lx.prevWidths[1] = lx.prevWidths[2]
lx.nprev--
lx.pos -= w
if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
lx.line--
}
@ -182,7 +213,7 @@ func (lx *lexer) skip(pred func(rune) bool) {
// errorf stops all lexing by emitting an error and returning `nil`.
// Note that any value that is a character is escaped if it's a special
// character (new lines, tabs, etc.).
// character (newlines, tabs, etc.).
func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
lx.items <- item{
itemError,
@ -198,7 +229,6 @@ func lexTop(lx *lexer) stateFn {
if isWhitespace(r) || isNL(r) {
return lexSkip(lx, lexTop)
}
switch r {
case commentStart:
lx.push(lexTop)
@ -207,7 +237,7 @@ func lexTop(lx *lexer) stateFn {
return lexTableStart
case eof:
if lx.pos > lx.start {
return lx.errorf("Unexpected EOF.")
return lx.errorf("unexpected EOF")
}
lx.emit(itemEOF)
return nil
@ -222,12 +252,12 @@ func lexTop(lx *lexer) stateFn {
// lexTopEnd is entered whenever a top-level item has been consumed. (A value
// or a table.) It must see only whitespace, and will turn back to lexTop
// upon a new line. If it sees EOF, it will quit the lexer successfully.
// upon a newline. If it sees EOF, it will quit the lexer successfully.
func lexTopEnd(lx *lexer) stateFn {
r := lx.next()
switch {
case r == commentStart:
// a comment will read to a new line for us.
// a comment will read to a newline for us.
lx.push(lexTop)
return lexCommentStart
case isWhitespace(r):
@ -236,11 +266,11 @@ func lexTopEnd(lx *lexer) stateFn {
lx.ignore()
return lexTop
case r == eof:
lx.ignore()
return lexTop
lx.emit(itemEOF)
return nil
}
return lx.errorf("Expected a top-level item to end with a new line, "+
"comment or EOF, but got %q instead.", r)
return lx.errorf("expected a top-level item to end with a newline, "+
"comment, or EOF, but got %q instead", r)
}
// lexTable lexes the beginning of a table. Namely, it makes sure that
@ -267,8 +297,8 @@ func lexTableEnd(lx *lexer) stateFn {
func lexArrayTableEnd(lx *lexer) stateFn {
if r := lx.next(); r != arrayTableEnd {
return lx.errorf("Expected end of table array name delimiter %q, "+
"but got %q instead.", arrayTableEnd, r)
return lx.errorf("expected end of table array name delimiter %q, "+
"but got %q instead", arrayTableEnd, r)
}
lx.emit(itemArrayTableEnd)
return lexTopEnd
@ -278,11 +308,11 @@ func lexTableNameStart(lx *lexer) stateFn {
lx.skip(isWhitespace)
switch r := lx.peek(); {
case r == tableEnd || r == eof:
return lx.errorf("Unexpected end of table name. (Table names cannot " +
"be empty.)")
return lx.errorf("unexpected end of table name " +
"(table names cannot be empty)")
case r == tableSep:
return lx.errorf("Unexpected table separator. (Table names cannot " +
"be empty.)")
return lx.errorf("unexpected table separator " +
"(table names cannot be empty)")
case r == stringStart || r == rawStringStart:
lx.ignore()
lx.push(lexTableNameEnd)
@ -317,8 +347,8 @@ func lexTableNameEnd(lx *lexer) stateFn {
case r == tableEnd:
return lx.pop()
default:
return lx.errorf("Expected '.' or ']' to end table name, but got %q "+
"instead.", r)
return lx.errorf("expected '.' or ']' to end table name, "+
"but got %q instead", r)
}
}
@ -328,7 +358,7 @@ func lexKeyStart(lx *lexer) stateFn {
r := lx.peek()
switch {
case r == keySep:
return lx.errorf("Unexpected key separator %q.", keySep)
return lx.errorf("unexpected key separator %q", keySep)
case isWhitespace(r) || isNL(r):
lx.next()
return lexSkip(lx, lexKeyStart)
@ -359,7 +389,7 @@ func lexBareKey(lx *lexer) stateFn {
lx.emit(itemText)
return lexKeyEnd
default:
return lx.errorf("Bare keys cannot contain %q.", r)
return lx.errorf("bare keys cannot contain %q", r)
}
}
@ -372,7 +402,7 @@ func lexKeyEnd(lx *lexer) stateFn {
case isWhitespace(r):
return lexSkip(lx, lexKeyEnd)
default:
return lx.errorf("Expected key separator %q, but got %q instead.",
return lx.errorf("expected key separator %q, but got %q instead",
keySep, r)
}
}
@ -381,9 +411,8 @@ func lexKeyEnd(lx *lexer) stateFn {
// lexValue will ignore whitespace.
// After a value is lexed, the last state on the next is popped and returned.
func lexValue(lx *lexer) stateFn {
// We allow whitespace to precede a value, but NOT new lines.
// In array syntax, the array states are responsible for ignoring new
// lines.
// We allow whitespace to precede a value, but NOT newlines.
// In array syntax, the array states are responsible for ignoring newlines.
r := lx.next()
switch {
case isWhitespace(r):
@ -397,6 +426,10 @@ func lexValue(lx *lexer) stateFn {
lx.ignore()
lx.emit(itemArray)
return lexArrayValue
case inlineTableStart:
lx.ignore()
lx.emit(itemInlineTableStart)
return lexInlineTableValue
case stringStart:
if lx.accept(stringStart) {
if lx.accept(stringStart) {
@ -420,7 +453,7 @@ func lexValue(lx *lexer) stateFn {
case '+', '-':
return lexNumberStart
case '.': // special error case, be kind to users
return lx.errorf("Floats must start with a digit, not '.'.")
return lx.errorf("floats must start with a digit, not '.'")
}
if unicode.IsLetter(r) {
// Be permissive here; lexBool will give a nice error if the
@ -430,11 +463,11 @@ func lexValue(lx *lexer) stateFn {
lx.backup()
return lexBool
}
return lx.errorf("Expected value but found %q instead.", r)
return lx.errorf("expected value but found %q instead", r)
}
// lexArrayValue consumes one value in an array. It assumes that '[' or ','
// have already been consumed. All whitespace and new lines are ignored.
// have already been consumed. All whitespace and newlines are ignored.
func lexArrayValue(lx *lexer) stateFn {
r := lx.next()
switch {
@ -443,10 +476,11 @@ func lexArrayValue(lx *lexer) stateFn {
case r == commentStart:
lx.push(lexArrayValue)
return lexCommentStart
case r == arrayValTerm:
return lx.errorf("Unexpected array value terminator %q.",
arrayValTerm)
case r == comma:
return lx.errorf("unexpected comma")
case r == arrayEnd:
// NOTE(caleb): The spec isn't clear about whether you can have
// a trailing comma or not, so we'll allow it.
return lexArrayEnd
}
@ -455,8 +489,9 @@ func lexArrayValue(lx *lexer) stateFn {
return lexValue
}
// lexArrayValueEnd consumes the cruft between values of an array. Namely,
// it ignores whitespace and expects either a ',' or a ']'.
// lexArrayValueEnd consumes everything between the end of an array value and
// the next value (or the end of the array): it ignores whitespace and newlines
// and expects either a ',' or a ']'.
func lexArrayValueEnd(lx *lexer) stateFn {
r := lx.next()
switch {
@ -465,31 +500,88 @@ func lexArrayValueEnd(lx *lexer) stateFn {
case r == commentStart:
lx.push(lexArrayValueEnd)
return lexCommentStart
case r == arrayValTerm:
case r == comma:
lx.ignore()
return lexArrayValue // move on to the next value
case r == arrayEnd:
return lexArrayEnd
}
return lx.errorf("Expected an array value terminator %q or an array "+
"terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r)
return lx.errorf(
"expected a comma or array terminator %q, but got %q instead",
arrayEnd, r,
)
}
// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has
// just been consumed.
// lexArrayEnd finishes the lexing of an array.
// It assumes that a ']' has just been consumed.
func lexArrayEnd(lx *lexer) stateFn {
lx.ignore()
lx.emit(itemArrayEnd)
return lx.pop()
}
// lexInlineTableValue consumes one key/value pair in an inline table.
// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
func lexInlineTableValue(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r):
return lexSkip(lx, lexInlineTableValue)
case isNL(r):
return lx.errorf("newlines not allowed within inline tables")
case r == commentStart:
lx.push(lexInlineTableValue)
return lexCommentStart
case r == comma:
return lx.errorf("unexpected comma")
case r == inlineTableEnd:
return lexInlineTableEnd
}
lx.backup()
lx.push(lexInlineTableValueEnd)
return lexKeyStart
}
// lexInlineTableValueEnd consumes everything between the end of an inline table
// key/value pair and the next pair (or the end of the table):
// it ignores whitespace and expects either a ',' or a '}'.
func lexInlineTableValueEnd(lx *lexer) stateFn {
r := lx.next()
switch {
case isWhitespace(r):
return lexSkip(lx, lexInlineTableValueEnd)
case isNL(r):
return lx.errorf("newlines not allowed within inline tables")
case r == commentStart:
lx.push(lexInlineTableValueEnd)
return lexCommentStart
case r == comma:
lx.ignore()
return lexInlineTableValue
case r == inlineTableEnd:
return lexInlineTableEnd
}
return lx.errorf("expected a comma or an inline table terminator %q, "+
"but got %q instead", inlineTableEnd, r)
}
// lexInlineTableEnd finishes the lexing of an inline table.
// It assumes that a '}' has just been consumed.
func lexInlineTableEnd(lx *lexer) stateFn {
lx.ignore()
lx.emit(itemInlineTableEnd)
return lx.pop()
}
// lexString consumes the inner contents of a string. It assumes that the
// beginning '"' has already been consumed and ignored.
func lexString(lx *lexer) stateFn {
r := lx.next()
switch {
case r == eof:
return lx.errorf("unexpected EOF")
case isNL(r):
return lx.errorf("Strings cannot contain new lines.")
return lx.errorf("strings cannot contain newlines")
case r == '\\':
lx.push(lexString)
return lexStringEscape
@ -506,11 +598,12 @@ func lexString(lx *lexer) stateFn {
// lexMultilineString consumes the inner contents of a string. It assumes that
// the beginning '"""' has already been consumed and ignored.
func lexMultilineString(lx *lexer) stateFn {
r := lx.next()
switch {
case r == '\\':
switch lx.next() {
case eof:
return lx.errorf("unexpected EOF")
case '\\':
return lexMultilineStringEscape
case r == stringEnd:
case stringEnd:
if lx.accept(stringEnd) {
if lx.accept(stringEnd) {
lx.backup()
@ -534,8 +627,10 @@ func lexMultilineString(lx *lexer) stateFn {
func lexRawString(lx *lexer) stateFn {
r := lx.next()
switch {
case r == eof:
return lx.errorf("unexpected EOF")
case isNL(r):
return lx.errorf("Strings cannot contain new lines.")
return lx.errorf("strings cannot contain newlines")
case r == rawStringEnd:
lx.backup()
lx.emit(itemRawString)
@ -547,12 +642,13 @@ func lexRawString(lx *lexer) stateFn {
}
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
// a string. It assumes that the beginning "'" has already been consumed and
// a string. It assumes that the beginning "'''" has already been consumed and
// ignored.
func lexMultilineRawString(lx *lexer) stateFn {
r := lx.next()
switch {
case r == rawStringEnd:
switch lx.next() {
case eof:
return lx.errorf("unexpected EOF")
case rawStringEnd:
if lx.accept(rawStringEnd) {
if lx.accept(rawStringEnd) {
lx.backup()
@ -605,10 +701,9 @@ func lexStringEscape(lx *lexer) stateFn {
case 'U':
return lexLongUnicodeEscape
}
return lx.errorf("Invalid escape character %q. Only the following "+
return lx.errorf("invalid escape character %q; only the following "+
"escape characters are allowed: "+
"\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, "+
"\\uXXXX and \\UXXXXXXXX.", r)
`\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
}
func lexShortUnicodeEscape(lx *lexer) stateFn {
@ -616,8 +711,8 @@ func lexShortUnicodeEscape(lx *lexer) stateFn {
for i := 0; i < 4; i++ {
r = lx.next()
if !isHexadecimal(r) {
return lx.errorf("Expected four hexadecimal digits after '\\u', "+
"but got '%s' instead.", lx.current())
return lx.errorf(`expected four hexadecimal digits after '\u', `+
"but got %q instead", lx.current())
}
}
return lx.pop()
@ -628,8 +723,8 @@ func lexLongUnicodeEscape(lx *lexer) stateFn {
for i := 0; i < 8; i++ {
r = lx.next()
if !isHexadecimal(r) {
return lx.errorf("Expected eight hexadecimal digits after '\\U', "+
"but got '%s' instead.", lx.current())
return lx.errorf(`expected eight hexadecimal digits after '\U', `+
"but got %q instead", lx.current())
}
}
return lx.pop()
@ -647,9 +742,9 @@ func lexNumberOrDateStart(lx *lexer) stateFn {
case 'e', 'E':
return lexFloat
case '.':
return lx.errorf("Floats must start with a digit, not '.'.")
return lx.errorf("floats must start with a digit, not '.'")
}
return lx.errorf("Expected a digit but got %q.", r)
return lx.errorf("expected a digit but got %q", r)
}
// lexNumberOrDate consumes either an integer, float or datetime.
@ -697,9 +792,9 @@ func lexNumberStart(lx *lexer) stateFn {
r := lx.next()
if !isDigit(r) {
if r == '.' {
return lx.errorf("Floats must start with a digit, not '.'.")
return lx.errorf("floats must start with a digit, not '.'")
}
return lx.errorf("Expected a digit but got %q.", r)
return lx.errorf("expected a digit but got %q", r)
}
return lexNumber
}
@ -757,7 +852,7 @@ func lexBool(lx *lexer) stateFn {
lx.emit(itemBool)
return lx.pop()
}
return lx.errorf("Expected value but found %q instead.", s)
return lx.errorf("expected value but found %q instead", s)
}
// lexCommentStart begins the lexing of a comment. It will emit
@ -769,7 +864,7 @@ func lexCommentStart(lx *lexer) stateFn {
}
// lexComment lexes an entire comment. It assumes that '#' has been consumed.
// It will consume *up to* the first new line character, and pass control
// It will consume *up to* the first newline character, and pass control
// back to the last state on the stack.
func lexComment(lx *lexer) stateFn {
r := lx.peek()

View File

@ -269,6 +269,41 @@ func (p *parser) value(it item) (interface{}, tomlType) {
types = append(types, typ)
}
return array, p.typeOfArray(types)
case itemInlineTableStart:
var (
hash = make(map[string]interface{})
outerContext = p.context
outerKey = p.currentKey
)
p.context = append(p.context, p.currentKey)
p.currentKey = ""
for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
if it.typ != itemKeyStart {
p.bug("Expected key start but instead found %q, around line %d",
it.val, p.approxLine)
}
if it.typ == itemCommentStart {
p.expect(itemText)
continue
}
// retrieve key
k := p.next()
p.approxLine = k.line
kname := p.keyString(k)
// retrieve value
p.currentKey = kname
val, typ := p.value(p.next())
// make sure we keep metadata up to date
p.setType(kname, typ)
p.ordered = append(p.ordered, p.context.add(p.currentKey))
hash[kname] = val
}
p.context = outerContext
p.currentKey = outerKey
return hash, tomlHash
}
p.bug("Unexpected value type: %s", it.typ)
panic("unreachable")

64
vendor/github.com/Sirupsen/logrus/alt_exit.go generated vendored Normal file
View File

@ -0,0 +1,64 @@
package logrus
// The following code was sourced and modified from the
// https://github.com/tebeka/atexit package governed by the following license:
//
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
//
// 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.
import (
"fmt"
"os"
)
var handlers = []func(){}
func runHandler(handler func()) {
defer func() {
if err := recover(); err != nil {
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
}
}()
handler()
}
func runHandlers() {
for _, handler := range handlers {
runHandler(handler)
}
}
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
func Exit(code int) {
runHandlers()
os.Exit(code)
}
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
// all handlers. The handlers will also be invoked when any Fatal log entry is
// made.
//
// This method is useful when a caller wishes to use logrus to log a fatal
// message but also needs to gracefully shutdown. An example usecase could be
// closing database connections, or sending a alert that the application is
// closing.
func RegisterExitHandler(handler func()) {
handlers = append(handlers, handler)
}

View File

@ -3,11 +3,21 @@ package logrus
import (
"bytes"
"fmt"
"io"
"os"
"sync"
"time"
)
var bufferPool *sync.Pool
func init() {
bufferPool = &sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
}
// Defines the key when adding errors using WithError.
var ErrorKey = "error"
@ -29,6 +39,9 @@ type Entry struct {
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
Message string
// When formatter is called in entry.log(), an Buffer may be set to entry
Buffer *bytes.Buffer
}
func NewEntry(logger *Logger) *Entry {
@ -39,21 +52,15 @@ func NewEntry(logger *Logger) *Entry {
}
}
// Returns a reader for the entry, which is a proxy to the formatter.
func (entry *Entry) Reader() (*bytes.Buffer, error) {
serialized, err := entry.Logger.Formatter.Format(entry)
return bytes.NewBuffer(serialized), err
}
// Returns the string representation from the reader and ultimately the
// formatter.
func (entry *Entry) String() (string, error) {
reader, err := entry.Reader()
serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil {
return "", err
}
return reader.String(), err
str := string(serialized)
return str, nil
}
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
@ -81,6 +88,7 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {
var buffer *bytes.Buffer
entry.Time = time.Now()
entry.Level = level
entry.Message = msg
@ -90,20 +98,23 @@ func (entry Entry) log(level Level, msg string) {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
entry.Logger.mu.Unlock()
}
reader, err := entry.Reader()
buffer = bufferPool.Get().(*bytes.Buffer)
buffer.Reset()
defer bufferPool.Put(buffer)
entry.Buffer = buffer
serialized, err := entry.Logger.Formatter.Format(&entry)
entry.Buffer = nil
if err != nil {
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
entry.Logger.mu.Unlock()
}
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
_, err = io.Copy(entry.Logger.Out, reader)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
} else {
entry.Logger.mu.Lock()
_, err = entry.Logger.Out.Write(serialized)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
entry.Logger.mu.Unlock()
}
// To avoid Entry#log() returning a value that only would make sense for
@ -150,7 +161,7 @@ func (entry *Entry) Fatal(args ...interface{}) {
if entry.Logger.Level >= FatalLevel {
entry.log(FatalLevel, fmt.Sprint(args...))
}
os.Exit(1)
Exit(1)
}
func (entry *Entry) Panic(args ...interface{}) {
@ -198,7 +209,7 @@ func (entry *Entry) Fatalf(format string, args ...interface{}) {
if entry.Logger.Level >= FatalLevel {
entry.Fatal(fmt.Sprintf(format, args...))
}
os.Exit(1)
Exit(1)
}
func (entry *Entry) Panicf(format string, args ...interface{}) {
@ -245,7 +256,7 @@ func (entry *Entry) Fatalln(args ...interface{}) {
if entry.Logger.Level >= FatalLevel {
entry.Fatal(entry.sprintlnn(args...))
}
os.Exit(1)
Exit(1)
}
func (entry *Entry) Panicln(args ...interface{}) {

View File

@ -2,6 +2,7 @@ package main
import (
"github.com/Sirupsen/logrus"
// "os"
)
var log = logrus.New()
@ -9,6 +10,14 @@ var log = logrus.New()
func init() {
log.Formatter = new(logrus.JSONFormatter)
log.Formatter = new(logrus.TextFormatter) // default
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }
log.Level = logrus.DebugLevel
}

View File

@ -31,18 +31,15 @@ type Formatter interface {
// It's not exported because it's still using Data in an opinionated way. It's to
// avoid code duplication between the two default formatters.
func prefixFieldClashes(data Fields) {
_, ok := data["time"]
if ok {
data["fields.time"] = data["time"]
if t, ok := data["time"]; ok {
data["fields.time"] = t
}
_, ok = data["msg"]
if ok {
data["fields.msg"] = data["msg"]
if m, ok := data["msg"]; ok {
data["fields.msg"] = m
}
_, ok = data["level"]
if ok {
data["fields.level"] = data["level"]
if l, ok := data["level"]; ok {
data["fields.level"] = l
}
}

View File

@ -1,61 +0,0 @@
package logstash
import (
"encoding/json"
"fmt"
"github.com/Sirupsen/logrus"
)
// Formatter generates json in logstash format.
// Logstash site: http://logstash.net/
type LogstashFormatter struct {
Type string // if not empty use for logstash type field.
// TimestampFormat sets the format used for timestamps.
TimestampFormat string
}
func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) {
fields := make(logrus.Fields)
for k, v := range entry.Data {
fields[k] = v
}
fields["@version"] = 1
if f.TimestampFormat == "" {
f.TimestampFormat = logrus.DefaultTimestampFormat
}
fields["@timestamp"] = entry.Time.Format(f.TimestampFormat)
// set message field
v, ok := entry.Data["message"]
if ok {
fields["fields.message"] = v
}
fields["message"] = entry.Message
// set level field
v, ok = entry.Data["level"]
if ok {
fields["fields.level"] = v
}
fields["level"] = entry.Level.String()
// set type field
if f.Type != "" {
v, ok = entry.Data["type"]
if ok {
fields["fields.type"] = v
}
fields["type"] = f.Type
}
serialized, err := json.Marshal(fields)
if err != nil {
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
}
return append(serialized, '\n'), nil
}

View File

@ -5,9 +5,40 @@ import (
"fmt"
)
type fieldKey string
type FieldMap map[fieldKey]string
const (
FieldKeyMsg = "msg"
FieldKeyLevel = "level"
FieldKeyTime = "time"
)
func (f FieldMap) resolve(key fieldKey) string {
if k, ok := f[key]; ok {
return k
}
return string(key)
}
type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// FieldMap allows users to customize the names of keys for various fields.
// As an example:
// formatter := &JSONFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyLevel: "@message",
// },
// }
FieldMap FieldMap
}
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
@ -29,9 +60,11 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat = DefaultTimestampFormat
}
data["time"] = entry.Time.Format(timestampFormat)
data["msg"] = entry.Message
data["level"] = entry.Level.String()
if !f.DisableTimestamp {
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
}
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
serialized, err := json.Marshal(data)
if err != nil {

View File

@ -26,8 +26,31 @@ type Logger struct {
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
// logged. `logrus.Debug` is useful in
Level Level
// Used to sync writing to the log.
mu sync.Mutex
// Used to sync writing to the log. Locking is enabled by Default
mu MutexWrap
// Reusable empty entry
entryPool sync.Pool
}
type MutexWrap struct {
lock sync.Mutex
disabled bool
}
func (mw *MutexWrap) Lock() {
if !mw.disabled {
mw.lock.Lock()
}
}
func (mw *MutexWrap) Unlock() {
if !mw.disabled {
mw.lock.Unlock()
}
}
func (mw *MutexWrap) Disable() {
mw.disabled = true
}
// Creates a new logger. Configuration should be set by changing `Formatter`,
@ -51,162 +74,235 @@ func New() *Logger {
}
}
// Adds a field to the log entry, note that you it doesn't log until you call
func (logger *Logger) newEntry() *Entry {
entry, ok := logger.entryPool.Get().(*Entry)
if ok {
return entry
}
return NewEntry(logger)
}
func (logger *Logger) releaseEntry(entry *Entry) {
logger.entryPool.Put(entry)
}
// Adds a field to the log entry, note that it doesn't log until you call
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
// If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry {
return NewEntry(logger).WithField(key, value)
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithField(key, value)
}
// Adds a struct of fields to the log entry. All it does is call `WithField` for
// each `Field`.
func (logger *Logger) WithFields(fields Fields) *Entry {
return NewEntry(logger).WithFields(fields)
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithFields(fields)
}
// Add an error as single field to the log entry. All it does is call
// `WithError` for the given `error`.
func (logger *Logger) WithError(err error) *Entry {
return NewEntry(logger).WithError(err)
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithError(err)
}
func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debugf(format, args...)
entry := logger.newEntry()
entry.Debugf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infof(format string, args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Infof(format, args...)
entry := logger.newEntry()
entry.Infof(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Printf(format string, args ...interface{}) {
NewEntry(logger).Printf(format, args...)
entry := logger.newEntry()
entry.Printf(format, args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warnf(format string, args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnf(format, args...)
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warningf(format string, args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnf(format, args...)
entry := logger.newEntry()
entry.Warnf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Errorf(format string, args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Errorf(format, args...)
entry := logger.newEntry()
entry.Errorf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatalf(format string, args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatalf(format, args...)
entry := logger.newEntry()
entry.Fatalf(format, args...)
logger.releaseEntry(entry)
}
os.Exit(1)
Exit(1)
}
func (logger *Logger) Panicf(format string, args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panicf(format, args...)
entry := logger.newEntry()
entry.Panicf(format, args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Debug(args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debug(args...)
entry := logger.newEntry()
entry.Debug(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Info(args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Info(args...)
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Print(args ...interface{}) {
NewEntry(logger).Info(args...)
entry := logger.newEntry()
entry.Info(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warn(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warn(args...)
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warning(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warn(args...)
entry := logger.newEntry()
entry.Warn(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Error(args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Error(args...)
entry := logger.newEntry()
entry.Error(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatal(args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatal(args...)
entry := logger.newEntry()
entry.Fatal(args...)
logger.releaseEntry(entry)
}
os.Exit(1)
Exit(1)
}
func (logger *Logger) Panic(args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panic(args...)
entry := logger.newEntry()
entry.Panic(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Debugln(args ...interface{}) {
if logger.Level >= DebugLevel {
NewEntry(logger).Debugln(args...)
entry := logger.newEntry()
entry.Debugln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Infoln(args ...interface{}) {
if logger.Level >= InfoLevel {
NewEntry(logger).Infoln(args...)
entry := logger.newEntry()
entry.Infoln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Println(args ...interface{}) {
NewEntry(logger).Println(args...)
entry := logger.newEntry()
entry.Println(args...)
logger.releaseEntry(entry)
}
func (logger *Logger) Warnln(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnln(args...)
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Warningln(args ...interface{}) {
if logger.Level >= WarnLevel {
NewEntry(logger).Warnln(args...)
entry := logger.newEntry()
entry.Warnln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Errorln(args ...interface{}) {
if logger.Level >= ErrorLevel {
NewEntry(logger).Errorln(args...)
entry := logger.newEntry()
entry.Errorln(args...)
logger.releaseEntry(entry)
}
}
func (logger *Logger) Fatalln(args ...interface{}) {
if logger.Level >= FatalLevel {
NewEntry(logger).Fatalln(args...)
entry := logger.newEntry()
entry.Fatalln(args...)
logger.releaseEntry(entry)
}
os.Exit(1)
Exit(1)
}
func (logger *Logger) Panicln(args ...interface{}) {
if logger.Level >= PanicLevel {
NewEntry(logger).Panicln(args...)
entry := logger.newEntry()
entry.Panicln(args...)
logger.releaseEntry(entry)
}
}
//When file is opened with appending mode, it's safe to
//write concurrently to a file (within 4k message on Linux).
//In these cases user can choose to disable the lock.
func (logger *Logger) SetNoLock() {
logger.mu.Disable()
}

View File

@ -0,0 +1,10 @@
// +build appengine
package logrus
import "io"
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
return true
}

View File

@ -1,4 +1,5 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus

View File

@ -3,6 +3,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
package logrus
import "syscall"

View File

@ -4,18 +4,25 @@
// license that can be found in the LICENSE file.
// +build linux darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
fd := syscall.Stderr
func IsTerminal(f io.Writer) bool {
var termios Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
switch v := f.(type) {
case *os.File:
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
default:
return false
}
}

View File

@ -1,15 +1,21 @@
// +build solaris
// +build solaris,!appengine
package logrus
import (
"io"
"os"
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal() bool {
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA)
return err == nil
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
return err == nil
default:
return false
}
}

View File

@ -3,11 +3,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// +build windows,!appengine
package logrus
import (
"io"
"os"
"syscall"
"unsafe"
)
@ -19,9 +21,13 @@ var (
)
// IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool {
fd := syscall.Stderr
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
func IsTerminal(f io.Writer) bool {
switch v := f.(type) {
case *os.File:
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
default:
return false
}
}

View File

@ -3,9 +3,9 @@ package logrus
import (
"bytes"
"fmt"
"runtime"
"sort"
"strings"
"sync"
"time"
)
@ -20,16 +20,10 @@ const (
var (
baseTimestamp time.Time
isTerminal bool
)
func init() {
baseTimestamp = time.Now()
isTerminal = IsTerminal()
}
func miniTS() int {
return int(time.Since(baseTimestamp) / time.Second)
}
type TextFormatter struct {
@ -54,10 +48,32 @@ type TextFormatter struct {
// that log extremely frequently and don't use the JSON formatter this may not
// be desired.
DisableSorting bool
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal
isTerminal bool
sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out)
}
}
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var keys []string = make([]string, 0, len(entry.Data))
var b *bytes.Buffer
keys := make([]string, 0, len(entry.Data))
for k := range entry.Data {
keys = append(keys, k)
}
@ -65,13 +81,17 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
if !f.DisableSorting {
sort.Strings(keys)
}
b := &bytes.Buffer{}
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
prefixFieldClashes(entry.Data)
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
timestampFormat := f.TimestampFormat
if timestampFormat == "" {
@ -111,51 +131,59 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
levelText := strings.ToUpper(entry.Level.String())[0:4]
if !f.FullTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
if f.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
} else if !f.FullTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
} else {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
}
for _, k := range keys {
v := entry.Data[k]
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
f.appendValue(b, v)
}
}
func needsQuoting(text string) bool {
func (f *TextFormatter) needsQuoting(text string) bool {
if f.QuoteEmptyFields && len(text) == 0 {
return true
}
for _, ch := range text {
if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
ch == '-' || ch == '.') {
return false
return true
}
}
return true
return false
}
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
b.WriteString(key)
b.WriteByte('=')
f.appendValue(b, value)
b.WriteByte(' ')
}
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) {
case string:
if needsQuoting(value) {
if !f.needsQuoting(value) {
b.WriteString(value)
} else {
fmt.Fprintf(b, "%q", value)
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
}
case error:
errmsg := value.Error()
if needsQuoting(errmsg) {
if !f.needsQuoting(errmsg) {
b.WriteString(errmsg)
} else {
fmt.Fprintf(b, "%q", value)
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
}
default:
fmt.Fprint(b, value)
}
b.WriteByte(' ')
}

View File

@ -7,21 +7,52 @@ import (
)
func (logger *Logger) Writer() *io.PipeWriter {
return logger.WriterLevel(InfoLevel)
}
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
return NewEntry(logger).WriterLevel(level)
}
func (entry *Entry) Writer() *io.PipeWriter {
return entry.WriterLevel(InfoLevel)
}
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
reader, writer := io.Pipe()
go logger.writerScanner(reader)
var printFunc func(args ...interface{})
switch level {
case DebugLevel:
printFunc = entry.Debug
case InfoLevel:
printFunc = entry.Info
case WarnLevel:
printFunc = entry.Warn
case ErrorLevel:
printFunc = entry.Error
case FatalLevel:
printFunc = entry.Fatal
case PanicLevel:
printFunc = entry.Panic
default:
printFunc = entry.Print
}
go entry.writerScanner(reader, printFunc)
runtime.SetFinalizer(writer, writerFinalizer)
return writer
}
func (logger *Logger) writerScanner(reader *io.PipeReader) {
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
logger.Print(scanner.Text())
printFunc(scanner.Text())
}
if err := scanner.Err(); err != nil {
logger.Errorf("Error while reading from Writer: %s", err)
entry.Errorf("Error while reading from Writer: %s", err)
}
reader.Close()
}

View File

@ -21,8 +21,10 @@ import (
// BotAPI allows you to interact with the Telegram Bot API.
type BotAPI struct {
Token string `json:"token"`
Debug bool `json:"debug"`
Token string `json:"token"`
Debug bool `json:"debug"`
Buffer int `json:"buffer"`
Self User `json:"-"`
Client *http.Client `json:"-"`
}
@ -42,11 +44,12 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
bot := &BotAPI{
Token: token,
Client: client,
Buffer: 100,
}
self, err := bot.GetMe()
if err != nil {
return &BotAPI{}, err
return nil, err
}
bot.Self = self
@ -68,6 +71,10 @@ func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse,
return APIResponse{}, errors.New(ErrAPIForbidden)
}
if resp.StatusCode != http.StatusOK {
return APIResponse{}, errors.New(http.StatusText(resp.StatusCode))
}
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return APIResponse{}, err
@ -457,7 +464,7 @@ func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) {
// GetUpdatesChan starts and returns a channel for getting updates.
func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
ch := make(chan Update, 100)
ch := make(chan Update, bot.Buffer)
go func() {
for {
@ -484,7 +491,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
// ListenForWebhook registers a http handler for a webhook.
func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
ch := make(chan Update, 100)
ch := make(chan Update, bot.Buffer)
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
bytes, _ := ioutil.ReadAll(r.Body)

View File

@ -768,8 +768,8 @@ type UpdateConfig struct {
// WebhookConfig contains information about a SetWebhook request.
type WebhookConfig struct {
URL *url.URL
Certificate interface{}
URL *url.URL
Certificate interface{}
MaxConnections int
}

View File

@ -318,21 +318,6 @@ func NewWebhookWithCert(link string, file interface{}) WebhookConfig {
}
}
// NewWebhookWithCert creates a new webhook with a certificate and max_connections.
//
// link is the url you wish to get webhooks,
// file contains a string to a file, FileReader, or FileBytes.
// maxConnections defines maximum number of connections from telegram to your server
func NewWebhookWithCertAndMaxConnections(link string, file interface{}, maxConnections int) WebhookConfig {
u, _ := url.Parse(link)
return WebhookConfig{
URL: u,
Certificate: file,
MaxConnections: maxConnections,
}
}
// NewInlineQueryResultArticle creates a new inline query article.
func NewInlineQueryResultArticle(id, title, messageText string) InlineQueryResultArticle {
return InlineQueryResultArticle{

View File

@ -194,7 +194,7 @@ func (m *Message) CommandArguments() string {
return ""
}
return strings.SplitN(m.Text, " ", 2)[1]
return split[1]
}
// MessageEntity contains information about data in a Message.

27
vendor/github.com/google/gops/agent/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2016 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.

237
vendor/github.com/google/gops/agent/agent.go generated vendored Normal file
View File

@ -0,0 +1,237 @@
// 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 agent provides hooks programs can register to retrieve
// diagnostics data by using gops.
package agent
import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
gosignal "os/signal"
"runtime"
"runtime/pprof"
"runtime/trace"
"strconv"
"sync"
"time"
"bufio"
"github.com/google/gops/internal"
"github.com/google/gops/signal"
"github.com/kardianos/osext"
)
const defaultAddr = "127.0.0.1:0"
var (
mu sync.Mutex
portfile string
listener net.Listener
units = []string{" bytes", "KB", "MB", "GB", "TB", "PB"}
)
// Options allows configuring the started agent.
type Options struct {
// Addr is the host:port the agent will be listening at.
// Optional.
Addr string
// NoShutdownCleanup tells the agent not to automatically cleanup
// resources if the running process receives an interrupt.
// Optional.
NoShutdownCleanup bool
}
// Listen starts the gops agent on a host process. Once agent started, users
// can use the advanced gops features. The agent will listen to Interrupt
// signals and exit the process, if you need to perform further work on the
// Interrupt signal use the options parameter to configure the agent
// accordingly.
//
// Note: The agent exposes an endpoint via a TCP connection that can be used by
// any program on the system. Review your security requirements before starting
// the agent.
func Listen(opts *Options) error {
mu.Lock()
defer mu.Unlock()
if opts == nil {
opts = &Options{}
}
if portfile != "" {
return fmt.Errorf("gops: agent already listening at: %v", listener.Addr())
}
gopsdir, err := internal.ConfigDir()
if err != nil {
return err
}
err = os.MkdirAll(gopsdir, os.ModePerm)
if err != nil {
return err
}
if !opts.NoShutdownCleanup {
gracefulShutdown()
}
addr := opts.Addr
if addr == "" {
addr = defaultAddr
}
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
listener = ln
port := listener.Addr().(*net.TCPAddr).Port
portfile = fmt.Sprintf("%s/%d", gopsdir, os.Getpid())
err = ioutil.WriteFile(portfile, []byte(strconv.Itoa(port)), os.ModePerm)
if err != nil {
return err
}
go listen()
return nil
}
func listen() {
buf := make([]byte, 1)
for {
fd, err := listener.Accept()
if err != nil {
fmt.Fprintf(os.Stderr, "gops: %v", err)
if netErr, ok := err.(net.Error); ok && !netErr.Temporary() {
break
}
continue
}
if _, err := fd.Read(buf); err != nil {
fmt.Fprintf(os.Stderr, "gops: %v", err)
continue
}
if err := handle(fd, buf); err != nil {
fmt.Fprintf(os.Stderr, "gops: %v", err)
continue
}
fd.Close()
}
}
func gracefulShutdown() {
c := make(chan os.Signal, 1)
gosignal.Notify(c, os.Interrupt)
go func() {
// cleanup the socket on shutdown.
<-c
Close()
os.Exit(1)
}()
}
// Close closes the agent, removing temporary files and closing the TCP listener.
// If no agent is listening, Close does nothing.
func Close() {
mu.Lock()
defer mu.Unlock()
if portfile != "" {
os.Remove(portfile)
portfile = ""
}
if listener != nil {
listener.Close()
}
}
func formatBytes(val uint64) string {
var i int
var target uint64
for i = range units {
target = 1 << uint(10*(i+1))
if val < target {
break
}
}
if i > 0 {
return fmt.Sprintf("%0.2f%s (%d bytes)", float64(val)/(float64(target)/1024), units[i], val)
}
return fmt.Sprintf("%d bytes", val)
}
func handle(conn io.Writer, msg []byte) error {
switch msg[0] {
case signal.StackTrace:
return pprof.Lookup("goroutine").WriteTo(conn, 2)
case signal.GC:
runtime.GC()
_, err := conn.Write([]byte("ok"))
return err
case signal.MemStats:
var s runtime.MemStats
runtime.ReadMemStats(&s)
fmt.Fprintf(conn, "alloc: %v\n", formatBytes(s.Alloc))
fmt.Fprintf(conn, "total-alloc: %v\n", formatBytes(s.TotalAlloc))
fmt.Fprintf(conn, "sys: %v\n", formatBytes(s.Sys))
fmt.Fprintf(conn, "lookups: %v\n", s.Lookups)
fmt.Fprintf(conn, "mallocs: %v\n", s.Mallocs)
fmt.Fprintf(conn, "frees: %v\n", s.Frees)
fmt.Fprintf(conn, "heap-alloc: %v\n", formatBytes(s.HeapAlloc))
fmt.Fprintf(conn, "heap-sys: %v\n", formatBytes(s.HeapSys))
fmt.Fprintf(conn, "heap-idle: %v\n", formatBytes(s.HeapIdle))
fmt.Fprintf(conn, "heap-in-use: %v\n", formatBytes(s.HeapInuse))
fmt.Fprintf(conn, "heap-released: %v\n", formatBytes(s.HeapReleased))
fmt.Fprintf(conn, "heap-objects: %v\n", s.HeapObjects)
fmt.Fprintf(conn, "stack-in-use: %v\n", formatBytes(s.StackInuse))
fmt.Fprintf(conn, "stack-sys: %v\n", formatBytes(s.StackSys))
fmt.Fprintf(conn, "next-gc: when heap-alloc >= %v\n", formatBytes(s.NextGC))
lastGC := "-"
if s.LastGC != 0 {
lastGC = fmt.Sprint(time.Unix(0, int64(s.LastGC)))
}
fmt.Fprintf(conn, "last-gc: %v\n", lastGC)
fmt.Fprintf(conn, "gc-pause: %v\n", time.Duration(s.PauseTotalNs))
fmt.Fprintf(conn, "num-gc: %v\n", s.NumGC)
fmt.Fprintf(conn, "enable-gc: %v\n", s.EnableGC)
fmt.Fprintf(conn, "debug-gc: %v\n", s.DebugGC)
case signal.Version:
fmt.Fprintf(conn, "%v\n", runtime.Version())
case signal.HeapProfile:
pprof.WriteHeapProfile(conn)
case signal.CPUProfile:
if err := pprof.StartCPUProfile(conn); err != nil {
return err
}
time.Sleep(30 * time.Second)
pprof.StopCPUProfile()
case signal.Stats:
fmt.Fprintf(conn, "goroutines: %v\n", runtime.NumGoroutine())
fmt.Fprintf(conn, "OS threads: %v\n", pprof.Lookup("threadcreate").Count())
fmt.Fprintf(conn, "GOMAXPROCS: %v\n", runtime.GOMAXPROCS(0))
fmt.Fprintf(conn, "num CPU: %v\n", runtime.NumCPU())
case signal.BinaryDump:
path, err := osext.Executable()
if err != nil {
return err
}
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
_, err = bufio.NewReader(f).WriteTo(conn)
return err
case signal.Trace:
trace.Start(conn)
time.Sleep(5 * time.Second)
trace.Stop()
}
return nil
}

27
vendor/github.com/google/gops/internal/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2016 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.

600
vendor/github.com/google/gops/internal/dwarf/dwarf.go generated vendored Normal file
View File

@ -0,0 +1,600 @@
// 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 dwarf generates DWARF debugging information.
// DWARF generation is split between the compiler and the linker,
// this package contains the shared code.
package dwarf
import (
"fmt"
)
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
const InfoPrefix = "go.info."
// Sym represents a symbol.
type Sym interface {
}
// A Var represents a local variable or a function parameter.
type Var struct {
Name string
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
Offset int32
Type Sym
Link *Var
}
// A Context specifies how to add data to a Sym.
type Context interface {
PtrSize() int
AddInt(s Sym, size int, i int64)
AddBytes(s Sym, b []byte)
AddAddress(s Sym, t interface{}, ofs int64)
AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
AddString(s Sym, v string)
SymValue(s Sym) int64
}
// AppendUleb128 appends v to b using DWARF's unsigned LEB128 encoding.
func AppendUleb128(b []byte, v uint64) []byte {
for {
c := uint8(v & 0x7f)
v >>= 7
if v != 0 {
c |= 0x80
}
b = append(b, c)
if c&0x80 == 0 {
break
}
}
return b
}
// AppendSleb128 appends v to b using DWARF's signed LEB128 encoding.
func AppendSleb128(b []byte, v int64) []byte {
for {
c := uint8(v & 0x7f)
s := uint8(v & 0x40)
v >>= 7
if (v != -1 || s == 0) && (v != 0 || s != 0) {
c |= 0x80
}
b = append(b, c)
if c&0x80 == 0 {
break
}
}
return b
}
var encbuf [20]byte
// AppendUleb128 appends v to s using DWARF's unsigned LEB128 encoding.
func Uleb128put(ctxt Context, s Sym, v int64) {
b := AppendUleb128(encbuf[:0], uint64(v))
ctxt.AddBytes(s, b)
}
// AppendUleb128 appends v to s using DWARF's signed LEB128 encoding.
func Sleb128put(ctxt Context, s Sym, v int64) {
b := AppendSleb128(encbuf[:0], v)
ctxt.AddBytes(s, b)
}
/*
* Defining Abbrevs. This is hardcoded, and there will be
* only a handful of them. The DWARF spec places no restriction on
* the ordering of attributes in the Abbrevs and DIEs, and we will
* always write them out in the order of declaration in the abbrev.
*/
type dwAttrForm struct {
attr uint16
form uint8
}
// Go-specific type attributes.
const (
DW_AT_go_kind = 0x2900
DW_AT_go_key = 0x2901
DW_AT_go_elem = 0x2902
DW_AT_internal_location = 253 // params and locals; not emitted
)
// Index into the abbrevs table below.
// Keep in sync with ispubname() and ispubtype() below.
// ispubtype considers >= NULLTYPE public
const (
DW_ABRV_NULL = iota
DW_ABRV_COMPUNIT
DW_ABRV_FUNCTION
DW_ABRV_VARIABLE
DW_ABRV_AUTO
DW_ABRV_PARAM
DW_ABRV_STRUCTFIELD
DW_ABRV_FUNCTYPEPARAM
DW_ABRV_DOTDOTDOT
DW_ABRV_ARRAYRANGE
DW_ABRV_NULLTYPE
DW_ABRV_BASETYPE
DW_ABRV_ARRAYTYPE
DW_ABRV_CHANTYPE
DW_ABRV_FUNCTYPE
DW_ABRV_IFACETYPE
DW_ABRV_MAPTYPE
DW_ABRV_PTRTYPE
DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6.
DW_ABRV_SLICETYPE
DW_ABRV_STRINGTYPE
DW_ABRV_STRUCTTYPE
DW_ABRV_TYPEDECL
DW_NABRV
)
type dwAbbrev struct {
tag uint8
children uint8
attr []dwAttrForm
}
var abbrevs = [DW_NABRV]dwAbbrev{
/* The mandatory DW_ABRV_NULL entry. */
{0, 0, []dwAttrForm{}},
/* COMPUNIT */
{
DW_TAG_compile_unit,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_language, DW_FORM_data1},
{DW_AT_low_pc, DW_FORM_addr},
{DW_AT_high_pc, DW_FORM_addr},
{DW_AT_stmt_list, DW_FORM_data4},
{DW_AT_comp_dir, DW_FORM_string},
},
},
/* FUNCTION */
{
DW_TAG_subprogram,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_low_pc, DW_FORM_addr},
{DW_AT_high_pc, DW_FORM_addr},
{DW_AT_external, DW_FORM_flag},
},
},
/* VARIABLE */
{
DW_TAG_variable,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_block1},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_external, DW_FORM_flag},
},
},
/* AUTO */
{
DW_TAG_variable,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_block1},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* PARAM */
{
DW_TAG_formal_parameter,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_location, DW_FORM_block1},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* STRUCTFIELD */
{
DW_TAG_member,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_data_member_location, DW_FORM_block1},
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* FUNCTYPEPARAM */
{
DW_TAG_formal_parameter,
DW_CHILDREN_no,
// No name!
[]dwAttrForm{
{DW_AT_type, DW_FORM_ref_addr},
},
},
/* DOTDOTDOT */
{
DW_TAG_unspecified_parameters,
DW_CHILDREN_no,
[]dwAttrForm{},
},
/* ARRAYRANGE */
{
DW_TAG_subrange_type,
DW_CHILDREN_no,
// No name!
[]dwAttrForm{
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_count, DW_FORM_udata},
},
},
// Below here are the types considered public by ispubtype
/* NULLTYPE */
{
DW_TAG_unspecified_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
},
},
/* BASETYPE */
{
DW_TAG_base_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_encoding, DW_FORM_data1},
{DW_AT_byte_size, DW_FORM_data1},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* ARRAYTYPE */
// child is subrange with upper bound
{
DW_TAG_array_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_byte_size, DW_FORM_udata},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* CHANTYPE */
{
DW_TAG_typedef,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
{DW_AT_go_elem, DW_FORM_ref_addr},
},
},
/* FUNCTYPE */
{
DW_TAG_subroutine_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
// {DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* IFACETYPE */
{
DW_TAG_typedef,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* MAPTYPE */
{
DW_TAG_typedef,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
{DW_AT_go_key, DW_FORM_ref_addr},
{DW_AT_go_elem, DW_FORM_ref_addr},
},
},
/* PTRTYPE */
{
DW_TAG_pointer_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* BARE_PTRTYPE */
{
DW_TAG_pointer_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
},
},
/* SLICETYPE */
{
DW_TAG_structure_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_byte_size, DW_FORM_udata},
{DW_AT_go_kind, DW_FORM_data1},
{DW_AT_go_elem, DW_FORM_ref_addr},
},
},
/* STRINGTYPE */
{
DW_TAG_structure_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_byte_size, DW_FORM_udata},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* STRUCTTYPE */
{
DW_TAG_structure_type,
DW_CHILDREN_yes,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_byte_size, DW_FORM_udata},
{DW_AT_go_kind, DW_FORM_data1},
},
},
/* TYPEDECL */
{
DW_TAG_typedef,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
},
},
}
// GetAbbrev returns the contents of the .debug_abbrev section.
func GetAbbrev() []byte {
var buf []byte
for i := 1; i < DW_NABRV; i++ {
// See section 7.5.3
buf = AppendUleb128(buf, uint64(i))
buf = AppendUleb128(buf, uint64(abbrevs[i].tag))
buf = append(buf, byte(abbrevs[i].children))
for _, f := range abbrevs[i].attr {
buf = AppendUleb128(buf, uint64(f.attr))
buf = AppendUleb128(buf, uint64(f.form))
}
buf = append(buf, 0, 0)
}
return append(buf, 0)
}
/*
* Debugging Information Entries and their attributes.
*/
// DWAttr represents an attribute of a DWDie.
//
// For DW_CLS_string and _block, value should contain the length, and
// data the data, for _reference, value is 0 and data is a DWDie* to
// the referenced instance, for all others, value is the whole thing
// and data is null.
type DWAttr struct {
Link *DWAttr
Atr uint16 // DW_AT_
Cls uint8 // DW_CLS_
Value int64
Data interface{}
}
// DWDie represents a DWARF debug info entry.
type DWDie struct {
Abbrev int
Link *DWDie
Child *DWDie
Attr *DWAttr
Sym Sym
}
func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, data interface{}) error {
switch form {
case DW_FORM_addr: // address
ctxt.AddAddress(s, data, value)
case DW_FORM_block1: // block
if cls == DW_CLS_ADDRESS {
ctxt.AddInt(s, 1, int64(1+ctxt.PtrSize()))
ctxt.AddInt(s, 1, DW_OP_addr)
ctxt.AddAddress(s, data, 0)
break
}
value &= 0xff
ctxt.AddInt(s, 1, value)
p := data.([]byte)[:value]
ctxt.AddBytes(s, p)
case DW_FORM_block2: // block
value &= 0xffff
ctxt.AddInt(s, 2, value)
p := data.([]byte)[:value]
ctxt.AddBytes(s, p)
case DW_FORM_block4: // block
value &= 0xffffffff
ctxt.AddInt(s, 4, value)
p := data.([]byte)[:value]
ctxt.AddBytes(s, p)
case DW_FORM_block: // block
Uleb128put(ctxt, s, value)
p := data.([]byte)[:value]
ctxt.AddBytes(s, p)
case DW_FORM_data1: // constant
ctxt.AddInt(s, 1, value)
case DW_FORM_data2: // constant
ctxt.AddInt(s, 2, value)
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
if cls == DW_CLS_PTR { // DW_AT_stmt_list
ctxt.AddSectionOffset(s, 4, data, 0)
break
}
ctxt.AddInt(s, 4, value)
case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
ctxt.AddInt(s, 8, value)
case DW_FORM_sdata: // constant
Sleb128put(ctxt, s, value)
case DW_FORM_udata: // constant
Uleb128put(ctxt, s, value)
case DW_FORM_string: // string
str := data.(string)
ctxt.AddString(s, str)
// TODO(ribrdb): verify padded strings are never used and remove this
for i := int64(len(str)); i < value; i++ {
ctxt.AddInt(s, 1, 0)
}
case DW_FORM_flag: // flag
if value != 0 {
ctxt.AddInt(s, 1, 1)
} else {
ctxt.AddInt(s, 1, 0)
}
// In DWARF 2 (which is what we claim to generate),
// the ref_addr is the same size as a normal address.
// In DWARF 3 it is always 32 bits, unless emitting a large
// (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
case DW_FORM_ref_addr: // reference to a DIE in the .info section
if data == nil {
return fmt.Errorf("dwarf: null reference in %d", abbrev)
} else {
ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, 0)
}
case DW_FORM_ref1, // reference within the compilation unit
DW_FORM_ref2, // reference
DW_FORM_ref4, // reference
DW_FORM_ref8, // reference
DW_FORM_ref_udata, // reference
DW_FORM_strp, // string
DW_FORM_indirect: // (see Section 7.5.3)
fallthrough
default:
return fmt.Errorf("dwarf: unsupported attribute form %d / class %d", form, cls)
}
return nil
}
// PutAttrs writes the attributes for a DIE to symbol 's'.
//
// Note that we can (and do) add arbitrary attributes to a DIE, but
// only the ones actually listed in the Abbrev will be written out.
func PutAttrs(ctxt Context, s Sym, abbrev int, attr *DWAttr) {
Outer:
for _, f := range abbrevs[abbrev].attr {
for ap := attr; ap != nil; ap = ap.Link {
if ap.Atr == f.attr {
putattr(ctxt, s, abbrev, int(f.form), int(ap.Cls), ap.Value, ap.Data)
continue Outer
}
}
putattr(ctxt, s, abbrev, int(f.form), 0, 0, nil)
}
}
// HasChildren returns true if 'die' uses an abbrev that supports children.
func HasChildren(die *DWDie) bool {
return abbrevs[die.Abbrev].children != 0
}
// PutFunc writes a DIE for a function to s.
// It also writes child DIEs for each variable in vars.
func PutFunc(ctxt Context, s Sym, name string, external bool, startPC Sym, size int64, vars *Var) {
Uleb128put(ctxt, s, DW_ABRV_FUNCTION)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size+ctxt.SymValue(startPC), startPC)
var ev int64
if external {
ev = 1
}
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
names := make(map[string]bool)
for v := vars; v != nil; v = v.Link {
var n string
if names[v.Name] {
n = fmt.Sprintf("%s#%d", v.Name, len(names))
} else {
n = v.Name
}
names[n] = true
Uleb128put(ctxt, s, int64(v.Abbrev))
putattr(ctxt, s, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
loc := append(encbuf[:0], DW_OP_call_frame_cfa)
if v.Offset != 0 {
loc = append(loc, DW_OP_consts)
loc = AppendSleb128(loc, int64(v.Offset))
loc = append(loc, DW_OP_plus)
}
putattr(ctxt, s, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
putattr(ctxt, s, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
}
Uleb128put(ctxt, s, 0)
}

View File

@ -0,0 +1,483 @@
// 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
)
// 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)
)
// 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
)

714
vendor/github.com/google/gops/internal/goobj/read.go generated vendored Normal file
View File

@ -0,0 +1,714 @@
// 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 goobj implements reading of Go object files and archives.
//
// TODO(rsc): Decide where this package should live. (golang.org/issue/6932)
// TODO(rsc): Decide the appropriate integer types for various fields.
// TODO(rsc): Write tests. (File format still up in the air a little.)
package goobj
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"strconv"
"strings"
"github.com/google/gops/internal/obj"
)
// A SymKind describes the kind of memory represented by a symbol.
type SymKind int
// This list is taken from include/link.h.
// Defined SymKind values.
// TODO(rsc): Give idiomatic Go names.
// TODO(rsc): Reduce the number of symbol types in the object files.
const (
// readonly, executable
STEXT = SymKind(obj.STEXT)
SELFRXSECT = SymKind(obj.SELFRXSECT)
// readonly, non-executable
STYPE = SymKind(obj.STYPE)
SSTRING = SymKind(obj.SSTRING)
SGOSTRING = SymKind(obj.SGOSTRING)
SGOFUNC = SymKind(obj.SGOFUNC)
SRODATA = SymKind(obj.SRODATA)
SFUNCTAB = SymKind(obj.SFUNCTAB)
STYPELINK = SymKind(obj.STYPELINK)
SITABLINK = SymKind(obj.SITABLINK)
SSYMTAB = SymKind(obj.SSYMTAB) // TODO: move to unmapped section
SPCLNTAB = SymKind(obj.SPCLNTAB)
SELFROSECT = SymKind(obj.SELFROSECT)
// writable, non-executable
SMACHOPLT = SymKind(obj.SMACHOPLT)
SELFSECT = SymKind(obj.SELFSECT)
SMACHO = SymKind(obj.SMACHO) // Mach-O __nl_symbol_ptr
SMACHOGOT = SymKind(obj.SMACHOGOT)
SWINDOWS = SymKind(obj.SWINDOWS)
SELFGOT = SymKind(obj.SELFGOT)
SNOPTRDATA = SymKind(obj.SNOPTRDATA)
SINITARR = SymKind(obj.SINITARR)
SDATA = SymKind(obj.SDATA)
SBSS = SymKind(obj.SBSS)
SNOPTRBSS = SymKind(obj.SNOPTRBSS)
STLSBSS = SymKind(obj.STLSBSS)
// not mapped
SXREF = SymKind(obj.SXREF)
SMACHOSYMSTR = SymKind(obj.SMACHOSYMSTR)
SMACHOSYMTAB = SymKind(obj.SMACHOSYMTAB)
SMACHOINDIRECTPLT = SymKind(obj.SMACHOINDIRECTPLT)
SMACHOINDIRECTGOT = SymKind(obj.SMACHOINDIRECTGOT)
SFILE = SymKind(obj.SFILE)
SFILEPATH = SymKind(obj.SFILEPATH)
SCONST = SymKind(obj.SCONST)
SDYNIMPORT = SymKind(obj.SDYNIMPORT)
SHOSTOBJ = SymKind(obj.SHOSTOBJ)
)
var symKindStrings = []string{
SBSS: "SBSS",
SCONST: "SCONST",
SDATA: "SDATA",
SDYNIMPORT: "SDYNIMPORT",
SELFROSECT: "SELFROSECT",
SELFRXSECT: "SELFRXSECT",
SELFSECT: "SELFSECT",
SFILE: "SFILE",
SFILEPATH: "SFILEPATH",
SFUNCTAB: "SFUNCTAB",
SGOFUNC: "SGOFUNC",
SGOSTRING: "SGOSTRING",
SHOSTOBJ: "SHOSTOBJ",
SINITARR: "SINITARR",
SMACHO: "SMACHO",
SMACHOGOT: "SMACHOGOT",
SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT",
SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT",
SMACHOPLT: "SMACHOPLT",
SMACHOSYMSTR: "SMACHOSYMSTR",
SMACHOSYMTAB: "SMACHOSYMTAB",
SNOPTRBSS: "SNOPTRBSS",
SNOPTRDATA: "SNOPTRDATA",
SPCLNTAB: "SPCLNTAB",
SRODATA: "SRODATA",
SSTRING: "SSTRING",
SSYMTAB: "SSYMTAB",
STEXT: "STEXT",
STLSBSS: "STLSBSS",
STYPE: "STYPE",
STYPELINK: "STYPELINK",
SITABLINK: "SITABLINK",
SWINDOWS: "SWINDOWS",
SXREF: "SXREF",
}
func (k SymKind) String() string {
if k < 0 || int(k) >= len(symKindStrings) {
return fmt.Sprintf("SymKind(%d)", k)
}
return symKindStrings[k]
}
// A Sym is a named symbol in an object file.
type Sym struct {
SymID // symbol identifier (name and version)
Kind SymKind // kind of symbol
DupOK bool // are duplicate definitions okay?
Size int // size of corresponding data
Type SymID // symbol for Go type information
Data Data // memory image of symbol
Reloc []Reloc // relocations to apply to Data
Func *Func // additional data for functions
}
// A SymID - the combination of Name and Version - uniquely identifies
// a symbol within a package.
type SymID struct {
// Name is the name of a symbol.
Name string
// Version is zero for symbols with global visibility.
// Symbols with only file visibility (such as file-level static
// declarations in C) have a non-zero version distinguishing
// a symbol in one file from a symbol of the same name
// in another file
Version int
}
func (s SymID) String() string {
if s.Version == 0 {
return s.Name
}
return fmt.Sprintf("%s<%d>", s.Name, s.Version)
}
// A Data is a reference to data stored in an object file.
// It records the offset and size of the data, so that a client can
// read the data only if necessary.
type Data struct {
Offset int64
Size int64
}
// A Reloc describes a relocation applied to a memory image to refer
// to an address within a particular symbol.
type Reloc struct {
// The bytes at [Offset, Offset+Size) within the containing Sym
// should be updated to refer to the address Add bytes after the start
// of the symbol Sym.
Offset int
Size int
Sym SymID
Add int
// The Type records the form of address expected in the bytes
// described by the previous fields: absolute, PC-relative, and so on.
// TODO(rsc): The interpretation of Type is not exposed by this package.
Type obj.RelocType
}
// A Var describes a variable in a function stack frame: a declared
// local variable, an input argument, or an output result.
type Var struct {
// The combination of Name, Kind, and Offset uniquely
// identifies a variable in a function stack frame.
// Using fewer of these - in particular, using only Name - does not.
Name string // Name of variable.
Kind int // TODO(rsc): Define meaning.
Offset int // Frame offset. TODO(rsc): Define meaning.
Type SymID // Go type for variable.
}
// Func contains additional per-symbol information specific to functions.
type Func struct {
Args int // size in bytes of argument frame: inputs and outputs
Frame int // size in bytes of local variable frame
Leaf bool // function omits save of link register (ARM)
NoSplit bool // function omits stack split prologue
Var []Var // detail about local variables
PCSP Data // PC → SP offset map
PCFile Data // PC → file number map (index into File)
PCLine Data // PC → line number map
PCData []Data // PC → runtime support data map
FuncData []FuncData // non-PC-specific runtime support data
File []string // paths indexed by PCFile
}
// TODO: Add PCData []byte and PCDataIter (similar to liblink).
// A FuncData is a single function-specific data value.
type FuncData struct {
Sym SymID // symbol holding data
Offset int64 // offset into symbol for funcdata pointer
}
// A Package is a parsed Go object file or archive defining a Go package.
type Package struct {
ImportPath string // import path denoting this package
Imports []string // packages imported by this package
SymRefs []SymID // list of symbol names and versions referred to by this pack
Syms []*Sym // symbols defined by this package
MaxVersion int // maximum Version in any SymID in Syms
Arch string // architecture
}
var (
archiveHeader = []byte("!<arch>\n")
archiveMagic = []byte("`\n")
goobjHeader = []byte("go objec") // truncated to size of archiveHeader
errCorruptArchive = errors.New("corrupt archive")
errTruncatedArchive = errors.New("truncated archive")
errCorruptObject = errors.New("corrupt object file")
errNotObject = errors.New("unrecognized object file format")
)
// An objReader is an object file reader.
type objReader struct {
p *Package
b *bufio.Reader
f io.ReadSeeker
err error
offset int64
dataOffset int64
limit int64
tmp [256]byte
pkgprefix string
}
// importPathToPrefix returns the prefix that will be used in the
// final symbol table for the given import path.
// We escape '%', '"', all control characters and non-ASCII bytes,
// and any '.' after the final slash.
//
// See ../../../cmd/ld/lib.c:/^pathtoprefix and
// ../../../cmd/gc/subr.c:/^pathtoprefix.
func importPathToPrefix(s string) string {
// find index of last slash, if any, or else -1.
// used for determining whether an index is after the last slash.
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)
}
// init initializes r to read package p from f.
func (r *objReader) init(f io.ReadSeeker, p *Package) {
r.f = f
r.p = p
r.offset, _ = f.Seek(0, io.SeekCurrent)
r.limit, _ = f.Seek(0, io.SeekEnd)
f.Seek(r.offset, io.SeekStart)
r.b = bufio.NewReader(f)
r.pkgprefix = importPathToPrefix(p.ImportPath) + "."
}
// error records that an error occurred.
// It returns only the first error, so that an error
// caused by an earlier error does not discard information
// about the earlier error.
func (r *objReader) error(err error) error {
if r.err == nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
r.err = err
}
// panic("corrupt") // useful for debugging
return r.err
}
// readByte reads and returns a byte from the input file.
// On I/O error or EOF, it records the error but returns byte 0.
// A sequence of 0 bytes will eventually terminate any
// parsing state in the object file. In particular, it ends the
// reading of a varint.
func (r *objReader) readByte() byte {
if r.err != nil {
return 0
}
if r.offset >= r.limit {
r.error(io.ErrUnexpectedEOF)
return 0
}
b, err := r.b.ReadByte()
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
r.error(err)
b = 0
} else {
r.offset++
}
return b
}
// read reads exactly len(b) bytes from the input file.
// If an error occurs, read returns the error but also
// records it, so it is safe for callers to ignore the result
// as long as delaying the report is not a problem.
func (r *objReader) readFull(b []byte) error {
if r.err != nil {
return r.err
}
if r.offset+int64(len(b)) > r.limit {
return r.error(io.ErrUnexpectedEOF)
}
n, err := io.ReadFull(r.b, b)
r.offset += int64(n)
if err != nil {
return r.error(err)
}
return nil
}
// readInt reads a zigzag varint from the input file.
func (r *objReader) readInt() int {
var u uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
r.error(errCorruptObject)
return 0
}
c := r.readByte()
u |= uint64(c&0x7F) << shift
if c&0x80 == 0 {
break
}
}
v := int64(u>>1) ^ (int64(u) << 63 >> 63)
if int64(int(v)) != v {
r.error(errCorruptObject) // TODO
return 0
}
return int(v)
}
// readString reads a length-delimited string from the input file.
func (r *objReader) readString() string {
n := r.readInt()
buf := make([]byte, n)
r.readFull(buf)
return string(buf)
}
// readSymID reads a SymID from the input file.
func (r *objReader) readSymID() SymID {
i := r.readInt()
return r.p.SymRefs[i]
}
func (r *objReader) readRef() {
name, vers := r.readString(), r.readInt()
// In a symbol name in an object file, "". denotes the
// prefix for the package in which the object file has been found.
// Expand it.
name = strings.Replace(name, `"".`, r.pkgprefix, -1)
// An individual object file only records version 0 (extern) or 1 (static).
// To make static symbols unique across all files being read, we
// replace version 1 with the version corresponding to the current
// file number. The number is incremented on each call to parseObject.
if vers != 0 {
vers = r.p.MaxVersion
}
r.p.SymRefs = append(r.p.SymRefs, SymID{name, vers})
}
// readData reads a data reference from the input file.
func (r *objReader) readData() Data {
n := r.readInt()
d := Data{Offset: r.dataOffset, Size: int64(n)}
r.dataOffset += int64(n)
return d
}
// skip skips n bytes in the input.
func (r *objReader) skip(n int64) {
if n < 0 {
r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip"))
}
if n < int64(len(r.tmp)) {
// Since the data is so small, a just reading from the buffered
// reader is better than flushing the buffer and seeking.
r.readFull(r.tmp[:n])
} else if n <= int64(r.b.Buffered()) {
// Even though the data is not small, it has already been read.
// Advance the buffer instead of seeking.
for n > int64(len(r.tmp)) {
r.readFull(r.tmp[:])
n -= int64(len(r.tmp))
}
r.readFull(r.tmp[:n])
} else {
// Seek, giving up buffered data.
_, err := r.f.Seek(r.offset+n, io.SeekStart)
if err != nil {
r.error(err)
}
r.offset += n
r.b.Reset(r.f)
}
}
// Parse parses an object file or archive from r,
// assuming that its import path is pkgpath.
func Parse(r io.ReadSeeker, pkgpath string) (*Package, error) {
if pkgpath == "" {
pkgpath = `""`
}
p := new(Package)
p.ImportPath = pkgpath
var rd objReader
rd.init(r, p)
err := rd.readFull(rd.tmp[:8])
if err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, err
}
switch {
default:
return nil, errNotObject
case bytes.Equal(rd.tmp[:8], archiveHeader):
if err := rd.parseArchive(); err != nil {
return nil, err
}
case bytes.Equal(rd.tmp[:8], goobjHeader):
if err := rd.parseObject(goobjHeader); err != nil {
return nil, err
}
}
return p, nil
}
// trimSpace removes trailing spaces from b and returns the corresponding string.
// This effectively parses the form used in archive headers.
func trimSpace(b []byte) string {
return string(bytes.TrimRight(b, " "))
}
// parseArchive parses a Unix archive of Go object files.
// TODO(rsc): Need to skip non-Go object files.
// TODO(rsc): Maybe record table of contents in r.p so that
// linker can avoid having code to parse archives too.
func (r *objReader) parseArchive() error {
for r.offset < r.limit {
if err := r.readFull(r.tmp[:60]); err != nil {
return err
}
data := r.tmp[:60]
// Each file is preceded by this text header (slice indices in first column):
// 0:16 name
// 16:28 date
// 28:34 uid
// 34:40 gid
// 40:48 mode
// 48:58 size
// 58:60 magic - `\n
// We only care about name, size, and magic.
// The fields are space-padded on the right.
// The size is in decimal.
// The file data - size bytes - follows the header.
// Headers are 2-byte aligned, so if size is odd, an extra padding
// byte sits between the file data and the next header.
// The file data that follows is padded to an even number of bytes:
// if size is odd, an extra padding byte is inserted betw the next header.
if len(data) < 60 {
return errTruncatedArchive
}
if !bytes.Equal(data[58:60], archiveMagic) {
return errCorruptArchive
}
name := trimSpace(data[0:16])
size, err := strconv.ParseInt(trimSpace(data[48:58]), 10, 64)
if err != nil {
return errCorruptArchive
}
data = data[60:]
fsize := size + size&1
if fsize < 0 || fsize < size {
return errCorruptArchive
}
switch name {
case "__.PKGDEF":
r.skip(size)
default:
oldLimit := r.limit
r.limit = r.offset + size
if err := r.parseObject(nil); err != nil {
return fmt.Errorf("parsing archive member %q: %v", name, err)
}
r.skip(r.limit - r.offset)
r.limit = oldLimit
}
if size&1 != 0 {
r.skip(1)
}
}
return nil
}
// parseObject parses a single Go object file.
// The prefix is the bytes already read from the file,
// typically in order to detect that this is an object file.
// The object file consists of a textual header ending in "\n!\n"
// and then the part we want to parse begins.
// The format of that part is defined in a comment at the top
// of src/liblink/objfile.c.
func (r *objReader) parseObject(prefix []byte) error {
r.p.MaxVersion++
h := make([]byte, 0, 256)
h = append(h, prefix...)
var c1, c2, c3 byte
for {
c1, c2, c3 = c2, c3, r.readByte()
h = append(h, c3)
// The new export format can contain 0 bytes.
// Don't consider them errors, only look for r.err != nil.
if r.err != nil {
return errCorruptObject
}
if c1 == '\n' && c2 == '!' && c3 == '\n' {
break
}
}
hs := strings.Fields(string(h))
if len(hs) >= 4 {
r.p.Arch = hs[3]
}
// TODO: extract OS + build ID if/when we need it
r.readFull(r.tmp[:8])
if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go17ld")) {
return r.error(errCorruptObject)
}
b := r.readByte()
if b != 1 {
return r.error(errCorruptObject)
}
// Direct package dependencies.
for {
s := r.readString()
if s == "" {
break
}
r.p.Imports = append(r.p.Imports, s)
}
r.p.SymRefs = []SymID{{"", 0}}
for {
if b := r.readByte(); b != 0xfe {
if b != 0xff {
return r.error(errCorruptObject)
}
break
}
r.readRef()
}
dataLength := r.readInt()
r.readInt() // n relocations - ignore
r.readInt() // n pcdata - ignore
r.readInt() // n autom - ignore
r.readInt() // n funcdata - ignore
r.readInt() // n files - ignore
r.dataOffset = r.offset
r.skip(int64(dataLength))
// Symbols.
for {
if b := r.readByte(); b != 0xfe {
if b != 0xff {
return r.error(errCorruptObject)
}
break
}
typ := r.readInt()
s := &Sym{SymID: r.readSymID()}
r.p.Syms = append(r.p.Syms, s)
s.Kind = SymKind(typ)
flags := r.readInt()
s.DupOK = flags&1 != 0
s.Size = r.readInt()
s.Type = r.readSymID()
s.Data = r.readData()
s.Reloc = make([]Reloc, r.readInt())
for i := range s.Reloc {
rel := &s.Reloc[i]
rel.Offset = r.readInt()
rel.Size = r.readInt()
rel.Type = obj.RelocType(r.readInt())
rel.Add = r.readInt()
rel.Sym = r.readSymID()
}
if s.Kind == STEXT {
f := new(Func)
s.Func = f
f.Args = r.readInt()
f.Frame = r.readInt()
flags := r.readInt()
f.Leaf = flags&1 != 0
f.NoSplit = r.readInt() != 0
f.Var = make([]Var, r.readInt())
for i := range f.Var {
v := &f.Var[i]
v.Name = r.readSymID().Name
v.Offset = r.readInt()
v.Kind = r.readInt()
v.Type = r.readSymID()
}
f.PCSP = r.readData()
f.PCFile = r.readData()
f.PCLine = r.readData()
f.PCData = make([]Data, r.readInt())
for i := range f.PCData {
f.PCData[i] = r.readData()
}
f.FuncData = make([]FuncData, r.readInt())
for i := range f.FuncData {
f.FuncData[i].Sym = r.readSymID()
}
for i := range f.FuncData {
f.FuncData[i].Offset = int64(r.readInt()) // TODO
}
f.File = make([]string, r.readInt())
for i := range f.File {
f.File[i] = r.readSymID().Name
}
}
}
r.readFull(r.tmp[:7])
if !bytes.Equal(r.tmp[:7], []byte("\xffgo17ld")) {
return r.error(errCorruptObject)
}
return nil
}
func (r *Reloc) String(insnOffset uint64) string {
delta := r.Offset - int(insnOffset)
s := fmt.Sprintf("[%d:%d]%s", delta, delta+r.Size, r.Type)
if r.Sym.Name != "" {
if r.Add != 0 {
return fmt.Sprintf("%s:%s+%d", s, r.Sym.Name, r.Add)
}
return fmt.Sprintf("%s:%s", s, r.Sym.Name)
}
if r.Add != 0 {
return fmt.Sprintf("%s:%d", s, r.Add)
}
return s
}

52
vendor/github.com/google/gops/internal/internal.go generated vendored Normal file
View File

@ -0,0 +1,52 @@
package internal
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
)
func ConfigDir() (string, error) {
if runtime.GOOS == "windows" {
return filepath.Join(os.Getenv("APPDATA"), "gops"), nil
}
homeDir := guessUnixHomeDir()
if homeDir == "" {
return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty")
}
return filepath.Join(homeDir, ".config", "gops"), nil
}
func guessUnixHomeDir() string {
usr, err := user.Current()
if err == nil {
return usr.HomeDir
}
return os.Getenv("HOME")
}
func PIDFile(pid int) (string, error) {
gopsdir, err := ConfigDir()
if err != nil {
return "", err
}
return fmt.Sprintf("%s/%d", gopsdir, pid), nil
}
func GetPort(pid int) (string, error) {
portfile, err := PIDFile(pid)
if err != nil {
return "", err
}
b, err := ioutil.ReadFile(portfile)
if err != nil {
return "", err
}
port := strings.TrimSpace(string(b))
return port, nil
}

View File

@ -0,0 +1,27 @@
// Code generated by "stringer -type AddrType cmd/internal/obj"; DO NOT EDIT
package obj
import "fmt"
const (
_AddrType_name_0 = "TYPE_NONE"
_AddrType_name_1 = "TYPE_BRANCHTYPE_TEXTSIZETYPE_MEMTYPE_CONSTTYPE_FCONSTTYPE_SCONSTTYPE_REGTYPE_ADDRTYPE_SHIFTTYPE_REGREGTYPE_REGREG2TYPE_INDIRTYPE_REGLIST"
)
var (
_AddrType_index_0 = [...]uint8{0, 9}
_AddrType_index_1 = [...]uint8{0, 11, 24, 32, 42, 53, 64, 72, 81, 91, 102, 114, 124, 136}
)
func (i AddrType) String() string {
switch {
case i == 0:
return _AddrType_name_0
case 6 <= i && i <= 18:
i -= 6
return _AddrType_name_1[_AddrType_index_1[i]:_AddrType_index_1[i+1]]
default:
return fmt.Sprintf("AddrType(%d)", i)
}
}

338
vendor/github.com/google/gops/internal/obj/arm/a.out.go generated vendored Normal file
View File

@ -0,0 +1,338 @@
// Inferno utils/5c/5.out.h
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/5.out.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 arm
import "github.com/google/gops/internal/obj"
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm
const (
NSNAME = 8
NSYM = 50
NREG = 16
)
/* -1 disables use of REGARG */
const (
REGARG = -1
)
const (
REG_R0 = obj.RBaseARM + iota // must be 16-aligned
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_F0 // must be 16-aligned
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_FPSR // must be 2-aligned
REG_FPCR
REG_CPSR // must be 2-aligned
REG_SPSR
MAXREG
REGRET = REG_R0
/* compiler allocates R1 up as temps */
/* compiler allocates register variables R3 up */
/* compiler allocates external registers R10 down */
REGEXT = REG_R10
/* these two registers are declared in runtime.h */
REGG = REGEXT - 0
REGM = REGEXT - 1
REGCTXT = REG_R7
REGTMP = REG_R11
REGSP = REG_R13
REGLINK = REG_R14
REGPC = REG_R15
NFREG = 16
/* compiler allocates register variables F0 up */
/* compiler allocates external registers F7 down */
FREGRET = REG_F0
FREGEXT = REG_F7
FREGTMP = REG_F15
)
const (
C_NONE = iota
C_REG
C_REGREG
C_REGREG2
C_REGLIST
C_SHIFT
C_FREG
C_PSR
C_FCR
C_RCON /* 0xff rotated */
C_NCON /* ~RCON */
C_SCON /* 0xffff */
C_LCON
C_LCONADDR
C_ZFCON
C_SFCON
C_LFCON
C_RACON
C_LACON
C_SBRA
C_LBRA
C_HAUTO /* halfword insn offset (-0xff to 0xff) */
C_FAUTO /* float insn offset (0 to 0x3fc, word aligned) */
C_HFAUTO /* both H and F */
C_SAUTO /* -0xfff to 0xfff */
C_LAUTO
C_HOREG
C_FOREG
C_HFOREG
C_SOREG
C_ROREG
C_SROREG /* both nil and R */
C_LOREG
C_PC
C_SP
C_HREG
C_ADDR /* reference to relocatable address */
// TLS "var" in local exec mode: will become a constant offset from
// thread local base that is ultimately chosen by the program linker.
C_TLS_LE
// TLS "var" in initial exec mode: will become a memory address (chosen
// by the program linker) that the dynamic linker will fill with the
// offset from the thread local base.
C_TLS_IE
C_TEXTSIZE
C_GOK
C_NCLASS /* must be the last */
)
const (
AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
AEOR
ASUB
ARSB
AADD
AADC
ASBC
ARSC
ATST
ATEQ
ACMP
ACMN
AORR
ABIC
AMVN
/*
* Do not reorder or fragment the conditional branch
* opcodes, or the predication code will break
*/
ABEQ
ABNE
ABCS
ABHS
ABCC
ABLO
ABMI
ABPL
ABVS
ABVC
ABHI
ABLS
ABGE
ABLT
ABGT
ABLE
AMOVWD
AMOVWF
AMOVDW
AMOVFW
AMOVFD
AMOVDF
AMOVF
AMOVD
ACMPF
ACMPD
AADDF
AADDD
ASUBF
ASUBD
AMULF
AMULD
ADIVF
ADIVD
ASQRTF
ASQRTD
AABSF
AABSD
ANEGF
ANEGD
ASRL
ASRA
ASLL
AMULU
ADIVU
AMUL
ADIV
AMOD
AMODU
AMOVB
AMOVBS
AMOVBU
AMOVH
AMOVHS
AMOVHU
AMOVW
AMOVM
ASWPBU
ASWPW
ARFE
ASWI
AMULA
AWORD
AMULL
AMULAL
AMULLU
AMULALU
ABX
ABXRET
ADWORD
ALDREX
ASTREX
ALDREXD
ASTREXD
APLD
ACLZ
AMULWT
AMULWB
AMULAWT
AMULAWB
ADATABUNDLE
ADATABUNDLEEND
AMRC // MRC/MCR
ALAST
// aliases
AB = obj.AJMP
ABL = obj.ACALL
)
/* scond byte */
const (
C_SCOND = (1 << 4) - 1
C_SBIT = 1 << 4
C_PBIT = 1 << 5
C_WBIT = 1 << 6
C_FBIT = 1 << 7 /* psr flags-only */
C_UBIT = 1 << 7 /* up bit, unsigned bit */
// These constants are the ARM condition codes encodings,
// XORed with 14 so that C_SCOND_NONE has value 0,
// so that a zeroed Prog.scond means "always execute".
C_SCOND_XOR = 14
C_SCOND_EQ = 0 ^ C_SCOND_XOR
C_SCOND_NE = 1 ^ C_SCOND_XOR
C_SCOND_HS = 2 ^ C_SCOND_XOR
C_SCOND_LO = 3 ^ C_SCOND_XOR
C_SCOND_MI = 4 ^ C_SCOND_XOR
C_SCOND_PL = 5 ^ C_SCOND_XOR
C_SCOND_VS = 6 ^ C_SCOND_XOR
C_SCOND_VC = 7 ^ C_SCOND_XOR
C_SCOND_HI = 8 ^ C_SCOND_XOR
C_SCOND_LS = 9 ^ C_SCOND_XOR
C_SCOND_GE = 10 ^ C_SCOND_XOR
C_SCOND_LT = 11 ^ C_SCOND_XOR
C_SCOND_GT = 12 ^ C_SCOND_XOR
C_SCOND_LE = 13 ^ C_SCOND_XOR
C_SCOND_NONE = 14 ^ C_SCOND_XOR
C_SCOND_NV = 15 ^ C_SCOND_XOR
/* D_SHIFT type */
SHIFT_LL = 0 << 5
SHIFT_LR = 1 << 5
SHIFT_AR = 2 << 5
SHIFT_RR = 3 << 5
)

View File

@ -0,0 +1,108 @@
// Generated by stringer -i a.out.go -o anames.go -p arm
// Do not edit.
package arm
import "github.com/google/gops/internal/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "AND",
"EOR",
"SUB",
"RSB",
"ADD",
"ADC",
"SBC",
"RSC",
"TST",
"TEQ",
"CMP",
"CMN",
"ORR",
"BIC",
"MVN",
"BEQ",
"BNE",
"BCS",
"BHS",
"BCC",
"BLO",
"BMI",
"BPL",
"BVS",
"BVC",
"BHI",
"BLS",
"BGE",
"BLT",
"BGT",
"BLE",
"MOVWD",
"MOVWF",
"MOVDW",
"MOVFW",
"MOVFD",
"MOVDF",
"MOVF",
"MOVD",
"CMPF",
"CMPD",
"ADDF",
"ADDD",
"SUBF",
"SUBD",
"MULF",
"MULD",
"DIVF",
"DIVD",
"SQRTF",
"SQRTD",
"ABSF",
"ABSD",
"NEGF",
"NEGD",
"SRL",
"SRA",
"SLL",
"MULU",
"DIVU",
"MUL",
"DIV",
"MOD",
"MODU",
"MOVB",
"MOVBS",
"MOVBU",
"MOVH",
"MOVHS",
"MOVHU",
"MOVW",
"MOVM",
"SWPBU",
"SWPW",
"RFE",
"SWI",
"MULA",
"WORD",
"MULL",
"MULAL",
"MULLU",
"MULALU",
"BX",
"BXRET",
"DWORD",
"LDREX",
"STREX",
"LDREXD",
"STREXD",
"PLD",
"CLZ",
"MULWT",
"MULWB",
"MULAWT",
"MULAWB",
"DATABUNDLE",
"DATABUNDLEEND",
"MRC",
"LAST",
}

View File

@ -0,0 +1,73 @@
// 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 arm
var cnames5 = []string{
"NONE",
"REG",
"REGREG",
"REGREG2",
"REGLIST",
"SHIFT",
"FREG",
"PSR",
"FCR",
"RCON",
"NCON",
"SCON",
"LCON",
"LCONADDR",
"ZFCON",
"SFCON",
"LFCON",
"RACON",
"LACON",
"SBRA",
"LBRA",
"HAUTO",
"FAUTO",
"HFAUTO",
"SAUTO",
"LAUTO",
"HOREG",
"FOREG",
"HFOREG",
"SOREG",
"ROREG",
"SROREG",
"LOREG",
"PC",
"SP",
"HREG",
"ADDR",
"C_TLS_LE",
"C_TLS_IE",
"TEXTSIZE",
"GOK",
"NCLASS",
"SCOND = (1<<4)-1",
"SBIT = 1<<4",
"PBIT = 1<<5",
"WBIT = 1<<6",
"FBIT = 1<<7",
"UBIT = 1<<7",
"SCOND_XOR = 14",
"SCOND_EQ = 0 ^ C_SCOND_XOR",
"SCOND_NE = 1 ^ C_SCOND_XOR",
"SCOND_HS = 2 ^ C_SCOND_XOR",
"SCOND_LO = 3 ^ C_SCOND_XOR",
"SCOND_MI = 4 ^ C_SCOND_XOR",
"SCOND_PL = 5 ^ C_SCOND_XOR",
"SCOND_VS = 6 ^ C_SCOND_XOR",
"SCOND_VC = 7 ^ C_SCOND_XOR",
"SCOND_HI = 8 ^ C_SCOND_XOR",
"SCOND_LS = 9 ^ C_SCOND_XOR",
"SCOND_GE = 10 ^ C_SCOND_XOR",
"SCOND_LT = 11 ^ C_SCOND_XOR",
"SCOND_GT = 12 ^ C_SCOND_XOR",
"SCOND_LE = 13 ^ C_SCOND_XOR",
"SCOND_NONE = 14 ^ C_SCOND_XOR",
"SCOND_NV = 15 ^ C_SCOND_XOR",
}

2846
vendor/github.com/google/gops/internal/obj/arm/asm5.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
// Inferno utils/5c/list.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/list.c
//
// 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 arm
import (
"fmt"
"github.com/google/gops/internal/obj"
)
func init() {
obj.RegisterRegister(obj.RBaseARM, MAXREG, Rconv)
obj.RegisterOpcode(obj.ABaseARM, Anames)
}
func Rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if REG_R0 <= r && r <= REG_R15 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F15 {
return fmt.Sprintf("F%d", r-REG_F0)
}
switch r {
case REG_FPSR:
return "FPSR"
case REG_FPCR:
return "FPCR"
case REG_CPSR:
return "CPSR"
case REG_SPSR:
return "SPSR"
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseARM)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnames5[a]
}
var fp string
fp += s
return fp
}

1055
vendor/github.com/google/gops/internal/obj/arm/obj5.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,719 @@
// cmd/7c/7.out.h from Vita Nuova.
// https://code.google.com/p/ken-cc/source/browse/src/cmd/7c/7.out.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 arm64
import "github.com/google/gops/internal/obj"
const (
NSNAME = 8
NSYM = 50
NREG = 32 /* number of general registers */
NFREG = 32 /* number of floating point registers */
)
// General purpose registers, kept in the low bits of Prog.Reg.
const (
// integer
REG_R0 = obj.RBaseARM64 + iota
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_R16
REG_R17
REG_R18
REG_R19
REG_R20
REG_R21
REG_R22
REG_R23
REG_R24
REG_R25
REG_R26
REG_R27
REG_R28
REG_R29
REG_R30
REG_R31
// scalar floating point
REG_F0
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_F16
REG_F17
REG_F18
REG_F19
REG_F20
REG_F21
REG_F22
REG_F23
REG_F24
REG_F25
REG_F26
REG_F27
REG_F28
REG_F29
REG_F30
REG_F31
// SIMD
REG_V0
REG_V1
REG_V2
REG_V3
REG_V4
REG_V5
REG_V6
REG_V7
REG_V8
REG_V9
REG_V10
REG_V11
REG_V12
REG_V13
REG_V14
REG_V15
REG_V16
REG_V17
REG_V18
REG_V19
REG_V20
REG_V21
REG_V22
REG_V23
REG_V24
REG_V25
REG_V26
REG_V27
REG_V28
REG_V29
REG_V30
REG_V31
// The EQ in
// CSET EQ, R0
// is encoded as TYPE_REG, even though it's not really a register.
COND_EQ
COND_NE
COND_HS
COND_LO
COND_MI
COND_PL
COND_VS
COND_VC
COND_HI
COND_LS
COND_GE
COND_LT
COND_GT
COND_LE
COND_AL
COND_NV
REG_RSP = REG_V31 + 32 // to differentiate ZR/SP, REG_RSP&0x1f = 31
)
// Not registers, but flags that can be combined with regular register
// constants to indicate extended register conversion. When checking,
// you should subtract obj.RBaseARM64 first. From this difference, bit 11
// indicates extended register, bits 8-10 select the conversion mode.
const REG_EXT = obj.RBaseARM64 + 1<<11
const (
REG_UXTB = REG_EXT + iota<<8
REG_UXTH
REG_UXTW
REG_UXTX
REG_SXTB
REG_SXTH
REG_SXTW
REG_SXTX
)
// Special registers, after subtracting obj.RBaseARM64, bit 12 indicates
// a special register and the low bits select the register.
const (
REG_SPECIAL = obj.RBaseARM64 + 1<<12 + iota
REG_DAIF
REG_NZCV
REG_FPSR
REG_FPCR
REG_SPSR_EL1
REG_ELR_EL1
REG_SPSR_EL2
REG_ELR_EL2
REG_CurrentEL
REG_SP_EL0
REG_SPSel
REG_DAIFSet
REG_DAIFClr
)
// Register assignments:
//
// compiler allocates R0 up as temps
// compiler allocates register variables R7-R25
// compiler allocates external registers R26 down
//
// compiler allocates register variables F7-F26
// compiler allocates external registers F26 down
const (
REGMIN = REG_R7 // register variables allocated from here to REGMAX
REGRT1 = REG_R16 // ARM64 IP0, for external linker, runtime, duffzero and duffcopy
REGRT2 = REG_R17 // ARM64 IP1, for external linker, runtime, duffcopy
REGPR = REG_R18 // ARM64 platform register, unused in the Go toolchain
REGMAX = REG_R25
REGCTXT = REG_R26 // environment for closures
REGTMP = REG_R27 // reserved for liblink
REGG = REG_R28 // G
REGFP = REG_R29 // frame pointer, unused in the Go toolchain
REGLINK = REG_R30
// ARM64 uses R31 as both stack pointer and zero register,
// depending on the instruction. To differentiate RSP from ZR,
// we use a different numeric value for REGZERO and REGSP.
REGZERO = REG_R31
REGSP = REG_RSP
FREGRET = REG_F0
FREGMIN = REG_F7 // first register variable
FREGMAX = REG_F26 // last register variable for 7g only
FREGEXT = REG_F26 // first external register
)
const (
BIG = 2048 - 8
)
const (
/* mark flags */
LABEL = 1 << iota
LEAF
FLOAT
BRANCH
LOAD
FCMP
SYNC
LIST
FOLL
NOSCHED
)
const (
C_NONE = iota
C_REG // R0..R30
C_RSP // R0..R30, RSP
C_FREG // F0..F31
C_VREG // V0..V31
C_PAIR // (Rn, Rm)
C_SHIFT // Rn<<2
C_EXTREG // Rn.UXTB<<3
C_SPR // REG_NZCV
C_COND // EQ, NE, etc
C_ZCON // $0 or ZR
C_ADDCON0 // 12-bit unsigned, unshifted
C_ADDCON // 12-bit unsigned, shifted left by 0 or 12
C_MOVCON // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16
C_BITCON // bitfield and logical immediate masks
C_ABCON0 // could be C_ADDCON0 or C_BITCON
C_ABCON // could be C_ADDCON or C_BITCON
C_MBCON // could be C_MOVCON or C_BITCON
C_LCON // 32-bit constant
C_VCON // 64-bit constant
C_FCON // floating-point constant
C_VCONADDR // 64-bit memory address
C_AACON // ADDCON offset in auto constant $a(FP)
C_LACON // 32-bit offset in auto constant $a(FP)
C_AECON // ADDCON offset in extern constant $e(SB)
// TODO(aram): only one branch class should be enough
C_SBRA // for TYPE_BRANCH
C_LBRA
C_NPAUTO // -512 <= x < 0, 0 mod 8
C_NSAUTO // -256 <= x < 0
C_PSAUTO // 0 to 255
C_PPAUTO // 0 to 504, 0 mod 8
C_UAUTO4K // 0 to 4095
C_UAUTO8K // 0 to 8190, 0 mod 2
C_UAUTO16K // 0 to 16380, 0 mod 4
C_UAUTO32K // 0 to 32760, 0 mod 8
C_UAUTO64K // 0 to 65520, 0 mod 16
C_LAUTO // any other 32-bit constant
C_SEXT1 // 0 to 4095, direct
C_SEXT2 // 0 to 8190
C_SEXT4 // 0 to 16380
C_SEXT8 // 0 to 32760
C_SEXT16 // 0 to 65520
C_LEXT
// TODO(aram): s/AUTO/INDIR/
C_ZOREG // 0(R)
C_NPOREG // mirror NPAUTO, etc
C_NSOREG
C_PSOREG
C_PPOREG
C_UOREG4K
C_UOREG8K
C_UOREG16K
C_UOREG32K
C_UOREG64K
C_LOREG
C_ADDR // TODO(aram): explain difference from C_VCONADDR
// The GOT slot for a symbol in -dynlink mode.
C_GOTADDR
// TLS "var" in local exec mode: will become a constant offset from
// thread local base that is ultimately chosen by the program linker.
C_TLS_LE
// TLS "var" in initial exec mode: will become a memory address (chosen
// by the program linker) that the dynamic linker will fill with the
// offset from the thread local base.
C_TLS_IE
C_ROFF // register offset (including register extended)
C_GOK
C_TEXTSIZE
C_NCLASS // must be last
)
const (
C_XPRE = 1 << 6 // match arm.C_WBIT, so Prog.String know how to print it
C_XPOST = 1 << 5 // match arm.C_PBIT, so Prog.String know how to print it
)
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm64
const (
AADC = obj.ABaseARM64 + obj.A_ARCHSPECIFIC + iota
AADCS
AADCSW
AADCW
AADD
AADDS
AADDSW
AADDW
AADR
AADRP
AAND
AANDS
AANDSW
AANDW
AASR
AASRW
AAT
ABFI
ABFIW
ABFM
ABFMW
ABFXIL
ABFXILW
ABIC
ABICS
ABICSW
ABICW
ABRK
ACBNZ
ACBNZW
ACBZ
ACBZW
ACCMN
ACCMNW
ACCMP
ACCMPW
ACINC
ACINCW
ACINV
ACINVW
ACLREX
ACLS
ACLSW
ACLZ
ACLZW
ACMN
ACMNW
ACMP
ACMPW
ACNEG
ACNEGW
ACRC32B
ACRC32CB
ACRC32CH
ACRC32CW
ACRC32CX
ACRC32H
ACRC32W
ACRC32X
ACSEL
ACSELW
ACSET
ACSETM
ACSETMW
ACSETW
ACSINC
ACSINCW
ACSINV
ACSINVW
ACSNEG
ACSNEGW
ADC
ADCPS1
ADCPS2
ADCPS3
ADMB
ADRPS
ADSB
AEON
AEONW
AEOR
AEORW
AERET
AEXTR
AEXTRW
AHINT
AHLT
AHVC
AIC
AISB
ALDAR
ALDARB
ALDARH
ALDARW
ALDAXP
ALDAXPW
ALDAXR
ALDAXRB
ALDAXRH
ALDAXRW
ALDP
ALDXR
ALDXRB
ALDXRH
ALDXRW
ALDXP
ALDXPW
ALSL
ALSLW
ALSR
ALSRW
AMADD
AMADDW
AMNEG
AMNEGW
AMOVK
AMOVKW
AMOVN
AMOVNW
AMOVZ
AMOVZW
AMRS
AMSR
AMSUB
AMSUBW
AMUL
AMULW
AMVN
AMVNW
ANEG
ANEGS
ANEGSW
ANEGW
ANGC
ANGCS
ANGCSW
ANGCW
AORN
AORNW
AORR
AORRW
APRFM
APRFUM
ARBIT
ARBITW
AREM
AREMW
AREV
AREV16
AREV16W
AREV32
AREVW
AROR
ARORW
ASBC
ASBCS
ASBCSW
ASBCW
ASBFIZ
ASBFIZW
ASBFM
ASBFMW
ASBFX
ASBFXW
ASDIV
ASDIVW
ASEV
ASEVL
ASMADDL
ASMC
ASMNEGL
ASMSUBL
ASMULH
ASMULL
ASTXR
ASTXRB
ASTXRH
ASTXP
ASTXPW
ASTXRW
ASTLP
ASTLPW
ASTLR
ASTLRB
ASTLRH
ASTLRW
ASTLXP
ASTLXPW
ASTLXR
ASTLXRB
ASTLXRH
ASTLXRW
ASTP
ASUB
ASUBS
ASUBSW
ASUBW
ASVC
ASXTB
ASXTBW
ASXTH
ASXTHW
ASXTW
ASYS
ASYSL
ATBNZ
ATBZ
ATLBI
ATST
ATSTW
AUBFIZ
AUBFIZW
AUBFM
AUBFMW
AUBFX
AUBFXW
AUDIV
AUDIVW
AUMADDL
AUMNEGL
AUMSUBL
AUMULH
AUMULL
AUREM
AUREMW
AUXTB
AUXTH
AUXTW
AUXTBW
AUXTHW
AWFE
AWFI
AYIELD
AMOVB
AMOVBU
AMOVH
AMOVHU
AMOVW
AMOVWU
AMOVD
AMOVNP
AMOVNPW
AMOVP
AMOVPD
AMOVPQ
AMOVPS
AMOVPSW
AMOVPW
ABEQ
ABNE
ABCS
ABHS
ABCC
ABLO
ABMI
ABPL
ABVS
ABVC
ABHI
ABLS
ABGE
ABLT
ABGT
ABLE
AFABSD
AFABSS
AFADDD
AFADDS
AFCCMPD
AFCCMPED
AFCCMPS
AFCCMPES
AFCMPD
AFCMPED
AFCMPES
AFCMPS
AFCVTSD
AFCVTDS
AFCVTZSD
AFCVTZSDW
AFCVTZSS
AFCVTZSSW
AFCVTZUD
AFCVTZUDW
AFCVTZUS
AFCVTZUSW
AFDIVD
AFDIVS
AFMOVD
AFMOVS
AFMULD
AFMULS
AFNEGD
AFNEGS
AFSQRTD
AFSQRTS
AFSUBD
AFSUBS
ASCVTFD
ASCVTFS
ASCVTFWD
ASCVTFWS
AUCVTFD
AUCVTFS
AUCVTFWD
AUCVTFWS
AWORD
ADWORD
AFCSELS
AFCSELD
AFMAXS
AFMINS
AFMAXD
AFMIND
AFMAXNMS
AFMAXNMD
AFNMULS
AFNMULD
AFRINTNS
AFRINTND
AFRINTPS
AFRINTPD
AFRINTMS
AFRINTMD
AFRINTZS
AFRINTZD
AFRINTAS
AFRINTAD
AFRINTXS
AFRINTXD
AFRINTIS
AFRINTID
AFMADDS
AFMADDD
AFMSUBS
AFMSUBD
AFNMADDS
AFNMADDD
AFNMSUBS
AFNMSUBD
AFMINNMS
AFMINNMD
AFCVTDH
AFCVTHS
AFCVTHD
AFCVTSH
AAESD
AAESE
AAESIMC
AAESMC
ASHA1C
ASHA1H
ASHA1M
ASHA1P
ASHA1SU0
ASHA1SU1
ASHA256H
ASHA256H2
ASHA256SU0
ASHA256SU1
ALAST
AB = obj.AJMP
ABL = obj.ACALL
)
const (
// shift types
SHIFT_LL = 0 << 22
SHIFT_LR = 1 << 22
SHIFT_AR = 2 << 22
)

View File

@ -0,0 +1,370 @@
// Generated by stringer -i a.out.go -o anames.go -p arm64
// Do not edit.
package arm64
import "github.com/google/gops/internal/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADC",
"ADCS",
"ADCSW",
"ADCW",
"ADD",
"ADDS",
"ADDSW",
"ADDW",
"ADR",
"ADRP",
"AND",
"ANDS",
"ANDSW",
"ANDW",
"ASR",
"ASRW",
"AT",
"BFI",
"BFIW",
"BFM",
"BFMW",
"BFXIL",
"BFXILW",
"BIC",
"BICS",
"BICSW",
"BICW",
"BRK",
"CBNZ",
"CBNZW",
"CBZ",
"CBZW",
"CCMN",
"CCMNW",
"CCMP",
"CCMPW",
"CINC",
"CINCW",
"CINV",
"CINVW",
"CLREX",
"CLS",
"CLSW",
"CLZ",
"CLZW",
"CMN",
"CMNW",
"CMP",
"CMPW",
"CNEG",
"CNEGW",
"CRC32B",
"CRC32CB",
"CRC32CH",
"CRC32CW",
"CRC32CX",
"CRC32H",
"CRC32W",
"CRC32X",
"CSEL",
"CSELW",
"CSET",
"CSETM",
"CSETMW",
"CSETW",
"CSINC",
"CSINCW",
"CSINV",
"CSINVW",
"CSNEG",
"CSNEGW",
"DC",
"DCPS1",
"DCPS2",
"DCPS3",
"DMB",
"DRPS",
"DSB",
"EON",
"EONW",
"EOR",
"EORW",
"ERET",
"EXTR",
"EXTRW",
"HINT",
"HLT",
"HVC",
"IC",
"ISB",
"LDAR",
"LDARB",
"LDARH",
"LDARW",
"LDAXP",
"LDAXPW",
"LDAXR",
"LDAXRB",
"LDAXRH",
"LDAXRW",
"LDP",
"LDXR",
"LDXRB",
"LDXRH",
"LDXRW",
"LDXP",
"LDXPW",
"LSL",
"LSLW",
"LSR",
"LSRW",
"MADD",
"MADDW",
"MNEG",
"MNEGW",
"MOVK",
"MOVKW",
"MOVN",
"MOVNW",
"MOVZ",
"MOVZW",
"MRS",
"MSR",
"MSUB",
"MSUBW",
"MUL",
"MULW",
"MVN",
"MVNW",
"NEG",
"NEGS",
"NEGSW",
"NEGW",
"NGC",
"NGCS",
"NGCSW",
"NGCW",
"ORN",
"ORNW",
"ORR",
"ORRW",
"PRFM",
"PRFUM",
"RBIT",
"RBITW",
"REM",
"REMW",
"REV",
"REV16",
"REV16W",
"REV32",
"REVW",
"ROR",
"RORW",
"SBC",
"SBCS",
"SBCSW",
"SBCW",
"SBFIZ",
"SBFIZW",
"SBFM",
"SBFMW",
"SBFX",
"SBFXW",
"SDIV",
"SDIVW",
"SEV",
"SEVL",
"SMADDL",
"SMC",
"SMNEGL",
"SMSUBL",
"SMULH",
"SMULL",
"STXR",
"STXRB",
"STXRH",
"STXP",
"STXPW",
"STXRW",
"STLP",
"STLPW",
"STLR",
"STLRB",
"STLRH",
"STLRW",
"STLXP",
"STLXPW",
"STLXR",
"STLXRB",
"STLXRH",
"STLXRW",
"STP",
"SUB",
"SUBS",
"SUBSW",
"SUBW",
"SVC",
"SXTB",
"SXTBW",
"SXTH",
"SXTHW",
"SXTW",
"SYS",
"SYSL",
"TBNZ",
"TBZ",
"TLBI",
"TST",
"TSTW",
"UBFIZ",
"UBFIZW",
"UBFM",
"UBFMW",
"UBFX",
"UBFXW",
"UDIV",
"UDIVW",
"UMADDL",
"UMNEGL",
"UMSUBL",
"UMULH",
"UMULL",
"UREM",
"UREMW",
"UXTB",
"UXTH",
"UXTW",
"UXTBW",
"UXTHW",
"WFE",
"WFI",
"YIELD",
"MOVB",
"MOVBU",
"MOVH",
"MOVHU",
"MOVW",
"MOVWU",
"MOVD",
"MOVNP",
"MOVNPW",
"MOVP",
"MOVPD",
"MOVPQ",
"MOVPS",
"MOVPSW",
"MOVPW",
"BEQ",
"BNE",
"BCS",
"BHS",
"BCC",
"BLO",
"BMI",
"BPL",
"BVS",
"BVC",
"BHI",
"BLS",
"BGE",
"BLT",
"BGT",
"BLE",
"FABSD",
"FABSS",
"FADDD",
"FADDS",
"FCCMPD",
"FCCMPED",
"FCCMPS",
"FCCMPES",
"FCMPD",
"FCMPED",
"FCMPES",
"FCMPS",
"FCVTSD",
"FCVTDS",
"FCVTZSD",
"FCVTZSDW",
"FCVTZSS",
"FCVTZSSW",
"FCVTZUD",
"FCVTZUDW",
"FCVTZUS",
"FCVTZUSW",
"FDIVD",
"FDIVS",
"FMOVD",
"FMOVS",
"FMULD",
"FMULS",
"FNEGD",
"FNEGS",
"FSQRTD",
"FSQRTS",
"FSUBD",
"FSUBS",
"SCVTFD",
"SCVTFS",
"SCVTFWD",
"SCVTFWS",
"UCVTFD",
"UCVTFS",
"UCVTFWD",
"UCVTFWS",
"WORD",
"DWORD",
"FCSELS",
"FCSELD",
"FMAXS",
"FMINS",
"FMAXD",
"FMIND",
"FMAXNMS",
"FMAXNMD",
"FNMULS",
"FNMULD",
"FRINTNS",
"FRINTND",
"FRINTPS",
"FRINTPD",
"FRINTMS",
"FRINTMD",
"FRINTZS",
"FRINTZD",
"FRINTAS",
"FRINTAD",
"FRINTXS",
"FRINTXD",
"FRINTIS",
"FRINTID",
"FMADDS",
"FMADDD",
"FMSUBS",
"FMSUBD",
"FNMADDS",
"FNMADDD",
"FNMSUBS",
"FNMSUBD",
"FMINNMS",
"FMINNMD",
"FCVTDH",
"FCVTHS",
"FCVTHD",
"FCVTSH",
"AESD",
"AESE",
"AESIMC",
"AESMC",
"SHA1C",
"SHA1H",
"SHA1M",
"SHA1P",
"SHA1SU0",
"SHA1SU1",
"SHA256H",
"SHA256H2",
"SHA256SU0",
"SHA256SU1",
"LAST",
}

View File

@ -0,0 +1,70 @@
// 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 arm64
var cnames7 = []string{
"NONE",
"REG",
"RSP",
"FREG",
"VREG",
"PAIR",
"SHIFT",
"EXTREG",
"SPR",
"COND",
"ZCON",
"ADDCON0",
"ADDCON",
"MOVCON",
"BITCON",
"ABCON0",
"ABCON",
"MBCON",
"LCON",
"VCON",
"FCON",
"VCONADDR",
"AACON",
"LACON",
"AECON",
"SBRA",
"LBRA",
"NPAUTO",
"NSAUTO",
"PSAUTO",
"PPAUTO",
"UAUTO4K",
"UAUTO8K",
"UAUTO16K",
"UAUTO32K",
"UAUTO64K",
"LAUTO",
"SEXT1",
"SEXT2",
"SEXT4",
"SEXT8",
"SEXT16",
"LEXT",
"ZOREG",
"NPOREG",
"NSOREG",
"PSOREG",
"PPOREG",
"UOREG4K",
"UOREG8K",
"UOREG16K",
"UOREG32K",
"UOREG64K",
"LOREG",
"ADDR",
"GOTADDR",
"TLS_LE",
"TLS_IE",
"ROFF",
"GOK",
"TEXTSIZE",
"NCLASS",
}

4374
vendor/github.com/google/gops/internal/obj/arm64/asm7.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
// cmd/7l/list.c and cmd/7l/sub.c from Vita Nuova.
// https://code.google.com/p/ken-cc/source/browse/
//
// 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 arm64
import (
"fmt"
"github.com/google/gops/internal/obj"
)
var strcond = [16]string{
"EQ",
"NE",
"HS",
"LO",
"MI",
"PL",
"VS",
"VC",
"HI",
"LS",
"GE",
"LT",
"GT",
"LE",
"AL",
"NV",
}
func init() {
obj.RegisterRegister(obj.RBaseARM64, REG_SPECIAL+1024, Rconv)
obj.RegisterOpcode(obj.ABaseARM64, Anames)
}
func Rconv(r int) string {
if r == REGG {
return "g"
}
switch {
case REG_R0 <= r && r <= REG_R30:
return fmt.Sprintf("R%d", r-REG_R0)
case r == REG_R31:
return "ZR"
case REG_F0 <= r && r <= REG_F31:
return fmt.Sprintf("F%d", r-REG_F0)
case REG_V0 <= r && r <= REG_V31:
return fmt.Sprintf("V%d", r-REG_V0)
case COND_EQ <= r && r <= COND_NV:
return strcond[r-COND_EQ]
case r == REGSP:
return "RSP"
case r == REG_DAIF:
return "DAIF"
case r == REG_NZCV:
return "NZCV"
case r == REG_FPSR:
return "FPSR"
case r == REG_FPCR:
return "FPCR"
case r == REG_SPSR_EL1:
return "SPSR_EL1"
case r == REG_ELR_EL1:
return "ELR_EL1"
case r == REG_SPSR_EL2:
return "SPSR_EL2"
case r == REG_ELR_EL2:
return "ELR_EL2"
case r == REG_CurrentEL:
return "CurrentEL"
case r == REG_SP_EL0:
return "SP_EL0"
case r == REG_SPSel:
return "SPSel"
case r == REG_DAIFSet:
return "DAIFSet"
case r == REG_DAIFClr:
return "DAIFClr"
}
return fmt.Sprintf("badreg(%d)", r)
}
func DRconv(a int) string {
if a >= C_NONE && a <= C_NCLASS {
return cnames7[a]
}
return "C_??"
}

1005
vendor/github.com/google/gops/internal/obj/arm64/obj7.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

190
vendor/github.com/google/gops/internal/obj/data.go generated vendored Normal file
View File

@ -0,0 +1,190 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// 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 obj
import (
"log"
"math"
)
// Grow increases the length of s.P to lsiz.
func (s *LSym) Grow(lsiz int64) {
siz := int(lsiz)
if int64(siz) != lsiz {
log.Fatalf("LSym.Grow size %d too long", lsiz)
}
if len(s.P) >= siz {
return
}
// TODO(dfc) append cap-len at once, rather than
// one byte at a time.
for cap(s.P) < siz {
s.P = append(s.P[:cap(s.P)], 0)
}
s.P = s.P[:siz]
}
// GrowCap increases the capacity of s.P to c.
func (s *LSym) GrowCap(c int64) {
if int64(cap(s.P)) >= c {
return
}
if s.P == nil {
s.P = make([]byte, 0, c)
return
}
b := make([]byte, len(s.P), c)
copy(b, s.P)
s.P = b
}
// prepwrite prepares to write data of size siz into s at offset off.
func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) {
if off < 0 || siz < 0 || off >= 1<<30 {
log.Fatalf("prepwrite: bad off=%d siz=%d", off, siz)
}
if s.Type == SBSS || s.Type == STLSBSS {
ctxt.Diag("cannot supply data for BSS var")
}
l := off + int64(siz)
s.Grow(l)
if l > s.Size {
s.Size = l
}
}
// WriteFloat32 writes f into s at offset off.
func (s *LSym) WriteFloat32(ctxt *Link, off int64, f float32) {
s.prepwrite(ctxt, off, 4)
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], math.Float32bits(f))
}
// WriteFloat64 writes f into s at offset off.
func (s *LSym) WriteFloat64(ctxt *Link, off int64, f float64) {
s.prepwrite(ctxt, off, 8)
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], math.Float64bits(f))
}
// WriteInt writes an integer i of size siz into s at offset off.
func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) {
s.prepwrite(ctxt, off, siz)
switch siz {
default:
ctxt.Diag("WriteInt: bad integer size: %d", siz)
case 1:
s.P[off] = byte(i)
case 2:
ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i))
case 4:
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(i))
case 8:
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(i))
}
}
// WriteAddr writes an address of size siz into s at offset off.
// rsym and roff specify the relocation for the address.
func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
if siz != ctxt.Arch.PtrSize {
ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name)
}
s.prepwrite(ctxt, off, siz)
r := Addrel(s)
r.Off = int32(off)
if int64(r.Off) != off {
ctxt.Diag("WriteAddr: off overflow %d in %s", off, s.Name)
}
r.Siz = uint8(siz)
r.Sym = rsym
r.Type = R_ADDR
r.Add = roff
}
// WriteOff writes a 4 byte offset to rsym+roff into s at offset off.
// After linking the 4 bytes stored at s+off will be
// rsym+roff-(start of section that s is in).
func (s *LSym) WriteOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
s.prepwrite(ctxt, off, 4)
r := Addrel(s)
r.Off = int32(off)
if int64(r.Off) != off {
ctxt.Diag("WriteOff: off overflow %d in %s", off, s.Name)
}
r.Siz = 4
r.Sym = rsym
r.Type = R_ADDROFF
r.Add = roff
}
// WriteString writes a string of size siz into s at offset off.
func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) {
if siz < len(str) {
ctxt.Diag("WriteString: bad string size: %d < %d", siz, len(str))
}
s.prepwrite(ctxt, off, siz)
copy(s.P[off:off+int64(siz)], str)
}
// WriteBytes writes a slice of bytes into s at offset off.
func (s *LSym) WriteBytes(ctxt *Link, off int64, b []byte) int64 {
s.prepwrite(ctxt, off, len(b))
copy(s.P[off:], b)
return off + int64(len(b))
}
func Addrel(s *LSym) *Reloc {
s.R = append(s.R, Reloc{})
return &s.R[len(s.R)-1]
}
func Setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
if s.Type == 0 {
s.Type = SDATA
}
if s.Size < off+wid {
s.Size = off + wid
s.Grow(s.Size)
}
switch wid {
case 1:
s.P[off] = uint8(v)
case 2:
ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
case 4:
ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
case 8:
ctxt.Arch.ByteOrder.PutUint64(s.P[off:], v)
}
return off + wid
}

115
vendor/github.com/google/gops/internal/obj/flag.go generated vendored Normal file
View File

@ -0,0 +1,115 @@
// 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 obj
import (
"flag"
"fmt"
"os"
"strconv"
)
func Flagfn2(string, string, func(string, string)) { panic("flag") }
func Flagcount(name, usage string, val *int) {
flag.Var((*count)(val), name, usage)
}
func Flagint32(name, usage string, val *int32) {
flag.Var((*int32Value)(val), name, usage)
}
func Flagint64(name, usage string, val *int64) {
flag.Int64Var(val, name, *val, usage)
}
func Flagstr(name, usage string, val *string) {
flag.StringVar(val, name, *val, usage)
}
func Flagfn0(name, usage string, f func()) {
flag.Var(fn0(f), name, usage)
}
func Flagfn1(name, usage string, f func(string)) {
flag.Var(fn1(f), name, usage)
}
func Flagprint(fd int) {
if fd == 1 {
flag.CommandLine.SetOutput(os.Stdout)
}
flag.PrintDefaults()
}
func Flagparse(usage func()) {
flag.Usage = usage
flag.Parse()
}
// 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) IsBoolFlag() bool {
return true
}
type int32Value int32
func (i *int32Value) Set(s string) error {
v, err := strconv.ParseInt(s, 0, 64)
*i = int32Value(v)
return err
}
func (i *int32Value) Get() interface{} { return int32(*i) }
func (i *int32Value) String() string { return fmt.Sprint(*i) }
type fn0 func()
func (f fn0) Set(s string) error {
f()
return nil
}
func (f fn0) Get() interface{} { return nil }
func (f fn0) String() string { return "" }
func (f fn0) IsBoolFlag() bool {
return true
}
type fn1 func(string)
func (f fn1) Set(s string) error {
f(s)
return nil
}
func (f fn1) String() string { return "" }

48
vendor/github.com/google/gops/internal/obj/funcdata.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
// 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 obj
// This file defines the IDs for PCDATA and FUNCDATA instructions
// in Go binaries. It is included by assembly sources, so it must
// be written using #defines.
//
// The Go compiler also #includes this file, for now.
//
// symtab.go also contains a copy of these constants.
// Pseudo-assembly statements.
// GO_ARGS, GO_RESULTS_INITIALIZED, and NO_LOCAL_POINTERS are macros
// that communicate to the runtime information about the location and liveness
// of pointers in an assembly function's arguments, results, and stack frame.
// This communication is only required in assembly functions that make calls
// to other functions that might be preempted or grow the stack.
// NOSPLIT functions that make no calls do not need to use these macros.
// GO_ARGS indicates that the Go prototype for this assembly function
// defines the pointer map for the function's arguments.
// GO_ARGS should be the first instruction in a function that uses it.
// It can be omitted if there are no arguments at all.
// GO_ARGS is inserted implicitly by the linker for any function
// that also has a Go prototype and therefore is usually not necessary
// to write explicitly.
// GO_RESULTS_INITIALIZED indicates that the assembly function
// has initialized the stack space for its results and that those results
// should be considered live for the remainder of the function.
// NO_LOCAL_POINTERS indicates that the assembly function stores
// no pointers to heap objects in its local stack variables.
// 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.
const (
PCDATA_StackMapIndex = 0
FUNCDATA_ArgsPointerMaps = 0
FUNCDATA_LocalsPointerMaps = 1
ArgsSizeUnknown = -0x80000000
)

86
vendor/github.com/google/gops/internal/obj/go.go generated vendored Normal file
View File

@ -0,0 +1,86 @@
// 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 obj
import (
"fmt"
"os"
"strings"
)
// go-specific code shared across loaders (5l, 6l, 8l).
var (
framepointer_enabled int
Fieldtrack_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},
{"framepointer", &framepointer_enabled},
}
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)
}
func init() {
framepointer_enabled = 1 // default
for _, f := range strings.Split(goexperiment, ",") {
if f != "" {
addexp(f)
}
}
}
func Framepointer_enabled(goos, goarch string) bool {
return framepointer_enabled != 0 && goarch == "amd64" && goos != "nacl"
}
func Nopout(p *Prog) {
p.As = ANOP
p.Scond = 0
p.From = Addr{}
p.From3 = nil
p.Reg = 0
p.To = Addr{}
}
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:]
}

92
vendor/github.com/google/gops/internal/obj/ld.go generated vendored Normal file
View File

@ -0,0 +1,92 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// 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 obj
/*
* add library to library list.
* srcref: src file referring to package
* objref: object file referring to package
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
* pkg: package import path, e.g. container/vector
*/
const (
LOG = 5
)
func mkfwd(sym *LSym) {
var dwn [LOG]int32
var cnt [LOG]int32
var lst [LOG]*Prog
for i := 0; i < LOG; i++ {
if i == 0 {
cnt[i] = 1
} else {
cnt[i] = LOG * cnt[i-1]
}
dwn[i] = 1
lst[i] = nil
}
i := 0
for p := sym.Text; p != nil && p.Link != nil; p = p.Link {
i--
if i < 0 {
i = LOG - 1
}
p.Forwd = nil
dwn[i]--
if dwn[i] <= 0 {
dwn[i] = cnt[i]
if lst[i] != nil {
lst[i].Forwd = p
}
lst[i] = p
}
}
}
func Copyp(ctxt *Link, q *Prog) *Prog {
p := ctxt.NewProg()
*p = *q
return p
}
func Appendp(ctxt *Link, q *Prog) *Prog {
p := ctxt.NewProg()
p.Link = q.Link
q.Link = p
p.Lineno = q.Lineno
p.Mode = q.Mode
return p
}

974
vendor/github.com/google/gops/internal/obj/link.go generated vendored Normal file
View File

@ -0,0 +1,974 @@
// Derived from Inferno utils/6l/l.h and related files.
// https://bitbucket.org/inferno-os/inferno-os/src/default/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 obj
import (
"bufio"
"fmt"
"github.com/google/gops/internal/sys"
)
// An Addr is an argument to an instruction.
// The general forms and their encodings are:
//
// sym±offset(symkind)(reg)(index*scale)
// Memory reference at address &sym(symkind) + offset + reg + index*scale.
// Any of sym(symkind), ±offset, (reg), (index*scale), and *scale can be omitted.
// If (reg) and *scale are both omitted, the resulting expression (index) is parsed as (reg).
// To force a parsing as index*scale, write (index*1).
// Encoding:
// type = TYPE_MEM
// name = symkind (NAME_AUTO, ...) or 0 (NAME_NONE)
// sym = sym
// offset = ±offset
// reg = reg (REG_*)
// index = index (REG_*)
// scale = scale (1, 2, 4, 8)
//
// $<mem>
// Effective address of memory reference <mem>, defined above.
// Encoding: same as memory reference, but type = TYPE_ADDR.
//
// $<±integer value>
// This is a special case of $<mem>, in which only ±offset is present.
// It has a separate type for easy recognition.
// Encoding:
// type = TYPE_CONST
// offset = ±integer value
//
// *<mem>
// Indirect reference through memory reference <mem>, defined above.
// Only used on x86 for CALL/JMP *sym(SB), which calls/jumps to a function
// pointer stored in the data word sym(SB), not a function named sym(SB).
// Encoding: same as above, but type = TYPE_INDIR.
//
// $*$<mem>
// No longer used.
// On machines with actual SB registers, $*$<mem> forced the
// instruction encoding to use a full 32-bit constant, never a
// reference relative to SB.
//
// $<floating point literal>
// Floating point constant value.
// Encoding:
// type = TYPE_FCONST
// val = floating point value
//
// $<string literal, up to 8 chars>
// String literal value (raw bytes used for DATA instruction).
// Encoding:
// type = TYPE_SCONST
// val = string
//
// <register name>
// Any register: integer, floating point, control, segment, and so on.
// If looking for specific register kind, must check type and reg value range.
// Encoding:
// type = TYPE_REG
// reg = reg (REG_*)
//
// x(PC)
// Encoding:
// type = TYPE_BRANCH
// val = Prog* reference OR ELSE offset = target pc (branch takes priority)
//
// $±x-±y
// Final argument to TEXT, specifying local frame size x and argument size y.
// In this form, x and y are integer literals only, not arbitrary expressions.
// This avoids parsing ambiguities due to the use of - as a separator.
// The ± are optional.
// If the final argument to TEXT omits the -±y, the encoding should still
// use TYPE_TEXTSIZE (not TYPE_CONST), with u.argsize = ArgsSizeUnknown.
// Encoding:
// type = TYPE_TEXTSIZE
// offset = x
// val = int32(y)
//
// reg<<shift, reg>>shift, reg->shift, reg@>shift
// Shifted register value, for ARM and ARM64.
// In this form, reg must be a register and shift can be a register or an integer constant.
// Encoding:
// type = TYPE_SHIFT
// On ARM:
// offset = (reg&15) | shifttype<<5 | count
// shifttype = 0, 1, 2, 3 for <<, >>, ->, @>
// count = (reg&15)<<8 | 1<<4 for a register shift count, (n&31)<<7 for an integer constant.
// On ARM64:
// offset = (reg&31)<<16 | shifttype<<22 | (count&63)<<10
// shifttype = 0, 1, 2 for <<, >>, ->
//
// (reg, reg)
// A destination register pair. When used as the last argument of an instruction,
// this form makes clear that both registers are destinations.
// Encoding:
// type = TYPE_REGREG
// reg = first register
// offset = second register
//
// [reg, reg, reg-reg]
// Register list for ARM.
// Encoding:
// type = TYPE_REGLIST
// offset = bit mask of registers in list; R0 is low bit.
//
// reg, reg
// Register pair for ARM.
// TYPE_REGREG2
//
// (reg+reg)
// Register pair for PPC64.
// Encoding:
// type = TYPE_MEM
// reg = first register
// index = second register
// scale = 1
//
type Addr struct {
Reg int16
Index int16
Scale int16 // Sometimes holds a register.
Type AddrType
Name int8
Class int8
Offset int64
Sym *LSym
// argument value:
// for TYPE_SCONST, a string
// for TYPE_FCONST, a float64
// for TYPE_BRANCH, a *Prog (optional)
// for TYPE_TEXTSIZE, an int32 (optional)
Val interface{}
Node interface{} // for use by compiler
}
type AddrType uint8
const (
NAME_NONE = 0 + iota
NAME_EXTERN
NAME_STATIC
NAME_AUTO
NAME_PARAM
// A reference to name@GOT(SB) is a reference to the entry in the global offset
// table for 'name'.
NAME_GOTREF
)
const (
TYPE_NONE AddrType = 0
TYPE_BRANCH AddrType = 5 + iota
TYPE_TEXTSIZE
TYPE_MEM
TYPE_CONST
TYPE_FCONST
TYPE_SCONST
TYPE_REG
TYPE_ADDR
TYPE_SHIFT
TYPE_REGREG
TYPE_REGREG2
TYPE_INDIR
TYPE_REGLIST
)
// Prog describes a single machine instruction.
//
// The general instruction form is:
//
// As.Scond From, Reg, From3, To, RegTo2
//
// where As is an opcode and the others are arguments:
// From, Reg, From3 are sources, and To, RegTo2 are destinations.
// Usually, not all arguments are present.
// For example, MOVL R1, R2 encodes using only As=MOVL, From=R1, To=R2.
// The Scond field holds additional condition bits for systems (like arm)
// that have generalized conditional execution.
//
// Jump instructions use the Pcond field to point to the target instruction,
// which must be in the same linked list as the jump instruction.
//
// The Progs for a given function are arranged in a list linked through the Link field.
//
// Each Prog is charged to a specific source line in the debug information,
// specified by Lineno, an index into the line history (see LineHist).
// Every Prog has a Ctxt field that defines various context, including the current LineHist.
// Progs should be allocated using ctxt.NewProg(), not new(Prog).
//
// The other fields not yet mentioned are for use by the back ends and should
// be left zeroed by creators of Prog lists.
type Prog struct {
Ctxt *Link // linker context
Link *Prog // next Prog in linked list
From Addr // first source operand
From3 *Addr // third source operand (second is Reg below)
To Addr // destination operand (second is RegTo2 below)
Pcond *Prog // target of conditional jump
Opt interface{} // available to optimization passes to hold per-Prog state
Forwd *Prog // for x86 back end
Rel *Prog // for x86, arm back ends
Pc int64 // for back ends or assembler: virtual or actual program counter, depending on phase
Lineno int32 // line number of this instruction
Spadj int32 // effect of instruction on stack pointer (increment or decrement amount)
As As // assembler opcode
Reg int16 // 2nd source operand
RegTo2 int16 // 2nd destination operand
Mark uint16 // bitmask of arch-specific items
Optab uint16 // arch-specific opcode index
Scond uint8 // condition bits for conditional instruction (e.g., on ARM)
Back uint8 // for x86 back end: backwards branch state
Ft uint8 // for x86 back end: type index of Prog.From
Tt uint8 // for x86 back end: type index of Prog.To
Isize uint8 // for x86 back end: size of the instruction in bytes
Mode int8 // for x86 back end: 32- or 64-bit mode
}
// From3Type returns From3.Type, or TYPE_NONE when From3 is nil.
func (p *Prog) From3Type() AddrType {
if p.From3 == nil {
return TYPE_NONE
}
return p.From3.Type
}
// From3Offset returns From3.Offset, or 0 when From3 is nil.
func (p *Prog) From3Offset() int64 {
if p.From3 == nil {
return 0
}
return p.From3.Offset
}
// An As denotes an assembler opcode.
// There are some portable opcodes, declared here in package obj,
// that are common to all architectures.
// However, the majority of opcodes are arch-specific
// and are declared in their respective architecture's subpackage.
type As int16
// These are the portable opcodes.
const (
AXXX As = iota
ACALL
ADUFFCOPY
ADUFFZERO
AEND
AFUNCDATA
AJMP
ANOP
APCDATA
ARET
ATEXT
ATYPE
AUNDEF
AUSEFIELD
AVARDEF
AVARKILL
AVARLIVE
A_ARCHSPECIFIC
)
// Each architecture is allotted a distinct subspace of opcode values
// for declaring its arch-specific opcodes.
// Within this subspace, the first arch-specific opcode should be
// at offset A_ARCHSPECIFIC.
//
// Subspaces are aligned to a power of two so opcodes can be masked
// with AMask and used as compact array indices.
const (
ABase386 = (1 + iota) << 10
ABaseARM
ABaseAMD64
ABasePPC64
ABaseARM64
ABaseMIPS64
ABaseS390X
AllowedOpCodes = 1 << 10 // The number of opcodes available for any given architecture.
AMask = AllowedOpCodes - 1 // AND with this to use the opcode as an array index.
)
// An LSym is the sort of symbol that is written to an object file.
type LSym struct {
Name string
Type SymKind
Version int16
Attribute
RefIdx int // Index of this symbol in the symbol reference list.
Args int32
Locals int32
Size int64
Gotype *LSym
Autom *Auto
Text *Prog
Pcln *Pcln
P []byte
R []Reloc
}
// Attribute is a set of symbol attributes.
type Attribute int16
const (
AttrDuplicateOK Attribute = 1 << iota
AttrCFunc
AttrNoSplit
AttrLeaf
AttrSeenGlobl
AttrOnList
// MakeTypelink means that the type should have an entry in the typelink table.
AttrMakeTypelink
// ReflectMethod means the function may call reflect.Type.Method or
// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
// can be used through a custom interface), so ReflectMethod may be
// set in some cases when the reflect package is not called.
//
// Used by the linker to determine what methods can be pruned.
AttrReflectMethod
// Local means make the symbol local even when compiling Go code to reference Go
// symbols in other shared libraries, as in this mode symbols are global by
// default. "local" here means in the sense of the dynamic linker, i.e. not
// visible outside of the module (shared library or executable) that contains its
// definition. (When not compiling to support Go shared libraries, all symbols are
// local in this sense unless there is a cgo_export_* directive).
AttrLocal
)
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
func (a Attribute) CFunc() bool { return a&AttrCFunc != 0 }
func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 }
func (a Attribute) Leaf() bool { return a&AttrLeaf != 0 }
func (a Attribute) SeenGlobl() bool { return a&AttrSeenGlobl != 0 }
func (a Attribute) OnList() bool { return a&AttrOnList != 0 }
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
func (a Attribute) Local() bool { return a&AttrLocal != 0 }
func (a *Attribute) Set(flag Attribute, value bool) {
if value {
*a |= flag
} else {
*a &^= flag
}
}
// The compiler needs LSym to satisfy fmt.Stringer, because it stores
// an LSym in ssa.ExternSymbol.
func (s *LSym) String() string {
return s.Name
}
type Pcln struct {
Pcsp Pcdata
Pcfile Pcdata
Pcline Pcdata
Pcdata []Pcdata
Funcdata []*LSym
Funcdataoff []int64
File []*LSym
Lastfile *LSym
Lastindex int
}
// A SymKind describes the kind of memory represented by a symbol.
type SymKind int16
// Defined SymKind values.
//
// TODO(rsc): Give idiomatic Go names.
// TODO(rsc): Reduce the number of symbol types in the object files.
//go:generate stringer -type=SymKind
const (
Sxxx SymKind = iota
STEXT
SELFRXSECT
// Read-only sections.
STYPE
SSTRING
SGOSTRING
SGOFUNC
SGCBITS
SRODATA
SFUNCTAB
SELFROSECT
SMACHOPLT
// Read-only sections with relocations.
//
// Types STYPE-SFUNCTAB above are written to the .rodata section by default.
// When linking a shared object, some conceptually "read only" types need to
// be written to by relocations and putting them in a section called
// ".rodata" interacts poorly with the system linkers. The GNU linkers
// support this situation by arranging for sections of the name
// ".data.rel.ro.XXX" to be mprotected read only by the dynamic linker after
// relocations have applied, so when the Go linker is creating a shared
// object it checks all objects of the above types and bumps any object that
// has a relocation to it to the corresponding type below, which are then
// written to sections with appropriate magic names.
STYPERELRO
SSTRINGRELRO
SGOSTRINGRELRO
SGOFUNCRELRO
SGCBITSRELRO
SRODATARELRO
SFUNCTABRELRO
// Part of .data.rel.ro if it exists, otherwise part of .rodata.
STYPELINK
SITABLINK
SSYMTAB
SPCLNTAB
// Writable sections.
SELFSECT
SMACHO
SMACHOGOT
SWINDOWS
SELFGOT
SNOPTRDATA
SINITARR
SDATA
SBSS
SNOPTRBSS
STLSBSS
SXREF
SMACHOSYMSTR
SMACHOSYMTAB
SMACHOINDIRECTPLT
SMACHOINDIRECTGOT
SFILE
SFILEPATH
SCONST
SDYNIMPORT
SHOSTOBJ
SDWARFSECT
SDWARFINFO
SSUB = SymKind(1 << 8)
SMASK = SymKind(SSUB - 1)
SHIDDEN = SymKind(1 << 9)
SCONTAINER = SymKind(1 << 10) // has a sub-symbol
)
// ReadOnly are the symbol kinds that form read-only sections. In some
// cases, if they will require relocations, they are transformed into
// rel-ro sections using RelROMap.
var ReadOnly = []SymKind{
STYPE,
SSTRING,
SGOSTRING,
SGOFUNC,
SGCBITS,
SRODATA,
SFUNCTAB,
}
// RelROMap describes the transformation of read-only symbols to rel-ro
// symbols.
var RelROMap = map[SymKind]SymKind{
STYPE: STYPERELRO,
SSTRING: SSTRINGRELRO,
SGOSTRING: SGOSTRINGRELRO,
SGOFUNC: SGOFUNCRELRO,
SGCBITS: SGCBITSRELRO,
SRODATA: SRODATARELRO,
SFUNCTAB: SFUNCTABRELRO,
}
type Reloc struct {
Off int32
Siz uint8
Type RelocType
Add int64
Sym *LSym
}
type RelocType int32
//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 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_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_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_DWARFREF resolves to the offset of the symbol from its section.
R_DWARFREF
// 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
// 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
// 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 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 the
// relocated symbol rather than the symbol's address.
R_ADDRPOWER_TOCREL_DS
// 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 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
)
// IsDirectJump returns whether r is a relocation for a direct jump.
// A direct jump is a CALL or JMP instruction that takes the target address
// as immediate. The address is embedded into the instruction, possibly
// with limited width.
// An indirect jump is a CALL or JMP instruction that takes the target address
// in register or memory.
func (r RelocType) IsDirectJump() bool {
switch r {
case R_CALL, R_CALLARM, R_CALLARM64, R_CALLPOWER, R_CALLMIPS, R_JMPMIPS:
return true
}
return false
}
type Auto struct {
Asym *LSym
Link *Auto
Aoffset int32
Name int16
Gotype *LSym
}
// Auto.name
const (
A_AUTO = 1 + iota
A_PARAM
)
type Pcdata struct {
P []byte
}
// symbol version, incremented each time a file is loaded.
// version==1 is reserved for savehist.
const (
HistVersion = 1
)
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
type Link struct {
Headtype HeadType
Arch *LinkArch
Debugasm int32
Debugvlog int32
Debugdivmod int32
Debugpcln int32
Flag_shared bool
Flag_dynlink bool
Flag_optimize bool
Bso *bufio.Writer
Pathname string
Hash map[SymVer]*LSym
LineHist LineHist
Imports []string
Plists []*Plist
Sym_div *LSym
Sym_divu *LSym
Sym_mod *LSym
Sym_modu *LSym
Plan9privates *LSym
Curp *Prog
Printp *Prog
Blitrl *Prog
Elitrl *Prog
Rexflag int
Vexflag int
Rep int
Repn int
Lock int
Asmode int
AsmBuf AsmBuf // instruction buffer for x86
Instoffset int64
Autosize int32
Armsize int32
Pc int64
DiagFunc func(string, ...interface{})
Mode int
Cursym *LSym
Version int
Errors int
Framepointer_enabled bool
// state for writing objects
Text []*LSym
Data []*LSym
// Cache of Progs
allocIdx int
progs [10000]Prog
}
func (ctxt *Link) Diag(format string, args ...interface{}) {
ctxt.Errors++
ctxt.DiagFunc(format, args...)
}
func (ctxt *Link) Logf(format string, args ...interface{}) {
fmt.Fprintf(ctxt.Bso, format, args...)
ctxt.Bso.Flush()
}
// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
// the hardware stack pointer and the local variable area.
func (ctxt *Link) FixedFrameSize() int64 {
switch ctxt.Arch.Family {
case sys.AMD64, sys.I386:
return 0
case sys.PPC64:
// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
// just use that much stack always on ppc64x.
return int64(4 * ctxt.Arch.PtrSize)
default:
return int64(ctxt.Arch.PtrSize)
}
}
type SymVer struct {
Name string
Version int // TODO: make int16 to match LSym.Version?
}
// LinkArch is the definition of a single architecture.
type LinkArch struct {
*sys.Arch
Preprocess func(*Link, *LSym)
Assemble func(*Link, *LSym)
Follow func(*Link, *LSym)
Progedit func(*Link, *Prog)
UnaryDst map[As]bool // Instruction takes one operand, a destination.
}
// HeadType is the executable header type.
type HeadType uint8
const (
Hunknown HeadType = iota
Hdarwin
Hdragonfly
Hfreebsd
Hlinux
Hnacl
Hnetbsd
Hopenbsd
Hplan9
Hsolaris
Hwindows
Hwindowsgui
)
func (h *HeadType) Set(s string) error {
switch s {
case "darwin":
*h = Hdarwin
case "dragonfly":
*h = Hdragonfly
case "freebsd":
*h = Hfreebsd
case "linux", "android":
*h = Hlinux
case "nacl":
*h = Hnacl
case "netbsd":
*h = Hnetbsd
case "openbsd":
*h = Hopenbsd
case "plan9":
*h = Hplan9
case "solaris":
*h = Hsolaris
case "windows":
*h = Hwindows
case "windowsgui":
*h = Hwindowsgui
default:
return fmt.Errorf("invalid headtype: %q", s)
}
return nil
}
func (h *HeadType) String() string {
switch *h {
case Hdarwin:
return "darwin"
case Hdragonfly:
return "dragonfly"
case Hfreebsd:
return "freebsd"
case Hlinux:
return "linux"
case Hnacl:
return "nacl"
case Hnetbsd:
return "netbsd"
case Hopenbsd:
return "openbsd"
case Hplan9:
return "plan9"
case Hsolaris:
return "solaris"
case Hwindows:
return "windows"
case Hwindowsgui:
return "windowsgui"
}
return fmt.Sprintf("HeadType(%d)", *h)
}
// AsmBuf is a simple buffer to assemble variable-length x86 instructions into.
type AsmBuf struct {
buf [100]byte
off int
}
// Put1 appends one byte to the end of the buffer.
func (a *AsmBuf) Put1(x byte) {
a.buf[a.off] = x
a.off++
}
// Put2 appends two bytes to the end of the buffer.
func (a *AsmBuf) Put2(x, y byte) {
a.buf[a.off+0] = x
a.buf[a.off+1] = y
a.off += 2
}
// Put3 appends three bytes to the end of the buffer.
func (a *AsmBuf) Put3(x, y, z byte) {
a.buf[a.off+0] = x
a.buf[a.off+1] = y
a.buf[a.off+2] = z
a.off += 3
}
// Put4 appends four bytes to the end of the buffer.
func (a *AsmBuf) Put4(x, y, z, w byte) {
a.buf[a.off+0] = x
a.buf[a.off+1] = y
a.buf[a.off+2] = z
a.buf[a.off+3] = w
a.off += 4
}
// PutInt16 writes v into the buffer using little-endian encoding.
func (a *AsmBuf) PutInt16(v int16) {
a.buf[a.off+0] = byte(v)
a.buf[a.off+1] = byte(v >> 8)
a.off += 2
}
// PutInt32 writes v into the buffer using little-endian encoding.
func (a *AsmBuf) PutInt32(v int32) {
a.buf[a.off+0] = byte(v)
a.buf[a.off+1] = byte(v >> 8)
a.buf[a.off+2] = byte(v >> 16)
a.buf[a.off+3] = byte(v >> 24)
a.off += 4
}
// PutInt64 writes v into the buffer using little-endian encoding.
func (a *AsmBuf) PutInt64(v int64) {
a.buf[a.off+0] = byte(v)
a.buf[a.off+1] = byte(v >> 8)
a.buf[a.off+2] = byte(v >> 16)
a.buf[a.off+3] = byte(v >> 24)
a.buf[a.off+4] = byte(v >> 32)
a.buf[a.off+5] = byte(v >> 40)
a.buf[a.off+6] = byte(v >> 48)
a.buf[a.off+7] = byte(v >> 56)
a.off += 8
}
// Put copies b into the buffer.
func (a *AsmBuf) Put(b []byte) {
copy(a.buf[a.off:], b)
a.off += len(b)
}
// Insert inserts b at offset i.
func (a *AsmBuf) Insert(i int, b byte) {
a.off++
copy(a.buf[i+1:a.off], a.buf[i:a.off-1])
a.buf[i] = b
}
// Last returns the byte at the end of the buffer.
func (a *AsmBuf) Last() byte { return a.buf[a.off-1] }
// Len returns the length of the buffer.
func (a *AsmBuf) Len() int { return a.off }
// Bytes returns the contents of the buffer.
func (a *AsmBuf) Bytes() []byte { return a.buf[:a.off] }
// Reset empties the buffer.
func (a *AsmBuf) Reset() { a.off = 0 }
// Peek returns the byte at offset i.
func (a *AsmBuf) Peek(i int) byte { return a.buf[i] }

View File

@ -0,0 +1,375 @@
// cmd/9c/9.out.h from Vita Nuova.
//
// 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-2008 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-2008 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 mips
import "github.com/google/gops/internal/obj"
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p mips
/*
* mips 64
*/
const (
NSNAME = 8
NSYM = 50
NREG = 32 /* number of general registers */
NFREG = 32 /* number of floating point registers */
)
const (
REG_R0 = obj.RBaseMIPS64 + iota
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_R16
REG_R17
REG_R18
REG_R19
REG_R20
REG_R21
REG_R22
REG_R23
REG_R24
REG_R25
REG_R26
REG_R27
REG_R28
REG_R29
REG_R30
REG_R31
REG_F0
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_F16
REG_F17
REG_F18
REG_F19
REG_F20
REG_F21
REG_F22
REG_F23
REG_F24
REG_F25
REG_F26
REG_F27
REG_F28
REG_F29
REG_F30
REG_F31
REG_HI
REG_LO
// co-processor 0 control registers
REG_M0
REG_M1
REG_M2
REG_M3
REG_M4
REG_M5
REG_M6
REG_M7
REG_M8
REG_M9
REG_M10
REG_M11
REG_M12
REG_M13
REG_M14
REG_M15
REG_M16
REG_M17
REG_M18
REG_M19
REG_M20
REG_M21
REG_M22
REG_M23
REG_M24
REG_M25
REG_M26
REG_M27
REG_M28
REG_M29
REG_M30
REG_M31
// FPU control registers
REG_FCR0
REG_FCR1
REG_FCR2
REG_FCR3
REG_FCR4
REG_FCR5
REG_FCR6
REG_FCR7
REG_FCR8
REG_FCR9
REG_FCR10
REG_FCR11
REG_FCR12
REG_FCR13
REG_FCR14
REG_FCR15
REG_FCR16
REG_FCR17
REG_FCR18
REG_FCR19
REG_FCR20
REG_FCR21
REG_FCR22
REG_FCR23
REG_FCR24
REG_FCR25
REG_FCR26
REG_FCR27
REG_FCR28
REG_FCR29
REG_FCR30
REG_FCR31
REG_LAST = REG_FCR31 // the last defined register
REG_SPECIAL = REG_M0
REGZERO = REG_R0 /* set to zero */
REGSP = REG_R29
REGSB = REG_R28
REGLINK = REG_R31
REGRET = REG_R1
REGARG = -1 /* -1 disables passing the first argument in register */
REGRT1 = REG_R1 /* reserved for runtime, duffzero and duffcopy */
REGRT2 = REG_R2 /* reserved for runtime, duffcopy */
REGCTXT = REG_R22 /* context for closures */
REGG = REG_R30 /* G */
REGTMP = REG_R23 /* used by the linker */
FREGRET = REG_F0
)
const (
BIG = 32766
)
const (
/* mark flags */
FOLL = 1 << 0
LABEL = 1 << 1
LEAF = 1 << 2
SYNC = 1 << 3
BRANCH = 1 << 4
LOAD = 1 << 5
FCMP = 1 << 6
NOSCHED = 1 << 7
NSCHED = 20
)
const (
C_NONE = iota
C_REG
C_FREG
C_FCREG
C_MREG /* special processor register */
C_HI
C_LO
C_ZCON
C_SCON /* 16 bit signed */
C_UCON /* 32 bit signed, low 16 bits 0 */
C_ADD0CON
C_AND0CON
C_ADDCON /* -0x8000 <= v < 0 */
C_ANDCON /* 0 < v <= 0xFFFF */
C_LCON /* other 32 */
C_DCON /* other 64 (could subdivide further) */
C_SACON /* $n(REG) where n <= int16 */
C_SECON
C_LACON /* $n(REG) where int16 < n <= int32 */
C_LECON
C_DACON /* $n(REG) where int32 < n */
C_STCON /* $tlsvar */
C_SBRA
C_LBRA
C_SAUTO
C_LAUTO
C_SEXT
C_LEXT
C_ZOREG
C_SOREG
C_LOREG
C_GOK
C_ADDR
C_TLS
C_TEXTSIZE
C_NCLASS /* must be the last */
)
const (
AABSD = obj.ABaseMIPS64 + obj.A_ARCHSPECIFIC + iota
AABSF
AABSW
AADD
AADDD
AADDF
AADDU
AADDW
AAND
ABEQ
ABFPF
ABFPT
ABGEZ
ABGEZAL
ABGTZ
ABLEZ
ABLTZ
ABLTZAL
ABNE
ABREAK
ACMPEQD
ACMPEQF
ACMPGED
ACMPGEF
ACMPGTD
ACMPGTF
ADIV
ADIVD
ADIVF
ADIVU
ADIVW
AGOK
ALUI
AMOVB
AMOVBU
AMOVD
AMOVDF
AMOVDW
AMOVF
AMOVFD
AMOVFW
AMOVH
AMOVHU
AMOVW
AMOVWD
AMOVWF
AMOVWL
AMOVWR
AMUL
AMULD
AMULF
AMULU
AMULW
ANEGD
ANEGF
ANEGW
ANOR
AOR
AREM
AREMU
ARFE
ASGT
ASGTU
ASLL
ASRA
ASRL
ASUB
ASUBD
ASUBF
ASUBU
ASUBW
ASYSCALL
ATLBP
ATLBR
ATLBWI
ATLBWR
AWORD
AXOR
/* 64-bit */
AMOVV
AMOVVL
AMOVVR
ASLLV
ASRAV
ASRLV
ADIVV
ADIVVU
AREMV
AREMVU
AMULV
AMULVU
AADDV
AADDVU
ASUBV
ASUBVU
/* 64-bit FP */
ATRUNCFV
ATRUNCDV
ATRUNCFW
ATRUNCDW
AMOVWU
AMOVFV
AMOVDV
AMOVVF
AMOVVD
ALAST
// aliases
AJMP = obj.AJMP
AJAL = obj.ACALL
ARET = obj.ARET
)

View File

@ -0,0 +1,113 @@
// Generated by stringer -i a.out.go -o anames.go -p mips
// Do not edit.
package mips
import "github.com/google/gops/internal/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ABSD",
"ABSF",
"ABSW",
"ADD",
"ADDD",
"ADDF",
"ADDU",
"ADDW",
"AND",
"BEQ",
"BFPF",
"BFPT",
"BGEZ",
"BGEZAL",
"BGTZ",
"BLEZ",
"BLTZ",
"BLTZAL",
"BNE",
"BREAK",
"CMPEQD",
"CMPEQF",
"CMPGED",
"CMPGEF",
"CMPGTD",
"CMPGTF",
"DIV",
"DIVD",
"DIVF",
"DIVU",
"DIVW",
"GOK",
"LUI",
"MOVB",
"MOVBU",
"MOVD",
"MOVDF",
"MOVDW",
"MOVF",
"MOVFD",
"MOVFW",
"MOVH",
"MOVHU",
"MOVW",
"MOVWD",
"MOVWF",
"MOVWL",
"MOVWR",
"MUL",
"MULD",
"MULF",
"MULU",
"MULW",
"NEGD",
"NEGF",
"NEGW",
"NOR",
"OR",
"REM",
"REMU",
"RFE",
"SGT",
"SGTU",
"SLL",
"SRA",
"SRL",
"SUB",
"SUBD",
"SUBF",
"SUBU",
"SUBW",
"SYSCALL",
"TLBP",
"TLBR",
"TLBWI",
"TLBWR",
"WORD",
"XOR",
"MOVV",
"MOVVL",
"MOVVR",
"SLLV",
"SRAV",
"SRLV",
"DIVV",
"DIVVU",
"REMV",
"REMVU",
"MULV",
"MULVU",
"ADDV",
"ADDVU",
"SUBV",
"SUBVU",
"TRUNCFV",
"TRUNCDV",
"TRUNCFW",
"TRUNCDW",
"MOVWU",
"MOVFV",
"MOVDV",
"MOVVF",
"MOVVD",
"LAST",
}

View File

@ -0,0 +1,44 @@
// 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 mips
var cnames0 = []string{
"NONE",
"REG",
"FREG",
"FCREG",
"MREG",
"HI",
"LO",
"ZCON",
"SCON",
"UCON",
"ADD0CON",
"AND0CON",
"ADDCON",
"ANDCON",
"LCON",
"DCON",
"SACON",
"SECON",
"LACON",
"LECON",
"DACON",
"STCON",
"SBRA",
"LBRA",
"SAUTO",
"LAUTO",
"SEXT",
"LEXT",
"ZOREG",
"SOREG",
"LOREG",
"GOK",
"ADDR",
"TLS",
"TEXTSIZE",
"NCLASS",
}

1783
vendor/github.com/google/gops/internal/obj/mips/asm0.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
// cmd/9l/list.c from Vita Nuova.
//
// 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-2008 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-2008 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 mips
import (
"fmt"
"github.com/google/gops/internal/obj"
)
func init() {
obj.RegisterRegister(obj.RBaseMIPS64, REG_LAST&^1023+1024, Rconv)
obj.RegisterOpcode(obj.ABaseMIPS64, Anames)
}
func Rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if r == REGSB {
// Special case.
return "RSB"
}
if REG_R0 <= r && r <= REG_R31 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F31 {
return fmt.Sprintf("F%d", r-REG_F0)
}
if REG_M0 <= r && r <= REG_M31 {
return fmt.Sprintf("M%d", r-REG_M0)
}
if REG_FCR0 <= r && r <= REG_FCR31 {
return fmt.Sprintf("FCR%d", r-REG_FCR0)
}
if r == REG_HI {
return "HI"
}
if r == REG_LO {
return "LO"
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseMIPS64)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnames0[a]
}
var fp string
fp += s
return fp
}

1497
vendor/github.com/google/gops/internal/obj/mips/obj0.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

306
vendor/github.com/google/gops/internal/obj/obj.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
// 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 obj
import (
"fmt"
"path/filepath"
"sort"
"strings"
)
// A LineHist records the history of the file input stack, which maps the virtual line number,
// an incrementing count of lines processed in any input file and typically named lineno,
// to a stack of file:line pairs showing the path of inclusions that led to that position.
// The first line directive (//line in Go, #line in assembly) is treated as pushing
// a new entry on the stack, so that errors can report both the actual and translated
// line number.
//
// In typical use, the virtual lineno begins at 1, and file line numbers also begin at 1,
// but the only requirements placed upon the numbers by this code are:
// - calls to Push, Update, and Pop must be monotonically increasing in lineno
// - except as specified by those methods, virtual and file line number increase
// together, so that given (only) calls Push(10, "x.go", 1) and Pop(15),
// virtual line 12 corresponds to x.go line 3.
type LineHist struct {
Top *LineStack // current top of stack
Ranges []LineRange // ranges for lookup
Dir string // directory to qualify relative paths
TrimPathPrefix string // remove leading TrimPath from recorded file names
PrintFilenameOnly bool // ignore path when pretty-printing a line; internal use only
GOROOT string // current GOROOT
}
// A LineStack is an entry in the recorded line history.
// Although the history at any given line number is a stack,
// the record for all line processed forms a tree, with common
// stack prefixes acting as parents.
type LineStack struct {
Parent *LineStack // parent in inclusion stack
Lineno int // virtual line number where this entry takes effect
File string // file name used to open source file, for error messages
AbsFile string // absolute file name, for pcln tables
FileLine int // line number in file at Lineno
Directive bool
Sym *LSym // for linkgetline - TODO(rsc): remove
}
func (stk *LineStack) fileLineAt(lineno int) int {
return stk.FileLine + lineno - stk.Lineno
}
// The span of valid linenos in the recorded line history can be broken
// into a set of ranges, each with a particular stack.
// A LineRange records one such range.
type LineRange struct {
Start int // starting lineno
Stack *LineStack // top of stack for this range
}
// startRange starts a new range with the given top of stack.
func (h *LineHist) startRange(lineno int, top *LineStack) {
h.Top = top
h.Ranges = append(h.Ranges, LineRange{top.Lineno, top})
}
// setFile sets stk.File = file and also derives stk.AbsFile.
func (h *LineHist) setFile(stk *LineStack, file string) {
// Note: The exclusion of stk.Directive may be wrong but matches what we've done before.
// The check for < avoids putting a path prefix on "<autogenerated>".
abs := file
if h.Dir != "" && !filepath.IsAbs(file) && !strings.HasPrefix(file, "<") && !stk.Directive {
abs = filepath.Join(h.Dir, file)
}
// Remove leading TrimPathPrefix, or else rewrite $GOROOT to literal $GOROOT.
if h.TrimPathPrefix != "" && hasPathPrefix(abs, h.TrimPathPrefix) {
if abs == h.TrimPathPrefix {
abs = ""
} else {
abs = abs[len(h.TrimPathPrefix)+1:]
}
} else if hasPathPrefix(abs, h.GOROOT) {
abs = "$GOROOT" + abs[len(h.GOROOT):]
}
if abs == "" {
abs = "??"
}
abs = filepath.Clean(abs)
stk.AbsFile = abs
if file == "" {
file = "??"
}
stk.File = file
}
// 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] == '\\'
}
// Push records that at that lineno a new file with the given name was pushed onto the input stack.
func (h *LineHist) Push(lineno int, file string) {
stk := &LineStack{
Parent: h.Top,
Lineno: lineno,
FileLine: 1,
}
h.setFile(stk, file)
h.startRange(lineno, stk)
}
// Pop records that at lineno the current file was popped from the input stack.
func (h *LineHist) Pop(lineno int) {
top := h.Top
if top == nil {
return
}
if top.Directive && top.Parent != nil { // pop #line level too
top = top.Parent
}
next := top.Parent
if next == nil {
h.Top = nil
h.Ranges = append(h.Ranges, LineRange{lineno, nil})
return
}
// Popping included file. Update parent offset to account for
// the virtual line number range taken by the included file.
// Cannot modify the LineStack directly, or else lookups
// for the earlier line numbers will get the wrong answers,
// so make a new one.
stk := new(LineStack)
*stk = *next
stk.Lineno = lineno
stk.FileLine = next.fileLineAt(top.Lineno)
h.startRange(lineno, stk)
}
// Update records that at lineno the file name and line number were changed using
// a line directive (//line in Go, #line in assembly).
func (h *LineHist) Update(lineno int, file string, line int) {
top := h.Top
if top == nil {
return // shouldn't happen
}
var stk *LineStack
if top.Directive {
// Update existing entry, except make copy to avoid changing earlier history.
stk = new(LineStack)
*stk = *top
} else {
// Push new entry.
stk = &LineStack{
Parent: top,
Directive: true,
}
}
stk.Lineno = lineno
if stk.File != file {
h.setFile(stk, file) // only retain string if needed
}
stk.FileLine = line
h.startRange(lineno, stk)
}
// AddImport adds a package to the list of imported packages.
func (ctxt *Link) AddImport(pkg string) {
ctxt.Imports = append(ctxt.Imports, pkg)
}
// At returns the input stack in effect at lineno.
func (h *LineHist) At(lineno int) *LineStack {
i := sort.Search(len(h.Ranges), func(i int) bool {
return h.Ranges[i].Start > lineno
})
// Found first entry beyond lineno.
if i == 0 {
return nil
}
return h.Ranges[i-1].Stack
}
// LineString returns a string giving the file and line number
// corresponding to lineno, for use in error messages.
func (h *LineHist) LineString(lineno int) string {
stk := h.At(lineno)
if stk == nil {
return "<unknown line number>"
}
filename := stk.File
if h.PrintFilenameOnly {
filename = filepath.Base(filename)
}
text := fmt.Sprintf("%s:%d", filename, stk.fileLineAt(lineno))
if stk.Directive && stk.Parent != nil {
stk = stk.Parent
filename = stk.File
if h.PrintFilenameOnly {
filename = filepath.Base(filename)
}
text += fmt.Sprintf("[%s:%d]", filename, stk.fileLineAt(lineno))
}
const showFullStack = false // was used by old C compilers
if showFullStack {
for stk.Parent != nil {
lineno = stk.Lineno - 1
stk = stk.Parent
text += fmt.Sprintf(" %s:%d", filename, stk.fileLineAt(lineno))
if stk.Directive && stk.Parent != nil {
stk = stk.Parent
text += fmt.Sprintf("[%s:%d]", filename, stk.fileLineAt(lineno))
}
}
}
return text
}
// FileLine returns the file name and line number
// at the top of the stack for the given lineno.
func (h *LineHist) FileLine(lineno int) (file string, line int) {
stk := h.At(lineno)
if stk == nil {
return "??", 0
}
return stk.File, stk.fileLineAt(lineno)
}
// AbsFileLine returns the absolute file name and line number
// at the top of the stack for the given lineno.
func (h *LineHist) AbsFileLine(lineno int) (file string, line int) {
stk := h.At(lineno)
if stk == nil {
return "??", 0
}
return stk.AbsFile, stk.fileLineAt(lineno)
}
// This is a simplified copy of linklinefmt above.
// It doesn't allow printing the full stack, and it returns the file name and line number separately.
// TODO: Unify with linklinefmt somehow.
func linkgetline(ctxt *Link, lineno int32) (f *LSym, l int32) {
stk := ctxt.LineHist.At(int(lineno))
if stk == nil || stk.AbsFile == "" {
return Linklookup(ctxt, "??", HistVersion), 0
}
if stk.Sym == nil {
stk.Sym = Linklookup(ctxt, stk.AbsFile, HistVersion)
}
return stk.Sym, int32(stk.fileLineAt(int(lineno)))
}
func Linkprfile(ctxt *Link, line int) {
fmt.Printf("%s ", ctxt.LineHist.LineString(line))
}
func fieldtrack(ctxt *Link, cursym *LSym) {
p := cursym.Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
ctxt.Cursym = cursym
for ; p != nil; p = p.Link {
if p.As == AUSEFIELD {
r := Addrel(ctxt.Cursym)
r.Off = 0
r.Siz = 0
r.Sym = p.From.Sym
r.Type = R_USEFIELD
}
}
}

606
vendor/github.com/google/gops/internal/obj/objfile.go generated vendored Normal file
View File

@ -0,0 +1,606 @@
// 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.
// Writing of Go object files.
//
// Originally, Go object files were Plan 9 object files, but no longer.
// Now they are more like standard object files, in that each symbol is defined
// by an associated memory image (bytes) and a list of relocations to apply
// during linking. We do not (yet?) use a standard file format, however.
// For now, the format is chosen to be as simple as possible to read and write.
// It may change for reasons of efficiency, or we may even switch to a
// standard file format if there are compelling benefits to doing so.
// See golang.org/s/go13linker for more background.
//
// The file format is:
//
// - magic header: "\x00\x00go17ld"
// - byte 1 - version number
// - sequence of strings giving dependencies (imported packages)
// - empty string (marks end of sequence)
// - sequence of symbol references used by the defined symbols
// - byte 0xff (marks end of sequence)
// - sequence of integer lengths:
// - total data length
// - total number of relocations
// - total number of pcdata
// - total number of automatics
// - total number of funcdata
// - total number of files
// - data, the content of the defined symbols
// - sequence of defined symbols
// - byte 0xff (marks end of sequence)
// - magic footer: "\xff\xffgo17ld"
//
// All integers are stored in a zigzag varint format.
// See golang.org/s/go12symtab for a definition.
//
// Data blocks and strings are both stored as an integer
// followed by that many bytes.
//
// A symbol reference is a string name followed by a version.
//
// A symbol points to other symbols using an index into the symbol
// reference sequence. Index 0 corresponds to a nil LSym* pointer.
// In the symbol layout described below "symref index" stands for this
// index.
//
// Each symbol is laid out as the following fields (taken from LSym*):
//
// - byte 0xfe (sanity check for synchronization)
// - type [int]
// - name & version [symref index]
// - flags [int]
// 1<<0 dupok
// 1<<1 local
// 1<<2 add to typelink table
// - size [int]
// - gotype [symref index]
// - p [data block]
// - nr [int]
// - r [nr relocations, sorted by off]
//
// If type == STEXT, there are a few more fields:
//
// - args [int]
// - locals [int]
// - nosplit [int]
// - flags [int]
// 1<<0 leaf
// 1<<1 C function
// 1<<2 function may call reflect.Type.Method
// - nlocal [int]
// - local [nlocal automatics]
// - pcln [pcln table]
//
// Each relocation has the encoding:
//
// - off [int]
// - siz [int]
// - type [int]
// - add [int]
// - sym [symref index]
//
// Each local has the encoding:
//
// - asym [symref index]
// - offset [int]
// - type [int]
// - gotype [symref index]
//
// The pcln table has the encoding:
//
// - pcsp [data block]
// - pcfile [data block]
// - pcline [data block]
// - npcdata [int]
// - pcdata [npcdata data blocks]
// - nfuncdata [int]
// - funcdata [nfuncdata symref index]
// - funcdatasym [nfuncdata ints]
// - nfile [int]
// - file [nfile symref index]
//
// The file layout and meaning of type integers are architecture-independent.
//
// TODO(rsc): The file format is good for a first pass but needs work.
// - There are SymID in the object file that should really just be strings.
package obj
import (
"bufio"
"fmt"
"log"
"path/filepath"
"sort"
"github.com/google/gops/internal/dwarf"
"github.com/google/gops/internal/sys"
)
// The Go and C compilers, and the assembler, call writeobj to write
// out a Go object file. The linker does not call this; the linker
// does not write out object files.
func Writeobjdirect(ctxt *Link, b *bufio.Writer) {
Flushplist(ctxt)
WriteObjFile(ctxt, b)
}
// objWriter writes Go object files.
type objWriter struct {
wr *bufio.Writer
ctxt *Link
// Temporary buffer for zigzag int writing.
varintbuf [10]uint8
// Provide the the index of a symbol reference by symbol name.
// One map for versioned symbols and one for unversioned symbols.
// Used for deduplicating the symbol reference list.
refIdx map[string]int
vrefIdx map[string]int
// Number of objects written of each type.
nRefs int
nData int
nReloc int
nPcdata int
nAutom int
nFuncdata int
nFile int
}
func (w *objWriter) addLengths(s *LSym) {
w.nData += len(s.P)
w.nReloc += len(s.R)
if s.Type != STEXT {
return
}
pc := s.Pcln
data := 0
data += len(pc.Pcsp.P)
data += len(pc.Pcfile.P)
data += len(pc.Pcline.P)
for i := 0; i < len(pc.Pcdata); i++ {
data += len(pc.Pcdata[i].P)
}
w.nData += data
w.nPcdata += len(pc.Pcdata)
autom := 0
for a := s.Autom; a != nil; a = a.Link {
autom++
}
w.nAutom += autom
w.nFuncdata += len(pc.Funcdataoff)
w.nFile += len(pc.File)
}
func (w *objWriter) writeLengths() {
w.writeInt(int64(w.nData))
w.writeInt(int64(w.nReloc))
w.writeInt(int64(w.nPcdata))
w.writeInt(int64(w.nAutom))
w.writeInt(int64(w.nFuncdata))
w.writeInt(int64(w.nFile))
}
func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
return &objWriter{
ctxt: ctxt,
wr: b,
vrefIdx: make(map[string]int),
refIdx: make(map[string]int),
}
}
func WriteObjFile(ctxt *Link, b *bufio.Writer) {
w := newObjWriter(ctxt, b)
// Magic header
w.wr.WriteString("\x00\x00go17ld")
// Version
w.wr.WriteByte(1)
// Autolib
for _, pkg := range ctxt.Imports {
w.writeString(pkg)
}
w.writeString("")
// Symbol references
for _, s := range ctxt.Text {
w.writeRefs(s)
w.addLengths(s)
}
for _, s := range ctxt.Data {
w.writeRefs(s)
w.addLengths(s)
}
// End symbol references
w.wr.WriteByte(0xff)
// Lengths
w.writeLengths()
// Data block
for _, s := range ctxt.Text {
w.wr.Write(s.P)
pc := s.Pcln
w.wr.Write(pc.Pcsp.P)
w.wr.Write(pc.Pcfile.P)
w.wr.Write(pc.Pcline.P)
for i := 0; i < len(pc.Pcdata); i++ {
w.wr.Write(pc.Pcdata[i].P)
}
}
for _, s := range ctxt.Data {
w.wr.Write(s.P)
}
// Symbols
for _, s := range ctxt.Text {
w.writeSym(s)
}
for _, s := range ctxt.Data {
w.writeSym(s)
}
// Magic footer
w.wr.WriteString("\xff\xffgo17ld")
}
// Symbols are prefixed so their content doesn't get confused with the magic footer.
const symPrefix = 0xfe
func (w *objWriter) writeRef(s *LSym, isPath bool) {
if s == nil || s.RefIdx != 0 {
return
}
var m map[string]int
switch s.Version {
case 0:
m = w.refIdx
case 1:
m = w.vrefIdx
default:
log.Fatalf("%s: invalid version number %d", s.Name, s.Version)
}
idx := m[s.Name]
if idx != 0 {
s.RefIdx = idx
return
}
w.wr.WriteByte(symPrefix)
if isPath {
w.writeString(filepath.ToSlash(s.Name))
} else {
w.writeString(s.Name)
}
w.writeInt(int64(s.Version))
w.nRefs++
s.RefIdx = w.nRefs
m[s.Name] = w.nRefs
}
func (w *objWriter) writeRefs(s *LSym) {
w.writeRef(s, false)
w.writeRef(s.Gotype, false)
for i := range s.R {
w.writeRef(s.R[i].Sym, false)
}
if s.Type == STEXT {
for a := s.Autom; a != nil; a = a.Link {
w.writeRef(a.Asym, false)
w.writeRef(a.Gotype, false)
}
pc := s.Pcln
for _, d := range pc.Funcdata {
w.writeRef(d, false)
}
for _, f := range pc.File {
w.writeRef(f, true)
}
}
}
func (w *objWriter) writeSymDebug(s *LSym) {
ctxt := w.ctxt
fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
if s.Version != 0 {
fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
}
if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
}
if s.DuplicateOK() {
fmt.Fprintf(ctxt.Bso, "dupok ")
}
if s.CFunc() {
fmt.Fprintf(ctxt.Bso, "cfunc ")
}
if s.NoSplit() {
fmt.Fprintf(ctxt.Bso, "nosplit ")
}
fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
if s.Type == STEXT {
fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
if s.Leaf() {
fmt.Fprintf(ctxt.Bso, " leaf")
}
}
fmt.Fprintf(ctxt.Bso, "\n")
for p := s.Text; p != nil; p = p.Link {
fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
}
var c int
var j int
for i := 0; i < len(s.P); {
fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
for j = i; j < i+16 && j < len(s.P); j++ {
fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
}
for ; j < i+16; j++ {
fmt.Fprintf(ctxt.Bso, " ")
}
fmt.Fprintf(ctxt.Bso, " ")
for j = i; j < i+16 && j < len(s.P); j++ {
c = int(s.P[j])
if ' ' <= c && c <= 0x7e {
fmt.Fprintf(ctxt.Bso, "%c", c)
} else {
fmt.Fprintf(ctxt.Bso, ".")
}
}
fmt.Fprintf(ctxt.Bso, "\n")
i += 16
}
sort.Sort(relocByOff(s.R)) // generate stable output
for _, r := range s.R {
name := ""
if r.Sym != nil {
name = r.Sym.Name
} else if r.Type == R_TLS_LE {
name = "TLS"
}
if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
} else {
fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
}
}
}
func (w *objWriter) writeSym(s *LSym) {
ctxt := w.ctxt
if ctxt.Debugasm != 0 {
w.writeSymDebug(s)
}
w.wr.WriteByte(symPrefix)
w.writeInt(int64(s.Type))
w.writeRefIndex(s)
flags := int64(0)
if s.DuplicateOK() {
flags |= 1
}
if s.Local() {
flags |= 1 << 1
}
if s.MakeTypelink() {
flags |= 1 << 2
}
w.writeInt(flags)
w.writeInt(s.Size)
w.writeRefIndex(s.Gotype)
w.writeInt(int64(len(s.P)))
w.writeInt(int64(len(s.R)))
var r *Reloc
for i := 0; i < len(s.R); i++ {
r = &s.R[i]
w.writeInt(int64(r.Off))
w.writeInt(int64(r.Siz))
w.writeInt(int64(r.Type))
w.writeInt(r.Add)
w.writeRefIndex(r.Sym)
}
if s.Type != STEXT {
return
}
w.writeInt(int64(s.Args))
w.writeInt(int64(s.Locals))
if s.NoSplit() {
w.writeInt(1)
} else {
w.writeInt(0)
}
flags = int64(0)
if s.Leaf() {
flags |= 1
}
if s.CFunc() {
flags |= 1 << 1
}
if s.ReflectMethod() {
flags |= 1 << 2
}
w.writeInt(flags)
n := 0
for a := s.Autom; a != nil; a = a.Link {
n++
}
w.writeInt(int64(n))
for a := s.Autom; a != nil; a = a.Link {
w.writeRefIndex(a.Asym)
w.writeInt(int64(a.Aoffset))
if a.Name == NAME_AUTO {
w.writeInt(A_AUTO)
} else if a.Name == NAME_PARAM {
w.writeInt(A_PARAM)
} else {
log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
}
w.writeRefIndex(a.Gotype)
}
pc := s.Pcln
w.writeInt(int64(len(pc.Pcsp.P)))
w.writeInt(int64(len(pc.Pcfile.P)))
w.writeInt(int64(len(pc.Pcline.P)))
w.writeInt(int64(len(pc.Pcdata)))
for i := 0; i < len(pc.Pcdata); i++ {
w.writeInt(int64(len(pc.Pcdata[i].P)))
}
w.writeInt(int64(len(pc.Funcdataoff)))
for i := 0; i < len(pc.Funcdataoff); i++ {
w.writeRefIndex(pc.Funcdata[i])
}
for i := 0; i < len(pc.Funcdataoff); i++ {
w.writeInt(pc.Funcdataoff[i])
}
w.writeInt(int64(len(pc.File)))
for _, f := range pc.File {
w.writeRefIndex(f)
}
}
func (w *objWriter) writeInt(sval int64) {
var v uint64
uv := (uint64(sval) << 1) ^ uint64(sval>>63)
p := w.varintbuf[:]
for v = uv; v >= 0x80; v >>= 7 {
p[0] = uint8(v | 0x80)
p = p[1:]
}
p[0] = uint8(v)
p = p[1:]
w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
}
func (w *objWriter) writeString(s string) {
w.writeInt(int64(len(s)))
w.wr.WriteString(s)
}
func (w *objWriter) writeRefIndex(s *LSym) {
if s == nil {
w.writeInt(0)
return
}
if s.RefIdx == 0 {
log.Fatalln("writing an unreferenced symbol", s.Name)
}
w.writeInt(int64(s.RefIdx))
}
// relocByOff sorts relocations by their offsets.
type relocByOff []Reloc
func (x relocByOff) Len() int { return len(x) }
func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
// implement dwarf.Context
type dwCtxt struct{ *Link }
func (c dwCtxt) PtrSize() int {
return c.Arch.PtrSize
}
func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
ls := s.(*LSym)
ls.WriteInt(c.Link, ls.Size, size, i)
}
func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
ls := s.(*LSym)
ls.WriteBytes(c.Link, ls.Size, b)
}
func (c dwCtxt) AddString(s dwarf.Sym, v string) {
ls := s.(*LSym)
ls.WriteString(c.Link, ls.Size, len(v), v)
ls.WriteInt(c.Link, ls.Size, 1, 0)
}
func (c dwCtxt) SymValue(s dwarf.Sym) int64 {
return 0
}
func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
rsym := data.(*LSym)
ls := s.(*LSym)
size := c.PtrSize()
ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
}
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
ls := s.(*LSym)
rsym := t.(*LSym)
ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
r := &ls.R[len(ls.R)-1]
r.Type = R_DWARFREF
}
func gendwarf(ctxt *Link, text []*LSym) []*LSym {
dctxt := dwCtxt{ctxt}
var dw []*LSym
for _, s := range text {
dsym := Linklookup(ctxt, dwarf.InfoPrefix+s.Name, int(s.Version))
if dsym.Size != 0 {
continue
}
dw = append(dw, dsym)
dsym.Type = SDWARFINFO
dsym.Set(AttrDuplicateOK, s.DuplicateOK())
var vars dwarf.Var
var abbrev int
var offs int32
for a := s.Autom; a != nil; a = a.Link {
switch a.Name {
case NAME_AUTO:
abbrev = dwarf.DW_ABRV_AUTO
offs = a.Aoffset
if ctxt.FixedFrameSize() == 0 {
offs -= int32(ctxt.Arch.PtrSize)
}
if Framepointer_enabled(GOOS, GOARCH) {
offs -= int32(ctxt.Arch.PtrSize)
}
case NAME_PARAM:
abbrev = dwarf.DW_ABRV_PARAM
offs = a.Aoffset + int32(ctxt.FixedFrameSize())
default:
continue
}
typename := dwarf.InfoPrefix + a.Gotype.Name[len("type."):]
dwvar := &dwarf.Var{
Name: a.Asym.Name,
Abbrev: abbrev,
Offset: int32(offs),
Type: Linklookup(ctxt, typename, 0),
}
dws := &vars.Link
for ; *dws != nil; dws = &(*dws).Link {
if offs <= (*dws).Offset {
break
}
}
dwvar.Link = *dws
*dws = dwvar
}
dwarf.PutFunc(dctxt, dsym, s.Name, s.Version == 0, s, s.Size, vars.Link)
}
return dw
}

217
vendor/github.com/google/gops/internal/obj/pass.go generated vendored Normal file
View File

@ -0,0 +1,217 @@
// Inferno utils/6l/pass.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/pass.c
//
// 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 obj
// Code and data passes.
func Brchain(ctxt *Link, p *Prog) *Prog {
for i := 0; i < 20; i++ {
if p == nil || p.As != AJMP || p.Pcond == nil {
return p
}
p = p.Pcond
}
return nil
}
func brloop(ctxt *Link, p *Prog) *Prog {
var q *Prog
c := 0
for q = p; q != nil; q = q.Pcond {
if q.As != AJMP || q.Pcond == nil {
break
}
c++
if c >= 5000 {
return nil
}
}
return q
}
func checkaddr(ctxt *Link, p *Prog, a *Addr) {
// Check expected encoding, especially TYPE_CONST vs TYPE_ADDR.
switch a.Type {
case TYPE_NONE:
return
case TYPE_BRANCH:
if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
break
}
return
case TYPE_TEXTSIZE:
if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
break
}
return
//if(a->u.bits != 0)
// break;
case TYPE_MEM:
return
// TODO(rsc): After fixing SHRQ, check a->index != 0 too.
case TYPE_CONST:
if a.Name != 0 || a.Sym != nil || a.Reg != 0 {
ctxt.Diag("argument is TYPE_CONST, should be TYPE_ADDR, in %v", p)
return
}
if a.Reg != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
break
}
return
case TYPE_FCONST, TYPE_SCONST:
if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Offset != 0 || a.Sym != nil {
break
}
return
// TODO(rsc): After fixing PINSRQ, check a->offset != 0 too.
// TODO(rsc): After fixing SHRQ, check a->index != 0 too.
case TYPE_REG:
if a.Scale != 0 || a.Name != 0 || a.Sym != nil {
break
}
return
case TYPE_ADDR:
if a.Val != nil {
break
}
if a.Reg == 0 && a.Index == 0 && a.Scale == 0 && a.Name == 0 && a.Sym == nil {
ctxt.Diag("argument is TYPE_ADDR, should be TYPE_CONST, in %v", p)
}
return
case TYPE_SHIFT:
if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
break
}
return
case TYPE_REGREG:
if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
break
}
return
case TYPE_REGREG2:
return
case TYPE_REGLIST:
return
// Expect sym and name to be set, nothing else.
// Technically more is allowed, but this is only used for *name(SB).
case TYPE_INDIR:
if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name == 0 || a.Offset != 0 || a.Sym == nil || a.Val != nil {
break
}
return
}
ctxt.Diag("invalid encoding for argument %v", p)
}
func linkpatch(ctxt *Link, sym *LSym) {
var c int32
var name string
var q *Prog
ctxt.Cursym = sym
for p := sym.Text; p != nil; p = p.Link {
checkaddr(ctxt, p, &p.From)
if p.From3 != nil {
checkaddr(ctxt, p, p.From3)
}
checkaddr(ctxt, p, &p.To)
if ctxt.Arch.Progedit != nil {
ctxt.Arch.Progedit(ctxt, p)
}
if p.To.Type != TYPE_BRANCH {
continue
}
if p.To.Val != nil {
// TODO: Remove To.Val.(*Prog) in favor of p->pcond.
p.Pcond = p.To.Val.(*Prog)
continue
}
if p.To.Sym != nil {
continue
}
c = int32(p.To.Offset)
for q = sym.Text; q != nil; {
if int64(c) == q.Pc {
break
}
if q.Forwd != nil && int64(c) >= q.Forwd.Pc {
q = q.Forwd
} else {
q = q.Link
}
}
if q == nil {
name = "<nil>"
if p.To.Sym != nil {
name = p.To.Sym.Name
}
ctxt.Diag("branch out of range (%#x)\n%v [%s]", uint32(c), p, name)
p.To.Type = TYPE_NONE
}
p.To.Val = q
p.Pcond = q
}
if ctxt.Flag_optimize {
for p := sym.Text; p != nil; p = p.Link {
if p.Pcond != nil {
p.Pcond = brloop(ctxt, p.Pcond)
if p.Pcond != nil {
if p.To.Type == TYPE_BRANCH {
p.To.Offset = p.Pcond.Pc
}
}
}
}
}
}

281
vendor/github.com/google/gops/internal/obj/pcln.go generated vendored Normal file
View File

@ -0,0 +1,281 @@
// 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 obj
import "log"
func addvarint(ctxt *Link, d *Pcdata, val uint32) {
var v uint32
for v = val; v >= 0x80; v >>= 7 {
d.P = append(d.P, uint8(v|0x80))
}
d.P = append(d.P, uint8(v))
}
// funcpctab writes to dst a pc-value table mapping the code in func to the values
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
// current value is, for each p,
//
// val = valfunc(func, val, p, 0, arg);
// record val as value at p->pc;
// val = valfunc(func, val, p, 1, arg);
//
// where func is the function, val is the current value, p is the instruction being
// considered, and arg can be used to further parameterize valfunc.
func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
// To debug a specific function, uncomment lines and change name.
dbg := 0
//if func_.Name == "main.main" || desc == "pctospadj" {
// dbg = 1
//}
ctxt.Debugpcln += int32(dbg)
dst.P = dst.P[:0]
if ctxt.Debugpcln != 0 {
ctxt.Logf("funcpctab %s [valfunc=%s]\n", func_.Name, desc)
}
val := int32(-1)
oldval := val
if func_.Text == nil {
ctxt.Debugpcln -= int32(dbg)
return
}
pc := func_.Text.Pc
if ctxt.Debugpcln != 0 {
ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Text)
}
started := int32(0)
var delta uint32
for p := func_.Text; p != nil; p = p.Link {
// Update val. If it's not changing, keep going.
val = valfunc(ctxt, func_, val, p, 0, arg)
if val == oldval && started != 0 {
val = valfunc(ctxt, func_, val, p, 1, arg)
if ctxt.Debugpcln != 0 {
ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
}
continue
}
// If the pc of the next instruction is the same as the
// pc of this instruction, this instruction is not a real
// instruction. Keep going, so that we only emit a delta
// for a true instruction boundary in the program.
if p.Link != nil && p.Link.Pc == p.Pc {
val = valfunc(ctxt, func_, val, p, 1, arg)
if ctxt.Debugpcln != 0 {
ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
}
continue
}
// The table is a sequence of (value, pc) pairs, where each
// pair states that the given value is in effect from the current position
// up to the given pc, which becomes the new current position.
// To generate the table as we scan over the program instructions,
// we emit a "(value" when pc == func->value, and then
// each time we observe a change in value we emit ", pc) (value".
// When the scan is over, we emit the closing ", pc)".
//
// The table is delta-encoded. The value deltas are signed and
// transmitted in zig-zag form, where a complement bit is placed in bit 0,
// and the pc deltas are unsigned. Both kinds of deltas are sent
// as variable-length little-endian base-128 integers,
// where the 0x80 bit indicates that the integer continues.
if ctxt.Debugpcln != 0 {
ctxt.Logf("%6x %6d %v\n", uint64(p.Pc), val, p)
}
if started != 0 {
addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.MinLC)))
pc = p.Pc
}
delta = uint32(val) - uint32(oldval)
if delta>>31 != 0 {
delta = 1 | ^(delta << 1)
} else {
delta <<= 1
}
addvarint(ctxt, dst, delta)
oldval = val
started = 1
val = valfunc(ctxt, func_, val, p, 1, arg)
}
if started != 0 {
if ctxt.Debugpcln != 0 {
ctxt.Logf("%6x done\n", uint64(func_.Text.Pc+func_.Size))
}
addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
addvarint(ctxt, dst, 0) // terminator
}
if ctxt.Debugpcln != 0 {
ctxt.Logf("wrote %d bytes to %p\n", len(dst.P), dst)
for i := 0; i < len(dst.P); i++ {
ctxt.Logf(" %02x", dst.P[i])
}
ctxt.Logf("\n")
}
ctxt.Debugpcln -= int32(dbg)
}
// pctofileline computes either the file number (arg == 0)
// or the line number (arg == 1) to use at p.
// Because p->lineno applies to p, phase == 0 (before p)
// takes care of the update.
func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
if p.As == ATEXT || p.As == ANOP || p.As == AUSEFIELD || p.Lineno == 0 || phase == 1 {
return oldval
}
f, l := linkgetline(ctxt, p.Lineno)
if f == nil {
// print("getline failed for %s %v\n", ctxt->cursym->name, p);
return oldval
}
if arg == nil {
return l
}
pcln := arg.(*Pcln)
if f == pcln.Lastfile {
return int32(pcln.Lastindex)
}
for i, file := range pcln.File {
if file == f {
pcln.Lastfile = f
pcln.Lastindex = i
return int32(i)
}
}
i := len(pcln.File)
pcln.File = append(pcln.File, f)
pcln.Lastfile = f
pcln.Lastindex = i
return int32(i)
}
// pctospadj computes the sp adjustment in effect.
// It is oldval plus any adjustment made by p itself.
// The adjustment by p takes effect only after p, so we
// apply the change during phase == 1.
func pctospadj(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
if oldval == -1 { // starting
oldval = 0
}
if phase == 0 {
return oldval
}
if oldval+p.Spadj < -10000 || oldval+p.Spadj > 1100000000 {
ctxt.Diag("overflow in spadj: %d + %d = %d", oldval, p.Spadj, oldval+p.Spadj)
log.Fatalf("bad code")
}
return oldval + p.Spadj
}
// pctopcdata computes the pcdata value in effect at p.
// A PCDATA instruction sets the value in effect at future
// non-PCDATA instructions.
// Since PCDATA instructions have no width in the final code,
// it does not matter which phase we use for the update.
func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
if phase == 0 || p.As != APCDATA || p.From.Offset != int64(arg.(uint32)) {
return oldval
}
if int64(int32(p.To.Offset)) != p.To.Offset {
ctxt.Diag("overflow in PCDATA instruction: %v", p)
log.Fatalf("bad code")
}
return int32(p.To.Offset)
}
func linkpcln(ctxt *Link, cursym *LSym) {
ctxt.Cursym = cursym
pcln := new(Pcln)
cursym.Pcln = pcln
npcdata := 0
nfuncdata := 0
for p := cursym.Text; p != nil; p = p.Link {
// Find the highest ID of any used PCDATA table. This ignores PCDATA table
// that consist entirely of "-1", since that's the assumed default value.
// From.Offset is table ID
// To.Offset is data
if p.As == APCDATA && p.From.Offset >= int64(npcdata) && p.To.Offset != -1 { // ignore -1 as we start at -1, if we only see -1, nothing changed
npcdata = int(p.From.Offset + 1)
}
// Find the highest ID of any FUNCDATA table.
// From.Offset is table ID
if p.As == AFUNCDATA && p.From.Offset >= int64(nfuncdata) {
nfuncdata = int(p.From.Offset + 1)
}
}
pcln.Pcdata = make([]Pcdata, npcdata)
pcln.Pcdata = pcln.Pcdata[:npcdata]
pcln.Funcdata = make([]*LSym, nfuncdata)
pcln.Funcdataoff = make([]int64, nfuncdata)
pcln.Funcdataoff = pcln.Funcdataoff[:nfuncdata]
funcpctab(ctxt, &pcln.Pcsp, cursym, "pctospadj", pctospadj, nil)
funcpctab(ctxt, &pcln.Pcfile, cursym, "pctofile", pctofileline, pcln)
funcpctab(ctxt, &pcln.Pcline, cursym, "pctoline", pctofileline, nil)
// tabulate which pc and func data we have.
havepc := make([]uint32, (npcdata+31)/32)
havefunc := make([]uint32, (nfuncdata+31)/32)
for p := cursym.Text; p != nil; p = p.Link {
if p.As == AFUNCDATA {
if (havefunc[p.From.Offset/32]>>uint64(p.From.Offset%32))&1 != 0 {
ctxt.Diag("multiple definitions for FUNCDATA $%d", p.From.Offset)
}
havefunc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
}
if p.As == APCDATA && p.To.Offset != -1 {
havepc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
}
}
// pcdata.
for i := 0; i < npcdata; i++ {
if (havepc[i/32]>>uint(i%32))&1 == 0 {
continue
}
funcpctab(ctxt, &pcln.Pcdata[i], cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
}
// funcdata
if nfuncdata > 0 {
var i int
for p := cursym.Text; p != nil; p = p.Link {
if p.As == AFUNCDATA {
i = int(p.From.Offset)
pcln.Funcdataoff[i] = p.To.Offset
if p.To.Type != TYPE_CONST {
// TODO: Dedup.
//funcdata_bytes += p->to.sym->size;
pcln.Funcdata[i] = p.To.Sym
}
}
}
}
}

208
vendor/github.com/google/gops/internal/obj/plist.go generated vendored Normal file
View File

@ -0,0 +1,208 @@
// 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 obj
import (
"fmt"
"log"
"strings"
)
type Plist struct {
Firstpc *Prog
}
/*
* start a new Prog list.
*/
func Linknewplist(ctxt *Link) *Plist {
pl := new(Plist)
ctxt.Plists = append(ctxt.Plists, pl)
return pl
}
func Flushplist(ctxt *Link) {
flushplist(ctxt, ctxt.Debugasm == 0)
}
func FlushplistNoFree(ctxt *Link) {
flushplist(ctxt, false)
}
func flushplist(ctxt *Link, freeProgs bool) {
// Build list of symbols, and assign instructions to lists.
// Ignore ctxt->plist boundaries. There are no guarantees there,
// and the assemblers just use one big list.
var curtext *LSym
var etext *Prog
var text []*LSym
for _, pl := range ctxt.Plists {
var plink *Prog
for p := pl.Firstpc; p != nil; p = plink {
if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
fmt.Printf("obj: %v\n", p)
}
plink = p.Link
p.Link = nil
switch p.As {
case AEND:
continue
case ATYPE:
// Assume each TYPE instruction describes
// a different local variable or parameter,
// so no dedup.
// Using only the TYPE instructions means
// that we discard location information about local variables
// in C and assembly functions; that information is inferred
// from ordinary references, because there are no TYPE
// instructions there. Without the type information, gdb can't
// use the locations, so we don't bother to save them.
// If something else could use them, we could arrange to
// preserve them.
if curtext == nil {
continue
}
a := new(Auto)
a.Asym = p.From.Sym
a.Aoffset = int32(p.From.Offset)
a.Name = int16(p.From.Name)
a.Gotype = p.To.Sym
a.Link = curtext.Autom
curtext.Autom = a
continue
case ATEXT:
s := p.From.Sym
if s == nil {
// func _() { }
curtext = nil
continue
}
if s.Text != nil {
log.Fatalf("duplicate TEXT for %s", s.Name)
}
if s.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Set(AttrOnList, true)
text = append(text, s)
flag := int(p.From3Offset())
if flag&DUPOK != 0 {
s.Set(AttrDuplicateOK, true)
}
if flag&NOSPLIT != 0 {
s.Set(AttrNoSplit, true)
}
if flag&REFLECTMETHOD != 0 {
s.Set(AttrReflectMethod, true)
}
s.Type = STEXT
s.Text = p
etext = p
curtext = s
continue
case AFUNCDATA:
// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
if curtext == nil { // func _() {}
continue
}
if p.To.Sym.Name == "go_args_stackmap" {
if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps {
ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
}
p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version))
}
}
if curtext == nil {
etext = nil
continue
}
etext.Link = p
etext = p
}
}
// Add reference to Go arguments for C or assembly functions without them.
for _, s := range text {
if !strings.HasPrefix(s.Name, "\"\".") {
continue
}
found := false
var p *Prog
for p = s.Text; p != nil; p = p.Link {
if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
found = true
break
}
}
if !found {
p = Appendp(ctxt, s.Text)
p.As = AFUNCDATA
p.From.Type = TYPE_CONST
p.From.Offset = FUNCDATA_ArgsPointerMaps
p.To.Type = TYPE_MEM
p.To.Name = NAME_EXTERN
p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version))
}
}
// Turn functions into machine code images.
for _, s := range text {
mkfwd(s)
linkpatch(ctxt, s)
if ctxt.Flag_optimize {
ctxt.Arch.Follow(ctxt, s)
}
ctxt.Arch.Preprocess(ctxt, s)
ctxt.Arch.Assemble(ctxt, s)
fieldtrack(ctxt, s)
linkpcln(ctxt, s)
if freeProgs {
s.Text = nil
}
}
// Add to running list in ctxt.
ctxt.Text = append(ctxt.Text, text...)
ctxt.Data = append(ctxt.Data, gendwarf(ctxt, text)...)
ctxt.Plists = nil
ctxt.Curp = nil
if freeProgs {
ctxt.freeProgs()
}
}
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
if s.SeenGlobl() {
fmt.Printf("duplicate %v\n", s)
}
s.Set(AttrSeenGlobl, true)
if s.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Set(AttrOnList, true)
ctxt.Data = append(ctxt.Data, s)
s.Size = size
if s.Type == 0 || s.Type == SXREF {
s.Type = SBSS
}
if flag&DUPOK != 0 {
s.Set(AttrDuplicateOK, true)
}
if flag&RODATA != 0 {
s.Type = SRODATA
} else if flag&NOPTR != 0 {
s.Type = SNOPTRBSS
} else if flag&TLSBSS != 0 {
s.Type = STLSBSS
}
}

View File

@ -0,0 +1,941 @@
// cmd/9c/9.out.h from Vita Nuova.
//
// 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-2008 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-2008 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 ppc64
import "github.com/google/gops/internal/obj"
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p ppc64
/*
* powerpc 64
*/
const (
NSNAME = 8
NSYM = 50
NREG = 32 /* number of general registers */
NFREG = 32 /* number of floating point registers */
)
const (
/* RBasePPC64 = 4096 */
/* R0=4096 ... R31=4127 */
REG_R0 = obj.RBasePPC64 + iota
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
REG_R16
REG_R17
REG_R18
REG_R19
REG_R20
REG_R21
REG_R22
REG_R23
REG_R24
REG_R25
REG_R26
REG_R27
REG_R28
REG_R29
REG_R30
REG_R31
/* F0=4128 ... F31=4159 */
REG_F0
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
REG_F16
REG_F17
REG_F18
REG_F19
REG_F20
REG_F21
REG_F22
REG_F23
REG_F24
REG_F25
REG_F26
REG_F27
REG_F28
REG_F29
REG_F30
REG_F31
/* V0=4160 ... V31=4191 */
REG_V0
REG_V1
REG_V2
REG_V3
REG_V4
REG_V5
REG_V6
REG_V7
REG_V8
REG_V9
REG_V10
REG_V11
REG_V12
REG_V13
REG_V14
REG_V15
REG_V16
REG_V17
REG_V18
REG_V19
REG_V20
REG_V21
REG_V22
REG_V23
REG_V24
REG_V25
REG_V26
REG_V27
REG_V28
REG_V29
REG_V30
REG_V31
/* VS0=4192 ... VS63=4255 */
REG_VS0
REG_VS1
REG_VS2
REG_VS3
REG_VS4
REG_VS5
REG_VS6
REG_VS7
REG_VS8
REG_VS9
REG_VS10
REG_VS11
REG_VS12
REG_VS13
REG_VS14
REG_VS15
REG_VS16
REG_VS17
REG_VS18
REG_VS19
REG_VS20
REG_VS21
REG_VS22
REG_VS23
REG_VS24
REG_VS25
REG_VS26
REG_VS27
REG_VS28
REG_VS29
REG_VS30
REG_VS31
REG_VS32
REG_VS33
REG_VS34
REG_VS35
REG_VS36
REG_VS37
REG_VS38
REG_VS39
REG_VS40
REG_VS41
REG_VS42
REG_VS43
REG_VS44
REG_VS45
REG_VS46
REG_VS47
REG_VS48
REG_VS49
REG_VS50
REG_VS51
REG_VS52
REG_VS53
REG_VS54
REG_VS55
REG_VS56
REG_VS57
REG_VS58
REG_VS59
REG_VS60
REG_VS61
REG_VS62
REG_VS63
REG_CR0
REG_CR1
REG_CR2
REG_CR3
REG_CR4
REG_CR5
REG_CR6
REG_CR7
REG_MSR
REG_FPSCR
REG_CR
REG_SPECIAL = REG_CR0
REG_SPR0 = obj.RBasePPC64 + 1024 // first of 1024 registers
REG_DCR0 = obj.RBasePPC64 + 2048 // first of 1024 registers
REG_XER = REG_SPR0 + 1
REG_LR = REG_SPR0 + 8
REG_CTR = REG_SPR0 + 9
REGZERO = REG_R0 /* set to zero */
REGSP = REG_R1
REGSB = REG_R2
REGRET = REG_R3
REGARG = -1 /* -1 disables passing the first argument in register */
REGRT1 = REG_R3 /* reserved for runtime, duffzero and duffcopy */
REGRT2 = REG_R4 /* reserved for runtime, duffcopy */
REGMIN = REG_R7 /* register variables allocated from here to REGMAX */
REGCTXT = REG_R11 /* context for closures */
REGTLS = REG_R13 /* C ABI TLS base pointer */
REGMAX = REG_R27
REGEXT = REG_R30 /* external registers allocated from here down */
REGG = REG_R30 /* G */
REGTMP = REG_R31 /* used by the linker */
FREGRET = REG_F0
FREGMIN = REG_F17 /* first register variable */
FREGMAX = REG_F26 /* last register variable for 9g only */
FREGEXT = REG_F26 /* first external register */
)
/*
* GENERAL:
*
* compiler allocates R3 up as temps
* compiler allocates register variables R7-R27
* compiler allocates external registers R30 down
*
* compiler allocates register variables F17-F26
* compiler allocates external registers F26 down
*/
const (
BIG = 32768 - 8
)
const (
/* mark flags */
LABEL = 1 << 0
LEAF = 1 << 1
FLOAT = 1 << 2
BRANCH = 1 << 3
LOAD = 1 << 4
FCMP = 1 << 5
SYNC = 1 << 6
LIST = 1 << 7
FOLL = 1 << 8
NOSCHED = 1 << 9
)
// Values for use in branch instruction BC
// BC B0,BI,label
// BO is type of branch + likely bits described below
// BI is CR value + branch type
// ex: BEQ CR2,label is BC 12,10,label
// 12 = BO_BCR
// 10 = BI_CR2 + BI_EQ
const (
BI_CR0 = 0
BI_CR1 = 4
BI_CR2 = 8
BI_CR3 = 12
BI_CR4 = 16
BI_CR5 = 20
BI_CR6 = 24
BI_CR7 = 28
BI_LT = 0
BI_GT = 1
BI_EQ = 2
BI_OVF = 3
)
// Values for the BO field. Add the branch type to
// the likely bits, if a likely setting is known.
// If branch likely or unlikely is not known, don't set it.
// e.g. branch on cr+likely = 15
const (
BO_BCTR = 16 // branch on ctr value
BO_BCR = 12 // branch on cr value
BO_BCRBCTR = 8 // branch on ctr and cr value
BO_NOTBCR = 4 // branch on not cr value
BO_UNLIKELY = 2 // value for unlikely
BO_LIKELY = 3 // value for likely
)
// Bit settings from the CR
const (
C_COND_LT = iota // 0 result is negative
C_COND_GT // 1 result is positive
C_COND_EQ // 2 result is zero
C_COND_SO // 3 summary overflow or FP compare w/ NaN
)
const (
C_NONE = iota
C_REG
C_FREG
C_VREG
C_VSREG
C_CREG
C_SPR /* special processor register */
C_ZCON
C_SCON /* 16 bit signed */
C_UCON /* 32 bit signed, low 16 bits 0 */
C_ADDCON /* -0x8000 <= v < 0 */
C_ANDCON /* 0 < v <= 0xFFFF */
C_LCON /* other 32 */
C_DCON /* other 64 (could subdivide further) */
C_SACON /* $n(REG) where n <= int16 */
C_SECON
C_LACON /* $n(REG) where int16 < n <= int32 */
C_LECON
C_DACON /* $n(REG) where int32 < n */
C_SBRA
C_LBRA
C_LBRAPIC
C_SAUTO
C_LAUTO
C_SEXT
C_LEXT
C_ZOREG // conjecture: either (1) register + zeroed offset, or (2) "R0" implies zero or C_REG
C_SOREG // register + signed offset
C_LOREG
C_FPSCR
C_MSR
C_XER
C_LR
C_CTR
C_ANY
C_GOK
C_ADDR
C_GOTADDR
C_TLS_LE
C_TLS_IE
C_TEXTSIZE
C_NCLASS /* must be the last */
)
const (
AADD = obj.ABasePPC64 + obj.A_ARCHSPECIFIC + iota
AADDCC
AADDV
AADDVCC
AADDC
AADDCCC
AADDCV
AADDCVCC
AADDME
AADDMECC
AADDMEVCC
AADDMEV
AADDE
AADDECC
AADDEVCC
AADDEV
AADDZE
AADDZECC
AADDZEVCC
AADDZEV
AAND
AANDCC
AANDN
AANDNCC
ABC
ABCL
ABEQ
ABGE // not LT = G/E/U
ABGT
ABLE // not GT = L/E/U
ABLT
ABNE // not EQ = L/G/U
ABVC // Unordered-clear
ABVS // Unordered-set
ACMP
ACMPU
ACNTLZW
ACNTLZWCC
ACRAND
ACRANDN
ACREQV
ACRNAND
ACRNOR
ACROR
ACRORN
ACRXOR
ADIVW
ADIVWCC
ADIVWVCC
ADIVWV
ADIVWU
ADIVWUCC
ADIVWUVCC
ADIVWUV
AEQV
AEQVCC
AEXTSB
AEXTSBCC
AEXTSH
AEXTSHCC
AFABS
AFABSCC
AFADD
AFADDCC
AFADDS
AFADDSCC
AFCMPO
AFCMPU
AFCTIW
AFCTIWCC
AFCTIWZ
AFCTIWZCC
AFDIV
AFDIVCC
AFDIVS
AFDIVSCC
AFMADD
AFMADDCC
AFMADDS
AFMADDSCC
AFMOVD
AFMOVDCC
AFMOVDU
AFMOVS
AFMOVSU
AFMOVSX
AFMOVSZ
AFMSUB
AFMSUBCC
AFMSUBS
AFMSUBSCC
AFMUL
AFMULCC
AFMULS
AFMULSCC
AFNABS
AFNABSCC
AFNEG
AFNEGCC
AFNMADD
AFNMADDCC
AFNMADDS
AFNMADDSCC
AFNMSUB
AFNMSUBCC
AFNMSUBS
AFNMSUBSCC
AFRSP
AFRSPCC
AFSUB
AFSUBCC
AFSUBS
AFSUBSCC
AISEL
AMOVMW
ALBAR
ALSW
ALWAR
ALWSYNC
AMOVDBR
AMOVWBR
AMOVB
AMOVBU
AMOVBZ
AMOVBZU
AMOVH
AMOVHBR
AMOVHU
AMOVHZ
AMOVHZU
AMOVW
AMOVWU
AMOVFL
AMOVCRFS
AMTFSB0
AMTFSB0CC
AMTFSB1
AMTFSB1CC
AMULHW
AMULHWCC
AMULHWU
AMULHWUCC
AMULLW
AMULLWCC
AMULLWVCC
AMULLWV
ANAND
ANANDCC
ANEG
ANEGCC
ANEGVCC
ANEGV
ANOR
ANORCC
AOR
AORCC
AORN
AORNCC
AREM
AREMCC
AREMV
AREMVCC
AREMU
AREMUCC
AREMUV
AREMUVCC
ARFI
ARLWMI
ARLWMICC
ARLWNM
ARLWNMCC
ASLW
ASLWCC
ASRW
ASRAW
ASRAWCC
ASRWCC
ASTBCCC
ASTSW
ASTWCCC
ASUB
ASUBCC
ASUBVCC
ASUBC
ASUBCCC
ASUBCV
ASUBCVCC
ASUBME
ASUBMECC
ASUBMEVCC
ASUBMEV
ASUBV
ASUBE
ASUBECC
ASUBEV
ASUBEVCC
ASUBZE
ASUBZECC
ASUBZEVCC
ASUBZEV
ASYNC
AXOR
AXORCC
ADCBF
ADCBI
ADCBST
ADCBT
ADCBTST
ADCBZ
AECIWX
AECOWX
AEIEIO
AICBI
AISYNC
APTESYNC
ATLBIE
ATLBIEL
ATLBSYNC
ATW
ASYSCALL
AWORD
ARFCI
/* optional on 32-bit */
AFRES
AFRESCC
AFRIM
AFRIMCC
AFRIP
AFRIPCC
AFRIZ
AFRIZCC
AFRSQRTE
AFRSQRTECC
AFSEL
AFSELCC
AFSQRT
AFSQRTCC
AFSQRTS
AFSQRTSCC
/* 64-bit */
ACNTLZD
ACNTLZDCC
ACMPW /* CMP with L=0 */
ACMPWU
ADIVD
ADIVDCC
ADIVDE
ADIVDECC
ADIVDEU
ADIVDEUCC
ADIVDVCC
ADIVDV
ADIVDU
ADIVDUCC
ADIVDUVCC
ADIVDUV
AEXTSW
AEXTSWCC
/* AFCFIW; AFCFIWCC */
AFCFID
AFCFIDCC
AFCFIDU
AFCFIDUCC
AFCTID
AFCTIDCC
AFCTIDZ
AFCTIDZCC
ALDAR
AMOVD
AMOVDU
AMOVWZ
AMOVWZU
AMULHD
AMULHDCC
AMULHDU
AMULHDUCC
AMULLD
AMULLDCC
AMULLDVCC
AMULLDV
ARFID
ARLDMI
ARLDMICC
ARLDIMI
ARLDIMICC
ARLDC
ARLDCCC
ARLDCR
ARLDCRCC
ARLDICR
ARLDICRCC
ARLDCL
ARLDCLCC
ARLDICL
ARLDICLCC
ASLBIA
ASLBIE
ASLBMFEE
ASLBMFEV
ASLBMTE
ASLD
ASLDCC
ASRD
ASRAD
ASRADCC
ASRDCC
ASTDCCC
ATD
/* 64-bit pseudo operation */
ADWORD
AREMD
AREMDCC
AREMDV
AREMDVCC
AREMDU
AREMDUCC
AREMDUV
AREMDUVCC
/* more 64-bit operations */
AHRFID
/* Vector */
ALV
ALVEBX
ALVEHX
ALVEWX
ALVX
ALVXL
ALVSL
ALVSR
ASTV
ASTVEBX
ASTVEHX
ASTVEWX
ASTVX
ASTVXL
AVAND
AVANDL
AVANDC
AVNAND
AVOR
AVORL
AVORC
AVNOR
AVXOR
AVEQV
AVADDUM
AVADDUBM
AVADDUHM
AVADDUWM
AVADDUDM
AVADDUQM
AVADDCU
AVADDCUQ
AVADDCUW
AVADDUS
AVADDUBS
AVADDUHS
AVADDUWS
AVADDSS
AVADDSBS
AVADDSHS
AVADDSWS
AVADDE
AVADDEUQM
AVADDECUQ
AVSUBUM
AVSUBUBM
AVSUBUHM
AVSUBUWM
AVSUBUDM
AVSUBUQM
AVSUBCU
AVSUBCUQ
AVSUBCUW
AVSUBUS
AVSUBUBS
AVSUBUHS
AVSUBUWS
AVSUBSS
AVSUBSBS
AVSUBSHS
AVSUBSWS
AVSUBE
AVSUBEUQM
AVSUBECUQ
AVR
AVRLB
AVRLH
AVRLW
AVRLD
AVS
AVSLB
AVSLH
AVSLW
AVSL
AVSLO
AVSRB
AVSRH
AVSRW
AVSR
AVSRO
AVSLD
AVSRD
AVSA
AVSRAB
AVSRAH
AVSRAW
AVSRAD
AVSOI
AVSLDOI
AVCLZ
AVCLZB
AVCLZH
AVCLZW
AVCLZD
AVPOPCNT
AVPOPCNTB
AVPOPCNTH
AVPOPCNTW
AVPOPCNTD
AVCMPEQ
AVCMPEQUB
AVCMPEQUBCC
AVCMPEQUH
AVCMPEQUHCC
AVCMPEQUW
AVCMPEQUWCC
AVCMPEQUD
AVCMPEQUDCC
AVCMPGT
AVCMPGTUB
AVCMPGTUBCC
AVCMPGTUH
AVCMPGTUHCC
AVCMPGTUW
AVCMPGTUWCC
AVCMPGTUD
AVCMPGTUDCC
AVCMPGTSB
AVCMPGTSBCC
AVCMPGTSH
AVCMPGTSHCC
AVCMPGTSW
AVCMPGTSWCC
AVCMPGTSD
AVCMPGTSDCC
AVPERM
AVSEL
AVSPLT
AVSPLTB
AVSPLTH
AVSPLTW
AVSPLTI
AVSPLTISB
AVSPLTISH
AVSPLTISW
AVCIPH
AVCIPHER
AVCIPHERLAST
AVNCIPH
AVNCIPHER
AVNCIPHERLAST
AVSBOX
AVSHASIGMA
AVSHASIGMAW
AVSHASIGMAD
/* VSX */
ALXV
ALXVD2X
ALXVDSX
ALXVW4X
ASTXV
ASTXVD2X
ASTXVW4X
ALXS
ALXSDX
ASTXS
ASTXSDX
ALXSI
ALXSIWAX
ALXSIWZX
ASTXSI
ASTXSIWX
AMFVSR
AMFVSRD
AMFVSRWZ
AMTVSR
AMTVSRD
AMTVSRWA
AMTVSRWZ
AXXLAND
AXXLANDQ
AXXLANDC
AXXLEQV
AXXLNAND
AXXLOR
AXXLORC
AXXLNOR
AXXLORQ
AXXLXOR
AXXSEL
AXXMRG
AXXMRGHW
AXXMRGLW
AXXSPLT
AXXSPLTW
AXXPERM
AXXPERMDI
AXXSI
AXXSLDWI
AXSCV
AXSCVDPSP
AXSCVSPDP
AXSCVDPSPN
AXSCVSPDPN
AXVCV
AXVCVDPSP
AXVCVSPDP
AXSCVX
AXSCVDPSXDS
AXSCVDPSXWS
AXSCVDPUXDS
AXSCVDPUXWS
AXSCVXP
AXSCVSXDDP
AXSCVUXDDP
AXSCVSXDSP
AXSCVUXDSP
AXVCVX
AXVCVDPSXDS
AXVCVDPSXWS
AXVCVDPUXDS
AXVCVDPUXWS
AXVCVSPSXDS
AXVCVSPSXWS
AXVCVSPUXDS
AXVCVSPUXWS
AXVCVXP
AXVCVSXDDP
AXVCVSXWDP
AXVCVUXDDP
AXVCVUXWDP
AXVCVSXDSP
AXVCVSXWSP
AXVCVUXDSP
AXVCVUXWSP
ALAST
// aliases
ABR = obj.AJMP
ABL = obj.ACALL
)

View File

@ -0,0 +1,549 @@
// Generated by stringer -i a.out.go -o anames.go -p ppc64
// Do not edit.
package ppc64
import "github.com/google/gops/internal/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADD",
"ADDCC",
"ADDV",
"ADDVCC",
"ADDC",
"ADDCCC",
"ADDCV",
"ADDCVCC",
"ADDME",
"ADDMECC",
"ADDMEVCC",
"ADDMEV",
"ADDE",
"ADDECC",
"ADDEVCC",
"ADDEV",
"ADDZE",
"ADDZECC",
"ADDZEVCC",
"ADDZEV",
"AND",
"ANDCC",
"ANDN",
"ANDNCC",
"BC",
"BCL",
"BEQ",
"BGE",
"BGT",
"BLE",
"BLT",
"BNE",
"BVC",
"BVS",
"CMP",
"CMPU",
"CNTLZW",
"CNTLZWCC",
"CRAND",
"CRANDN",
"CREQV",
"CRNAND",
"CRNOR",
"CROR",
"CRORN",
"CRXOR",
"DIVW",
"DIVWCC",
"DIVWVCC",
"DIVWV",
"DIVWU",
"DIVWUCC",
"DIVWUVCC",
"DIVWUV",
"EQV",
"EQVCC",
"EXTSB",
"EXTSBCC",
"EXTSH",
"EXTSHCC",
"FABS",
"FABSCC",
"FADD",
"FADDCC",
"FADDS",
"FADDSCC",
"FCMPO",
"FCMPU",
"FCTIW",
"FCTIWCC",
"FCTIWZ",
"FCTIWZCC",
"FDIV",
"FDIVCC",
"FDIVS",
"FDIVSCC",
"FMADD",
"FMADDCC",
"FMADDS",
"FMADDSCC",
"FMOVD",
"FMOVDCC",
"FMOVDU",
"FMOVS",
"FMOVSU",
"FMOVSX",
"FMOVSZ",
"FMSUB",
"FMSUBCC",
"FMSUBS",
"FMSUBSCC",
"FMUL",
"FMULCC",
"FMULS",
"FMULSCC",
"FNABS",
"FNABSCC",
"FNEG",
"FNEGCC",
"FNMADD",
"FNMADDCC",
"FNMADDS",
"FNMADDSCC",
"FNMSUB",
"FNMSUBCC",
"FNMSUBS",
"FNMSUBSCC",
"FRSP",
"FRSPCC",
"FSUB",
"FSUBCC",
"FSUBS",
"FSUBSCC",
"ISEL",
"MOVMW",
"LBAR",
"LSW",
"LWAR",
"LWSYNC",
"MOVDBR",
"MOVWBR",
"MOVB",
"MOVBU",
"MOVBZ",
"MOVBZU",
"MOVH",
"MOVHBR",
"MOVHU",
"MOVHZ",
"MOVHZU",
"MOVW",
"MOVWU",
"MOVFL",
"MOVCRFS",
"MTFSB0",
"MTFSB0CC",
"MTFSB1",
"MTFSB1CC",
"MULHW",
"MULHWCC",
"MULHWU",
"MULHWUCC",
"MULLW",
"MULLWCC",
"MULLWVCC",
"MULLWV",
"NAND",
"NANDCC",
"NEG",
"NEGCC",
"NEGVCC",
"NEGV",
"NOR",
"NORCC",
"OR",
"ORCC",
"ORN",
"ORNCC",
"REM",
"REMCC",
"REMV",
"REMVCC",
"REMU",
"REMUCC",
"REMUV",
"REMUVCC",
"RFI",
"RLWMI",
"RLWMICC",
"RLWNM",
"RLWNMCC",
"SLW",
"SLWCC",
"SRW",
"SRAW",
"SRAWCC",
"SRWCC",
"STBCCC",
"STSW",
"STWCCC",
"SUB",
"SUBCC",
"SUBVCC",
"SUBC",
"SUBCCC",
"SUBCV",
"SUBCVCC",
"SUBME",
"SUBMECC",
"SUBMEVCC",
"SUBMEV",
"SUBV",
"SUBE",
"SUBECC",
"SUBEV",
"SUBEVCC",
"SUBZE",
"SUBZECC",
"SUBZEVCC",
"SUBZEV",
"SYNC",
"XOR",
"XORCC",
"DCBF",
"DCBI",
"DCBST",
"DCBT",
"DCBTST",
"DCBZ",
"ECIWX",
"ECOWX",
"EIEIO",
"ICBI",
"ISYNC",
"PTESYNC",
"TLBIE",
"TLBIEL",
"TLBSYNC",
"TW",
"SYSCALL",
"WORD",
"RFCI",
"FRES",
"FRESCC",
"FRIM",
"FRIMCC",
"FRIP",
"FRIPCC",
"FRIZ",
"FRIZCC",
"FRSQRTE",
"FRSQRTECC",
"FSEL",
"FSELCC",
"FSQRT",
"FSQRTCC",
"FSQRTS",
"FSQRTSCC",
"CNTLZD",
"CNTLZDCC",
"CMPW",
"CMPWU",
"DIVD",
"DIVDCC",
"DIVDE",
"DIVDECC",
"DIVDEU",
"DIVDEUCC",
"DIVDVCC",
"DIVDV",
"DIVDU",
"DIVDUCC",
"DIVDUVCC",
"DIVDUV",
"EXTSW",
"EXTSWCC",
"FCFID",
"FCFIDCC",
"FCFIDU",
"FCFIDUCC",
"FCTID",
"FCTIDCC",
"FCTIDZ",
"FCTIDZCC",
"LDAR",
"MOVD",
"MOVDU",
"MOVWZ",
"MOVWZU",
"MULHD",
"MULHDCC",
"MULHDU",
"MULHDUCC",
"MULLD",
"MULLDCC",
"MULLDVCC",
"MULLDV",
"RFID",
"RLDMI",
"RLDMICC",
"RLDIMI",
"RLDIMICC",
"RLDC",
"RLDCCC",
"RLDCR",
"RLDCRCC",
"RLDICR",
"RLDICRCC",
"RLDCL",
"RLDCLCC",
"RLDICL",
"RLDICLCC",
"SLBIA",
"SLBIE",
"SLBMFEE",
"SLBMFEV",
"SLBMTE",
"SLD",
"SLDCC",
"SRD",
"SRAD",
"SRADCC",
"SRDCC",
"STDCCC",
"TD",
"DWORD",
"REMD",
"REMDCC",
"REMDV",
"REMDVCC",
"REMDU",
"REMDUCC",
"REMDUV",
"REMDUVCC",
"HRFID",
"LV",
"LVEBX",
"LVEHX",
"LVEWX",
"LVX",
"LVXL",
"LVSL",
"LVSR",
"STV",
"STVEBX",
"STVEHX",
"STVEWX",
"STVX",
"STVXL",
"VAND",
"VANDL",
"VANDC",
"VNAND",
"VOR",
"VORL",
"VORC",
"VNOR",
"VXOR",
"VEQV",
"VADDUM",
"VADDUBM",
"VADDUHM",
"VADDUWM",
"VADDUDM",
"VADDUQM",
"VADDCU",
"VADDCUQ",
"VADDCUW",
"VADDUS",
"VADDUBS",
"VADDUHS",
"VADDUWS",
"VADDSS",
"VADDSBS",
"VADDSHS",
"VADDSWS",
"VADDE",
"VADDEUQM",
"VADDECUQ",
"VSUBUM",
"VSUBUBM",
"VSUBUHM",
"VSUBUWM",
"VSUBUDM",
"VSUBUQM",
"VSUBCU",
"VSUBCUQ",
"VSUBCUW",
"VSUBUS",
"VSUBUBS",
"VSUBUHS",
"VSUBUWS",
"VSUBSS",
"VSUBSBS",
"VSUBSHS",
"VSUBSWS",
"VSUBE",
"VSUBEUQM",
"VSUBECUQ",
"VR",
"VRLB",
"VRLH",
"VRLW",
"VRLD",
"VS",
"VSLB",
"VSLH",
"VSLW",
"VSL",
"VSLO",
"VSRB",
"VSRH",
"VSRW",
"VSR",
"VSRO",
"VSLD",
"VSRD",
"VSA",
"VSRAB",
"VSRAH",
"VSRAW",
"VSRAD",
"VSOI",
"VSLDOI",
"VCLZ",
"VCLZB",
"VCLZH",
"VCLZW",
"VCLZD",
"VPOPCNT",
"VPOPCNTB",
"VPOPCNTH",
"VPOPCNTW",
"VPOPCNTD",
"VCMPEQ",
"VCMPEQUB",
"VCMPEQUBCC",
"VCMPEQUH",
"VCMPEQUHCC",
"VCMPEQUW",
"VCMPEQUWCC",
"VCMPEQUD",
"VCMPEQUDCC",
"VCMPGT",
"VCMPGTUB",
"VCMPGTUBCC",
"VCMPGTUH",
"VCMPGTUHCC",
"VCMPGTUW",
"VCMPGTUWCC",
"VCMPGTUD",
"VCMPGTUDCC",
"VCMPGTSB",
"VCMPGTSBCC",
"VCMPGTSH",
"VCMPGTSHCC",
"VCMPGTSW",
"VCMPGTSWCC",
"VCMPGTSD",
"VCMPGTSDCC",
"VPERM",
"VSEL",
"VSPLT",
"VSPLTB",
"VSPLTH",
"VSPLTW",
"VSPLTI",
"VSPLTISB",
"VSPLTISH",
"VSPLTISW",
"VCIPH",
"VCIPHER",
"VCIPHERLAST",
"VNCIPH",
"VNCIPHER",
"VNCIPHERLAST",
"VSBOX",
"VSHASIGMA",
"VSHASIGMAW",
"VSHASIGMAD",
"LXV",
"LXVD2X",
"LXVDSX",
"LXVW4X",
"STXV",
"STXVD2X",
"STXVW4X",
"LXS",
"LXSDX",
"STXS",
"STXSDX",
"LXSI",
"LXSIWAX",
"LXSIWZX",
"STXSI",
"STXSIWX",
"MFVSR",
"MFVSRD",
"MFVSRWZ",
"MTVSR",
"MTVSRD",
"MTVSRWA",
"MTVSRWZ",
"XXLAND",
"XXLANDQ",
"XXLANDC",
"XXLEQV",
"XXLNAND",
"XXLOR",
"XXLORC",
"XXLNOR",
"XXLORQ",
"XXLXOR",
"XXSEL",
"XXMRG",
"XXMRGHW",
"XXMRGLW",
"XXSPLT",
"XXSPLTW",
"XXPERM",
"XXPERMDI",
"XXSI",
"XXSLDWI",
"XSCV",
"XSCVDPSP",
"XSCVSPDP",
"XSCVDPSPN",
"XSCVSPDPN",
"XVCV",
"XVCVDPSP",
"XVCVSPDP",
"XSCVX",
"XSCVDPSXDS",
"XSCVDPSXWS",
"XSCVDPUXDS",
"XSCVDPUXWS",
"XSCVXP",
"XSCVSXDDP",
"XSCVUXDDP",
"XSCVSXDSP",
"XSCVUXDSP",
"XVCVX",
"XVCVDPSXDS",
"XVCVDPSXWS",
"XVCVDPUXDS",
"XVCVDPUXWS",
"XVCVSPSXDS",
"XVCVSPSXWS",
"XVCVSPUXDS",
"XVCVSPUXWS",
"XVCVXP",
"XVCVSXDDP",
"XVCVSXWDP",
"XVCVUXDDP",
"XVCVUXWDP",
"XVCVSXDSP",
"XVCVSXWSP",
"XVCVUXDSP",
"XVCVUXWSP",
"LAST",
}

View File

@ -0,0 +1,49 @@
// 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 ppc64
var cnames9 = []string{
"NONE",
"REG",
"FREG",
"VREG",
"VSREG",
"CREG",
"SPR",
"ZCON",
"SCON",
"UCON",
"ADDCON",
"ANDCON",
"LCON",
"DCON",
"SACON",
"SECON",
"LACON",
"LECON",
"DACON",
"SBRA",
"LBRA",
"SAUTO",
"LAUTO",
"SEXT",
"LEXT",
"ZOREG",
"SOREG",
"LOREG",
"FPSCR",
"MSR",
"XER",
"LR",
"CTR",
"ANY",
"GOK",
"ADDR",
"GOTADDR",
"TLS_LE",
"TLS_IE",
"TEXTSIZE",
"NCLASS",
}

4552
vendor/github.com/google/gops/internal/obj/ppc64/asm9.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
// cmd/9l/list.c from Vita Nuova.
//
// 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-2008 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-2008 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 ppc64
import (
"fmt"
"github.com/google/gops/internal/obj"
)
func init() {
obj.RegisterRegister(obj.RBasePPC64, REG_DCR0+1024, Rconv)
obj.RegisterOpcode(obj.ABasePPC64, Anames)
}
func Rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if REG_R0 <= r && r <= REG_R31 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F31 {
return fmt.Sprintf("F%d", r-REG_F0)
}
if REG_V0 <= r && r <= REG_V31 {
return fmt.Sprintf("V%d", r-REG_V0)
}
if REG_VS0 <= r && r <= REG_VS63 {
return fmt.Sprintf("VS%d", r-REG_VS0)
}
if REG_CR0 <= r && r <= REG_CR7 {
return fmt.Sprintf("CR%d", r-REG_CR0)
}
if r == REG_CR {
return "CR"
}
if REG_SPR0 <= r && r <= REG_SPR0+1023 {
switch r {
case REG_XER:
return "XER"
case REG_LR:
return "LR"
case REG_CTR:
return "CTR"
}
return fmt.Sprintf("SPR(%d)", r-REG_SPR0)
}
if REG_DCR0 <= r && r <= REG_DCR0+1023 {
return fmt.Sprintf("DCR(%d)", r-REG_DCR0)
}
if r == REG_FPSCR {
return "FPSCR"
}
if r == REG_MSR {
return "MSR"
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBasePPC64)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnames9[a]
}
var fp string
fp += s
return fp
}

1251
vendor/github.com/google/gops/internal/obj/ppc64/obj9.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
// Code generated by "stringer -type=RelocType"; DO NOT EDIT
package obj
import "fmt"
const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLS"
var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 195, 206, 216, 225, 235, 249, 263, 279, 293, 307, 318, 332, 347, 364, 382, 403, 413, 424, 437}
func (i RelocType) String() string {
i -= 1
if i < 0 || i >= RelocType(len(_RelocType_index)-1) {
return fmt.Sprintf("RelocType(%d)", i+1)
}
return _RelocType_name[_RelocType_index[i]:_RelocType_index[i+1]]
}

View File

@ -0,0 +1,926 @@
// Based on cmd/internal/obj/ppc64/a.out.go.
//
// 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-2008 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-2008 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 s390x
import "github.com/google/gops/internal/obj"
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p s390x
const (
NSNAME = 8
NSYM = 50
NREG = 16 // number of general purpose registers
NFREG = 16 // number of floating point registers
)
const (
// General purpose registers (GPRs).
REG_R0 = obj.RBaseS390X + iota
REG_R1
REG_R2
REG_R3
REG_R4
REG_R5
REG_R6
REG_R7
REG_R8
REG_R9
REG_R10
REG_R11
REG_R12
REG_R13
REG_R14
REG_R15
// Floating point registers (FPRs).
REG_F0
REG_F1
REG_F2
REG_F3
REG_F4
REG_F5
REG_F6
REG_F7
REG_F8
REG_F9
REG_F10
REG_F11
REG_F12
REG_F13
REG_F14
REG_F15
// Vector registers (VRs) - only available when the vector
// facility is installed.
// V0-V15 are aliases for F0-F15.
// We keep them in a separate space to make printing etc. easier
// If the code generator ever emits vector instructions it will
// need to take into account the aliasing.
REG_V0
REG_V1
REG_V2
REG_V3
REG_V4
REG_V5
REG_V6
REG_V7
REG_V8
REG_V9
REG_V10
REG_V11
REG_V12
REG_V13
REG_V14
REG_V15
REG_V16
REG_V17
REG_V18
REG_V19
REG_V20
REG_V21
REG_V22
REG_V23
REG_V24
REG_V25
REG_V26
REG_V27
REG_V28
REG_V29
REG_V30
REG_V31
// Access registers (ARs).
// The thread pointer is typically stored in the register pair
// AR0 and AR1.
REG_AR0
REG_AR1
REG_AR2
REG_AR3
REG_AR4
REG_AR5
REG_AR6
REG_AR7
REG_AR8
REG_AR9
REG_AR10
REG_AR11
REG_AR12
REG_AR13
REG_AR14
REG_AR15
REG_RESERVED // end of allocated registers
REGZERO = REG_R0 // set to zero
REGARG = -1 // -1 disables passing the first argument in register
REGRT1 = REG_R3 // used during zeroing of the stack - not reserved
REGRT2 = REG_R4 // used during zeroing of the stack - not reserved
REGTMP = REG_R10 // scratch register used in the assembler and linker
REGTMP2 = REG_R11 // scratch register used in the assembler and linker
REGCTXT = REG_R12 // context for closures
REGG = REG_R13 // G
REG_LR = REG_R14 // link register
REGSP = REG_R15 // stack pointer
)
const (
BIG = 32768 - 8
DISP12 = 4096
DISP16 = 65536
DISP20 = 1048576
)
const (
// mark flags
LABEL = 1 << 0
LEAF = 1 << 1
FLOAT = 1 << 2
BRANCH = 1 << 3
LOAD = 1 << 4
FCMP = 1 << 5
SYNC = 1 << 6
LIST = 1 << 7
FOLL = 1 << 8
NOSCHED = 1 << 9
)
const ( // comments from func aclass in asmz.go
C_NONE = iota
C_REG // general-purpose register (64-bit)
C_FREG // floating-point register (64-bit)
C_VREG // vector register (128-bit)
C_AREG // access register (32-bit)
C_ZCON // constant == 0
C_SCON // 0 <= constant <= 0x7fff (positive int16)
C_UCON // constant & 0xffff == 0 (int16 or uint16)
C_ADDCON // 0 > constant >= -0x8000 (negative int16)
C_ANDCON // constant <= 0xffff
C_LCON // constant (int32 or uint32)
C_DCON // constant (int64 or uint64)
C_SACON // computed address, 16-bit displacement, possibly SP-relative
C_LACON // computed address, 32-bit displacement, possibly SP-relative
C_DACON // computed address, 64-bit displacment?
C_SBRA // short branch
C_LBRA // long branch
C_SAUTO // short auto
C_LAUTO // long auto
C_ZOREG // heap address, register-based, displacement == 0
C_SOREG // heap address, register-based, int16 displacement
C_LOREG // heap address, register-based, int32 displacement
C_TLS_LE // TLS - local exec model (for executables)
C_TLS_IE // TLS - initial exec model (for shared libraries loaded at program startup)
C_GOK // general address
C_ADDR // relocation for extern or static symbols (loads and stores)
C_SYMADDR // relocation for extern or static symbols (address taking)
C_GOTADDR // GOT slot for a symbol in -dynlink mode
C_TEXTSIZE // text size
C_ANY
C_NCLASS // must be the last
)
const (
// integer arithmetic
AADD = obj.ABaseS390X + obj.A_ARCHSPECIFIC + iota
AADDC
AADDE
AADDW
ADIVW
ADIVWU
ADIVD
ADIVDU
AMODW
AMODWU
AMODD
AMODDU
AMULLW
AMULLD
AMULHD
AMULHDU
ASUB
ASUBC
ASUBV
ASUBE
ASUBW
ANEG
ANEGW
// integer moves
AMOVWBR
AMOVB
AMOVBZ
AMOVH
AMOVHBR
AMOVHZ
AMOVW
AMOVWZ
AMOVD
AMOVDBR
// conditional moves
AMOVDEQ
AMOVDGE
AMOVDGT
AMOVDLE
AMOVDLT
AMOVDNE
// find leftmost one
AFLOGR
// integer bitwise
AAND
AANDW
AOR
AORW
AXOR
AXORW
ASLW
ASLD
ASRW
ASRAW
ASRD
ASRAD
ARLL
ARLLG
// floating point
AFABS
AFADD
AFADDS
AFCMPO
AFCMPU
ACEBR
AFDIV
AFDIVS
AFMADD
AFMADDS
AFMOVD
AFMOVS
AFMSUB
AFMSUBS
AFMUL
AFMULS
AFNABS
AFNEG
AFNEGS
AFNMADD
AFNMADDS
AFNMSUB
AFNMSUBS
ALEDBR
ALDEBR
AFSUB
AFSUBS
AFSQRT
AFSQRTS
AFIEBR
AFIDBR
// convert from int32/int64 to float/float64
ACEFBRA
ACDFBRA
ACEGBRA
ACDGBRA
// convert from float/float64 to int32/int64
ACFEBRA
ACFDBRA
ACGEBRA
ACGDBRA
// convert from uint32/uint64 to float/float64
ACELFBR
ACDLFBR
ACELGBR
ACDLGBR
// convert from float/float64 to uint32/uint64
ACLFEBR
ACLFDBR
ACLGEBR
ACLGDBR
// compare
ACMP
ACMPU
ACMPW
ACMPWU
// compare and swap
ACS
ACSG
// serialize
ASYNC
// branch
ABC
ABCL
ABEQ
ABGE
ABGT
ABLE
ABLT
ABLEU
ABLTU
ABNE
ABVC
ABVS
ASYSCALL
// compare and branch
ACMPBEQ
ACMPBGE
ACMPBGT
ACMPBLE
ACMPBLT
ACMPBNE
ACMPUBEQ
ACMPUBGE
ACMPUBGT
ACMPUBLE
ACMPUBLT
ACMPUBNE
// storage-and-storage
AMVC
ACLC
AXC
AOC
ANC
// load
AEXRL
ALARL
ALA
ALAY
// interlocked load and op
ALAA
ALAAG
ALAAL
ALAALG
ALAN
ALANG
ALAX
ALAXG
ALAO
ALAOG
// load/store multiple
ALMY
ALMG
ASTMY
ASTMG
// store clock
ASTCK
ASTCKC
ASTCKE
ASTCKF
// macros
ACLEAR
// vector
AVA
AVAB
AVAH
AVAF
AVAG
AVAQ
AVACC
AVACCB
AVACCH
AVACCF
AVACCG
AVACCQ
AVAC
AVACQ
AVACCC
AVACCCQ
AVN
AVNC
AVAVG
AVAVGB
AVAVGH
AVAVGF
AVAVGG
AVAVGL
AVAVGLB
AVAVGLH
AVAVGLF
AVAVGLG
AVCKSM
AVCEQ
AVCEQB
AVCEQH
AVCEQF
AVCEQG
AVCEQBS
AVCEQHS
AVCEQFS
AVCEQGS
AVCH
AVCHB
AVCHH
AVCHF
AVCHG
AVCHBS
AVCHHS
AVCHFS
AVCHGS
AVCHL
AVCHLB
AVCHLH
AVCHLF
AVCHLG
AVCHLBS
AVCHLHS
AVCHLFS
AVCHLGS
AVCLZ
AVCLZB
AVCLZH
AVCLZF
AVCLZG
AVCTZ
AVCTZB
AVCTZH
AVCTZF
AVCTZG
AVEC
AVECB
AVECH
AVECF
AVECG
AVECL
AVECLB
AVECLH
AVECLF
AVECLG
AVERIM
AVERIMB
AVERIMH
AVERIMF
AVERIMG
AVERLL
AVERLLB
AVERLLH
AVERLLF
AVERLLG
AVERLLV
AVERLLVB
AVERLLVH
AVERLLVF
AVERLLVG
AVESLV
AVESLVB
AVESLVH
AVESLVF
AVESLVG
AVESL
AVESLB
AVESLH
AVESLF
AVESLG
AVESRA
AVESRAB
AVESRAH
AVESRAF
AVESRAG
AVESRAV
AVESRAVB
AVESRAVH
AVESRAVF
AVESRAVG
AVESRL
AVESRLB
AVESRLH
AVESRLF
AVESRLG
AVESRLV
AVESRLVB
AVESRLVH
AVESRLVF
AVESRLVG
AVX
AVFAE
AVFAEB
AVFAEH
AVFAEF
AVFAEBS
AVFAEHS
AVFAEFS
AVFAEZB
AVFAEZH
AVFAEZF
AVFAEZBS
AVFAEZHS
AVFAEZFS
AVFEE
AVFEEB
AVFEEH
AVFEEF
AVFEEBS
AVFEEHS
AVFEEFS
AVFEEZB
AVFEEZH
AVFEEZF
AVFEEZBS
AVFEEZHS
AVFEEZFS
AVFENE
AVFENEB
AVFENEH
AVFENEF
AVFENEBS
AVFENEHS
AVFENEFS
AVFENEZB
AVFENEZH
AVFENEZF
AVFENEZBS
AVFENEZHS
AVFENEZFS
AVFA
AVFADB
AWFADB
AWFK
AWFKDB
AVFCE
AVFCEDB
AVFCEDBS
AWFCEDB
AWFCEDBS
AVFCH
AVFCHDB
AVFCHDBS
AWFCHDB
AWFCHDBS
AVFCHE
AVFCHEDB
AVFCHEDBS
AWFCHEDB
AWFCHEDBS
AWFC
AWFCDB
AVCDG
AVCDGB
AWCDGB
AVCDLG
AVCDLGB
AWCDLGB
AVCGD
AVCGDB
AWCGDB
AVCLGD
AVCLGDB
AWCLGDB
AVFD
AVFDDB
AWFDDB
AVLDE
AVLDEB
AWLDEB
AVLED
AVLEDB
AWLEDB
AVFM
AVFMDB
AWFMDB
AVFMA
AVFMADB
AWFMADB
AVFMS
AVFMSDB
AWFMSDB
AVFPSO
AVFPSODB
AWFPSODB
AVFLCDB
AWFLCDB
AVFLNDB
AWFLNDB
AVFLPDB
AWFLPDB
AVFSQ
AVFSQDB
AWFSQDB
AVFS
AVFSDB
AWFSDB
AVFTCI
AVFTCIDB
AWFTCIDB
AVGFM
AVGFMB
AVGFMH
AVGFMF
AVGFMG
AVGFMA
AVGFMAB
AVGFMAH
AVGFMAF
AVGFMAG
AVGEF
AVGEG
AVGBM
AVZERO
AVONE
AVGM
AVGMB
AVGMH
AVGMF
AVGMG
AVISTR
AVISTRB
AVISTRH
AVISTRF
AVISTRBS
AVISTRHS
AVISTRFS
AVL
AVLR
AVLREP
AVLREPB
AVLREPH
AVLREPF
AVLREPG
AVLC
AVLCB
AVLCH
AVLCF
AVLCG
AVLEH
AVLEF
AVLEG
AVLEB
AVLEIH
AVLEIF
AVLEIG
AVLEIB
AVFI
AVFIDB
AWFIDB
AVLGV
AVLGVB
AVLGVH
AVLGVF
AVLGVG
AVLLEZ
AVLLEZB
AVLLEZH
AVLLEZF
AVLLEZG
AVLM
AVLP
AVLPB
AVLPH
AVLPF
AVLPG
AVLBB
AVLVG
AVLVGB
AVLVGH
AVLVGF
AVLVGG
AVLVGP
AVLL
AVMX
AVMXB
AVMXH
AVMXF
AVMXG
AVMXL
AVMXLB
AVMXLH
AVMXLF
AVMXLG
AVMRH
AVMRHB
AVMRHH
AVMRHF
AVMRHG
AVMRL
AVMRLB
AVMRLH
AVMRLF
AVMRLG
AVMN
AVMNB
AVMNH
AVMNF
AVMNG
AVMNL
AVMNLB
AVMNLH
AVMNLF
AVMNLG
AVMAE
AVMAEB
AVMAEH
AVMAEF
AVMAH
AVMAHB
AVMAHH
AVMAHF
AVMALE
AVMALEB
AVMALEH
AVMALEF
AVMALH
AVMALHB
AVMALHH
AVMALHF
AVMALO
AVMALOB
AVMALOH
AVMALOF
AVMAL
AVMALB
AVMALHW
AVMALF
AVMAO
AVMAOB
AVMAOH
AVMAOF
AVME
AVMEB
AVMEH
AVMEF
AVMH
AVMHB
AVMHH
AVMHF
AVMLE
AVMLEB
AVMLEH
AVMLEF
AVMLH
AVMLHB
AVMLHH
AVMLHF
AVMLO
AVMLOB
AVMLOH
AVMLOF
AVML
AVMLB
AVMLHW
AVMLF
AVMO
AVMOB
AVMOH
AVMOF
AVNO
AVNOT
AVO
AVPK
AVPKH
AVPKF
AVPKG
AVPKLS
AVPKLSH
AVPKLSF
AVPKLSG
AVPKLSHS
AVPKLSFS
AVPKLSGS
AVPKS
AVPKSH
AVPKSF
AVPKSG
AVPKSHS
AVPKSFS
AVPKSGS
AVPERM
AVPDI
AVPOPCT
AVREP
AVREPB
AVREPH
AVREPF
AVREPG
AVREPI
AVREPIB
AVREPIH
AVREPIF
AVREPIG
AVSCEF
AVSCEG
AVSEL
AVSL
AVSLB
AVSLDB
AVSRA
AVSRAB
AVSRL
AVSRLB
AVSEG
AVSEGB
AVSEGH
AVSEGF
AVST
AVSTEH
AVSTEF
AVSTEG
AVSTEB
AVSTM
AVSTL
AVSTRC
AVSTRCB
AVSTRCH
AVSTRCF
AVSTRCBS
AVSTRCHS
AVSTRCFS
AVSTRCZB
AVSTRCZH
AVSTRCZF
AVSTRCZBS
AVSTRCZHS
AVSTRCZFS
AVS
AVSB
AVSH
AVSF
AVSG
AVSQ
AVSCBI
AVSCBIB
AVSCBIH
AVSCBIF
AVSCBIG
AVSCBIQ
AVSBCBI
AVSBCBIQ
AVSBI
AVSBIQ
AVSUMG
AVSUMGH
AVSUMGF
AVSUMQ
AVSUMQF
AVSUMQG
AVSUM
AVSUMB
AVSUMH
AVTM
AVUPH
AVUPHB
AVUPHH
AVUPHF
AVUPLH
AVUPLHB
AVUPLHH
AVUPLHF
AVUPLL
AVUPLLB
AVUPLLH
AVUPLLF
AVUPL
AVUPLB
AVUPLHW
AVUPLF
// binary
ABYTE
AWORD
ADWORD
// end marker
ALAST
// aliases
ABR = obj.AJMP
ABL = obj.ACALL
)

View File

@ -0,0 +1,675 @@
// Generated by stringer -i a.out.go -o anames.go -p s390x
// Do not edit.
package s390x
import "github.com/google/gops/internal/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADD",
"ADDC",
"ADDE",
"ADDW",
"DIVW",
"DIVWU",
"DIVD",
"DIVDU",
"MODW",
"MODWU",
"MODD",
"MODDU",
"MULLW",
"MULLD",
"MULHD",
"MULHDU",
"SUB",
"SUBC",
"SUBV",
"SUBE",
"SUBW",
"NEG",
"NEGW",
"MOVWBR",
"MOVB",
"MOVBZ",
"MOVH",
"MOVHBR",
"MOVHZ",
"MOVW",
"MOVWZ",
"MOVD",
"MOVDBR",
"MOVDEQ",
"MOVDGE",
"MOVDGT",
"MOVDLE",
"MOVDLT",
"MOVDNE",
"FLOGR",
"AND",
"ANDW",
"OR",
"ORW",
"XOR",
"XORW",
"SLW",
"SLD",
"SRW",
"SRAW",
"SRD",
"SRAD",
"RLL",
"RLLG",
"FABS",
"FADD",
"FADDS",
"FCMPO",
"FCMPU",
"CEBR",
"FDIV",
"FDIVS",
"FMADD",
"FMADDS",
"FMOVD",
"FMOVS",
"FMSUB",
"FMSUBS",
"FMUL",
"FMULS",
"FNABS",
"FNEG",
"FNEGS",
"FNMADD",
"FNMADDS",
"FNMSUB",
"FNMSUBS",
"LEDBR",
"LDEBR",
"FSUB",
"FSUBS",
"FSQRT",
"FSQRTS",
"FIEBR",
"FIDBR",
"CEFBRA",
"CDFBRA",
"CEGBRA",
"CDGBRA",
"CFEBRA",
"CFDBRA",
"CGEBRA",
"CGDBRA",
"CELFBR",
"CDLFBR",
"CELGBR",
"CDLGBR",
"CLFEBR",
"CLFDBR",
"CLGEBR",
"CLGDBR",
"CMP",
"CMPU",
"CMPW",
"CMPWU",
"CS",
"CSG",
"SYNC",
"BC",
"BCL",
"BEQ",
"BGE",
"BGT",
"BLE",
"BLT",
"BLEU",
"BLTU",
"BNE",
"BVC",
"BVS",
"SYSCALL",
"CMPBEQ",
"CMPBGE",
"CMPBGT",
"CMPBLE",
"CMPBLT",
"CMPBNE",
"CMPUBEQ",
"CMPUBGE",
"CMPUBGT",
"CMPUBLE",
"CMPUBLT",
"CMPUBNE",
"MVC",
"CLC",
"XC",
"OC",
"NC",
"EXRL",
"LARL",
"LA",
"LAY",
"LAA",
"LAAG",
"LAAL",
"LAALG",
"LAN",
"LANG",
"LAX",
"LAXG",
"LAO",
"LAOG",
"LMY",
"LMG",
"STMY",
"STMG",
"STCK",
"STCKC",
"STCKE",
"STCKF",
"CLEAR",
"VA",
"VAB",
"VAH",
"VAF",
"VAG",
"VAQ",
"VACC",
"VACCB",
"VACCH",
"VACCF",
"VACCG",
"VACCQ",
"VAC",
"VACQ",
"VACCC",
"VACCCQ",
"VN",
"VNC",
"VAVG",
"VAVGB",
"VAVGH",
"VAVGF",
"VAVGG",
"VAVGL",
"VAVGLB",
"VAVGLH",
"VAVGLF",
"VAVGLG",
"VCKSM",
"VCEQ",
"VCEQB",
"VCEQH",
"VCEQF",
"VCEQG",
"VCEQBS",
"VCEQHS",
"VCEQFS",
"VCEQGS",
"VCH",
"VCHB",
"VCHH",
"VCHF",
"VCHG",
"VCHBS",
"VCHHS",
"VCHFS",
"VCHGS",
"VCHL",
"VCHLB",
"VCHLH",
"VCHLF",
"VCHLG",
"VCHLBS",
"VCHLHS",
"VCHLFS",
"VCHLGS",
"VCLZ",
"VCLZB",
"VCLZH",
"VCLZF",
"VCLZG",
"VCTZ",
"VCTZB",
"VCTZH",
"VCTZF",
"VCTZG",
"VEC",
"VECB",
"VECH",
"VECF",
"VECG",
"VECL",
"VECLB",
"VECLH",
"VECLF",
"VECLG",
"VERIM",
"VERIMB",
"VERIMH",
"VERIMF",
"VERIMG",
"VERLL",
"VERLLB",
"VERLLH",
"VERLLF",
"VERLLG",
"VERLLV",
"VERLLVB",
"VERLLVH",
"VERLLVF",
"VERLLVG",
"VESLV",
"VESLVB",
"VESLVH",
"VESLVF",
"VESLVG",
"VESL",
"VESLB",
"VESLH",
"VESLF",
"VESLG",
"VESRA",
"VESRAB",
"VESRAH",
"VESRAF",
"VESRAG",
"VESRAV",
"VESRAVB",
"VESRAVH",
"VESRAVF",
"VESRAVG",
"VESRL",
"VESRLB",
"VESRLH",
"VESRLF",
"VESRLG",
"VESRLV",
"VESRLVB",
"VESRLVH",
"VESRLVF",
"VESRLVG",
"VX",
"VFAE",
"VFAEB",
"VFAEH",
"VFAEF",
"VFAEBS",
"VFAEHS",
"VFAEFS",
"VFAEZB",
"VFAEZH",
"VFAEZF",
"VFAEZBS",
"VFAEZHS",
"VFAEZFS",
"VFEE",
"VFEEB",
"VFEEH",
"VFEEF",
"VFEEBS",
"VFEEHS",
"VFEEFS",
"VFEEZB",
"VFEEZH",
"VFEEZF",
"VFEEZBS",
"VFEEZHS",
"VFEEZFS",
"VFENE",
"VFENEB",
"VFENEH",
"VFENEF",
"VFENEBS",
"VFENEHS",
"VFENEFS",
"VFENEZB",
"VFENEZH",
"VFENEZF",
"VFENEZBS",
"VFENEZHS",
"VFENEZFS",
"VFA",
"VFADB",
"WFADB",
"WFK",
"WFKDB",
"VFCE",
"VFCEDB",
"VFCEDBS",
"WFCEDB",
"WFCEDBS",
"VFCH",
"VFCHDB",
"VFCHDBS",
"WFCHDB",
"WFCHDBS",
"VFCHE",
"VFCHEDB",
"VFCHEDBS",
"WFCHEDB",
"WFCHEDBS",
"WFC",
"WFCDB",
"VCDG",
"VCDGB",
"WCDGB",
"VCDLG",
"VCDLGB",
"WCDLGB",
"VCGD",
"VCGDB",
"WCGDB",
"VCLGD",
"VCLGDB",
"WCLGDB",
"VFD",
"VFDDB",
"WFDDB",
"VLDE",
"VLDEB",
"WLDEB",
"VLED",
"VLEDB",
"WLEDB",
"VFM",
"VFMDB",
"WFMDB",
"VFMA",
"VFMADB",
"WFMADB",
"VFMS",
"VFMSDB",
"WFMSDB",
"VFPSO",
"VFPSODB",
"WFPSODB",
"VFLCDB",
"WFLCDB",
"VFLNDB",
"WFLNDB",
"VFLPDB",
"WFLPDB",
"VFSQ",
"VFSQDB",
"WFSQDB",
"VFS",
"VFSDB",
"WFSDB",
"VFTCI",
"VFTCIDB",
"WFTCIDB",
"VGFM",
"VGFMB",
"VGFMH",
"VGFMF",
"VGFMG",
"VGFMA",
"VGFMAB",
"VGFMAH",
"VGFMAF",
"VGFMAG",
"VGEF",
"VGEG",
"VGBM",
"VZERO",
"VONE",
"VGM",
"VGMB",
"VGMH",
"VGMF",
"VGMG",
"VISTR",
"VISTRB",
"VISTRH",
"VISTRF",
"VISTRBS",
"VISTRHS",
"VISTRFS",
"VL",
"VLR",
"VLREP",
"VLREPB",
"VLREPH",
"VLREPF",
"VLREPG",
"VLC",
"VLCB",
"VLCH",
"VLCF",
"VLCG",
"VLEH",
"VLEF",
"VLEG",
"VLEB",
"VLEIH",
"VLEIF",
"VLEIG",
"VLEIB",
"VFI",
"VFIDB",
"WFIDB",
"VLGV",
"VLGVB",
"VLGVH",
"VLGVF",
"VLGVG",
"VLLEZ",
"VLLEZB",
"VLLEZH",
"VLLEZF",
"VLLEZG",
"VLM",
"VLP",
"VLPB",
"VLPH",
"VLPF",
"VLPG",
"VLBB",
"VLVG",
"VLVGB",
"VLVGH",
"VLVGF",
"VLVGG",
"VLVGP",
"VLL",
"VMX",
"VMXB",
"VMXH",
"VMXF",
"VMXG",
"VMXL",
"VMXLB",
"VMXLH",
"VMXLF",
"VMXLG",
"VMRH",
"VMRHB",
"VMRHH",
"VMRHF",
"VMRHG",
"VMRL",
"VMRLB",
"VMRLH",
"VMRLF",
"VMRLG",
"VMN",
"VMNB",
"VMNH",
"VMNF",
"VMNG",
"VMNL",
"VMNLB",
"VMNLH",
"VMNLF",
"VMNLG",
"VMAE",
"VMAEB",
"VMAEH",
"VMAEF",
"VMAH",
"VMAHB",
"VMAHH",
"VMAHF",
"VMALE",
"VMALEB",
"VMALEH",
"VMALEF",
"VMALH",
"VMALHB",
"VMALHH",
"VMALHF",
"VMALO",
"VMALOB",
"VMALOH",
"VMALOF",
"VMAL",
"VMALB",
"VMALHW",
"VMALF",
"VMAO",
"VMAOB",
"VMAOH",
"VMAOF",
"VME",
"VMEB",
"VMEH",
"VMEF",
"VMH",
"VMHB",
"VMHH",
"VMHF",
"VMLE",
"VMLEB",
"VMLEH",
"VMLEF",
"VMLH",
"VMLHB",
"VMLHH",
"VMLHF",
"VMLO",
"VMLOB",
"VMLOH",
"VMLOF",
"VML",
"VMLB",
"VMLHW",
"VMLF",
"VMO",
"VMOB",
"VMOH",
"VMOF",
"VNO",
"VNOT",
"VO",
"VPK",
"VPKH",
"VPKF",
"VPKG",
"VPKLS",
"VPKLSH",
"VPKLSF",
"VPKLSG",
"VPKLSHS",
"VPKLSFS",
"VPKLSGS",
"VPKS",
"VPKSH",
"VPKSF",
"VPKSG",
"VPKSHS",
"VPKSFS",
"VPKSGS",
"VPERM",
"VPDI",
"VPOPCT",
"VREP",
"VREPB",
"VREPH",
"VREPF",
"VREPG",
"VREPI",
"VREPIB",
"VREPIH",
"VREPIF",
"VREPIG",
"VSCEF",
"VSCEG",
"VSEL",
"VSL",
"VSLB",
"VSLDB",
"VSRA",
"VSRAB",
"VSRL",
"VSRLB",
"VSEG",
"VSEGB",
"VSEGH",
"VSEGF",
"VST",
"VSTEH",
"VSTEF",
"VSTEG",
"VSTEB",
"VSTM",
"VSTL",
"VSTRC",
"VSTRCB",
"VSTRCH",
"VSTRCF",
"VSTRCBS",
"VSTRCHS",
"VSTRCFS",
"VSTRCZB",
"VSTRCZH",
"VSTRCZF",
"VSTRCZBS",
"VSTRCZHS",
"VSTRCZFS",
"VS",
"VSB",
"VSH",
"VSF",
"VSG",
"VSQ",
"VSCBI",
"VSCBIB",
"VSCBIH",
"VSCBIF",
"VSCBIG",
"VSCBIQ",
"VSBCBI",
"VSBCBIQ",
"VSBI",
"VSBIQ",
"VSUMG",
"VSUMGH",
"VSUMGF",
"VSUMQ",
"VSUMQF",
"VSUMQG",
"VSUM",
"VSUMB",
"VSUMH",
"VTM",
"VUPH",
"VUPHB",
"VUPHH",
"VUPHF",
"VUPLH",
"VUPLHB",
"VUPLHH",
"VUPLHF",
"VUPLL",
"VUPLLB",
"VUPLLH",
"VUPLLF",
"VUPL",
"VUPLB",
"VUPLHW",
"VUPLF",
"BYTE",
"WORD",
"DWORD",
"LAST",
}

View File

@ -0,0 +1,39 @@
// 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 s390x
var cnamesz = []string{
"NONE",
"REG",
"FREG",
"VREG",
"AREG",
"ZCON",
"SCON",
"UCON",
"ADDCON",
"ANDCON",
"LCON",
"DCON",
"SACON",
"LACON",
"DACON",
"SBRA",
"LBRA",
"SAUTO",
"LAUTO",
"ZOREG",
"SOREG",
"LOREG",
"TLS_LE",
"TLS_IE",
"GOK",
"ADDR",
"SYMADDR",
"GOTADDR",
"TEXTSIZE",
"ANY",
"NCLASS",
}

4766
vendor/github.com/google/gops/internal/obj/s390x/asmz.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
// Based on cmd/internal/obj/ppc64/list9.go.
//
// 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-2008 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-2008 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 s390x
import (
"fmt"
"github.com/google/gops/internal/obj"
)
func init() {
obj.RegisterRegister(obj.RBaseS390X, REG_R0+1024, Rconv)
obj.RegisterOpcode(obj.ABaseS390X, Anames)
}
func Rconv(r int) string {
if r == 0 {
return "NONE"
}
if r == REGG {
// Special case.
return "g"
}
if REG_R0 <= r && r <= REG_R15 {
return fmt.Sprintf("R%d", r-REG_R0)
}
if REG_F0 <= r && r <= REG_F15 {
return fmt.Sprintf("F%d", r-REG_F0)
}
if REG_AR0 <= r && r <= REG_AR15 {
return fmt.Sprintf("AR%d", r-REG_AR0)
}
if REG_V0 <= r && r <= REG_V31 {
return fmt.Sprintf("V%d", r-REG_V0)
}
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseS390X)
}
func DRconv(a int) string {
s := "C_??"
if a >= C_NONE && a <= C_NCLASS {
s = cnamesz[a]
}
var fp string
fp += s
return fp
}

1029
vendor/github.com/google/gops/internal/obj/s390x/objz.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

21
vendor/github.com/google/gops/internal/obj/stack.go generated vendored Normal file
View File

@ -0,0 +1,21 @@
// 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 obj
// For the linkers. Must match Go definitions.
// TODO(rsc): Share Go definitions with linkers directly.
const (
STACKSYSTEM = 0
StackSystem = STACKSYSTEM
StackBig = 4096
StackGuard = 880*stackGuardMultiplier + StackSystem
StackSmall = 128
StackLimit = StackGuard - StackSystem - StackSmall
)
const (
StackPreempt = -1314 // 0xfff...fade
)

104
vendor/github.com/google/gops/internal/obj/stringer.go generated vendored Normal file
View File

@ -0,0 +1,104 @@
// 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.
// +build ignore
// This is a mini version of the stringer tool customized for the Anames table
// in the architecture support for obj.
// This version just generates the slice of strings, not the String method.
package main
import (
"bufio"
"flag"
"fmt"
"log"
"os"
"regexp"
"strings"
)
var (
input = flag.String("i", "", "input file name")
output = flag.String("o", "", "output file name")
pkg = flag.String("p", "", "package name")
)
var Are = regexp.MustCompile(`^\tA([A-Z0-9]+)`)
func main() {
flag.Parse()
if *input == "" || *output == "" || *pkg == "" {
flag.Usage()
os.Exit(2)
}
in, err := os.Open(*input)
if err != nil {
log.Fatal(err)
}
fd, err := os.Create(*output)
if err != nil {
log.Fatal(err)
}
out := bufio.NewWriter(fd)
defer out.Flush()
var on = false
s := bufio.NewScanner(in)
first := true
for s.Scan() {
line := s.Text()
if !on {
// First relevant line contains "= obj.ABase".
// If we find it, delete the = so we don't stop immediately.
const prefix = "= obj.ABase"
index := strings.Index(line, prefix)
if index < 0 {
continue
}
// It's on. Start with the header.
fmt.Fprintf(out, header, *input, *output, *pkg, *pkg)
on = true
line = line[:index]
}
// Strip comments so their text won't defeat our heuristic.
index := strings.Index(line, "//")
if index > 0 {
line = line[:index]
}
index = strings.Index(line, "/*")
if index > 0 {
line = line[:index]
}
// Termination condition: Any line with an = changes the sequence,
// so stop there, and stop at a closing brace.
if strings.HasPrefix(line, "}") || strings.ContainsRune(line, '=') {
break
}
sub := Are.FindStringSubmatch(line)
if len(sub) < 2 {
continue
}
if first {
fmt.Fprintf(out, "\tobj.A_ARCHSPECIFIC: %q,\n", sub[1])
first = false
} else {
fmt.Fprintf(out, "\t%q,\n", sub[1])
}
}
fmt.Fprintln(out, "}")
if s.Err() != nil {
log.Fatal(err)
}
}
const header = `// Generated by stringer -i %s -o %s -p %s
// Do not edit.
package %s
import "github.com/google/gops/internal/obj"
var Anames = []string{
`

88
vendor/github.com/google/gops/internal/obj/sym.go generated vendored Normal file
View File

@ -0,0 +1,88 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// 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 obj
import (
"log"
"os"
"path/filepath"
)
func Linknew(arch *LinkArch) *Link {
ctxt := new(Link)
ctxt.Hash = make(map[SymVer]*LSym)
ctxt.Arch = arch
ctxt.Version = HistVersion
var buf string
buf, _ = os.Getwd()
if buf == "" {
buf = "/???"
}
buf = filepath.ToSlash(buf)
ctxt.Pathname = buf
ctxt.LineHist.GOROOT = GOROOT
ctxt.LineHist.Dir = ctxt.Pathname
ctxt.Headtype.Set(GOOS)
if ctxt.Headtype < 0 {
log.Fatalf("unknown goos %s", GOOS)
}
ctxt.Flag_optimize = true
ctxt.Framepointer_enabled = Framepointer_enabled(GOOS, arch.Name)
return ctxt
}
func Linklookup(ctxt *Link, name string, v int) *LSym {
s := ctxt.Hash[SymVer{name, v}]
if s != nil {
return s
}
s = &LSym{
Name: name,
Type: 0,
Version: int16(v),
Size: 0,
}
ctxt.Hash[SymVer{name, v}] = s
return s
}
func Linksymfmt(s *LSym) string {
if s == nil {
return "<nil>"
}
return s.Name
}

View File

@ -0,0 +1,16 @@
// Code generated by "stringer -type=SymKind"; DO NOT EDIT
package obj
import "fmt"
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFO"
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408}
func (i SymKind) String() string {
if i < 0 || i >= SymKind(len(_SymKind_index)-1) {
return fmt.Sprintf("SymKind(%d)", i)
}
return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]]
}

50
vendor/github.com/google/gops/internal/obj/textflag.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
// 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.
package obj
const (
// Don't profile the marked routine.
//
// Deprecated: Not implemented, do not use.
NOPROF = 1
// It is ok for the linker to get multiple of these symbols. It will
// pick one of the duplicates to use.
DUPOK = 2
// Don't insert stack check preamble.
NOSPLIT = 4
// Put this data in a read-only section.
RODATA = 8
// This data contains no pointers.
NOPTR = 16
// This is a wrapper function and should not count as disabling 'recover'.
WRAPPER = 32
// This function uses its incoming context register.
NEEDCTXT = 64
// When passed to ggloblsym, causes Local to be set to true on the LSym it creates.
LOCAL = 128
// 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 = 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.
NOFRAME = 512
// Function can call reflect.Type.Method or reflect.Type.MethodByName.
REFLECTMETHOD = 1024
)

41
vendor/github.com/google/gops/internal/obj/typekind.go generated vendored Normal file
View File

@ -0,0 +1,41 @@
// 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 obj
// 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
KindNoPointers = 1 << 7
KindMask = (1 << 5) - 1
)

499
vendor/github.com/google/gops/internal/obj/util.go generated vendored Normal file
View File

@ -0,0 +1,499 @@
// 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 obj
import (
"bytes"
"fmt"
"log"
"os"
"strings"
"time"
)
const REG_NONE = 0
var start time.Time
func Cputime() float64 {
if start.IsZero() {
start = time.Now()
}
return time.Since(start).Seconds()
}
func envOr(key, value string) string {
if x := os.Getenv(key); x != "" {
return x
}
return value
}
var (
GOROOT = envOr("GOROOT", defaultGOROOT)
GOARCH = envOr("GOARCH", defaultGOARCH)
GOOS = envOr("GOOS", defaultGOOS)
GO386 = envOr("GO386", defaultGO386)
GOARM = goarm()
Version = version
)
func goarm() int {
switch v := envOr("GOARM", defaultGOARM); 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 Getgoextlinkenabled() string {
return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
}
func (p *Prog) Line() string {
return p.Ctxt.LineHist.LineString(int(p.Lineno))
}
var armCondCode = []string{
".EQ",
".NE",
".CS",
".CC",
".MI",
".PL",
".VS",
".VC",
".HI",
".LS",
".GE",
".LT",
".GT",
".LE",
"",
".NV",
}
/* ARM scond byte */
const (
C_SCOND = (1 << 4) - 1
C_SBIT = 1 << 4
C_PBIT = 1 << 5
C_WBIT = 1 << 6
C_FBIT = 1 << 7
C_UBIT = 1 << 7
C_SCOND_XOR = 14
)
// CConv formats ARM condition codes.
func CConv(s uint8) string {
if s == 0 {
return ""
}
sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
if s&C_SBIT != 0 {
sc += ".S"
}
if s&C_PBIT != 0 {
sc += ".P"
}
if s&C_WBIT != 0 {
sc += ".W"
}
if s&C_UBIT != 0 { /* ambiguous with FBIT */
sc += ".U"
}
return sc
}
func (p *Prog) String() string {
if p == nil {
return "<nil Prog>"
}
if p.Ctxt == nil {
return "<Prog without ctxt>"
}
sc := CConv(p.Scond)
var buf bytes.Buffer
fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc)
sep := "\t"
quadOpAmd64 := p.RegTo2 == -1
if quadOpAmd64 {
fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset)
sep = ", "
}
if p.From.Type != TYPE_NONE {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
sep = ", "
}
if p.Reg != REG_NONE {
// Should not happen but might as well show it if it does.
fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
sep = ", "
}
if p.From3Type() != TYPE_NONE {
if p.From3.Type == TYPE_CONST && p.As == ATEXT {
// Special case - omit $.
fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
} else if quadOpAmd64 {
fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
} else {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
}
sep = ", "
}
if p.To.Type != TYPE_NONE {
fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
}
if p.RegTo2 != REG_NONE && !quadOpAmd64 {
fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
}
return buf.String()
}
func (ctxt *Link) NewProg() *Prog {
var p *Prog
if i := ctxt.allocIdx; i < len(ctxt.progs) {
p = &ctxt.progs[i]
ctxt.allocIdx = i + 1
} else {
p = new(Prog) // should be the only call to this; all others should use ctxt.NewProg
}
p.Ctxt = ctxt
return p
}
func (ctxt *Link) freeProgs() {
s := ctxt.progs[:ctxt.allocIdx]
for i := range s {
s[i] = Prog{}
}
ctxt.allocIdx = 0
}
func (ctxt *Link) Line(n int) string {
return ctxt.LineHist.LineString(n)
}
func Getcallerpc(interface{}) uintptr {
return 1
}
func (ctxt *Link) Dconv(a *Addr) string {
return Dconv(nil, a)
}
func Dconv(p *Prog, a *Addr) string {
var str string
switch a.Type {
default:
str = fmt.Sprintf("type=%d", a.Type)
case TYPE_NONE:
str = ""
if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
}
case TYPE_REG:
// TODO(rsc): This special case is for x86 instructions like
// PINSRQ CX,$1,X6
// where the $1 is included in the p->to Addr.
// Move into a new field.
if a.Offset != 0 {
str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
break
}
str = Rconv(int(a.Reg))
if a.Name != NAME_NONE || a.Sym != nil {
str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
}
case TYPE_BRANCH:
if a.Sym != nil {
str = fmt.Sprintf("%s(SB)", a.Sym.Name)
} else if p != nil && p.Pcond != nil {
str = fmt.Sprint(p.Pcond.Pc)
} else if a.Val != nil {
str = fmt.Sprint(a.Val.(*Prog).Pc)
} else {
str = fmt.Sprintf("%d(PC)", a.Offset)
}
case TYPE_INDIR:
str = fmt.Sprintf("*%s", Mconv(a))
case TYPE_MEM:
str = Mconv(a)
if a.Index != REG_NONE {
str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
}
case TYPE_CONST:
if a.Reg != 0 {
str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
} else {
str = fmt.Sprintf("$%v", Mconv(a))
}
case TYPE_TEXTSIZE:
if a.Val.(int32) == ArgsSizeUnknown {
str = fmt.Sprintf("$%d", a.Offset)
} else {
str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
}
case TYPE_FCONST:
str = fmt.Sprintf("%.17g", a.Val.(float64))
// Make sure 1 prints as 1.0
if !strings.ContainsAny(str, ".e") {
str += ".0"
}
str = fmt.Sprintf("$(%s)", str)
case TYPE_SCONST:
str = fmt.Sprintf("$%q", a.Val.(string))
case TYPE_ADDR:
str = fmt.Sprintf("$%s", Mconv(a))
case TYPE_SHIFT:
v := int(a.Offset)
ops := "<<>>->@>"
switch GOARCH {
case "arm":
op := ops[((v>>5)&3)<<1:]
if v&(1<<4) != 0 {
str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
} else {
str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
}
if a.Reg != 0 {
str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
}
case "arm64":
op := ops[((v>>22)&3)<<1:]
str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63)
default:
panic("TYPE_SHIFT is not supported on " + GOARCH)
}
case TYPE_REGREG:
str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
case TYPE_REGREG2:
str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
case TYPE_REGLIST:
str = regListConv(int(a.Offset))
}
return str
}
func Mconv(a *Addr) string {
var str string
switch a.Name {
default:
str = fmt.Sprintf("name=%d", a.Name)
case NAME_NONE:
switch {
case a.Reg == REG_NONE:
str = fmt.Sprint(a.Offset)
case a.Offset == 0:
str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
case a.Offset != 0:
str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
}
case NAME_EXTERN:
if a.Sym != nil {
str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
} else {
str = fmt.Sprintf("%s(SB)", offConv(a.Offset))
}
case NAME_GOTREF:
if a.Sym != nil {
str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
} else {
str = fmt.Sprintf("%s@GOT(SB)", offConv(a.Offset))
}
case NAME_STATIC:
if a.Sym != nil {
str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
} else {
str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset))
}
case NAME_AUTO:
if a.Sym != nil {
str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
} else {
str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
}
case NAME_PARAM:
if a.Sym != nil {
str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
} else {
str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
}
}
return str
}
func offConv(off int64) string {
if off == 0 {
return ""
}
return fmt.Sprintf("%+d", off)
}
type regSet struct {
lo int
hi int
Rconv func(int) string
}
// Few enough architectures that a linear scan is fastest.
// Not even worth sorting.
var regSpace []regSet
/*
Each architecture defines a register space as a unique
integer range.
Here is the list of architectures and the base of their register spaces.
*/
const (
// Because of masking operations in the encodings, each register
// space should start at 0 modulo some power of 2.
RBase386 = 1 * 1024
RBaseAMD64 = 2 * 1024
RBaseARM = 3 * 1024
RBasePPC64 = 4 * 1024 // range [4k, 8k)
RBaseARM64 = 8 * 1024 // range [8k, 13k)
RBaseMIPS64 = 13 * 1024 // range [13k, 14k)
RBaseS390X = 14 * 1024 // range [14k, 15k)
)
// RegisterRegister binds a pretty-printer (Rconv) for register
// numbers to a given register number range. Lo is inclusive,
// hi exclusive (valid registers are lo through hi-1).
func RegisterRegister(lo, hi int, Rconv func(int) string) {
regSpace = append(regSpace, regSet{lo, hi, Rconv})
}
func Rconv(reg int) string {
if reg == REG_NONE {
return "NONE"
}
for i := range regSpace {
rs := &regSpace[i]
if rs.lo <= reg && reg < rs.hi {
return rs.Rconv(reg)
}
}
return fmt.Sprintf("R???%d", reg)
}
func regListConv(list int) string {
str := ""
for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
if list&(1<<uint(i)) != 0 {
if str == "" {
str += "["
} else {
str += ","
}
// This is ARM-specific; R10 is g.
if i == 10 {
str += "g"
} else {
str += fmt.Sprintf("R%d", i)
}
}
}
str += "]"
return str
}
type opSet struct {
lo As
names []string
}
// Not even worth sorting
var aSpace []opSet
// RegisterOpcode binds a list of instruction names
// to a given instruction number range.
func RegisterOpcode(lo As, Anames []string) {
if len(Anames) > AllowedOpCodes {
panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
}
aSpace = append(aSpace, opSet{lo, Anames})
}
func (a As) String() string {
if 0 <= a && int(a) < len(Anames) {
return Anames[a]
}
for i := range aSpace {
as := &aSpace[i]
if as.lo <= a && int(a-as.lo) < len(as.names) {
return as.names[a-as.lo]
}
}
return fmt.Sprintf("A???%d", a)
}
var Anames = []string{
"XXX",
"CALL",
"DUFFCOPY",
"DUFFZERO",
"END",
"FUNCDATA",
"JMP",
"NOP",
"PCDATA",
"RET",
"TEXT",
"TYPE",
"UNDEF",
"USEFIELD",
"VARDEF",
"VARKILL",
"VARLIVE",
}
func Bool2int(b bool) int {
// The compiler currently only optimizes this form.
// See issue 6011.
var i int
if b {
i = 1
} else {
i = 0
}
return i
}

Some files were not shown because too many files have changed in this diff Show More