diff --git a/.circleci/config.yml b/.circleci/config.yml index 90424b75..2aec473b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,27 +18,11 @@ jobs: steps: - checkout - - restore_cache: - keys: - - go-mod-v4-{{ checksum "go.sum" }} - - run: - name: Install Dependencies - command: go mod download - - save_cache: - key: go-mod-v4-{{ checksum "go.sum" }} - paths: - - "/go/pkg/mod" - - - run: - name: install deps - command: | - sudo apt-get update && sudo apt-get install -y gcc flex bison make libelf-dev autoconf - make libpcap - run: name: build command: | - make build + make build-via-docker echo '========== info ==========' uname -a @@ -98,7 +82,7 @@ jobs: exit 1 - run: - name: e2e (test go tls keylog) + name: e2e (test go tls keylog, unstripped) command: | echo "wireshark-common wireshark-common/install-setuid boolean true" | sudo debconf-set-selections sudo add-apt-repository -y ppa:wireshark-dev/stable @@ -111,31 +95,60 @@ jobs: done exit 1 + - run: + name: e2e (test go tls keylog, PIE) + command: | + echo "wireshark-common wireshark-common/install-setuid boolean true" | sudo debconf-set-selections + sudo add-apt-repository -y ppa:wireshark-dev/stable + sudo apt update + sudo DEBIAN_FRONTEND=noninteractive apt install -y tshark + make -C testdata/gohttpapp build + + for i in {1..10}; do + sudo bash testdata/test_gotls_keylog_pie.sh ./ptcpdump && exit 0 || sleep 1 + done + exit 1 + + - run: + name: e2e (test go tls keylog, stripped) + command: | + echo "wireshark-common wireshark-common/install-setuid boolean true" | sudo debconf-set-selections + sudo add-apt-repository -y ppa:wireshark-dev/stable + sudo apt update + sudo DEBIAN_FRONTEND=noninteractive apt install -y tshark + make -C testdata/gohttpapp build + + for i in {1..10}; do + sudo bash testdata/test_gotls_keylog_stripped.sh ./ptcpdump && exit 0 || sleep 1 + done + exit 1 + + - run: + name: e2e (test go tls keylog, stripped + PIE) + command: | + echo "wireshark-common wireshark-common/install-setuid boolean true" | sudo debconf-set-selections + sudo add-apt-repository -y ppa:wireshark-dev/stable + sudo apt update + sudo DEBIAN_FRONTEND=noninteractive apt install -y tshark + make -C testdata/gohttpapp build + + for i in {1..10}; do + sudo bash testdata/test_gotls_keylog_stripped_pie.sh ./ptcpdump && exit 0 || sleep 1 + done + exit 1 + + docker-e2e: machine: image: ubuntu-2204:2024.04.4 resource_class: medium steps: - checkout - - restore_cache: - keys: - - go-mod-v4-{{ checksum "go.sum" }} - - run: - name: Install Dependencies - command: go mod download - - save_cache: - key: go-mod-v4-{{ checksum "go.sum" }} - paths: - - "/go/pkg/mod" - - run: - name: install deps - command: | - sudo apt-get update && sudo apt-get install -y gcc flex bison make libelf-dev autoconf - make libpcap + - run: name: build command: | - make build + make build-via-docker echo '========== info ==========' uname -a @@ -171,25 +184,11 @@ jobs: wget https://github.com/containernetworking/plugins/releases/download/v1.5.0/cni-plugins-linux-amd64-v1.5.0.tgz sudo mkdir -p /opt/cni/bin sudo tar Cxzvvf /opt/cni/bin cni-plugins-linux-amd64-v1.5.0.tgz - - restore_cache: - keys: - - go-mod-v4-{{ checksum "go.sum" }} - - run: - name: Install Dependencies - command: go mod download - - save_cache: - key: go-mod-v4-{{ checksum "go.sum" }} - paths: - - "/go/pkg/mod" - - run: - name: install deps - command: | - sudo apt-get update && sudo apt-get install -y gcc flex bison make libelf-dev autoconf - make libpcap + - run: name: build command: | - make build + make build-via-docker echo '========== info ==========' uname -a @@ -232,25 +231,10 @@ jobs: sudo kind load docker-image busybox:1 sudo kind export kubeconfig - - restore_cache: - keys: - - go-mod-v4-{{ checksum "go.sum" }} - - run: - name: Install Dependencies - command: go mod download - - save_cache: - key: go-mod-v4-{{ checksum "go.sum" }} - paths: - - "/go/pkg/mod" - - run: - name: install deps - command: | - sudo apt-get update && sudo apt-get install -y gcc flex bison make libelf-dev autoconf - make libpcap - run: name: build command: | - make build + make build-via-docker echo '========== info ==========' uname -a diff --git a/.github/workflows/docker-dev-image.yml b/.github/workflows/docker-dev-image.yml index d1db2100..07e0beb9 100644 --- a/.github/workflows/docker-dev-image.yml +++ b/.github/workflows/docker-dev-image.yml @@ -67,8 +67,8 @@ jobs: with: context: . file: .github/build.Dockerfile - # platforms: linux/amd64,linux/arm64 - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 + # platforms: linux/amd64 push: ${{ github.event_name != 'pull_request' }} tags: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.TAG_NAME }}' labels: ${{ steps.meta.outputs.labels }} @@ -97,8 +97,8 @@ jobs: with: context: . file: .github/build.Dockerfile - # platforms: linux/amd64,linux/arm64 - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 + # platforms: linux/amd64 push: ${{ github.event_name != 'pull_request' }} tags: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest' labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9ad66cb7..ba5f889d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,12 +22,8 @@ jobs: with: go-version: '1.22.4' - - name: Set up deps - run: | - sudo apt-get install -y gcc flex bison make libelf-dev autoconf - - name: Build - run: make build + run: make build-via-docker - name: Test run: make test @@ -255,7 +251,7 @@ jobs: run: | make -C testdata/gohttpapp build - - name: Test go tls keylog + - name: Test go tls keylog (unstripped) uses: cilium/little-vm-helper@97c89f004bd0ab4caeacfe92ebc956e13e362e6b # v0.0.19 with: provision: 'false' @@ -272,3 +268,57 @@ jobs: bash /host/testdata/test_gotls_keylog.sh /host/ptcpdump/ptcpdump && exit 0 || sleep 1 done exit 1 + + - name: Test go tls keylog (PIE) + uses: cilium/little-vm-helper@97c89f004bd0ab4caeacfe92ebc956e13e362e6b # v0.0.19 + with: + provision: 'false' + cmd: | + set -ex + uname -a + cat /etc/issue + + ls -lh /host/testdata/gohttpapp + + apt update && yes | apt install -y tshark + + for i in {1..10}; do + bash /host/testdata/test_gotls_keylog_pie.sh /host/ptcpdump/ptcpdump && exit 0 || sleep 1 + done + exit 1 + + - name: Test go tls keylog (stripped) + uses: cilium/little-vm-helper@97c89f004bd0ab4caeacfe92ebc956e13e362e6b # v0.0.19 + with: + provision: 'false' + cmd: | + set -ex + uname -a + cat /etc/issue + + ls -lh /host/testdata/gohttpapp + + apt update && yes | apt install -y tshark + + for i in {1..10}; do + bash /host/testdata/test_gotls_keylog_stripped.sh /host/ptcpdump/ptcpdump && exit 0 || sleep 1 + done + exit 1 + + - name: Test go tls keylog (stripped + PIE) + uses: cilium/little-vm-helper@97c89f004bd0ab4caeacfe92ebc956e13e362e6b # v0.0.19 + with: + provision: 'false' + cmd: | + set -ex + uname -a + cat /etc/issue + + ls -lh /host/testdata/gohttpapp + + apt update && yes | apt install -y tshark + + for i in {1..10}; do + bash /host/testdata/test_gotls_keylog_stripped_pie.sh /host/ptcpdump/ptcpdump && exit 0 || sleep 1 + done + exit 1 diff --git a/README.md b/README.md index aee30d30..6b07cbe0 100644 --- a/README.md +++ b/README.md @@ -334,7 +334,7 @@ Flags: ### Building -1. Build eBPF programs: +1. Build eBPF programs (optional): ``` make build-bpf diff --git a/README.zh-CN.md b/README.zh-CN.md index c572c3ec..0b13cba2 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -353,7 +353,7 @@ Flags: 如何编程项目源代码。 -1. Build eBPF programs: +1. Build eBPF programs (optional): ``` make build-bpf diff --git a/bpf/gotls.go b/bpf/gotls.go index 247fa25a..3d153b50 100644 --- a/bpf/gotls.go +++ b/bpf/gotls.go @@ -3,6 +3,7 @@ package bpf import ( "fmt" "github.com/cilium/ebpf/link" + "github.com/mozillazg/ptcpdump/internal/log" ) func (b *BPF) AttachGoTLSUprobeHooks(exec *link.Executable, symbol string, @@ -13,17 +14,22 @@ func (b *BPF) AttachGoTLSUprobeHooks(exec *link.Executable, symbol string, Address: funcAddr, }) if err != nil { - return fmt.Errorf("attach uprobe for %s: %w", symbol, err) + err = fmt.Errorf("attach uprobe for %s: %w", symbol, err) + log.Infof("%s", err) + return err } b.links = append(b.links, lk) lk, err = exec.Uprobe(symbol, b.objs.UprobeGoBuiltinTlsWriteKeyLogRet, &link.UprobeOptions{ - PID: pid, - Offset: retOffset, // if c.KeyLogWriter == nil { return nil } + PID: pid, + Address: funcAddr, + Offset: retOffset, // if c.KeyLogWriter == nil { return nil } }) if err != nil { - return fmt.Errorf("attach uprobe for %s: %w", symbol, err) + err = fmt.Errorf("attach uprobe for %s: %w", symbol, err) + log.Infof("%s", err) + return err } b.links = append(b.links, lk) return nil diff --git a/cmd/gotls.go b/cmd/gotls.go index a97b8544..7bae3459 100644 --- a/cmd/gotls.go +++ b/cmd/gotls.go @@ -53,34 +53,47 @@ func attachGoTLSHooks(opts Options, bf *bpf.BPF) error { return fmt.Errorf("could not find %s in PATH", opts.subProgArgs[0]) } if _, err := buildinfo.ReadFile(path); err != nil { - log.Debugf("skip go TLS related logics due to %s", err) + log.Debugf("skip go TLS related logics due to %+v", err) return nil } elff, err := elf.Open(path) if err != nil { - log.Debugf("skip go TLS related logics due to %s", err) + log.Debugf("skip go TLS related logics due to %+v", err) return nil } exc, err := link.OpenExecutable(path) if err != nil { - log.Warnf("skip go TLS related logics due to %s", err) + log.DWarnf("skip go TLS related logics due to open elf file failed: %+v", err) return nil } - retOffsets, err := gosym.GetGoFuncRetOffsetsFromELF(elff, goTLSSymbolWriteKeyLog) + + var symbolOffset uint64 + var retOffsets []uint64 + retOffsets, err = gosym.GetFuncRetOffsetsViaSymbolTable(elff, goTLSSymbolWriteKeyLog) if err == nil && len(retOffsets) == 0 { err = errors.New("not found any RET instruction") } if err != nil { - log.Warnf("skip go TLS related logics due to %s", err) + log.Infof("get offsets via symbol table failed: %+v", err) + symbolOffset, retOffsets, err = gosym.GetFuncRetOffsetsViaPclntab(path, elff, goTLSSymbolWriteKeyLog) + } + if err == nil && len(retOffsets) == 0 { + err = errors.New("not found any RET instruction") + } + if err != nil { + log.DWarnf("skip go TLS related logics due to parse elf failed: %s", err) return nil } + retOffset := retOffsets[len(retOffsets)-1] - log.Infof("got retOffsets: %v, will attach at ret offset: %d", retOffsets, retOffset) + log.Infof("got symbolOffset: %d, got retOffsets: %v, will attach at ret offset: %d", + symbolOffset, retOffsets, retOffset) if err := bf.AttachGoTLSUprobeHooks(exc, goTLSSymbolWriteKeyLog, - 0, retOffset, 0); err != nil { - log.Warnf("skip go TLS related logics due to could not attach go TLS hooks base on %s: %s", path, err) + symbolOffset, retOffset, 0); err != nil { + log.DWarnf( + "skip go TLS related logics due to could not attach go TLS hooks base on %s: %+v", path, err) } return nil } diff --git a/go.mod b/go.mod index 37f44707..0d585739 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( ) require ( + github.com/mandiant/GoReSym v1.7.2-0.20240819162932-534ca84b42d5 github.com/smira/go-xz v0.1.0 github.com/stretchr/testify v1.9.0 golang.org/x/arch v0.10.0 @@ -29,6 +30,7 @@ require ( github.com/containerd/typeurl v1.0.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/elliotchance/orderedmap v1.4.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/runc v1.1.14 // indirect @@ -37,6 +39,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apimachinery v0.31.0-alpha.3 // indirect k8s.io/apiserver v0.26.2 // indirect + rsc.io/binaryregexp v0.2.0 // indirect ) require ( @@ -83,7 +86,7 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect + golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/text v0.16.0 // indirect diff --git a/go.sum b/go.sum index 5e362e0f..94b026dc 100644 --- a/go.sum +++ b/go.sum @@ -94,6 +94,8 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A= +github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -212,6 +214,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mandiant/GoReSym v1.7.2-0.20240819162932-534ca84b42d5 h1:OyxMVWG+V2gzLNCXfLGyze3zN9Zbi2CKtAlCWtS0L64= +github.com/mandiant/GoReSym v1.7.2-0.20240819162932-534ca84b42d5/go.mod h1:C9Cyl7dQTqNzm5KyrZ78bS54bzwMd1fu3cWDWULCzLc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= @@ -364,8 +368,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= -golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= +golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -569,3 +573,5 @@ k8s.io/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20230824000246-2cb31c9333ad k8s.io/kubernetes/staging/src/k8s.io/cri-api v0.0.0-20230824000246-2cb31c9333ad/go.mod h1:92B+ezOsw1+IWrnyKuKTKb9ioXD7xacrEml1MI6lv2I= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/internal/gosym/offset.go b/internal/gosym/offset.go index 74d315bd..d52fb813 100644 --- a/internal/gosym/offset.go +++ b/internal/gosym/offset.go @@ -4,6 +4,7 @@ import ( "debug/elf" "errors" "fmt" + "github.com/mozillazg/ptcpdump/internal/log" "golang.org/x/arch/arm64/arm64asm" "golang.org/x/arch/x86/x86asm" @@ -11,7 +12,8 @@ import ( const arm64InstructionLen = 4 -func GetGoFuncRetOffsetsFromELF(f *elf.File, symbolName string) ([]uint64, error) { +func GetFuncRetOffsetsViaSymbolTable(f *elf.File, symbolName string) ([]uint64, error) { + log.Info("start to get ret offsets via symbol table") syms, err := f.Symbols() if err != nil && !errors.Is(err, elf.ErrNoSymbols) { return nil, err @@ -43,11 +45,12 @@ func GetGoFuncRetOffsetsFromELF(f *elf.File, symbolName string) ([]uint64, error symbol = s break } + log.Infof("textSec.Addr: %d, %#v", textSec.Addr, textSec) start := symbolAddr - textSec.Addr symbolData := make([]byte, symbol.Size) if _, err := textSec.ReadAt(symbolData, int64(start)); err != nil { - return nil, err + return nil, fmt.Errorf("read text section: %w", err) } switch f.FileHeader.Machine { case elf.EM_X86_64: @@ -59,6 +62,42 @@ func GetGoFuncRetOffsetsFromELF(f *elf.File, symbolName string) ([]uint64, error return nil, fmt.Errorf("symbol %q not found", symbolName) } +func GetFuncRetOffsetsViaPclntab(fpath string, f *elf.File, symbolName string) ( + symbolOffset uint64, retOffsets []uint64, err error) { + log.Info("start to get ret offsets via pclntab") + textSec := f.Section(".text") + if textSec == nil { + return 0, nil, errors.New("no .text section") + } + log.Infof("textSec.Addr: %d, %#v", textSec.Addr, textSec) + + meta, err := getFuncMetadataViaPclntab(fpath, symbolName) + if err != nil { + return 0, nil, + fmt.Errorf("could not get metadata for %q via pclntab: %v", symbolName, err) + } + + symbolAddr := meta.Start + symbolSize := meta.End - symbolAddr + start := symbolAddr - textSec.Addr + symbolData := make([]byte, symbolSize) + if _, err := textSec.ReadAt(symbolData, int64(start)); err != nil { + return 0, nil, fmt.Errorf("read text section: %w", err) + } + symbolOffset = symbolAddr - textSec.Addr + textSec.Offset + + switch f.FileHeader.Machine { + case elf.EM_X86_64: + retOffsets, err = findAMD64RetInstructions(symbolData) + return + case elf.EM_AARCH64: + retOffsets, err = findARM64RetInstructions(symbolData) + return + } + + return 0, nil, fmt.Errorf("symbol %q not found", symbolName) +} + func findAMD64RetInstructions(data []byte) ([]uint64, error) { var retOffsets []uint64 var cursor int diff --git a/internal/gosym/pclntab.go b/internal/gosym/pclntab.go new file mode 100644 index 00000000..6be1e5b1 --- /dev/null +++ b/internal/gosym/pclntab.go @@ -0,0 +1,104 @@ +package gosym + +import ( + "fmt" + "github.com/mandiant/GoReSym/objfile" +) + +type pcLnTabMetadata struct { + VA uint64 + Version string + Endianess string + CpuQuantum uint32 + CpuQuantumStr string + PointerSize uint32 +} + +type funcMetadata struct { + Start uint64 + End uint64 + PackageName string + FullName string +} + +type extractMetadata struct { + Version string + TabMeta pcLnTabMetadata + Func funcMetadata +} + +func getFuncMetadataViaPclntab(fileName string, symbolName string) (*funcMetadata, error) { + metadata := extractMetadata{} + file, err := objfile.Open(fileName) + if err != nil { + return nil, fmt.Errorf("invalid file: %w", err) + } + + var knownPclntabVA = uint64(0) + var knownGoTextBase = uint64(0) +restartParseWithRealTextBase: + tabs, err := file.PCLineTable("", knownPclntabVA, knownGoTextBase) + if err != nil { + return nil, fmt.Errorf("failed to read pclntab: %w", err) + } + + if len(tabs) == 0 { + return nil, fmt.Errorf("no pclntab candidates found") + } + + var moduleData *objfile.ModuleData = nil + var finalTab *objfile.PclntabCandidate = &tabs[0] + for _, tab := range tabs { + metadata.TabMeta.VA = tab.PclntabVA + metadata.TabMeta.Version = tab.ParsedPclntab.Go12line.Version.String() + metadata.TabMeta.Endianess = tab.ParsedPclntab.Go12line.Binary.String() + metadata.TabMeta.PointerSize = tab.ParsedPclntab.Go12line.Ptrsize + + // this can be a little tricky to locate and parse properly across all go versions + // since moduledata holds a pointer to the pclntab, we can (hopefully) find the right candidate by using it to find the moduledata. + // if that location works, then we must have given it the correct pclntab VA. At least in theory... + // The resolved offsets within the pclntab might have used the wrong base though! We'll fix that later. + _, tmpModData, err := file.ModuleDataTable(tab.PclntabVA, metadata.Version, metadata.TabMeta.Version, metadata.TabMeta.PointerSize == 8, metadata.TabMeta.Endianess == "LittleEndian") + if err == nil && tmpModData != nil { + // if the search candidate relied on a moduledata va, make sure it lines up with ours now + stomppedMagicMetaConstraintsValid := true + if tab.StompMagicCandidateMeta != nil { + stomppedMagicMetaConstraintsValid = tab.StompMagicCandidateMeta.SuspectedModuleDataVa == tmpModData.VA + } + + if knownGoTextBase == 0 && knownPclntabVA == 0 && stomppedMagicMetaConstraintsValid { + // assign real base and restart pclntab parsing with correct VAs! + knownGoTextBase = tmpModData.TextVA + knownPclntabVA = tab.PclntabVA + goto restartParseWithRealTextBase + } + + // we already have pclntab candidates with the right VA, but which candidate?? The one that finds a valid moduledata! + finalTab = &tab + moduleData = tmpModData + break + } + } + + // to be sure we got the right pclntab we had to have found a moduledat as well. If we didn't, then we failed to find the pclntab (correctly) as well + if moduleData == nil { + return nil, fmt.Errorf("no valid pclntab or moduledata found") + } + + for _, elem := range finalTab.ParsedPclntab.Funcs { + if !(elem.Name == symbolName) { + continue + } + metadata.Func = funcMetadata{ + Start: elem.Entry, + End: elem.End, + PackageName: elem.PackageName(), + FullName: elem.Name, + } + } + if metadata.Func.Start == 0 { + return nil, fmt.Errorf("not found symbol %q", symbolName) + } + + return &metadata.Func, nil +} diff --git a/internal/log/log.go b/internal/log/log.go index 50acdd30..6be52c54 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -50,11 +50,11 @@ func Debugf(format string, v ...any) { } func Info(msg string) { - defaultLogger.Info().Msg(msg) + debugLogger.Info().Msg(msg) } func Infof(format string, v ...any) { - defaultLogger.Info().Msgf(format, v...) + debugLogger.Info().Msgf(format, v...) } func Warn(msg string) { @@ -65,6 +65,14 @@ func Warnf(format string, v ...any) { defaultLogger.Warn().Msgf(format, v...) } +func DWarnf(format string, v ...any) { + debugLogger.Warn().Msgf(format, v...) +} + +func DWarn(format string) { + debugLogger.Warn().Msg(format) +} + func Error(msg string) { debugLogger.Error().Msg(msg) } diff --git a/testdata/gohttpapp/Makefile b/testdata/gohttpapp/Makefile index afaa6ecc..11dfc9e0 100644 --- a/testdata/gohttpapp/Makefile +++ b/testdata/gohttpapp/Makefile @@ -4,3 +4,6 @@ .PHONY: build build: go build -o gohttpapp main.go + go build -buildmode=pie -o gohttpapp_pie main.go + go build -ldflags="-s -w" -trimpath -o gohttpapp_stripped main.go + go build -buildmode=pie -ldflags="-s -w" -trimpath -o gohttpapp_stripped_pie main.go diff --git a/testdata/test_gotls_keylog_pie.sh b/testdata/test_gotls_keylog_pie.sh new file mode 100644 index 00000000..b1c9978d --- /dev/null +++ b/testdata/test_gotls_keylog_pie.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -xe + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" +CMD="$1" +APP="${SCRIPT_DIR}/gohttpapp/gohttpapp_pie" +FILE_PREFIX="/tmp/ptcpdump" +KEYLOG_PATH="${FILE_PREFIX}_keylog_pie.txt" +PCAP_FILE="${FILE_PREFIX}_keylog_pie.pcap" +PCAPNG_FILE="${FILE_PREFIX}_keylog_pie.pcapng" + +function test_keylog_to_file() { + ${CMD} -i any --write-keylog-file ${KEYLOG_PATH} -w ${PCAP_FILE} -- ${APP} + cat ${KEYLOG_PATH} + tshark -r ${PCAP_FILE} -o tls.keylog_file:${KEYLOG_PATH} | grep "GET /foo/bar HTTP/1.1" +} + +function test_keylog_to_pcapng() { + ${CMD} -i any --embed-keylog-to-pcapng -w ${PCAPNG_FILE} -- ${APP} + tshark -r ${PCAPNG_FILE} | grep "GET /foo/bar HTTP/1.1" +} + +function main() { + test_keylog_to_file + test_keylog_to_pcapng +} + +main diff --git a/testdata/test_gotls_keylog_stripped.sh b/testdata/test_gotls_keylog_stripped.sh new file mode 100644 index 00000000..92c7fbee --- /dev/null +++ b/testdata/test_gotls_keylog_stripped.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -xe + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" +CMD="$1" +APP="${SCRIPT_DIR}/gohttpapp/gohttpapp_stripped" +FILE_PREFIX="/tmp/ptcpdump" +KEYLOG_PATH="${FILE_PREFIX}_keylog_stripped.txt" +PCAP_FILE="${FILE_PREFIX}_keylog_stripped.pcap" +PCAPNG_FILE="${FILE_PREFIX}_keylog_stripped.pcapng" + +function test_keylog_to_file() { + ${CMD} -i any --write-keylog-file ${KEYLOG_PATH} -w ${PCAP_FILE} -- ${APP} + cat ${KEYLOG_PATH} + tshark -r ${PCAP_FILE} -o tls.keylog_file:${KEYLOG_PATH} | grep "GET /foo/bar HTTP/1.1" +} + +function test_keylog_to_pcapng() { + ${CMD} -i any --embed-keylog-to-pcapng -w ${PCAPNG_FILE} -- ${APP} + tshark -r ${PCAPNG_FILE} | grep "GET /foo/bar HTTP/1.1" +} + +function main() { + test_keylog_to_file + test_keylog_to_pcapng +} + +main diff --git a/testdata/test_gotls_keylog_stripped_pie.sh b/testdata/test_gotls_keylog_stripped_pie.sh new file mode 100644 index 00000000..fa1f2fea --- /dev/null +++ b/testdata/test_gotls_keylog_stripped_pie.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -xe + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" +CMD="$1" +APP="${SCRIPT_DIR}/gohttpapp/gohttpapp_stripped_pie" +FILE_PREFIX="/tmp/ptcpdump" +KEYLOG_PATH="${FILE_PREFIX}_keylog_stripped_pie.txt" +PCAP_FILE="${FILE_PREFIX}_keylog_stripped_pie.pcap" +PCAPNG_FILE="${FILE_PREFIX}_keylog_stripped_pie.pcapng" + +function test_keylog_to_file() { + ${CMD} -i any --write-keylog-file ${KEYLOG_PATH} -w ${PCAP_FILE} -- ${APP} + cat ${KEYLOG_PATH} + tshark -r ${PCAP_FILE} -o tls.keylog_file:${KEYLOG_PATH} | grep "GET /foo/bar HTTP/1.1" +} + +function test_keylog_to_pcapng() { + ${CMD} -i any --embed-keylog-to-pcapng -w ${PCAPNG_FILE} -- ${APP} + tshark -r ${PCAPNG_FILE} | grep "GET /foo/bar HTTP/1.1" +} + +function main() { + test_keylog_to_file + test_keylog_to_pcapng +} + +main diff --git a/vendor/github.com/elliotchance/orderedmap/.editorconfig b/vendor/github.com/elliotchance/orderedmap/.editorconfig new file mode 100644 index 00000000..6b86d807 --- /dev/null +++ b/vendor/github.com/elliotchance/orderedmap/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.go] +indent_style = tab +indent_size = 4 +max_line_length = 80 diff --git a/vendor/github.com/elliotchance/orderedmap/.gitignore b/vendor/github.com/elliotchance/orderedmap/.gitignore new file mode 100644 index 00000000..a09c56df --- /dev/null +++ b/vendor/github.com/elliotchance/orderedmap/.gitignore @@ -0,0 +1 @@ +/.idea diff --git a/vendor/github.com/elliotchance/orderedmap/.travis.yml b/vendor/github.com/elliotchance/orderedmap/.travis.yml new file mode 100644 index 00000000..a336fc90 --- /dev/null +++ b/vendor/github.com/elliotchance/orderedmap/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - 1.11.x + - 1.12.x + - master + +script: + - env GO111MODULE=on go test diff --git a/vendor/github.com/elliotchance/orderedmap/LICENSE b/vendor/github.com/elliotchance/orderedmap/LICENSE new file mode 100644 index 00000000..852bb97f --- /dev/null +++ b/vendor/github.com/elliotchance/orderedmap/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Elliot Chance + +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. diff --git a/vendor/github.com/elliotchance/orderedmap/README.md b/vendor/github.com/elliotchance/orderedmap/README.md new file mode 100644 index 00000000..b9238368 --- /dev/null +++ b/vendor/github.com/elliotchance/orderedmap/README.md @@ -0,0 +1,102 @@ +# 🔃 github.com/elliotchance/orderedmap [![GoDoc](https://godoc.org/github.com/elliotchance/orderedmap?status.svg)](https://godoc.org/github.com/elliotchance/orderedmap) [![Build Status](https://travis-ci.org/elliotchance/orderedmap.svg?branch=master)](https://travis-ci.org/elliotchance/orderedmap) + +## Installation + +```bash +go get -u github.com/elliotchance/orderedmap +``` + +## Basic Usage + +An `*OrderedMap` is a high performance ordered map that maintains amortized O(1) +for `Set`, `Get`, `Delete` and `Len`: + +```go +m := orderedmap.NewOrderedMap() + +m.Set("foo", "bar") +m.Set("qux", 1.23) +m.Set(123, true) + +m.Delete("qux") +``` + +Internally an `*OrderedMap` uses a combination of a map and linked list. + +## Iterating + +Be careful using `Keys()` as it will create a copy of all of the keys so it's +only suitable for a small number of items: + +```go +for _, key := range m.Keys() { + value, _:= m.Get(key) + fmt.Println(key, value) +} +``` + +For larger maps you should use `Front()` or `Back()` to iterate per element: + +```go +// Iterate through all elements from oldest to newest: +for el := m.Front(); el != nil; el = el.Next() { + fmt.Println(el.Key, el.Value) +} + +// You can also use Back and Prev to iterate in reverse: +for el := m.Back(); el != nil; el = el.Prev() { + fmt.Println(el.Key, el.Value) +} +``` + +The iterator is safe to use bidirectionally, and will return `nil` once it goes +beyond the first or last item. + +If the map is changing while the iteration is in-flight it may produce +unexpected behavior. + +## Performance + +CPU: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz + +RAM: 8GB + +System: Windows 10 + +```shell +$go test -benchmem -run=^$ github.com/elliotchance/orderedmap -bench BenchmarkAll +``` + +map[int]bool + +| | map | orderedmap | +| ------- | ------------------- | ------------------- | +| set | 198 ns/op, 44 B/op | 722 ns/op, 211 B/op | +| get | 18 ns/op, 0 B/op | 37.3 ns/op, 0 B/op | +| delete | 888 ns/op, 211 B/op | 280 ns/op, 44 B/op | +| Iterate | 206 ns/op, 44 B/op | 693 ns/op, 259 B/op | + +map[string]bool(PS : Use strconv.Itoa()) + +| | map | orderedmap | +| ----------- | ------------------- | ----------------------- | +| set | 421 ns/op, 86 B/op | 1048 ns/op, 243 B/op | +| get | 81.1 ns/op, 2 B/op | 97.8 ns/op, 2 B/op | +| delete | 737 ns/op, 122 B/op | 1188 ns/op, 251 B/op | +| Iterate all | 14706 ns/op, 1 B/op | 52671 ns/op, 16391 B/op | + +Big map[int]bool (10000000 keys) + +| | map | orderedmap | +| ----------- | -------------------------------- | ------------------------------- | +| set all | 1.834559 s/op, 423.9470291 MB/op | 7.5564667 s/op, 1784.1483 MB/op | +| get all | 2.6367878 s/op, 423.9698 MB/op | 9.0232475 s/op, 1784.1086 MB/op | +| Iterate all | 1.9526784 s/op, 423.9042 MB/op | 8.2495265 s/op, 1936.7619 MB/op | + +Big map[string]bool (10000000 keys) + +| | map | orderedmap | +| ----------- | --------------------------------- | ----------------------------------- | +| set all | 4.8893923 s/op, 921.33435 MB/op | 10.4405527 s/op, 2089.0144 MB/op | +| get all | 7.122791 s/op, 997.3802643 MB/op | 13.2613692 s/op, 2165.09521 MB/op | +| Iterate all | 5.1688922 s/op, 921.4619293 MB/op | 12.6623711 s/op, 2241.5272064 MB/op | diff --git a/vendor/github.com/elliotchance/orderedmap/element.go b/vendor/github.com/elliotchance/orderedmap/element.go new file mode 100644 index 00000000..08bf2b22 --- /dev/null +++ b/vendor/github.com/elliotchance/orderedmap/element.go @@ -0,0 +1,33 @@ +package orderedmap + +import "container/list" + +type Element struct { + Key, Value interface{} + + element *list.Element +} + +func newElement(e *list.Element) *Element { + if e == nil { + return nil + } + + element := e.Value.(*orderedMapElement) + + return &Element{ + element: e, + Key: element.key, + Value: element.value, + } +} + +// Next returns the next element, or nil if it finished. +func (e *Element) Next() *Element { + return newElement(e.element.Next()) +} + +// Prev returns the previous element, or nil if it finished. +func (e *Element) Prev() *Element { + return newElement(e.element.Prev()) +} diff --git a/vendor/github.com/elliotchance/orderedmap/orderedmap.go b/vendor/github.com/elliotchance/orderedmap/orderedmap.go new file mode 100644 index 00000000..a8488db5 --- /dev/null +++ b/vendor/github.com/elliotchance/orderedmap/orderedmap.go @@ -0,0 +1,150 @@ +package orderedmap + +import "container/list" + +type orderedMapElement struct { + key, value interface{} +} + +type OrderedMap struct { + kv map[interface{}]*list.Element + ll *list.List +} + +func NewOrderedMap() *OrderedMap { + return &OrderedMap{ + kv: make(map[interface{}]*list.Element), + ll: list.New(), + } +} + +// Get returns the value for a key. If the key does not exist, the second return +// parameter will be false and the value will be nil. +func (m *OrderedMap) Get(key interface{}) (interface{}, bool) { + value, ok := m.kv[key] + if ok { + return value.Value.(*orderedMapElement).value, true + } + + return nil, false +} + +// Set will set (or replace) a value for a key. If the key was new, then true +// will be returned. The returned value will be false if the value was replaced +// (even if the value was the same). +func (m *OrderedMap) Set(key, value interface{}) bool { + _, didExist := m.kv[key] + + if !didExist { + element := m.ll.PushBack(&orderedMapElement{key, value}) + m.kv[key] = element + } else { + m.kv[key].Value.(*orderedMapElement).value = value + } + + return !didExist +} + +// GetOrDefault returns the value for a key. If the key does not exist, returns +// the default value instead. +func (m *OrderedMap) GetOrDefault(key, defaultValue interface{}) interface{} { + if value, ok := m.kv[key]; ok { + return value.Value.(*orderedMapElement).value + } + + return defaultValue +} + +// GetElement returns the element for a key. If the key does not exist, the +// pointer will be nil. +func (m *OrderedMap) GetElement(key interface{}) *Element { + value, ok := m.kv[key] + if ok { + element := value.Value.(*orderedMapElement) + return &Element{ + element: value, + Key: element.key, + Value: element.value, + } + } + + return nil +} + +// Len returns the number of elements in the map. +func (m *OrderedMap) Len() int { + return len(m.kv) +} + +// Keys returns all of the keys in the order they were inserted. If a key was +// replaced it will retain the same position. To ensure most recently set keys +// are always at the end you must always Delete before Set. +func (m *OrderedMap) Keys() (keys []interface{}) { + keys = make([]interface{}, m.Len()) + + element := m.ll.Front() + for i := 0; element != nil; i++ { + keys[i] = element.Value.(*orderedMapElement).key + element = element.Next() + } + + return keys +} + +// Delete will remove a key from the map. It will return true if the key was +// removed (the key did exist). +func (m *OrderedMap) Delete(key interface{}) (didDelete bool) { + element, ok := m.kv[key] + if ok { + m.ll.Remove(element) + delete(m.kv, key) + } + + return ok +} + +// Front will return the element that is the first (oldest Set element). If +// there are no elements this will return nil. +func (m *OrderedMap) Front() *Element { + front := m.ll.Front() + if front == nil { + return nil + } + + element := front.Value.(*orderedMapElement) + + return &Element{ + element: front, + Key: element.key, + Value: element.value, + } +} + +// Back will return the element that is the last (most recent Set element). If +// there are no elements this will return nil. +func (m *OrderedMap) Back() *Element { + back := m.ll.Back() + if back == nil { + return nil + } + + element := back.Value.(*orderedMapElement) + + return &Element{ + element: back, + Key: element.key, + Value: element.value, + } +} + +// Copy returns a new OrderedMap with the same elements. +// Using Copy while there are concurrent writes may mangle the result. +func (m *OrderedMap) Copy() *OrderedMap { + m2 := NewOrderedMap() + + for el := m.Front(); el != nil; el = el.Next() { + m2.Set(el.Key, el.Value) + } + + return m2 +} diff --git a/vendor/github.com/mandiant/GoReSym/LICENSE b/vendor/github.com/mandiant/GoReSym/LICENSE new file mode 100644 index 00000000..0a232e7e --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 MANDIANT + +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. diff --git a/vendor/github.com/mandiant/GoReSym/archive/archive.go b/vendor/github.com/mandiant/GoReSym/archive/archive.go new file mode 100644 index 00000000..0736c48d --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/archive/archive.go @@ -0,0 +1,487 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Package archive implements reading of archive files generated by the Go +// toolchain. +package archive + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "log" + "os" + "strconv" + "strings" + "time" + "unicode/utf8" + + "github.com/mandiant/GoReSym/bio" + "github.com/mandiant/GoReSym/goobj" +) + +/* +The archive format is: + +First, on a line by itself + ! + +Then zero or more file records. Each file record has a fixed-size one-line header +followed by data bytes followed by an optional padding byte. The header is: + + %-16s%-12d%-6d%-6d%-8o%-10d` + name mtime uid gid mode size + +(note the trailing backquote). The %-16s here means at most 16 *bytes* of +the name, and if shorter, space padded on the right. +*/ + +// 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 +} + +type Archive struct { + f *os.File + Entries []Entry +} + +func (a *Archive) File() *os.File { return a.f } + +type Entry struct { + Name string + Type EntryType + Mtime int64 + Uid int + Gid int + Mode os.FileMode + Data + Obj *GoObj // nil if this entry is not a Go object file +} + +type EntryType int + +const ( + EntryPkgDef EntryType = iota + EntryGoObj + EntryNativeObj + EntrySentinelNonObj +) + +func (e *Entry) String() string { + return fmt.Sprintf("%s %6d/%-6d %12d %s %s", + (e.Mode & 0777).String(), + e.Uid, + e.Gid, + e.Size, + time.Unix(e.Mtime, 0).Format(timeFormat), + e.Name) +} + +type GoObj struct { + TextHeader []byte + Arch string + Data +} + +const ( + entryHeader = "%s%-12d%-6d%-6d%-8o%-10d`\n" + // In entryHeader the first entry, the name, is always printed as 16 bytes right-padded. + entryLen = 16 + 12 + 6 + 6 + 8 + 10 + 1 + 1 + timeFormat = "Jan _2 15:04 2006" +) + +var ( + archiveHeader = []byte("!\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 { + a *Archive + b *bio.Reader + err error + offset int64 + limit int64 + tmp [256]byte +} + +func (r *objReader) init(f *os.File) { + r.a = &Archive{f, nil} + r.offset, _ = f.Seek(0, io.SeekCurrent) + r.limit, _ = f.Seek(0, io.SeekEnd) + f.Seek(r.offset, io.SeekStart) + r.b = bio.NewReader(f) +} + +// 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 +} + +// peek returns the next n bytes without advancing the reader. +func (r *objReader) peek(n int) ([]byte, error) { + if r.err != nil { + return nil, r.err + } + if r.offset >= r.limit { + r.error(io.ErrUnexpectedEOF) + return nil, r.err + } + b, err := r.b.Peek(n) + if err != nil { + if err != bufio.ErrBufferFull { + r.error(err) + } + } + return b, 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 +} + +// 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. + r.b.MustSeek(r.offset+n, io.SeekStart) + r.offset += n + } +} + +// New writes to f to make a new archive. +func New(f *os.File) (*Archive, error) { + _, err := f.Write(archiveHeader) + if err != nil { + return nil, err + } + return &Archive{f: f}, nil +} + +// Parse parses an object file or archive from f. +func Parse(f *os.File, verbose bool) (*Archive, error) { + var r objReader + r.init(f) + t, err := r.peek(8) + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return nil, err + } + + switch { + default: + return nil, errNotObject + + case bytes.Equal(t, archiveHeader): + if err := r.parseArchive(verbose); err != nil { + return nil, err + } + case bytes.Equal(t, goobjHeader): + off := r.offset + o := &GoObj{} + if err := r.parseObject(o, r.limit-off); err != nil { + return nil, err + } + r.a.Entries = []Entry{{ + Name: f.Name(), + Type: EntryGoObj, + Data: Data{off, r.limit - off}, + Obj: o, + }} + } + + return r.a, 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. +func (r *objReader) parseArchive(verbose bool) error { + r.readFull(r.tmp[:8]) // consume header (already checked) + 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, unless in verbose mode. + // 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]) + var err error + get := func(start, end, base, bitsize int) int64 { + if err != nil { + return 0 + } + var v int64 + v, err = strconv.ParseInt(trimSpace(data[start:end]), base, bitsize) + return v + } + size := get(48, 58, 10, 64) + var ( + mtime int64 + uid, gid int + mode os.FileMode + ) + if verbose { + mtime = get(16, 28, 10, 64) + uid = int(get(28, 34, 10, 32)) + gid = int(get(34, 40, 10, 32)) + mode = os.FileMode(get(40, 48, 8, 32)) + } + if err != nil { + return errCorruptArchive + } + data = data[60:] + fsize := size + size&1 + if fsize < 0 || fsize < size { + return errCorruptArchive + } + switch name { + case "__.PKGDEF": + r.a.Entries = append(r.a.Entries, Entry{ + Name: name, + Type: EntryPkgDef, + Mtime: mtime, + Uid: uid, + Gid: gid, + Mode: mode, + Data: Data{r.offset, size}, + }) + r.skip(size) + case "preferlinkext", "dynimportfail": + if size == 0 { + // These are not actual objects, but rather sentinel + // entries put into the archive by the Go command to + // be read by the linker. See #62036. + r.a.Entries = append(r.a.Entries, Entry{ + Name: name, + Type: EntrySentinelNonObj, + Mtime: mtime, + Uid: uid, + Gid: gid, + Mode: mode, + Data: Data{r.offset, size}, + }) + break + } + fallthrough + default: + var typ EntryType + var o *GoObj + offset := r.offset + p, err := r.peek(8) + if err != nil { + return err + } + if bytes.Equal(p, goobjHeader) { + typ = EntryGoObj + o = &GoObj{} + r.parseObject(o, size) + } else { + typ = EntryNativeObj + r.skip(size) + } + r.a.Entries = append(r.a.Entries, Entry{ + Name: name, + Type: typ, + Mtime: mtime, + Uid: uid, + Gid: gid, + Mode: mode, + Data: Data{offset, size}, + Obj: o, + }) + } + if size&1 != 0 { + r.skip(1) + } + } + return nil +} + +// parseObject parses a single Go 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(o *GoObj, size int64) error { + h := make([]byte, 0, 256) + 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 + } + } + o.TextHeader = h + hs := strings.Fields(string(h)) + if len(hs) >= 4 { + o.Arch = hs[3] + } + o.Offset = r.offset + o.Size = size - int64(len(h)) + + p, err := r.peek(8) + if err != nil { + return err + } + if !bytes.Equal(p, []byte(goobj.Magic)) { + return r.error(errCorruptObject) + } + r.skip(o.Size) + return nil +} + +// AddEntry adds an entry to the end of a, with the content from r. +func (a *Archive) AddEntry(typ EntryType, name string, mtime int64, uid, gid int, mode os.FileMode, size int64, r io.Reader) { + off, err := a.f.Seek(0, io.SeekEnd) + if err != nil { + log.Fatal(err) + } + n, err := fmt.Fprintf(a.f, entryHeader, exactly16Bytes(name), mtime, uid, gid, mode, size) + if err != nil || n != entryLen { + log.Fatal("writing entry header: ", err) + } + n1, _ := io.CopyN(a.f, r, size) + if n1 != size { + log.Fatal(err) + } + if (off+size)&1 != 0 { + a.f.Write([]byte{0}) // pad to even byte + } + a.Entries = append(a.Entries, Entry{ + Name: name, + Type: typ, + Mtime: mtime, + Uid: uid, + Gid: gid, + Mode: mode, + Data: Data{off + entryLen, size}, + }) +} + +// exactly16Bytes truncates the string if necessary so it is at most 16 bytes long, +// then pads the result with spaces to be exactly 16 bytes. +// Fmt uses runes for its width calculation, but we need bytes in the entry header. +func exactly16Bytes(s string) string { + for len(s) > 16 { + _, wid := utf8.DecodeLastRuneInString(s) + s = s[:len(s)-wid] + } + const sixteenSpaces = " " + s += sixteenSpaces[:16-len(s)] + return s +} diff --git a/vendor/github.com/mandiant/GoReSym/bio/buf.go b/vendor/github.com/mandiant/GoReSym/bio/buf.go new file mode 100644 index 00000000..c4c25149 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/bio/buf.go @@ -0,0 +1,148 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bio implements common I/O abstractions used within the Go toolchain. +package bio + +import ( + "bufio" + "io" + "log" + "os" +) + +// Reader implements a seekable buffered io.Reader. +type Reader struct { + f *os.File + *bufio.Reader +} + +// Writer implements a seekable buffered io.Writer. +type Writer struct { + f *os.File + *bufio.Writer +} + +// Create creates the file named name and returns a Writer +// for that file. +func Create(name string) (*Writer, error) { + f, err := os.Create(name) + if err != nil { + return nil, err + } + return &Writer{f: f, Writer: bufio.NewWriter(f)}, nil +} + +// Open returns a Reader for the file named name. +func Open(name string) (*Reader, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + return NewReader(f), nil +} + +// NewReader returns a Reader from an open file. +func NewReader(f *os.File) *Reader { + return &Reader{f: f, Reader: bufio.NewReader(f)} +} + +func (r *Reader) MustSeek(offset int64, whence int) int64 { + if whence == 1 { + offset -= int64(r.Buffered()) + } + off, err := r.f.Seek(offset, whence) + if err != nil { + log.Fatalf("seeking in output: %v", err) + } + r.Reset(r.f) + return off +} + +func (w *Writer) MustSeek(offset int64, whence int) int64 { + if err := w.Flush(); err != nil { + log.Fatalf("writing output: %v", err) + } + off, err := w.f.Seek(offset, whence) + if err != nil { + log.Fatalf("seeking in output: %v", err) + } + return off +} + +func (r *Reader) Offset() int64 { + off, err := r.f.Seek(0, 1) + if err != nil { + log.Fatalf("seeking in output [0, 1]: %v", err) + } + off -= int64(r.Buffered()) + return off +} + +func (w *Writer) Offset() int64 { + if err := w.Flush(); err != nil { + log.Fatalf("writing output: %v", err) + } + off, err := w.f.Seek(0, 1) + if err != nil { + log.Fatalf("seeking in output [0, 1]: %v", err) + } + return off +} + +func (r *Reader) Close() error { + return r.f.Close() +} + +func (w *Writer) Close() error { + err := w.Flush() + err1 := w.f.Close() + if err == nil { + err = err1 + } + return err +} + +func (r *Reader) File() *os.File { + return r.f +} + +func (w *Writer) File() *os.File { + return w.f +} + +// Slice reads the next length bytes of r into a slice. +// +// This slice may be backed by mmap'ed memory. Currently, this memory +// will never be unmapped. The second result reports whether the +// backing memory is read-only. +func (r *Reader) Slice(length uint64) ([]byte, bool, error) { + if length == 0 { + return []byte{}, false, nil + } + + data, ok := r.sliceOS(length) + if ok { + return data, true, nil + } + + data = make([]byte, length) + _, err := io.ReadFull(r, data) + if err != nil { + return nil, false, err + } + return data, false, nil +} + +// SliceRO returns a slice containing the next length bytes of r +// backed by a read-only mmap'd data. If the mmap cannot be +// established (limit exceeded, region too small, etc) a nil slice +// will be returned. If mmap succeeds, it will never be unmapped. +func (r *Reader) SliceRO(length uint64) []byte { + data, ok := r.sliceOS(length) + if ok { + return data + } + return nil +} diff --git a/vendor/github.com/mandiant/GoReSym/bio/buf_mmap.go b/vendor/github.com/mandiant/GoReSym/bio/buf_mmap.go new file mode 100644 index 00000000..4b43d74f --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/bio/buf_mmap.go @@ -0,0 +1,62 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd + +package bio + +import ( + "runtime" + "sync/atomic" + "syscall" +) + +// mmapLimit is the maximum number of mmaped regions to create before +// falling back to reading into a heap-allocated slice. This exists +// because some operating systems place a limit on the number of +// distinct mapped regions per process. As of this writing: +// +// Darwin unlimited +// DragonFly 1000000 (vm.max_proc_mmap) +// FreeBSD unlimited +// Linux 65530 (vm.max_map_count) // TODO: query /proc/sys/vm/max_map_count? +// NetBSD unlimited +// OpenBSD unlimited +var mmapLimit int32 = 1<<31 - 1 + +func init() { + // Linux is the only practically concerning OS. + if runtime.GOOS == "linux" { + mmapLimit = 30000 + } +} + +func (r *Reader) sliceOS(length uint64) ([]byte, bool) { + // For small slices, don't bother with the overhead of a + // mapping, especially since we have no way to unmap it. + const threshold = 16 << 10 + if length < threshold { + return nil, false + } + + // Have we reached the mmap limit? + if atomic.AddInt32(&mmapLimit, -1) < 0 { + atomic.AddInt32(&mmapLimit, 1) + return nil, false + } + + // Page-align the offset. + off := r.Offset() + align := syscall.Getpagesize() + aoff := off &^ int64(align-1) + + data, err := syscall.Mmap(int(r.f.Fd()), aoff, int(length+uint64(off-aoff)), syscall.PROT_READ, syscall.MAP_SHARED|syscall.MAP_FILE) + if err != nil { + return nil, false + } + + data = data[off-aoff:] + r.MustSeek(int64(length), 1) + return data, true +} diff --git a/vendor/github.com/mandiant/GoReSym/bio/buf_nommap.go b/vendor/github.com/mandiant/GoReSym/bio/buf_nommap.go new file mode 100644 index 00000000..f43c67ac --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/bio/buf_nommap.go @@ -0,0 +1,11 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd + +package bio + +func (r *Reader) sliceOS(length uint64) ([]byte, bool) { + return nil, false +} diff --git a/vendor/github.com/mandiant/GoReSym/bio/must.go b/vendor/github.com/mandiant/GoReSym/bio/must.go new file mode 100644 index 00000000..3604b291 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/bio/must.go @@ -0,0 +1,43 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bio + +import ( + "io" + "log" +) + +// MustClose closes Closer c and calls log.Fatal if it returns a non-nil error. +func MustClose(c io.Closer) { + if err := c.Close(); err != nil { + log.Fatal(err) + } +} + +// MustWriter returns a Writer that wraps the provided Writer, +// except that it calls log.Fatal instead of returning a non-nil error. +func MustWriter(w io.Writer) io.Writer { + return mustWriter{w} +} + +type mustWriter struct { + w io.Writer +} + +func (w mustWriter) Write(b []byte) (int, error) { + n, err := w.w.Write(b) + if err != nil { + log.Fatal(err) + } + return n, nil +} + +func (w mustWriter) WriteString(s string) (int, error) { + n, err := io.WriteString(w.w, s) + if err != nil { + log.Fatal(err) + } + return n, nil +} diff --git a/vendor/github.com/mandiant/GoReSym/cmd/src/pos.go b/vendor/github.com/mandiant/GoReSym/cmd/src/pos.go new file mode 100644 index 00000000..b6816a56 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/cmd/src/pos.go @@ -0,0 +1,470 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements the encoding of source positions. + +package src + +import ( + "bytes" + "fmt" + "io" +) + +// A Pos encodes a source position consisting of a (line, column) number pair +// and a position base. A zero Pos is a ready to use "unknown" position (nil +// position base and zero line number). +// +// The (line, column) values refer to a position in a file independent of any +// position base ("absolute" file position). +// +// The position base is used to determine the "relative" position, that is the +// filename and line number relative to the position base. If the base refers +// to the current file, there is no difference between absolute and relative +// positions. If it refers to a //line directive, a relative position is relative +// to that directive. A position base in turn contains the position at which it +// was introduced in the current file. +type Pos struct { + base *PosBase + lico +} + +// NoPos is a valid unknown position. +var NoPos Pos + +// MakePos creates a new Pos value with the given base, and (file-absolute) +// line and column. +func MakePos(base *PosBase, line, col uint) Pos { + return Pos{base, makeLico(line, col)} +} + +// IsKnown reports whether the position p is known. +// A position is known if it either has a non-nil +// position base, or a non-zero line number. +func (p Pos) IsKnown() bool { + return p.base != nil || p.Line() != 0 +} + +// Before reports whether the position p comes before q in the source. +// For positions in different files, ordering is by filename. +func (p Pos) Before(q Pos) bool { + n, m := p.Filename(), q.Filename() + return n < m || n == m && p.lico < q.lico +} + +// After reports whether the position p comes after q in the source. +// For positions in different files, ordering is by filename. +func (p Pos) After(q Pos) bool { + n, m := p.Filename(), q.Filename() + return n > m || n == m && p.lico > q.lico +} + +func (p Pos) LineNumber() string { + if !p.IsKnown() { + return "?" + } + return p.lico.lineNumber() +} + +func (p Pos) LineNumberHTML() string { + if !p.IsKnown() { + return "?" + } + return p.lico.lineNumberHTML() +} + +// Filename returns the name of the actual file containing this position. +func (p Pos) Filename() string { return p.base.Pos().RelFilename() } + +// Base returns the position base. +func (p Pos) Base() *PosBase { return p.base } + +// SetBase sets the position base. +func (p *Pos) SetBase(base *PosBase) { p.base = base } + +// RelFilename returns the filename recorded with the position's base. +func (p Pos) RelFilename() string { return p.base.Filename() } + +// RelLine returns the line number relative to the position's base. +func (p Pos) RelLine() uint { + b := p.base + if b.Line() == 0 { + // base line is unknown => relative line is unknown + return 0 + } + return b.Line() + (p.Line() - b.Pos().Line()) +} + +// RelCol returns the column number relative to the position's base. +func (p Pos) RelCol() uint { + b := p.base + if b.Col() == 0 { + // base column is unknown => relative column is unknown + // (the current specification for line directives requires + // this to apply until the next PosBase/line directive, + // not just until the new newline) + return 0 + } + if p.Line() == b.Pos().Line() { + // p on same line as p's base => column is relative to p's base + return b.Col() + (p.Col() - b.Pos().Col()) + } + return p.Col() +} + +// AbsFilename() returns the absolute filename recorded with the position's base. +func (p Pos) AbsFilename() string { return p.base.AbsFilename() } + +// SymFilename() returns the absolute filename recorded with the position's base, +// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol. +func (p Pos) SymFilename() string { return p.base.SymFilename() } + +func (p Pos) String() string { + return p.Format(true, true) +} + +// Format formats a position as "filename:line" or "filename:line:column", +// controlled by the showCol flag and if the column is known (!= 0). +// For positions relative to line directives, the original position is +// shown as well, as in "filename:line[origfile:origline:origcolumn] if +// showOrig is set. +func (p Pos) Format(showCol, showOrig bool) string { + buf := new(bytes.Buffer) + p.WriteTo(buf, showCol, showOrig) + return buf.String() +} + +// WriteTo a position to w, formatted as Format does. +func (p Pos) WriteTo(w io.Writer, showCol, showOrig bool) { + if !p.IsKnown() { + io.WriteString(w, "") + return + } + + if b := p.base; b == b.Pos().base { + // base is file base (incl. nil) + format(w, p.Filename(), p.Line(), p.Col(), showCol) + return + } + + // base is relative + // Print the column only for the original position since the + // relative position's column information may be bogus (it's + // typically generated code and we can't say much about the + // original source at that point but for the file:line info + // that's provided via a line directive). + // TODO(gri) This may not be true if we have an inlining base. + // We may want to differentiate at some point. + format(w, p.RelFilename(), p.RelLine(), p.RelCol(), showCol) + if showOrig { + io.WriteString(w, "[") + format(w, p.Filename(), p.Line(), p.Col(), showCol) + io.WriteString(w, "]") + } +} + +// format formats a (filename, line, col) tuple as "filename:line" (showCol +// is false or col == 0) or "filename:line:column" (showCol is true and col != 0). +func format(w io.Writer, filename string, line, col uint, showCol bool) { + io.WriteString(w, filename) + io.WriteString(w, ":") + fmt.Fprint(w, line) + // col == 0 and col == colMax are interpreted as unknown column values + if showCol && 0 < col && col < colMax { + io.WriteString(w, ":") + fmt.Fprint(w, col) + } +} + +// formatstr wraps format to return a string. +func formatstr(filename string, line, col uint, showCol bool) string { + buf := new(bytes.Buffer) + format(buf, filename, line, col, showCol) + return buf.String() +} + +// ---------------------------------------------------------------------------- +// PosBase + +// A PosBase encodes a filename and base position. +// Typically, each file and line directive introduce a PosBase. +type PosBase struct { + pos Pos // position at which the relative position is (line, col) + filename string // file name used to open source file, for error messages + absFilename string // absolute file name, for PC-Line tables + symFilename string // cached symbol file name, to avoid repeated string concatenation + line, col uint // relative line, column number at pos + inl int // inlining index (see cmd/internal/obj/inl.go) +} + +// NewFileBase returns a new *PosBase for a file with the given (relative and +// absolute) filenames. +func NewFileBase(filename, absFilename string) *PosBase { + base := &PosBase{ + filename: filename, + absFilename: absFilename, + symFilename: FileSymPrefix + absFilename, + line: 1, + col: 1, + inl: -1, + } + base.pos = MakePos(base, 1, 1) + return base +} + +// NewLinePragmaBase returns a new *PosBase for a line directive of the form +// //line filename:line:col +// /*line filename:line:col*/ +// at position pos. +func NewLinePragmaBase(pos Pos, filename, absFilename string, line, col uint) *PosBase { + return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line, col, -1} +} + +// NewInliningBase returns a copy of the old PosBase with the given inlining +// index. If old == nil, the resulting PosBase has no filename. +func NewInliningBase(old *PosBase, inlTreeIndex int) *PosBase { + if old == nil { + base := &PosBase{line: 1, col: 1, inl: inlTreeIndex} + base.pos = MakePos(base, 1, 1) + return base + } + copy := *old + base := © + base.inl = inlTreeIndex + if old == old.pos.base { + base.pos.base = base + } + return base +} + +var noPos Pos + +// Pos returns the position at which base is located. +// If b == nil, the result is the zero position. +func (b *PosBase) Pos() *Pos { + if b != nil { + return &b.pos + } + return &noPos +} + +// Filename returns the filename recorded with the base. +// If b == nil, the result is the empty string. +func (b *PosBase) Filename() string { + if b != nil { + return b.filename + } + return "" +} + +// AbsFilename returns the absolute filename recorded with the base. +// If b == nil, the result is the empty string. +func (b *PosBase) AbsFilename() string { + if b != nil { + return b.absFilename + } + return "" +} + +const FileSymPrefix = "gofile.." + +// SymFilename returns the absolute filename recorded with the base, +// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol. +// If b is nil, SymFilename returns FileSymPrefix + "??". +func (b *PosBase) SymFilename() string { + if b != nil { + return b.symFilename + } + return FileSymPrefix + "??" +} + +// Line returns the line number recorded with the base. +// If b == nil, the result is 0. +func (b *PosBase) Line() uint { + if b != nil { + return b.line + } + return 0 +} + +// Col returns the column number recorded with the base. +// If b == nil, the result is 0. +func (b *PosBase) Col() uint { + if b != nil { + return b.col + } + return 0 +} + +// InliningIndex returns the index into the global inlining +// tree recorded with the base. If b == nil or the base has +// not been inlined, the result is < 0. +func (b *PosBase) InliningIndex() int { + if b != nil { + return b.inl + } + return -1 +} + +// ---------------------------------------------------------------------------- +// lico + +// A lico is a compact encoding of a LIne and COlumn number. +type lico uint32 + +// Layout constants: 20 bits for line, 8 bits for column, 2 for isStmt, 2 for pro/epilogue +// (If this is too tight, we can either make lico 64b wide, +// or we can introduce a tiered encoding where we remove column +// information as line numbers grow bigger; similar to what gcc +// does.) +// The bitfield order is chosen to make IsStmt be the least significant +// part of a position; its use is to communicate statement edges through +// instruction scrambling in code generation, not to impose an order. +// TODO: Prologue and epilogue are perhaps better handled as pseudo-ops for the assembler, +// because they have almost no interaction with other uses of the position. +const ( + lineBits, lineMax = 20, 1< lineMax { + // cannot represent line, use max. line so we have some information + line = lineMax + } + if col > colMax { + // cannot represent column, use max. column so we have some information + col = colMax + } + // default is not-sure-if-statement + return makeLicoRaw(line, col) +} + +func (x lico) Line() uint { return uint(x) >> lineShift } +func (x lico) SameLine(y lico) bool { return 0 == (x^y)&^lico(1<> colShift & colMax } +func (x lico) IsStmt() uint { + if x == 0 { + return PosNotStmt + } + return uint(x) >> isStmtShift & isStmtMax +} +func (x lico) Xlogue() PosXlogue { + return PosXlogue(uint(x) >> xlogueShift & xlogueMax) +} + +// withNotStmt returns a lico for the same location, but not a statement +func (x lico) withNotStmt() lico { + return x.withStmt(PosNotStmt) +} + +// withDefaultStmt returns a lico for the same location, with default isStmt +func (x lico) withDefaultStmt() lico { + return x.withStmt(PosDefaultStmt) +} + +// withIsStmt returns a lico for the same location, tagged as definitely a statement +func (x lico) withIsStmt() lico { + return x.withStmt(PosIsStmt) +} + +// withLogue attaches a prologue/epilogue attribute to a lico +func (x lico) withXlogue(xlogue PosXlogue) lico { + if x == 0 { + if xlogue == 0 { + return x + } + // Normalize 0 to "not a statement" + x = lico(PosNotStmt << isStmtShift) + } + return lico(uint(x) & ^uint(xlogueMax<%s%d", style, pfx, x.Line(), style) +} + +func (x lico) atColumn1() lico { + return makeLico(x.Line(), 1).withIsStmt() +} diff --git a/vendor/github.com/mandiant/GoReSym/cmd/src/xpos.go b/vendor/github.com/mandiant/GoReSym/cmd/src/xpos.go new file mode 100644 index 00000000..867d0ab0 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/cmd/src/xpos.go @@ -0,0 +1,176 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements the compressed encoding of source +// positions using a lookup table. + +package src + +// XPos is a more compact representation of Pos. +type XPos struct { + index int32 + lico +} + +// NoXPos is a valid unknown position. +var NoXPos XPos + +// IsKnown reports whether the position p is known. +// XPos.IsKnown() matches Pos.IsKnown() for corresponding +// positions. +func (p XPos) IsKnown() bool { + return p.index != 0 || p.Line() != 0 +} + +// Before reports whether the position p comes before q in the source. +// For positions with different bases, ordering is by base index. +func (p XPos) Before(q XPos) bool { + n, m := p.index, q.index + return n < m || n == m && p.lico < q.lico +} + +// SameFile reports whether p and q are positions in the same file. +func (p XPos) SameFile(q XPos) bool { + return p.index == q.index +} + +// SameFileAndLine reports whether p and q are positions on the same line in the same file. +func (p XPos) SameFileAndLine(q XPos) bool { + return p.index == q.index && p.lico.SameLine(q.lico) +} + +// After reports whether the position p comes after q in the source. +// For positions with different bases, ordering is by base index. +func (p XPos) After(q XPos) bool { + n, m := p.index, q.index + return n > m || n == m && p.lico > q.lico +} + +// WithNotStmt returns the same location to be marked with DWARF is_stmt=0 +func (p XPos) WithNotStmt() XPos { + p.lico = p.lico.withNotStmt() + return p +} + +// WithDefaultStmt returns the same location with undetermined is_stmt +func (p XPos) WithDefaultStmt() XPos { + p.lico = p.lico.withDefaultStmt() + return p +} + +// WithIsStmt returns the same location to be marked with DWARF is_stmt=1 +func (p XPos) WithIsStmt() XPos { + p.lico = p.lico.withIsStmt() + return p +} + +// WithBogusLine returns a bogus line that won't match any recorded for the source code. +// Its use is to disrupt the statements within an infinite loop so that the debugger +// will not itself loop infinitely waiting for the line number to change. +// gdb chooses not to display the bogus line; delve shows it with a complaint, but the +// alternative behavior is to hang. +func (p XPos) WithBogusLine() XPos { + if p.index == 0 { + // See #35652 + panic("Assigning a bogus line to XPos with no file will cause mysterious downstream failures.") + } + p.lico = makeBogusLico() + return p +} + +// WithXlogue returns the same location but marked with DWARF function prologue/epilogue +func (p XPos) WithXlogue(x PosXlogue) XPos { + p.lico = p.lico.withXlogue(x) + return p +} + +// LineNumber returns a string for the line number, "?" if it is not known. +func (p XPos) LineNumber() string { + if !p.IsKnown() { + return "?" + } + return p.lico.lineNumber() +} + +// FileIndex returns a smallish non-negative integer corresponding to the +// file for this source position. Smallish is relative; it can be thousands +// large, but not millions. +func (p XPos) FileIndex() int32 { + return p.index +} + +func (p XPos) LineNumberHTML() string { + if !p.IsKnown() { + return "?" + } + return p.lico.lineNumberHTML() +} + +// AtColumn1 returns the same location but shifted to column 1. +func (p XPos) AtColumn1() XPos { + p.lico = p.lico.atColumn1() + return p +} + +// A PosTable tracks Pos -> XPos conversions and vice versa. +// Its zero value is a ready-to-use PosTable. +type PosTable struct { + baseList []*PosBase + indexMap map[*PosBase]int + nameMap map[string]int // Maps file symbol name to index for debug information. +} + +// XPos returns the corresponding XPos for the given pos, +// adding pos to t if necessary. +func (t *PosTable) XPos(pos Pos) XPos { + m := t.indexMap + if m == nil { + // Create new list and map and populate with nil + // base so that NoPos always gets index 0. + t.baseList = append(t.baseList, nil) + m = map[*PosBase]int{nil: 0} + t.indexMap = m + t.nameMap = make(map[string]int) + } + i, ok := m[pos.base] + if !ok { + i = len(t.baseList) + t.baseList = append(t.baseList, pos.base) + t.indexMap[pos.base] = i + if _, ok := t.nameMap[pos.base.symFilename]; !ok { + t.nameMap[pos.base.symFilename] = len(t.nameMap) + } + } + return XPos{int32(i), pos.lico} +} + +// Pos returns the corresponding Pos for the given p. +// If p cannot be translated via t, the function panics. +func (t *PosTable) Pos(p XPos) Pos { + var base *PosBase + if p.index != 0 { + base = t.baseList[p.index] + } + return Pos{base, p.lico} +} + +// FileIndex returns the index of the given filename(symbol) in the PosTable, or -1 if not found. +func (t *PosTable) FileIndex(filename string) int { + if v, ok := t.nameMap[filename]; ok { + return v + } + return -1 +} + +// FileTable returns a slice of all files used to build this package. +func (t *PosTable) FileTable() []string { + // Create a LUT of the global package level file indices. This table is what + // is written in the debug_lines header, the file[N] will be referenced as + // N+1 in the debug_lines table. + fileLUT := make([]string, len(t.nameMap)) + for str, i := range t.nameMap { + fileLUT[i] = str + } + return fileLUT +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/attr_string.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/attr_string.go new file mode 100644 index 00000000..8a4fff85 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/attr_string.go @@ -0,0 +1,265 @@ +// Code generated by "stringer -type Attr -trimprefix=Attr"; DO NOT EDIT. + +package dwarf + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[AttrSibling-1] + _ = x[AttrLocation-2] + _ = x[AttrName-3] + _ = x[AttrOrdering-9] + _ = x[AttrByteSize-11] + _ = x[AttrBitOffset-12] + _ = x[AttrBitSize-13] + _ = x[AttrStmtList-16] + _ = x[AttrLowpc-17] + _ = x[AttrHighpc-18] + _ = x[AttrLanguage-19] + _ = x[AttrDiscr-21] + _ = x[AttrDiscrValue-22] + _ = x[AttrVisibility-23] + _ = x[AttrImport-24] + _ = x[AttrStringLength-25] + _ = x[AttrCommonRef-26] + _ = x[AttrCompDir-27] + _ = x[AttrConstValue-28] + _ = x[AttrContainingType-29] + _ = x[AttrDefaultValue-30] + _ = x[AttrInline-32] + _ = x[AttrIsOptional-33] + _ = x[AttrLowerBound-34] + _ = x[AttrProducer-37] + _ = x[AttrPrototyped-39] + _ = x[AttrReturnAddr-42] + _ = x[AttrStartScope-44] + _ = x[AttrStrideSize-46] + _ = x[AttrUpperBound-47] + _ = x[AttrAbstractOrigin-49] + _ = x[AttrAccessibility-50] + _ = x[AttrAddrClass-51] + _ = x[AttrArtificial-52] + _ = x[AttrBaseTypes-53] + _ = x[AttrCalling-54] + _ = x[AttrCount-55] + _ = x[AttrDataMemberLoc-56] + _ = x[AttrDeclColumn-57] + _ = x[AttrDeclFile-58] + _ = x[AttrDeclLine-59] + _ = x[AttrDeclaration-60] + _ = x[AttrDiscrList-61] + _ = x[AttrEncoding-62] + _ = x[AttrExternal-63] + _ = x[AttrFrameBase-64] + _ = x[AttrFriend-65] + _ = x[AttrIdentifierCase-66] + _ = x[AttrMacroInfo-67] + _ = x[AttrNamelistItem-68] + _ = x[AttrPriority-69] + _ = x[AttrSegment-70] + _ = x[AttrSpecification-71] + _ = x[AttrStaticLink-72] + _ = x[AttrType-73] + _ = x[AttrUseLocation-74] + _ = x[AttrVarParam-75] + _ = x[AttrVirtuality-76] + _ = x[AttrVtableElemLoc-77] + _ = x[AttrAllocated-78] + _ = x[AttrAssociated-79] + _ = x[AttrDataLocation-80] + _ = x[AttrStride-81] + _ = x[AttrEntrypc-82] + _ = x[AttrUseUTF8-83] + _ = x[AttrExtension-84] + _ = x[AttrRanges-85] + _ = x[AttrTrampoline-86] + _ = x[AttrCallColumn-87] + _ = x[AttrCallFile-88] + _ = x[AttrCallLine-89] + _ = x[AttrDescription-90] + _ = x[AttrBinaryScale-91] + _ = x[AttrDecimalScale-92] + _ = x[AttrSmall-93] + _ = x[AttrDecimalSign-94] + _ = x[AttrDigitCount-95] + _ = x[AttrPictureString-96] + _ = x[AttrMutable-97] + _ = x[AttrThreadsScaled-98] + _ = x[AttrExplicit-99] + _ = x[AttrObjectPointer-100] + _ = x[AttrEndianity-101] + _ = x[AttrElemental-102] + _ = x[AttrPure-103] + _ = x[AttrRecursive-104] + _ = x[AttrSignature-105] + _ = x[AttrMainSubprogram-106] + _ = x[AttrDataBitOffset-107] + _ = x[AttrConstExpr-108] + _ = x[AttrEnumClass-109] + _ = x[AttrLinkageName-110] + _ = x[AttrStringLengthBitSize-111] + _ = x[AttrStringLengthByteSize-112] + _ = x[AttrRank-113] + _ = x[AttrStrOffsetsBase-114] + _ = x[AttrAddrBase-115] + _ = x[AttrRnglistsBase-116] + _ = x[AttrDwoName-118] + _ = x[AttrReference-119] + _ = x[AttrRvalueReference-120] + _ = x[AttrMacros-121] + _ = x[AttrCallAllCalls-122] + _ = x[AttrCallAllSourceCalls-123] + _ = x[AttrCallAllTailCalls-124] + _ = x[AttrCallReturnPC-125] + _ = x[AttrCallValue-126] + _ = x[AttrCallOrigin-127] + _ = x[AttrCallParameter-128] + _ = x[AttrCallPC-129] + _ = x[AttrCallTailCall-130] + _ = x[AttrCallTarget-131] + _ = x[AttrCallTargetClobbered-132] + _ = x[AttrCallDataLocation-133] + _ = x[AttrCallDataValue-134] + _ = x[AttrNoreturn-135] + _ = x[AttrAlignment-136] + _ = x[AttrExportSymbols-137] + _ = x[AttrDeleted-138] + _ = x[AttrDefaulted-139] + _ = x[AttrLoclistsBase-140] +} + +const _Attr_name = "SiblingLocationNameOrderingByteSizeBitOffsetBitSizeStmtListLowpcHighpcLanguageDiscrDiscrValueVisibilityImportStringLengthCommonRefCompDirConstValueContainingTypeDefaultValueInlineIsOptionalLowerBoundProducerPrototypedReturnAddrStartScopeStrideSizeUpperBoundAbstractOriginAccessibilityAddrClassArtificialBaseTypesCallingCountDataMemberLocDeclColumnDeclFileDeclLineDeclarationDiscrListEncodingExternalFrameBaseFriendIdentifierCaseMacroInfoNamelistItemPrioritySegmentSpecificationStaticLinkTypeUseLocationVarParamVirtualityVtableElemLocAllocatedAssociatedDataLocationStrideEntrypcUseUTF8ExtensionRangesTrampolineCallColumnCallFileCallLineDescriptionBinaryScaleDecimalScaleSmallDecimalSignDigitCountPictureStringMutableThreadsScaledExplicitObjectPointerEndianityElementalPureRecursiveSignatureMainSubprogramDataBitOffsetConstExprEnumClassLinkageNameStringLengthBitSizeStringLengthByteSizeRankStrOffsetsBaseAddrBaseRnglistsBaseDwoNameReferenceRvalueReferenceMacrosCallAllCallsCallAllSourceCallsCallAllTailCallsCallReturnPCCallValueCallOriginCallParameterCallPCCallTailCallCallTargetCallTargetClobberedCallDataLocationCallDataValueNoreturnAlignmentExportSymbolsDeletedDefaultedLoclistsBase" + +var _Attr_map = map[Attr]string{ + 1: _Attr_name[0:7], + 2: _Attr_name[7:15], + 3: _Attr_name[15:19], + 9: _Attr_name[19:27], + 11: _Attr_name[27:35], + 12: _Attr_name[35:44], + 13: _Attr_name[44:51], + 16: _Attr_name[51:59], + 17: _Attr_name[59:64], + 18: _Attr_name[64:70], + 19: _Attr_name[70:78], + 21: _Attr_name[78:83], + 22: _Attr_name[83:93], + 23: _Attr_name[93:103], + 24: _Attr_name[103:109], + 25: _Attr_name[109:121], + 26: _Attr_name[121:130], + 27: _Attr_name[130:137], + 28: _Attr_name[137:147], + 29: _Attr_name[147:161], + 30: _Attr_name[161:173], + 32: _Attr_name[173:179], + 33: _Attr_name[179:189], + 34: _Attr_name[189:199], + 37: _Attr_name[199:207], + 39: _Attr_name[207:217], + 42: _Attr_name[217:227], + 44: _Attr_name[227:237], + 46: _Attr_name[237:247], + 47: _Attr_name[247:257], + 49: _Attr_name[257:271], + 50: _Attr_name[271:284], + 51: _Attr_name[284:293], + 52: _Attr_name[293:303], + 53: _Attr_name[303:312], + 54: _Attr_name[312:319], + 55: _Attr_name[319:324], + 56: _Attr_name[324:337], + 57: _Attr_name[337:347], + 58: _Attr_name[347:355], + 59: _Attr_name[355:363], + 60: _Attr_name[363:374], + 61: _Attr_name[374:383], + 62: _Attr_name[383:391], + 63: _Attr_name[391:399], + 64: _Attr_name[399:408], + 65: _Attr_name[408:414], + 66: _Attr_name[414:428], + 67: _Attr_name[428:437], + 68: _Attr_name[437:449], + 69: _Attr_name[449:457], + 70: _Attr_name[457:464], + 71: _Attr_name[464:477], + 72: _Attr_name[477:487], + 73: _Attr_name[487:491], + 74: _Attr_name[491:502], + 75: _Attr_name[502:510], + 76: _Attr_name[510:520], + 77: _Attr_name[520:533], + 78: _Attr_name[533:542], + 79: _Attr_name[542:552], + 80: _Attr_name[552:564], + 81: _Attr_name[564:570], + 82: _Attr_name[570:577], + 83: _Attr_name[577:584], + 84: _Attr_name[584:593], + 85: _Attr_name[593:599], + 86: _Attr_name[599:609], + 87: _Attr_name[609:619], + 88: _Attr_name[619:627], + 89: _Attr_name[627:635], + 90: _Attr_name[635:646], + 91: _Attr_name[646:657], + 92: _Attr_name[657:669], + 93: _Attr_name[669:674], + 94: _Attr_name[674:685], + 95: _Attr_name[685:695], + 96: _Attr_name[695:708], + 97: _Attr_name[708:715], + 98: _Attr_name[715:728], + 99: _Attr_name[728:736], + 100: _Attr_name[736:749], + 101: _Attr_name[749:758], + 102: _Attr_name[758:767], + 103: _Attr_name[767:771], + 104: _Attr_name[771:780], + 105: _Attr_name[780:789], + 106: _Attr_name[789:803], + 107: _Attr_name[803:816], + 108: _Attr_name[816:825], + 109: _Attr_name[825:834], + 110: _Attr_name[834:845], + 111: _Attr_name[845:864], + 112: _Attr_name[864:884], + 113: _Attr_name[884:888], + 114: _Attr_name[888:902], + 115: _Attr_name[902:910], + 116: _Attr_name[910:922], + 118: _Attr_name[922:929], + 119: _Attr_name[929:938], + 120: _Attr_name[938:953], + 121: _Attr_name[953:959], + 122: _Attr_name[959:971], + 123: _Attr_name[971:989], + 124: _Attr_name[989:1005], + 125: _Attr_name[1005:1017], + 126: _Attr_name[1017:1026], + 127: _Attr_name[1026:1036], + 128: _Attr_name[1036:1049], + 129: _Attr_name[1049:1055], + 130: _Attr_name[1055:1067], + 131: _Attr_name[1067:1077], + 132: _Attr_name[1077:1096], + 133: _Attr_name[1096:1112], + 134: _Attr_name[1112:1125], + 135: _Attr_name[1125:1133], + 136: _Attr_name[1133:1142], + 137: _Attr_name[1142:1155], + 138: _Attr_name[1155:1162], + 139: _Attr_name[1162:1171], + 140: _Attr_name[1171:1183], +} + +func (i Attr) String() string { + if str, ok := _Attr_map[i]; ok { + return str + } + return "Attr(" + strconv.FormatInt(int64(i), 10) + ")" +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/buf.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/buf.go new file mode 100644 index 00000000..7ac53efc --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/buf.go @@ -0,0 +1,205 @@ +// 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. + +// Buffered reading and decoding of DWARF data streams. + +package dwarf + +import ( + "bytes" + "encoding/binary" + "strconv" +) + +// Data buffer being decoded. +type buf struct { + dwarf *Data + order binary.ByteOrder + format dataFormat + name string + off Offset + data []byte + err error +} + +// Data format, other than byte order. This affects the handling of +// certain field formats. +type dataFormat interface { + // DWARF version number. Zero means unknown. + version() int + + // 64-bit DWARF format? + dwarf64() (dwarf64 bool, isKnown bool) + + // Size of an address, in bytes. Zero means unknown. + addrsize() int +} + +// Some parts of DWARF have no data format, e.g., abbrevs. +type unknownFormat struct{} + +func (u unknownFormat) version() int { + return 0 +} + +func (u unknownFormat) dwarf64() (bool, bool) { + return false, false +} + +func (u unknownFormat) addrsize() int { + return 0 +} + +func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf { + return buf{d, d.order, format, name, off, data, nil} +} + +func (b *buf) uint8() uint8 { + if len(b.data) < 1 { + b.error("underflow") + return 0 + } + val := b.data[0] + b.data = b.data[1:] + b.off++ + return val +} + +func (b *buf) bytes(n int) []byte { + if n < 0 || len(b.data) < n { + b.error("underflow") + return nil + } + data := b.data[0:n] + b.data = b.data[n:] + b.off += Offset(n) + return data +} + +func (b *buf) skip(n int) { b.bytes(n) } + +func (b *buf) string() string { + i := bytes.IndexByte(b.data, 0) + if i < 0 { + b.error("underflow") + return "" + } + + s := string(b.data[0:i]) + b.data = b.data[i+1:] + b.off += Offset(i + 1) + return s +} + +func (b *buf) uint16() uint16 { + a := b.bytes(2) + if a == nil { + return 0 + } + return b.order.Uint16(a) +} + +func (b *buf) uint24() uint32 { + a := b.bytes(3) + if a == nil { + return 0 + } + if b.dwarf.bigEndian { + return uint32(a[2]) | uint32(a[1])<<8 | uint32(a[0])<<16 + } else { + return uint32(a[0]) | uint32(a[1])<<8 | uint32(a[2])<<16 + } +} + +func (b *buf) uint32() uint32 { + a := b.bytes(4) + if a == nil { + return 0 + } + return b.order.Uint32(a) +} + +func (b *buf) uint64() uint64 { + a := b.bytes(8) + if a == nil { + return 0 + } + return b.order.Uint64(a) +} + +// Read a varint, which is 7 bits per byte, little endian. +// the 0x80 bit means read another byte. +func (b *buf) varint() (c uint64, bits uint) { + for i := 0; i < len(b.data); i++ { + byte := b.data[i] + c |= uint64(byte&0x7F) << bits + bits += 7 + if byte&0x80 == 0 { + b.off += Offset(i + 1) + b.data = b.data[i+1:] + return c, bits + } + } + return 0, 0 +} + +// Unsigned int is just a varint. +func (b *buf) uint() uint64 { + x, _ := b.varint() + return x +} + +// Signed int is a sign-extended varint. +func (b *buf) int() int64 { + ux, bits := b.varint() + x := int64(ux) + if x&(1<<(bits-1)) != 0 { + x |= -1 << bits + } + return x +} + +// Address-sized uint. +func (b *buf) addr() uint64 { + switch b.format.addrsize() { + case 1: + return uint64(b.uint8()) + case 2: + return uint64(b.uint16()) + case 4: + return uint64(b.uint32()) + case 8: + return b.uint64() + } + b.error("unknown address size") + return 0 +} + +func (b *buf) unitLength() (length Offset, dwarf64 bool) { + length = Offset(b.uint32()) + if length == 0xffffffff { + dwarf64 = true + length = Offset(b.uint64()) + } else if length >= 0xfffffff0 { + b.error("unit length has reserved value") + } + return +} + +func (b *buf) error(s string) { + if b.err == nil { + b.data = nil + b.err = DecodeError{b.name, b.off, s} + } +} + +type DecodeError struct { + Name string + Offset Offset + Err string +} + +func (e DecodeError) Error() string { + return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.FormatInt(int64(e.Offset), 16) + ": " + e.Err +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/class_string.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/class_string.go new file mode 100644 index 00000000..76de7cad --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/class_string.go @@ -0,0 +1,37 @@ +// Code generated by "stringer -type=Class"; DO NOT EDIT. + +package dwarf + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[ClassUnknown-0] + _ = x[ClassAddress-1] + _ = x[ClassBlock-2] + _ = x[ClassConstant-3] + _ = x[ClassExprLoc-4] + _ = x[ClassFlag-5] + _ = x[ClassLinePtr-6] + _ = x[ClassLocListPtr-7] + _ = x[ClassMacPtr-8] + _ = x[ClassRangeListPtr-9] + _ = x[ClassReference-10] + _ = x[ClassReferenceSig-11] + _ = x[ClassString-12] + _ = x[ClassReferenceAlt-13] + _ = x[ClassStringAlt-14] +} + +const _Class_name = "ClassUnknownClassAddressClassBlockClassConstantClassExprLocClassFlagClassLinePtrClassLocListPtrClassMacPtrClassRangeListPtrClassReferenceClassReferenceSigClassStringClassReferenceAltClassStringAlt" + +var _Class_index = [...]uint8{0, 12, 24, 34, 47, 59, 68, 80, 95, 106, 123, 137, 154, 165, 182, 196} + +func (i Class) String() string { + if i < 0 || i >= Class(len(_Class_index)-1) { + return "Class(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Class_name[_Class_index[i]:_Class_index[i+1]] +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/const.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/const.go new file mode 100644 index 00000000..c0a74b08 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/const.go @@ -0,0 +1,475 @@ +// 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. + +// Constants + +package dwarf + +//go:generate stringer -type Attr -trimprefix=Attr + +// An Attr identifies the attribute type in a DWARF Entry's Field. +type Attr uint32 + +const ( + AttrSibling Attr = 0x01 + AttrLocation Attr = 0x02 + AttrName Attr = 0x03 + AttrOrdering Attr = 0x09 + AttrByteSize Attr = 0x0B + AttrBitOffset Attr = 0x0C + AttrBitSize Attr = 0x0D + AttrStmtList Attr = 0x10 + AttrLowpc Attr = 0x11 + AttrHighpc Attr = 0x12 + AttrLanguage Attr = 0x13 + AttrDiscr Attr = 0x15 + AttrDiscrValue Attr = 0x16 + AttrVisibility Attr = 0x17 + AttrImport Attr = 0x18 + AttrStringLength Attr = 0x19 + AttrCommonRef Attr = 0x1A + AttrCompDir Attr = 0x1B + AttrConstValue Attr = 0x1C + AttrContainingType Attr = 0x1D + AttrDefaultValue Attr = 0x1E + AttrInline Attr = 0x20 + AttrIsOptional Attr = 0x21 + AttrLowerBound Attr = 0x22 + AttrProducer Attr = 0x25 + AttrPrototyped Attr = 0x27 + AttrReturnAddr Attr = 0x2A + AttrStartScope Attr = 0x2C + AttrStrideSize Attr = 0x2E + AttrUpperBound Attr = 0x2F + AttrAbstractOrigin Attr = 0x31 + AttrAccessibility Attr = 0x32 + AttrAddrClass Attr = 0x33 + AttrArtificial Attr = 0x34 + AttrBaseTypes Attr = 0x35 + AttrCalling Attr = 0x36 + AttrCount Attr = 0x37 + AttrDataMemberLoc Attr = 0x38 + AttrDeclColumn Attr = 0x39 + AttrDeclFile Attr = 0x3A + AttrDeclLine Attr = 0x3B + AttrDeclaration Attr = 0x3C + AttrDiscrList Attr = 0x3D + AttrEncoding Attr = 0x3E + AttrExternal Attr = 0x3F + AttrFrameBase Attr = 0x40 + AttrFriend Attr = 0x41 + AttrIdentifierCase Attr = 0x42 + AttrMacroInfo Attr = 0x43 + AttrNamelistItem Attr = 0x44 + AttrPriority Attr = 0x45 + AttrSegment Attr = 0x46 + AttrSpecification Attr = 0x47 + AttrStaticLink Attr = 0x48 + AttrType Attr = 0x49 + AttrUseLocation Attr = 0x4A + AttrVarParam Attr = 0x4B + AttrVirtuality Attr = 0x4C + AttrVtableElemLoc Attr = 0x4D + // The following are new in DWARF 3. + AttrAllocated Attr = 0x4E + AttrAssociated Attr = 0x4F + AttrDataLocation Attr = 0x50 + AttrStride Attr = 0x51 + AttrEntrypc Attr = 0x52 + AttrUseUTF8 Attr = 0x53 + AttrExtension Attr = 0x54 + AttrRanges Attr = 0x55 + AttrTrampoline Attr = 0x56 + AttrCallColumn Attr = 0x57 + AttrCallFile Attr = 0x58 + AttrCallLine Attr = 0x59 + AttrDescription Attr = 0x5A + AttrBinaryScale Attr = 0x5B + AttrDecimalScale Attr = 0x5C + AttrSmall Attr = 0x5D + AttrDecimalSign Attr = 0x5E + AttrDigitCount Attr = 0x5F + AttrPictureString Attr = 0x60 + AttrMutable Attr = 0x61 + AttrThreadsScaled Attr = 0x62 + AttrExplicit Attr = 0x63 + AttrObjectPointer Attr = 0x64 + AttrEndianity Attr = 0x65 + AttrElemental Attr = 0x66 + AttrPure Attr = 0x67 + AttrRecursive Attr = 0x68 + // The following are new in DWARF 4. + AttrSignature Attr = 0x69 + AttrMainSubprogram Attr = 0x6A + AttrDataBitOffset Attr = 0x6B + AttrConstExpr Attr = 0x6C + AttrEnumClass Attr = 0x6D + AttrLinkageName Attr = 0x6E + // The following are new in DWARF 5. + AttrStringLengthBitSize Attr = 0x6F + AttrStringLengthByteSize Attr = 0x70 + AttrRank Attr = 0x71 + AttrStrOffsetsBase Attr = 0x72 + AttrAddrBase Attr = 0x73 + AttrRnglistsBase Attr = 0x74 + AttrDwoName Attr = 0x76 + AttrReference Attr = 0x77 + AttrRvalueReference Attr = 0x78 + AttrMacros Attr = 0x79 + AttrCallAllCalls Attr = 0x7A + AttrCallAllSourceCalls Attr = 0x7B + AttrCallAllTailCalls Attr = 0x7C + AttrCallReturnPC Attr = 0x7D + AttrCallValue Attr = 0x7E + AttrCallOrigin Attr = 0x7F + AttrCallParameter Attr = 0x80 + AttrCallPC Attr = 0x81 + AttrCallTailCall Attr = 0x82 + AttrCallTarget Attr = 0x83 + AttrCallTargetClobbered Attr = 0x84 + AttrCallDataLocation Attr = 0x85 + AttrCallDataValue Attr = 0x86 + AttrNoreturn Attr = 0x87 + AttrAlignment Attr = 0x88 + AttrExportSymbols Attr = 0x89 + AttrDeleted Attr = 0x8A + AttrDefaulted Attr = 0x8B + AttrLoclistsBase Attr = 0x8C +) + +func (a Attr) GoString() string { + if str, ok := _Attr_map[a]; ok { + return "dwarf.Attr" + str + } + return "dwarf." + a.String() +} + +// A format is a DWARF data encoding format. +type format uint32 + +const ( + // value formats + formAddr format = 0x01 + formDwarfBlock2 format = 0x03 + formDwarfBlock4 format = 0x04 + formData2 format = 0x05 + formData4 format = 0x06 + formData8 format = 0x07 + formString format = 0x08 + formDwarfBlock format = 0x09 + formDwarfBlock1 format = 0x0A + formData1 format = 0x0B + formFlag format = 0x0C + formSdata format = 0x0D + formStrp format = 0x0E + formUdata format = 0x0F + formRefAddr format = 0x10 + formRef1 format = 0x11 + formRef2 format = 0x12 + formRef4 format = 0x13 + formRef8 format = 0x14 + formRefUdata format = 0x15 + formIndirect format = 0x16 + // The following are new in DWARF 4. + formSecOffset format = 0x17 + formExprloc format = 0x18 + formFlagPresent format = 0x19 + formRefSig8 format = 0x20 + // The following are new in DWARF 5. + formStrx format = 0x1A + formAddrx format = 0x1B + formRefSup4 format = 0x1C + formStrpSup format = 0x1D + formData16 format = 0x1E + formLineStrp format = 0x1F + formImplicitConst format = 0x21 + formLoclistx format = 0x22 + formRnglistx format = 0x23 + formRefSup8 format = 0x24 + formStrx1 format = 0x25 + formStrx2 format = 0x26 + formStrx3 format = 0x27 + formStrx4 format = 0x28 + formAddrx1 format = 0x29 + formAddrx2 format = 0x2A + formAddrx3 format = 0x2B + formAddrx4 format = 0x2C + // Extensions for multi-file compression (.dwz) + // http://www.dwarfstd.org/ShowIssue.php?issue=120604.1 + formGnuRefAlt format = 0x1f20 + formGnuStrpAlt format = 0x1f21 +) + +//go:generate stringer -type Tag -trimprefix=Tag + +// A Tag is the classification (the type) of an Entry. +type Tag uint32 + +const ( + TagArrayType Tag = 0x01 + TagClassType Tag = 0x02 + TagEntryPoint Tag = 0x03 + TagEnumerationType Tag = 0x04 + TagFormalParameter Tag = 0x05 + TagImportedDeclaration Tag = 0x08 + TagLabel Tag = 0x0A + TagLexDwarfBlock Tag = 0x0B + TagMember Tag = 0x0D + TagPointerType Tag = 0x0F + TagReferenceType Tag = 0x10 + TagCompileUnit Tag = 0x11 + TagStringType Tag = 0x12 + TagStructType Tag = 0x13 + TagSubroutineType Tag = 0x15 + TagTypedef Tag = 0x16 + TagUnionType Tag = 0x17 + TagUnspecifiedParameters Tag = 0x18 + TagVariant Tag = 0x19 + TagCommonDwarfBlock Tag = 0x1A + TagCommonInclusion Tag = 0x1B + TagInheritance Tag = 0x1C + TagInlinedSubroutine Tag = 0x1D + TagModule Tag = 0x1E + TagPtrToMemberType Tag = 0x1F + TagSetType Tag = 0x20 + TagSubrangeType Tag = 0x21 + TagWithStmt Tag = 0x22 + TagAccessDeclaration Tag = 0x23 + TagBaseType Tag = 0x24 + TagCatchDwarfBlock Tag = 0x25 + TagConstType Tag = 0x26 + TagConstant Tag = 0x27 + TagEnumerator Tag = 0x28 + TagFileType Tag = 0x29 + TagFriend Tag = 0x2A + TagNamelist Tag = 0x2B + TagNamelistItem Tag = 0x2C + TagPackedType Tag = 0x2D + TagSubprogram Tag = 0x2E + TagTemplateTypeParameter Tag = 0x2F + TagTemplateValueParameter Tag = 0x30 + TagThrownType Tag = 0x31 + TagTryDwarfBlock Tag = 0x32 + TagVariantPart Tag = 0x33 + TagVariable Tag = 0x34 + TagVolatileType Tag = 0x35 + // The following are new in DWARF 3. + TagDwarfProcedure Tag = 0x36 + TagRestrictType Tag = 0x37 + TagInterfaceType Tag = 0x38 + TagNamespace Tag = 0x39 + TagImportedModule Tag = 0x3A + TagUnspecifiedType Tag = 0x3B + TagPartialUnit Tag = 0x3C + TagImportedUnit Tag = 0x3D + TagMutableType Tag = 0x3E // Later removed from DWARF. + TagCondition Tag = 0x3F + TagSharedType Tag = 0x40 + // The following are new in DWARF 4. + TagTypeUnit Tag = 0x41 + TagRvalueReferenceType Tag = 0x42 + TagTemplateAlias Tag = 0x43 + // The following are new in DWARF 5. + TagCoarrayType Tag = 0x44 + TagGenericSubrange Tag = 0x45 + TagDynamicType Tag = 0x46 + TagAtomicType Tag = 0x47 + TagCallSite Tag = 0x48 + TagCallSiteParameter Tag = 0x49 + TagSkeletonUnit Tag = 0x4A + TagImmutableType Tag = 0x4B +) + +func (t Tag) GoString() string { + if t <= TagTemplateAlias { + return "dwarf.Tag" + t.String() + } + return "dwarf." + t.String() +} + +// Location expression operators. +// The debug info encodes value locations like 8(R3) +// as a sequence of these op codes. +// This package does not implement full expressions; +// the opPlusUconst operator is expected by the type parser. +const ( + opAddr = 0x03 /* 1 op, const addr */ + opDeref = 0x06 + opConst1u = 0x08 /* 1 op, 1 byte const */ + opConst1s = 0x09 /* " signed */ + opConst2u = 0x0A /* 1 op, 2 byte const */ + opConst2s = 0x0B /* " signed */ + opConst4u = 0x0C /* 1 op, 4 byte const */ + opConst4s = 0x0D /* " signed */ + opConst8u = 0x0E /* 1 op, 8 byte const */ + opConst8s = 0x0F /* " signed */ + opConstu = 0x10 /* 1 op, LEB128 const */ + opConsts = 0x11 /* " signed */ + opDup = 0x12 + opDrop = 0x13 + opOver = 0x14 + opPick = 0x15 /* 1 op, 1 byte stack index */ + opSwap = 0x16 + opRot = 0x17 + opXderef = 0x18 + opAbs = 0x19 + opAnd = 0x1A + opDiv = 0x1B + opMinus = 0x1C + opMod = 0x1D + opMul = 0x1E + opNeg = 0x1F + opNot = 0x20 + opOr = 0x21 + opPlus = 0x22 + opPlusUconst = 0x23 /* 1 op, ULEB128 addend */ + opShl = 0x24 + opShr = 0x25 + opShra = 0x26 + opXor = 0x27 + opSkip = 0x2F /* 1 op, signed 2-byte constant */ + opBra = 0x28 /* 1 op, signed 2-byte constant */ + opEq = 0x29 + opGe = 0x2A + opGt = 0x2B + opLe = 0x2C + opLt = 0x2D + opNe = 0x2E + opLit0 = 0x30 + /* OpLitN = OpLit0 + N for N = 0..31 */ + opReg0 = 0x50 + /* OpRegN = OpReg0 + N for N = 0..31 */ + opBreg0 = 0x70 /* 1 op, signed LEB128 constant */ + /* OpBregN = OpBreg0 + N for N = 0..31 */ + opRegx = 0x90 /* 1 op, ULEB128 register */ + opFbreg = 0x91 /* 1 op, SLEB128 offset */ + opBregx = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */ + opPiece = 0x93 /* 1 op, ULEB128 size of piece */ + opDerefSize = 0x94 /* 1-byte size of data retrieved */ + opXderefSize = 0x95 /* 1-byte size of data retrieved */ + opNop = 0x96 + // The following are new in DWARF 3. + opPushObjAddr = 0x97 + opCall2 = 0x98 /* 2-byte offset of DIE */ + opCall4 = 0x99 /* 4-byte offset of DIE */ + opCallRef = 0x9A /* 4- or 8- byte offset of DIE */ + opFormTLSAddress = 0x9B + opCallFrameCFA = 0x9C + opBitPiece = 0x9D + // The following are new in DWARF 4. + opImplicitValue = 0x9E + opStackValue = 0x9F + // The following a new in DWARF 5. + opImplicitPointer = 0xA0 + opAddrx = 0xA1 + opConstx = 0xA2 + opEntryValue = 0xA3 + opConstType = 0xA4 + opRegvalType = 0xA5 + opDerefType = 0xA6 + opXderefType = 0xA7 + opConvert = 0xA8 + opReinterpret = 0xA9 + /* 0xE0-0xFF reserved for user-specific */ +) + +// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry. +const ( + encAddress = 0x01 + encBoolean = 0x02 + encComplexFloat = 0x03 + encFloat = 0x04 + encSigned = 0x05 + encSignedChar = 0x06 + encUnsigned = 0x07 + encUnsignedChar = 0x08 + // The following are new in DWARF 3. + encImaginaryFloat = 0x09 + encPackedDecimal = 0x0A + encNumericString = 0x0B + encEdited = 0x0C + encSignedFixed = 0x0D + encUnsignedFixed = 0x0E + encDecimalFloat = 0x0F + // The following are new in DWARF 4. + encUTF = 0x10 + // The following are new in DWARF 5. + encUCS = 0x11 + encASCII = 0x12 +) + +// Statement program standard opcode encodings. +const ( + lnsCopy = 1 + lnsAdvancePC = 2 + lnsAdvanceLine = 3 + lnsSetFile = 4 + lnsSetColumn = 5 + lnsNegateStmt = 6 + lnsSetBasicBlock = 7 + lnsConstAddPC = 8 + lnsFixedAdvancePC = 9 + + // DWARF 3 + lnsSetPrologueEnd = 10 + lnsSetEpilogueBegin = 11 + lnsSetISA = 12 +) + +// Statement program extended opcode encodings. +const ( + lneEndSequence = 1 + lneSetAddress = 2 + lneDefineFile = 3 + + // DWARF 4 + lneSetDiscriminator = 4 +) + +// Line table directory and file name entry formats. +// These are new in DWARF 5. +const ( + lnctPath = 0x01 + lnctDirectoryIndex = 0x02 + lnctTimestamp = 0x03 + lnctSize = 0x04 + lnctMD5 = 0x05 +) + +// Location list entry codes. +// These are new in DWARF 5. +const ( + lleEndOfList = 0x00 + lleBaseAddressx = 0x01 + lleStartxEndx = 0x02 + lleStartxLength = 0x03 + lleOffsetPair = 0x04 + lleDefaultLocation = 0x05 + lleBaseAddress = 0x06 + lleStartEnd = 0x07 + lleStartLength = 0x08 +) + +// Unit header unit type encodings. +// These are new in DWARF 5. +const ( + utCompile = 0x01 + utType = 0x02 + utPartial = 0x03 + utSkeleton = 0x04 + utSplitCompile = 0x05 + utSplitType = 0x06 +) + +// Opcodes for DWARFv5 debug_rnglists section. +const ( + rleEndOfList = 0x0 + rleBaseAddressx = 0x1 + rleStartxEndx = 0x2 + rleStartxLength = 0x3 + rleOffsetPair = 0x4 + rleBaseAddress = 0x5 + rleStartEnd = 0x6 + rleStartLength = 0x7 +) diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/entry.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/entry.go new file mode 100644 index 00000000..5bb4297b --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/entry.go @@ -0,0 +1,1218 @@ +// 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. + +// DWARF debug information entry parser. +// An entry is a sequence of data items of a given format. +// The first word in the entry is an index into what DWARF +// calls the ``abbreviation table.'' An abbreviation is really +// just a type descriptor: it's an array of attribute tag/value format pairs. + +package dwarf + +import ( + "encoding/binary" + "errors" + "fmt" + "strconv" +) + +// a single entry's description: a sequence of attributes +type abbrev struct { + tag Tag + children bool + field []afield +} + +type afield struct { + attr Attr + fmt format + class Class + val int64 // for formImplicitConst +} + +// a map from entry format ids to their descriptions +type abbrevTable map[uint32]abbrev + +// parseAbbrev returns the abbreviation table that starts at byte off +// in the .debug_abbrev section. +func (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) { + if m, ok := d.abbrevCache[off]; ok { + return m, nil + } + + data := d.abbrev + if off > uint64(len(data)) { + data = nil + } else { + data = data[off:] + } + b := makeBuf(d, unknownFormat{}, "abbrev", 0, data) + + // Error handling is simplified by the buf getters + // returning an endless stream of 0s after an error. + m := make(abbrevTable) + for { + // Table ends with id == 0. + id := uint32(b.uint()) + if id == 0 { + break + } + + // Walk over attributes, counting. + n := 0 + b1 := b // Read from copy of b. + b1.uint() + b1.uint8() + for { + tag := b1.uint() + fmt := b1.uint() + if tag == 0 && fmt == 0 { + break + } + if format(fmt) == formImplicitConst { + b1.int() + } + n++ + } + if b1.err != nil { + return nil, b1.err + } + + // Walk over attributes again, this time writing them down. + var a abbrev + a.tag = Tag(b.uint()) + a.children = b.uint8() != 0 + a.field = make([]afield, n) + for i := range a.field { + a.field[i].attr = Attr(b.uint()) + a.field[i].fmt = format(b.uint()) + a.field[i].class = formToClass(a.field[i].fmt, a.field[i].attr, vers, &b) + if a.field[i].fmt == formImplicitConst { + a.field[i].val = b.int() + } + } + b.uint() + b.uint() + + m[id] = a + } + if b.err != nil { + return nil, b.err + } + d.abbrevCache[off] = m + return m, nil +} + +// attrIsExprloc indicates attributes that allow exprloc values that +// are encoded as block values in DWARF 2 and 3. See DWARF 4, Figure +// 20. +var attrIsExprloc = map[Attr]bool{ + AttrLocation: true, + AttrByteSize: true, + AttrBitOffset: true, + AttrBitSize: true, + AttrStringLength: true, + AttrLowerBound: true, + AttrReturnAddr: true, + AttrStrideSize: true, + AttrUpperBound: true, + AttrCount: true, + AttrDataMemberLoc: true, + AttrFrameBase: true, + AttrSegment: true, + AttrStaticLink: true, + AttrUseLocation: true, + AttrVtableElemLoc: true, + AttrAllocated: true, + AttrAssociated: true, + AttrDataLocation: true, + AttrStride: true, +} + +// attrPtrClass indicates the *ptr class of attributes that have +// encoding formSecOffset in DWARF 4 or formData* in DWARF 2 and 3. +var attrPtrClass = map[Attr]Class{ + AttrLocation: ClassLocListPtr, + AttrStmtList: ClassLinePtr, + AttrStringLength: ClassLocListPtr, + AttrReturnAddr: ClassLocListPtr, + AttrStartScope: ClassRangeListPtr, + AttrDataMemberLoc: ClassLocListPtr, + AttrFrameBase: ClassLocListPtr, + AttrMacroInfo: ClassMacPtr, + AttrSegment: ClassLocListPtr, + AttrStaticLink: ClassLocListPtr, + AttrUseLocation: ClassLocListPtr, + AttrVtableElemLoc: ClassLocListPtr, + AttrRanges: ClassRangeListPtr, + // The following are new in DWARF 5. + AttrStrOffsetsBase: ClassStrOffsetsPtr, + AttrAddrBase: ClassAddrPtr, + AttrRnglistsBase: ClassRngListsPtr, + AttrLoclistsBase: ClassLocListPtr, +} + +// formToClass returns the DWARF 4 Class for the given form. If the +// DWARF version is less then 4, it will disambiguate some forms +// depending on the attribute. +func formToClass(form format, attr Attr, vers int, b *buf) Class { + switch form { + default: + b.error("cannot determine class of unknown attribute form") + return 0 + + case formIndirect: + return ClassUnknown + + case formAddr, formAddrx, formAddrx1, formAddrx2, formAddrx3, formAddrx4: + return ClassAddress + + case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock: + // In DWARF 2 and 3, ClassExprLoc was encoded as a + // block. DWARF 4 distinguishes ClassBlock and + // ClassExprLoc, but there are no attributes that can + // be both, so we also promote ClassBlock values in + // DWARF 4 that should be ClassExprLoc in case + // producers get this wrong. + if attrIsExprloc[attr] { + return ClassExprLoc + } + return ClassBlock + + case formData1, formData2, formData4, formData8, formSdata, formUdata, formData16, formImplicitConst: + // In DWARF 2 and 3, ClassPtr was encoded as a + // constant. Unlike ClassExprLoc/ClassBlock, some + // DWARF 4 attributes need to distinguish Class*Ptr + // from ClassConstant, so we only do this promotion + // for versions 2 and 3. + if class, ok := attrPtrClass[attr]; vers < 4 && ok { + return class + } + return ClassConstant + + case formFlag, formFlagPresent: + return ClassFlag + + case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata, formRefSup4, formRefSup8: + return ClassReference + + case formRefSig8: + return ClassReferenceSig + + case formString, formStrp, formStrx, formStrpSup, formLineStrp, formStrx1, formStrx2, formStrx3, formStrx4: + return ClassString + + case formSecOffset: + // DWARF 4 defines four *ptr classes, but doesn't + // distinguish them in the encoding. Disambiguate + // these classes using the attribute. + if class, ok := attrPtrClass[attr]; ok { + return class + } + return ClassUnknown + + case formExprloc: + return ClassExprLoc + + case formGnuRefAlt: + return ClassReferenceAlt + + case formGnuStrpAlt: + return ClassStringAlt + + case formLoclistx: + return ClassLocList + + case formRnglistx: + return ClassRngList + } +} + +// An entry is a sequence of attribute/value pairs. +type Entry struct { + Offset Offset // offset of Entry in DWARF info + Tag Tag // tag (kind of Entry) + Children bool // whether Entry is followed by children + Field []Field +} + +// A Field is a single attribute/value pair in an Entry. +// +// A value can be one of several "attribute classes" defined by DWARF. +// The Go types corresponding to each class are: +// +// DWARF class Go type Class +// ----------- ------- ----- +// address uint64 ClassAddress +// block []byte ClassBlock +// constant int64 ClassConstant +// flag bool ClassFlag +// reference +// to info dwarf.Offset ClassReference +// to type unit uint64 ClassReferenceSig +// string string ClassString +// exprloc []byte ClassExprLoc +// lineptr int64 ClassLinePtr +// loclistptr int64 ClassLocListPtr +// macptr int64 ClassMacPtr +// rangelistptr int64 ClassRangeListPtr +// +// For unrecognized or vendor-defined attributes, Class may be +// ClassUnknown. +type Field struct { + Attr Attr + Val any + Class Class +} + +// A Class is the DWARF 4 class of an attribute value. +// +// In general, a given attribute's value may take on one of several +// possible classes defined by DWARF, each of which leads to a +// slightly different interpretation of the attribute. +// +// DWARF version 4 distinguishes attribute value classes more finely +// than previous versions of DWARF. The reader will disambiguate +// coarser classes from earlier versions of DWARF into the appropriate +// DWARF 4 class. For example, DWARF 2 uses "constant" for constants +// as well as all types of section offsets, but the reader will +// canonicalize attributes in DWARF 2 files that refer to section +// offsets to one of the Class*Ptr classes, even though these classes +// were only defined in DWARF 3. +type Class int + +const ( + // ClassUnknown represents values of unknown DWARF class. + ClassUnknown Class = iota + + // ClassAddress represents values of type uint64 that are + // addresses on the target machine. + ClassAddress + + // ClassBlock represents values of type []byte whose + // interpretation depends on the attribute. + ClassBlock + + // ClassConstant represents values of type int64 that are + // constants. The interpretation of this constant depends on + // the attribute. + ClassConstant + + // ClassExprLoc represents values of type []byte that contain + // an encoded DWARF expression or location description. + ClassExprLoc + + // ClassFlag represents values of type bool. + ClassFlag + + // ClassLinePtr represents values that are an int64 offset + // into the "line" section. + ClassLinePtr + + // ClassLocListPtr represents values that are an int64 offset + // into the "loclist" section. + ClassLocListPtr + + // ClassMacPtr represents values that are an int64 offset into + // the "mac" section. + ClassMacPtr + + // ClassRangeListPtr represents values that are an int64 offset into + // the "rangelist" section. + ClassRangeListPtr + + // ClassReference represents values that are an Offset offset + // of an Entry in the info section (for use with Reader.Seek). + // The DWARF specification combines ClassReference and + // ClassReferenceSig into class "reference". + ClassReference + + // ClassReferenceSig represents values that are a uint64 type + // signature referencing a type Entry. + ClassReferenceSig + + // ClassString represents values that are strings. If the + // compilation unit specifies the AttrUseUTF8 flag (strongly + // recommended), the string value will be encoded in UTF-8. + // Otherwise, the encoding is unspecified. + ClassString + + // ClassReferenceAlt represents values of type int64 that are + // an offset into the DWARF "info" section of an alternate + // object file. + ClassReferenceAlt + + // ClassStringAlt represents values of type int64 that are an + // offset into the DWARF string section of an alternate object + // file. + ClassStringAlt + + // ClassAddrPtr represents values that are an int64 offset + // into the "addr" section. + ClassAddrPtr + + // ClassLocList represents values that are an int64 offset + // into the "loclists" section. + ClassLocList + + // ClassRngList represents values that are a uint64 offset + // from the base of the "rnglists" section. + ClassRngList + + // ClassRngListsPtr represents values that are an int64 offset + // into the "rnglists" section. These are used as the base for + // ClassRngList values. + ClassRngListsPtr + + // ClassStrOffsetsPtr represents values that are an int64 + // offset into the "str_offsets" section. + ClassStrOffsetsPtr +) + +//go:generate stringer -type=Class + +func (i Class) GoString() string { + return "dwarf." + i.String() +} + +// Val returns the value associated with attribute Attr in Entry, +// or nil if there is no such attribute. +// +// A common idiom is to merge the check for nil return with +// the check that the value has the expected dynamic type, as in: +// +// v, ok := e.Val(AttrSibling).(int64) +func (e *Entry) Val(a Attr) any { + if f := e.AttrField(a); f != nil { + return f.Val + } + return nil +} + +// AttrField returns the Field associated with attribute Attr in +// Entry, or nil if there is no such attribute. +func (e *Entry) AttrField(a Attr) *Field { + for i, f := range e.Field { + if f.Attr == a { + return &e.Field[i] + } + } + return nil +} + +// An Offset represents the location of an Entry within the DWARF info. +// (See Reader.Seek.) +type Offset uint32 + +// Entry reads a single entry from buf, decoding +// according to the given abbreviation table. +func (b *buf) entry(cu *Entry, atab abbrevTable, ubase Offset, vers int) *Entry { + off := b.off + id := uint32(b.uint()) + if id == 0 { + return &Entry{} + } + a, ok := atab[id] + if !ok { + b.error("unknown abbreviation table index") + return nil + } + e := &Entry{ + Offset: off, + Tag: a.tag, + Children: a.children, + Field: make([]Field, len(a.field)), + } + + // If we are currently parsing the compilation unit, + // we can't evaluate Addrx or Strx until we've seen the + // relevant base entry. + type delayed struct { + idx int + off uint64 + fmt format + } + var delay []delayed + + resolveStrx := func(strBase, off uint64) string { + off += strBase + if uint64(int(off)) != off { + b.error("DW_FORM_strx offset out of range") + } + + b1 := makeBuf(b.dwarf, b.format, "str_offsets", 0, b.dwarf.strOffsets) + b1.skip(int(off)) + is64, _ := b.format.dwarf64() + if is64 { + off = b1.uint64() + } else { + off = uint64(b1.uint32()) + } + if b1.err != nil { + b.err = b1.err + return "" + } + if uint64(int(off)) != off { + b.error("DW_FORM_strx indirect offset out of range") + } + b1 = makeBuf(b.dwarf, b.format, "str", 0, b.dwarf.str) + b1.skip(int(off)) + val := b1.string() + if b1.err != nil { + b.err = b1.err + } + return val + } + + resolveRnglistx := func(rnglistsBase, off uint64) uint64 { + is64, _ := b.format.dwarf64() + if is64 { + off *= 8 + } else { + off *= 4 + } + off += rnglistsBase + if uint64(int(off)) != off { + b.error("DW_FORM_rnglistx offset out of range") + } + + b1 := makeBuf(b.dwarf, b.format, "rnglists", 0, b.dwarf.rngLists) + b1.skip(int(off)) + if is64 { + off = b1.uint64() + } else { + off = uint64(b1.uint32()) + } + if b1.err != nil { + b.err = b1.err + return 0 + } + if uint64(int(off)) != off { + b.error("DW_FORM_rnglistx indirect offset out of range") + } + return rnglistsBase + off + } + + for i := range e.Field { + e.Field[i].Attr = a.field[i].attr + e.Field[i].Class = a.field[i].class + fmt := a.field[i].fmt + if fmt == formIndirect { + fmt = format(b.uint()) + e.Field[i].Class = formToClass(fmt, a.field[i].attr, vers, b) + } + var val any + switch fmt { + default: + b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16)) + + // address + case formAddr: + val = b.addr() + case formAddrx, formAddrx1, formAddrx2, formAddrx3, formAddrx4: + var off uint64 + switch fmt { + case formAddrx: + off = b.uint() + case formAddrx1: + off = uint64(b.uint8()) + case formAddrx2: + off = uint64(b.uint16()) + case formAddrx3: + off = uint64(b.uint24()) + case formAddrx4: + off = uint64(b.uint32()) + } + if b.dwarf.addr == nil { + b.error("DW_FORM_addrx with no .debug_addr section") + } + if b.err != nil { + return nil + } + + // We have to adjust by the offset of the + // compilation unit. This won't work if the + // program uses Reader.Seek to skip over the + // unit. Not much we can do about that. + var addrBase int64 + if cu != nil { + addrBase, _ = cu.Val(AttrAddrBase).(int64) + } else if a.tag == TagCompileUnit { + delay = append(delay, delayed{i, off, formAddrx}) + break + } + + var err error + val, err = b.dwarf.debugAddr(b.format, uint64(addrBase), off) + if err != nil { + if b.err == nil { + b.err = err + } + return nil + } + + // block + case formDwarfBlock1: + val = b.bytes(int(b.uint8())) + case formDwarfBlock2: + val = b.bytes(int(b.uint16())) + case formDwarfBlock4: + val = b.bytes(int(b.uint32())) + case formDwarfBlock: + val = b.bytes(int(b.uint())) + + // constant + case formData1: + val = int64(b.uint8()) + case formData2: + val = int64(b.uint16()) + case formData4: + val = int64(b.uint32()) + case formData8: + val = int64(b.uint64()) + case formData16: + val = b.bytes(16) + case formSdata: + val = int64(b.int()) + case formUdata: + val = int64(b.uint()) + case formImplicitConst: + val = a.field[i].val + + // flag + case formFlag: + val = b.uint8() == 1 + // New in DWARF 4. + case formFlagPresent: + // The attribute is implicitly indicated as present, and no value is + // encoded in the debugging information entry itself. + val = true + + // reference to other entry + case formRefAddr: + vers := b.format.version() + if vers == 0 { + b.error("unknown version for DW_FORM_ref_addr") + } else if vers == 2 { + val = Offset(b.addr()) + } else { + is64, known := b.format.dwarf64() + if !known { + b.error("unknown size for DW_FORM_ref_addr") + } else if is64 { + val = Offset(b.uint64()) + } else { + val = Offset(b.uint32()) + } + } + case formRef1: + val = Offset(b.uint8()) + ubase + case formRef2: + val = Offset(b.uint16()) + ubase + case formRef4: + val = Offset(b.uint32()) + ubase + case formRef8: + val = Offset(b.uint64()) + ubase + case formRefUdata: + val = Offset(b.uint()) + ubase + + // string + case formString: + val = b.string() + case formStrp, formLineStrp: + var off uint64 // offset into .debug_str + is64, known := b.format.dwarf64() + if !known { + b.error("unknown size for DW_FORM_strp/line_strp") + } else if is64 { + off = b.uint64() + } else { + off = uint64(b.uint32()) + } + if uint64(int(off)) != off { + b.error("DW_FORM_strp/line_strp offset out of range") + } + if b.err != nil { + return nil + } + var b1 buf + if fmt == formStrp { + b1 = makeBuf(b.dwarf, b.format, "str", 0, b.dwarf.str) + } else { + if len(b.dwarf.lineStr) == 0 { + b.error("DW_FORM_line_strp with no .debug_line_str section") + return nil + } + b1 = makeBuf(b.dwarf, b.format, "line_str", 0, b.dwarf.lineStr) + } + b1.skip(int(off)) + val = b1.string() + if b1.err != nil { + b.err = b1.err + return nil + } + case formStrx, formStrx1, formStrx2, formStrx3, formStrx4: + var off uint64 + switch fmt { + case formStrx: + off = b.uint() + case formStrx1: + off = uint64(b.uint8()) + case formStrx2: + off = uint64(b.uint16()) + case formStrx3: + off = uint64(b.uint24()) + case formStrx4: + off = uint64(b.uint32()) + } + if len(b.dwarf.strOffsets) == 0 { + b.error("DW_FORM_strx with no .debug_str_offsets section") + } + is64, known := b.format.dwarf64() + if !known { + b.error("unknown offset size for DW_FORM_strx") + } + if b.err != nil { + return nil + } + if is64 { + off *= 8 + } else { + off *= 4 + } + + // We have to adjust by the offset of the + // compilation unit. This won't work if the + // program uses Reader.Seek to skip over the + // unit. Not much we can do about that. + var strBase int64 + if cu != nil { + strBase, _ = cu.Val(AttrStrOffsetsBase).(int64) + } else if a.tag == TagCompileUnit { + delay = append(delay, delayed{i, off, formStrx}) + break + } + + val = resolveStrx(uint64(strBase), off) + + case formStrpSup: + is64, known := b.format.dwarf64() + if !known { + b.error("unknown size for DW_FORM_strp_sup") + } else if is64 { + val = b.uint64() + } else { + val = b.uint32() + } + + // lineptr, loclistptr, macptr, rangelistptr + // New in DWARF 4, but clang can generate them with -gdwarf-2. + // Section reference, replacing use of formData4 and formData8. + case formSecOffset, formGnuRefAlt, formGnuStrpAlt: + is64, known := b.format.dwarf64() + if !known { + b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16)) + } else if is64 { + val = int64(b.uint64()) + } else { + val = int64(b.uint32()) + } + + // exprloc + // New in DWARF 4. + case formExprloc: + val = b.bytes(int(b.uint())) + + // reference + // New in DWARF 4. + case formRefSig8: + // 64-bit type signature. + val = b.uint64() + case formRefSup4: + val = b.uint32() + case formRefSup8: + val = b.uint64() + + // loclist + case formLoclistx: + val = b.uint() + + // rnglist + case formRnglistx: + off := b.uint() + + // We have to adjust by the rnglists_base of + // the compilation unit. This won't work if + // the program uses Reader.Seek to skip over + // the unit. Not much we can do about that. + var rnglistsBase int64 + if cu != nil { + rnglistsBase, _ = cu.Val(AttrRnglistsBase).(int64) + } else if a.tag == TagCompileUnit { + delay = append(delay, delayed{i, off, formRnglistx}) + break + } + + val = resolveRnglistx(uint64(rnglistsBase), off) + } + + e.Field[i].Val = val + } + if b.err != nil { + return nil + } + + for _, del := range delay { + switch del.fmt { + case formAddrx: + addrBase, _ := e.Val(AttrAddrBase).(int64) + val, err := b.dwarf.debugAddr(b.format, uint64(addrBase), del.off) + if err != nil { + b.err = err + return nil + } + e.Field[del.idx].Val = val + case formStrx: + strBase, _ := e.Val(AttrStrOffsetsBase).(int64) + e.Field[del.idx].Val = resolveStrx(uint64(strBase), del.off) + if b.err != nil { + return nil + } + case formRnglistx: + rnglistsBase, _ := e.Val(AttrRnglistsBase).(int64) + e.Field[del.idx].Val = resolveRnglistx(uint64(rnglistsBase), del.off) + if b.err != nil { + return nil + } + } + } + + return e +} + +// A Reader allows reading Entry structures from a DWARF “info” section. +// The Entry structures are arranged in a tree. The Reader's Next function +// return successive entries from a pre-order traversal of the tree. +// If an entry has children, its Children field will be true, and the children +// follow, terminated by an Entry with Tag 0. +type Reader struct { + b buf + d *Data + err error + unit int + lastUnit bool // set if last entry returned by Next is TagCompileUnit/TagPartialUnit + lastChildren bool // .Children of last entry returned by Next + lastSibling Offset // .Val(AttrSibling) of last entry returned by Next + cu *Entry // current compilation unit +} + +// Reader returns a new Reader for Data. +// The reader is positioned at byte offset 0 in the DWARF “info” section. +func (d *Data) Reader() *Reader { + r := &Reader{d: d} + r.Seek(0) + return r +} + +// AddressSize returns the size in bytes of addresses in the current compilation +// unit. +func (r *Reader) AddressSize() int { + return r.d.unit[r.unit].asize +} + +// ByteOrder returns the byte order in the current compilation unit. +func (r *Reader) ByteOrder() binary.ByteOrder { + return r.b.order +} + +// Seek positions the Reader at offset off in the encoded entry stream. +// Offset 0 can be used to denote the first entry. +func (r *Reader) Seek(off Offset) { + d := r.d + r.err = nil + r.lastChildren = false + if off == 0 { + if len(d.unit) == 0 { + return + } + u := &d.unit[0] + r.unit = 0 + r.b = makeBuf(r.d, u, "info", u.off, u.data) + r.cu = nil + return + } + + i := d.offsetToUnit(off) + if i == -1 { + r.err = errors.New("offset out of range") + return + } + if i != r.unit { + r.cu = nil + } + u := &d.unit[i] + r.unit = i + r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:]) +} + +// maybeNextUnit advances to the next unit if this one is finished. +func (r *Reader) maybeNextUnit() { + for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) { + r.nextUnit() + } +} + +// nextUnit advances to the next unit. +func (r *Reader) nextUnit() { + r.unit++ + u := &r.d.unit[r.unit] + r.b = makeBuf(r.d, u, "info", u.off, u.data) + r.cu = nil +} + +// Next reads the next entry from the encoded entry stream. +// It returns nil, nil when it reaches the end of the section. +// It returns an error if the current offset is invalid or the data at the +// offset cannot be decoded as a valid Entry. +func (r *Reader) Next() (*Entry, error) { + if r.err != nil { + return nil, r.err + } + r.maybeNextUnit() + if len(r.b.data) == 0 { + return nil, nil + } + u := &r.d.unit[r.unit] + e := r.b.entry(r.cu, u.atable, u.base, u.vers) + if r.b.err != nil { + r.err = r.b.err + return nil, r.err + } + r.lastUnit = false + if e != nil { + r.lastChildren = e.Children + if r.lastChildren { + r.lastSibling, _ = e.Val(AttrSibling).(Offset) + } + if e.Tag == TagCompileUnit || e.Tag == TagPartialUnit { + r.lastUnit = true + r.cu = e + } + } else { + r.lastChildren = false + } + return e, nil +} + +// SkipChildren skips over the child entries associated with +// the last Entry returned by Next. If that Entry did not have +// children or Next has not been called, SkipChildren is a no-op. +func (r *Reader) SkipChildren() { + if r.err != nil || !r.lastChildren { + return + } + + // If the last entry had a sibling attribute, + // that attribute gives the offset of the next + // sibling, so we can avoid decoding the + // child subtrees. + if r.lastSibling >= r.b.off { + r.Seek(r.lastSibling) + return + } + + if r.lastUnit && r.unit+1 < len(r.d.unit) { + r.nextUnit() + return + } + + for { + e, err := r.Next() + if err != nil || e == nil || e.Tag == 0 { + break + } + if e.Children { + r.SkipChildren() + } + } +} + +// clone returns a copy of the reader. This is used by the typeReader +// interface. +func (r *Reader) clone() typeReader { + return r.d.Reader() +} + +// offset returns the current buffer offset. This is used by the +// typeReader interface. +func (r *Reader) offset() Offset { + return r.b.off +} + +// SeekPC returns the Entry for the compilation unit that includes pc, +// and positions the reader to read the children of that unit. If pc +// is not covered by any unit, SeekPC returns ErrUnknownPC and the +// position of the reader is undefined. +// +// Because compilation units can describe multiple regions of the +// executable, in the worst case SeekPC must search through all the +// ranges in all the compilation units. Each call to SeekPC starts the +// search at the compilation unit of the last call, so in general +// looking up a series of PCs will be faster if they are sorted. If +// the caller wishes to do repeated fast PC lookups, it should build +// an appropriate index using the Ranges method. +func (r *Reader) SeekPC(pc uint64) (*Entry, error) { + unit := r.unit + for i := 0; i < len(r.d.unit); i++ { + if unit >= len(r.d.unit) { + unit = 0 + } + r.err = nil + r.lastChildren = false + r.unit = unit + r.cu = nil + u := &r.d.unit[unit] + r.b = makeBuf(r.d, u, "info", u.off, u.data) + e, err := r.Next() + if err != nil || e == nil || e.Tag == 0 { + return nil, err + } + ranges, err := r.d.Ranges(e) + if err != nil { + return nil, err + } + for _, pcs := range ranges { + if pcs[0] <= pc && pc < pcs[1] { + return e, nil + } + } + unit++ + } + return nil, ErrUnknownPC +} + +// Ranges returns the PC ranges covered by e, a slice of [low,high) pairs. +// Only some entry types, such as TagCompileUnit or TagSubprogram, have PC +// ranges; for others, this will return nil with no error. +func (d *Data) Ranges(e *Entry) ([][2]uint64, error) { + var ret [][2]uint64 + + low, lowOK := e.Val(AttrLowpc).(uint64) + + var high uint64 + var highOK bool + highField := e.AttrField(AttrHighpc) + if highField != nil { + switch highField.Class { + case ClassAddress: + high, highOK = highField.Val.(uint64) + case ClassConstant: + off, ok := highField.Val.(int64) + if ok { + high = low + uint64(off) + highOK = true + } + } + } + + if lowOK && highOK { + ret = append(ret, [2]uint64{low, high}) + } + + var u *unit + if uidx := d.offsetToUnit(e.Offset); uidx >= 0 && uidx < len(d.unit) { + u = &d.unit[uidx] + } + + if u != nil && u.vers >= 5 && d.rngLists != nil { + // DWARF version 5 and later + field := e.AttrField(AttrRanges) + if field == nil { + return ret, nil + } + switch field.Class { + case ClassRangeListPtr: + ranges, rangesOK := field.Val.(int64) + if !rangesOK { + return ret, nil + } + cu, base, err := d.baseAddressForEntry(e) + if err != nil { + return nil, err + } + return d.dwarf5Ranges(u, cu, base, ranges, ret) + + case ClassRngList: + rnglist, ok := field.Val.(uint64) + if !ok { + return ret, nil + } + cu, base, err := d.baseAddressForEntry(e) + if err != nil { + return nil, err + } + return d.dwarf5Ranges(u, cu, base, int64(rnglist), ret) + + default: + return ret, nil + } + } + + // DWARF version 2 through 4 + ranges, rangesOK := e.Val(AttrRanges).(int64) + if rangesOK && d.ranges != nil { + _, base, err := d.baseAddressForEntry(e) + if err != nil { + return nil, err + } + return d.dwarf2Ranges(u, base, ranges, ret) + } + + return ret, nil +} + +// baseAddressForEntry returns the initial base address to be used when +// looking up the range list of entry e. +// DWARF specifies that this should be the lowpc attribute of the enclosing +// compilation unit, however comments in gdb/dwarf2read.c say that some +// versions of GCC use the entrypc attribute, so we check that too. +func (d *Data) baseAddressForEntry(e *Entry) (*Entry, uint64, error) { + var cu *Entry + if e.Tag == TagCompileUnit { + cu = e + } else { + i := d.offsetToUnit(e.Offset) + if i == -1 { + return nil, 0, errors.New("no unit for entry") + } + u := &d.unit[i] + b := makeBuf(d, u, "info", u.off, u.data) + cu = b.entry(nil, u.atable, u.base, u.vers) + if b.err != nil { + return nil, 0, b.err + } + } + + if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK { + return cu, cuEntry, nil + } else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK { + return cu, cuLow, nil + } + + return cu, 0, nil +} + +func (d *Data) dwarf2Ranges(u *unit, base uint64, ranges int64, ret [][2]uint64) ([][2]uint64, error) { + if ranges < 0 || ranges > int64(len(d.ranges)) { + return nil, fmt.Errorf("invalid range offset %d (max %d)", ranges, len(d.ranges)) + } + buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:]) + for len(buf.data) > 0 { + low := buf.addr() + high := buf.addr() + + if low == 0 && high == 0 { + break + } + + if low == ^uint64(0)>>uint((8-u.addrsize())*8) { + base = high + } else { + ret = append(ret, [2]uint64{base + low, base + high}) + } + } + + return ret, nil +} + +// dwarf5Ranges interprets a debug_rnglists sequence, see DWARFv5 section +// 2.17.3 (page 53). +func (d *Data) dwarf5Ranges(u *unit, cu *Entry, base uint64, ranges int64, ret [][2]uint64) ([][2]uint64, error) { + if ranges < 0 || ranges > int64(len(d.rngLists)) { + return nil, fmt.Errorf("invalid rnglist offset %d (max %d)", ranges, len(d.ranges)) + } + var addrBase int64 + if cu != nil { + addrBase, _ = cu.Val(AttrAddrBase).(int64) + } + + buf := makeBuf(d, u, "rnglists", 0, d.rngLists) + buf.skip(int(ranges)) + for { + opcode := buf.uint8() + switch opcode { + case rleEndOfList: + if buf.err != nil { + return nil, buf.err + } + return ret, nil + + case rleBaseAddressx: + baseIdx := buf.uint() + var err error + base, err = d.debugAddr(u, uint64(addrBase), baseIdx) + if err != nil { + return nil, err + } + + case rleStartxEndx: + startIdx := buf.uint() + endIdx := buf.uint() + + start, err := d.debugAddr(u, uint64(addrBase), startIdx) + if err != nil { + return nil, err + } + end, err := d.debugAddr(u, uint64(addrBase), endIdx) + if err != nil { + return nil, err + } + ret = append(ret, [2]uint64{start, end}) + + case rleStartxLength: + startIdx := buf.uint() + len := buf.uint() + start, err := d.debugAddr(u, uint64(addrBase), startIdx) + if err != nil { + return nil, err + } + ret = append(ret, [2]uint64{start, start + len}) + + case rleOffsetPair: + off1 := buf.uint() + off2 := buf.uint() + ret = append(ret, [2]uint64{base + off1, base + off2}) + + case rleBaseAddress: + base = buf.addr() + + case rleStartEnd: + start := buf.addr() + end := buf.addr() + ret = append(ret, [2]uint64{start, end}) + + case rleStartLength: + start := buf.addr() + len := buf.uint() + ret = append(ret, [2]uint64{start, start + len}) + } + } +} + +// debugAddr returns the address at idx in debug_addr +func (d *Data) debugAddr(format dataFormat, addrBase, idx uint64) (uint64, error) { + off := idx*uint64(format.addrsize()) + addrBase + + if uint64(int(off)) != off { + return 0, errors.New("offset out of range") + } + + b := makeBuf(d, format, "addr", 0, d.addr) + b.skip(int(off)) + val := b.addr() + if b.err != nil { + return 0, b.err + } + return val, nil +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/line.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/line.go new file mode 100644 index 00000000..4df4a175 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/line.go @@ -0,0 +1,852 @@ +// 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 dwarf + +import ( + "errors" + "fmt" + "io" + "path" + "strings" +) + +// A LineReader reads a sequence of LineEntry structures from a DWARF +// "line" section for a single compilation unit. LineEntries occur in +// order of increasing PC and each LineEntry gives metadata for the +// instructions from that LineEntry's PC to just before the next +// LineEntry's PC. The last entry will have its EndSequence field set. +type LineReader struct { + buf buf + + // Original .debug_line section data. Used by Seek. + section []byte + + str []byte // .debug_str + lineStr []byte // .debug_line_str + + // Header information + version uint16 + addrsize int + segmentSelectorSize int + minInstructionLength int + maxOpsPerInstruction int + defaultIsStmt bool + lineBase int + lineRange int + opcodeBase int + opcodeLengths []int + directories []string + fileEntries []*LineFile + + programOffset Offset // section offset of line number program + endOffset Offset // section offset of byte following program + + initialFileEntries int // initial length of fileEntries + + // Current line number program state machine registers + state LineEntry // public state + fileIndex int // private state +} + +// A LineEntry is a row in a DWARF line table. +type LineEntry struct { + // Address is the program-counter value of a machine + // instruction generated by the compiler. This LineEntry + // applies to each instruction from Address to just before the + // Address of the next LineEntry. + Address uint64 + + // OpIndex is the index of an operation within a VLIW + // instruction. The index of the first operation is 0. For + // non-VLIW architectures, it will always be 0. Address and + // OpIndex together form an operation pointer that can + // reference any individual operation within the instruction + // stream. + OpIndex int + + // File is the source file corresponding to these + // instructions. + File *LineFile + + // Line is the source code line number corresponding to these + // instructions. Lines are numbered beginning at 1. It may be + // 0 if these instructions cannot be attributed to any source + // line. + Line int + + // Column is the column number within the source line of these + // instructions. Columns are numbered beginning at 1. It may + // be 0 to indicate the "left edge" of the line. + Column int + + // IsStmt indicates that Address is a recommended breakpoint + // location, such as the beginning of a line, statement, or a + // distinct subpart of a statement. + IsStmt bool + + // BasicBlock indicates that Address is the beginning of a + // basic block. + BasicBlock bool + + // PrologueEnd indicates that Address is one (of possibly + // many) PCs where execution should be suspended for a + // breakpoint on entry to the containing function. + // + // Added in DWARF 3. + PrologueEnd bool + + // EpilogueBegin indicates that Address is one (of possibly + // many) PCs where execution should be suspended for a + // breakpoint on exit from this function. + // + // Added in DWARF 3. + EpilogueBegin bool + + // ISA is the instruction set architecture for these + // instructions. Possible ISA values should be defined by the + // applicable ABI specification. + // + // Added in DWARF 3. + ISA int + + // Discriminator is an arbitrary integer indicating the block + // to which these instructions belong. It serves to + // distinguish among multiple blocks that may all have with + // the same source file, line, and column. Where only one + // block exists for a given source position, it should be 0. + // + // Added in DWARF 3. + Discriminator int + + // EndSequence indicates that Address is the first byte after + // the end of a sequence of target machine instructions. If it + // is set, only this and the Address field are meaningful. A + // line number table may contain information for multiple + // potentially disjoint instruction sequences. The last entry + // in a line table should always have EndSequence set. + EndSequence bool +} + +// A LineFile is a source file referenced by a DWARF line table entry. +type LineFile struct { + Name string + Mtime uint64 // Implementation defined modification time, or 0 if unknown + Length int // File length, or 0 if unknown +} + +// LineReader returns a new reader for the line table of compilation +// unit cu, which must be an Entry with tag TagCompileUnit. +// +// If this compilation unit has no line table, it returns nil, nil. +func (d *Data) LineReader(cu *Entry) (*LineReader, error) { + if d.line == nil { + // No line tables available. + return nil, nil + } + + // Get line table information from cu. + off, ok := cu.Val(AttrStmtList).(int64) + if !ok { + // cu has no line table. + return nil, nil + } + if off < 0 || off > int64(len(d.line)) { + return nil, errors.New("AttrStmtList value out of range") + } + // AttrCompDir is optional if all file names are absolute. Use + // the empty string if it's not present. + compDir, _ := cu.Val(AttrCompDir).(string) + + // Create the LineReader. + u := &d.unit[d.offsetToUnit(cu.Offset)] + buf := makeBuf(d, u, "line", Offset(off), d.line[off:]) + // The compilation directory is implicitly directories[0]. + r := LineReader{ + buf: buf, + section: d.line, + str: d.str, + lineStr: d.lineStr, + } + + // Read the header. + if err := r.readHeader(compDir); err != nil { + return nil, err + } + + // Initialize line reader state. + r.Reset() + + return &r, nil +} + +// readHeader reads the line number program header from r.buf and sets +// all of the header fields in r. +func (r *LineReader) readHeader(compDir string) error { + buf := &r.buf + + // Read basic header fields [DWARF2 6.2.4]. + hdrOffset := buf.off + unitLength, dwarf64 := buf.unitLength() + r.endOffset = buf.off + unitLength + if r.endOffset > buf.off+Offset(len(buf.data)) { + return DecodeError{"line", hdrOffset, fmt.Sprintf("line table end %d exceeds section size %d", r.endOffset, buf.off+Offset(len(buf.data)))} + } + r.version = buf.uint16() + if buf.err == nil && (r.version < 2 || r.version > 5) { + // DWARF goes to all this effort to make new opcodes + // backward-compatible, and then adds fields right in + // the middle of the header in new versions, so we're + // picky about only supporting known line table + // versions. + return DecodeError{"line", hdrOffset, fmt.Sprintf("unknown line table version %d", r.version)} + } + if r.version >= 5 { + r.addrsize = int(buf.uint8()) + r.segmentSelectorSize = int(buf.uint8()) + } else { + r.addrsize = buf.format.addrsize() + r.segmentSelectorSize = 0 + } + var headerLength Offset + if dwarf64 { + headerLength = Offset(buf.uint64()) + } else { + headerLength = Offset(buf.uint32()) + } + programOffset := buf.off + headerLength + if programOffset > r.endOffset { + return DecodeError{"line", hdrOffset, fmt.Sprintf("malformed line table: program offset %d exceeds end offset %d", programOffset, r.endOffset)} + } + r.programOffset = programOffset + r.minInstructionLength = int(buf.uint8()) + if r.version >= 4 { + // [DWARF4 6.2.4] + r.maxOpsPerInstruction = int(buf.uint8()) + } else { + r.maxOpsPerInstruction = 1 + } + r.defaultIsStmt = buf.uint8() != 0 + r.lineBase = int(int8(buf.uint8())) + r.lineRange = int(buf.uint8()) + + // Validate header. + if buf.err != nil { + return buf.err + } + if r.maxOpsPerInstruction == 0 { + return DecodeError{"line", hdrOffset, "invalid maximum operations per instruction: 0"} + } + if r.lineRange == 0 { + return DecodeError{"line", hdrOffset, "invalid line range: 0"} + } + + // Read standard opcode length table. This table starts with opcode 1. + r.opcodeBase = int(buf.uint8()) + r.opcodeLengths = make([]int, r.opcodeBase) + for i := 1; i < r.opcodeBase; i++ { + r.opcodeLengths[i] = int(buf.uint8()) + } + + // Validate opcode lengths. + if buf.err != nil { + return buf.err + } + for i, length := range r.opcodeLengths { + if known, ok := knownOpcodeLengths[i]; ok && known != length { + return DecodeError{"line", hdrOffset, fmt.Sprintf("opcode %d expected to have length %d, but has length %d", i, known, length)} + } + } + + if r.version < 5 { + // Read include directories table. + r.directories = []string{compDir} + for { + directory := buf.string() + if buf.err != nil { + return buf.err + } + if len(directory) == 0 { + break + } + if !pathIsAbs(directory) { + // Relative paths are implicitly relative to + // the compilation directory. + directory = pathJoin(compDir, directory) + } + r.directories = append(r.directories, directory) + } + + // Read file name list. File numbering starts with 1, + // so leave the first entry nil. + r.fileEntries = make([]*LineFile, 1) + for { + if done, err := r.readFileEntry(); err != nil { + return err + } else if done { + break + } + } + } else { + dirFormat := r.readLNCTFormat() + c := buf.uint() + r.directories = make([]string, c) + for i := range r.directories { + dir, _, _, err := r.readLNCT(dirFormat, dwarf64) + if err != nil { + return err + } + r.directories[i] = dir + } + fileFormat := r.readLNCTFormat() + c = buf.uint() + r.fileEntries = make([]*LineFile, c) + for i := range r.fileEntries { + name, mtime, size, err := r.readLNCT(fileFormat, dwarf64) + if err != nil { + return err + } + r.fileEntries[i] = &LineFile{name, mtime, int(size)} + } + } + + r.initialFileEntries = len(r.fileEntries) + + return buf.err +} + +// lnctForm is a pair of an LNCT code and a form. This represents an +// entry in the directory name or file name description in the DWARF 5 +// line number program header. +type lnctForm struct { + lnct int + form format +} + +// readLNCTFormat reads an LNCT format description. +func (r *LineReader) readLNCTFormat() []lnctForm { + c := r.buf.uint8() + ret := make([]lnctForm, c) + for i := range ret { + ret[i].lnct = int(r.buf.uint()) + ret[i].form = format(r.buf.uint()) + } + return ret +} + +// readLNCT reads a sequence of LNCT entries and returns path information. +func (r *LineReader) readLNCT(s []lnctForm, dwarf64 bool) (path string, mtime uint64, size uint64, err error) { + var dir string + for _, lf := range s { + var str string + var val uint64 + switch lf.form { + case formString: + str = r.buf.string() + case formStrp, formLineStrp: + var off uint64 + if dwarf64 { + off = r.buf.uint64() + } else { + off = uint64(r.buf.uint32()) + } + if uint64(int(off)) != off { + return "", 0, 0, DecodeError{"line", r.buf.off, "strp/line_strp offset out of range"} + } + var b1 buf + if lf.form == formStrp { + b1 = makeBuf(r.buf.dwarf, r.buf.format, "str", 0, r.str) + } else { + b1 = makeBuf(r.buf.dwarf, r.buf.format, "line_str", 0, r.lineStr) + } + b1.skip(int(off)) + str = b1.string() + if b1.err != nil { + return "", 0, 0, DecodeError{"line", r.buf.off, b1.err.Error()} + } + case formStrpSup: + // Supplemental sections not yet supported. + if dwarf64 { + r.buf.uint64() + } else { + r.buf.uint32() + } + case formStrx: + // .debug_line.dwo sections not yet supported. + r.buf.uint() + case formStrx1: + r.buf.uint8() + case formStrx2: + r.buf.uint16() + case formStrx3: + r.buf.uint24() + case formStrx4: + r.buf.uint32() + case formData1: + val = uint64(r.buf.uint8()) + case formData2: + val = uint64(r.buf.uint16()) + case formData4: + val = uint64(r.buf.uint32()) + case formData8: + val = r.buf.uint64() + case formData16: + r.buf.bytes(16) + case formDwarfBlock: + r.buf.bytes(int(r.buf.uint())) + case formUdata: + val = r.buf.uint() + } + + switch lf.lnct { + case lnctPath: + path = str + case lnctDirectoryIndex: + if val >= uint64(len(r.directories)) { + return "", 0, 0, DecodeError{"line", r.buf.off, "directory index out of range"} + } + dir = r.directories[val] + case lnctTimestamp: + mtime = val + case lnctSize: + size = val + case lnctMD5: + // Ignored. + } + } + + if dir != "" && path != "" { + path = pathJoin(dir, path) + } + + return path, mtime, size, nil +} + +// readFileEntry reads a file entry from either the header or a +// DW_LNE_define_file extended opcode and adds it to r.fileEntries. A +// true return value indicates that there are no more entries to read. +func (r *LineReader) readFileEntry() (bool, error) { + name := r.buf.string() + if r.buf.err != nil { + return false, r.buf.err + } + if len(name) == 0 { + return true, nil + } + off := r.buf.off + dirIndex := int(r.buf.uint()) + if !pathIsAbs(name) { + if dirIndex >= len(r.directories) { + return false, DecodeError{"line", off, "directory index too large"} + } + name = pathJoin(r.directories[dirIndex], name) + } + mtime := r.buf.uint() + length := int(r.buf.uint()) + + // If this is a dynamically added path and the cursor was + // backed up, we may have already added this entry. Avoid + // updating existing line table entries in this case. This + // avoids an allocation and potential racy access to the slice + // backing store if the user called Files. + if len(r.fileEntries) < cap(r.fileEntries) { + fe := r.fileEntries[:len(r.fileEntries)+1] + if fe[len(fe)-1] != nil { + // We already processed this addition. + r.fileEntries = fe + return false, nil + } + } + r.fileEntries = append(r.fileEntries, &LineFile{name, mtime, length}) + return false, nil +} + +// updateFile updates r.state.File after r.fileIndex has +// changed or r.fileEntries has changed. +func (r *LineReader) updateFile() { + if r.fileIndex < len(r.fileEntries) { + r.state.File = r.fileEntries[r.fileIndex] + } else { + r.state.File = nil + } +} + +// Next sets *entry to the next row in this line table and moves to +// the next row. If there are no more entries and the line table is +// properly terminated, it returns io.EOF. +// +// Rows are always in order of increasing entry.Address, but +// entry.Line may go forward or backward. +func (r *LineReader) Next(entry *LineEntry) error { + if r.buf.err != nil { + return r.buf.err + } + + // Execute opcodes until we reach an opcode that emits a line + // table entry. + for { + if len(r.buf.data) == 0 { + return io.EOF + } + emit := r.step(entry) + if r.buf.err != nil { + return r.buf.err + } + if emit { + return nil + } + } +} + +// knownOpcodeLengths gives the opcode lengths (in varint arguments) +// of known standard opcodes. +var knownOpcodeLengths = map[int]int{ + lnsCopy: 0, + lnsAdvancePC: 1, + lnsAdvanceLine: 1, + lnsSetFile: 1, + lnsNegateStmt: 0, + lnsSetBasicBlock: 0, + lnsConstAddPC: 0, + lnsSetPrologueEnd: 0, + lnsSetEpilogueBegin: 0, + lnsSetISA: 1, + // lnsFixedAdvancePC takes a uint8 rather than a varint; it's + // unclear what length the header is supposed to claim, so + // ignore it. +} + +// step processes the next opcode and updates r.state. If the opcode +// emits a row in the line table, this updates *entry and returns +// true. +func (r *LineReader) step(entry *LineEntry) bool { + opcode := int(r.buf.uint8()) + + if opcode >= r.opcodeBase { + // Special opcode [DWARF2 6.2.5.1, DWARF4 6.2.5.1] + adjustedOpcode := opcode - r.opcodeBase + r.advancePC(adjustedOpcode / r.lineRange) + lineDelta := r.lineBase + adjustedOpcode%r.lineRange + r.state.Line += lineDelta + goto emit + } + + switch opcode { + case 0: + // Extended opcode [DWARF2 6.2.5.3] + length := Offset(r.buf.uint()) + startOff := r.buf.off + opcode := r.buf.uint8() + + switch opcode { + case lneEndSequence: + r.state.EndSequence = true + *entry = r.state + r.resetState() + + case lneSetAddress: + switch r.addrsize { + case 1: + r.state.Address = uint64(r.buf.uint8()) + case 2: + r.state.Address = uint64(r.buf.uint16()) + case 4: + r.state.Address = uint64(r.buf.uint32()) + case 8: + r.state.Address = r.buf.uint64() + default: + r.buf.error("unknown address size") + } + + case lneDefineFile: + if done, err := r.readFileEntry(); err != nil { + r.buf.err = err + return false + } else if done { + r.buf.err = DecodeError{"line", startOff, "malformed DW_LNE_define_file operation"} + return false + } + r.updateFile() + + case lneSetDiscriminator: + // [DWARF4 6.2.5.3] + r.state.Discriminator = int(r.buf.uint()) + } + + r.buf.skip(int(startOff + length - r.buf.off)) + + if opcode == lneEndSequence { + return true + } + + // Standard opcodes [DWARF2 6.2.5.2] + case lnsCopy: + goto emit + + case lnsAdvancePC: + r.advancePC(int(r.buf.uint())) + + case lnsAdvanceLine: + r.state.Line += int(r.buf.int()) + + case lnsSetFile: + r.fileIndex = int(r.buf.uint()) + r.updateFile() + + case lnsSetColumn: + r.state.Column = int(r.buf.uint()) + + case lnsNegateStmt: + r.state.IsStmt = !r.state.IsStmt + + case lnsSetBasicBlock: + r.state.BasicBlock = true + + case lnsConstAddPC: + r.advancePC((255 - r.opcodeBase) / r.lineRange) + + case lnsFixedAdvancePC: + r.state.Address += uint64(r.buf.uint16()) + + // DWARF3 standard opcodes [DWARF3 6.2.5.2] + case lnsSetPrologueEnd: + r.state.PrologueEnd = true + + case lnsSetEpilogueBegin: + r.state.EpilogueBegin = true + + case lnsSetISA: + r.state.ISA = int(r.buf.uint()) + + default: + // Unhandled standard opcode. Skip the number of + // arguments that the prologue says this opcode has. + for i := 0; i < r.opcodeLengths[opcode]; i++ { + r.buf.uint() + } + } + return false + +emit: + *entry = r.state + r.state.BasicBlock = false + r.state.PrologueEnd = false + r.state.EpilogueBegin = false + r.state.Discriminator = 0 + return true +} + +// advancePC advances "operation pointer" (the combination of Address +// and OpIndex) in r.state by opAdvance steps. +func (r *LineReader) advancePC(opAdvance int) { + opIndex := r.state.OpIndex + opAdvance + r.state.Address += uint64(r.minInstructionLength * (opIndex / r.maxOpsPerInstruction)) + r.state.OpIndex = opIndex % r.maxOpsPerInstruction +} + +// A LineReaderPos represents a position in a line table. +type LineReaderPos struct { + // off is the current offset in the DWARF line section. + off Offset + // numFileEntries is the length of fileEntries. + numFileEntries int + // state and fileIndex are the statement machine state at + // offset off. + state LineEntry + fileIndex int +} + +// Tell returns the current position in the line table. +func (r *LineReader) Tell() LineReaderPos { + return LineReaderPos{r.buf.off, len(r.fileEntries), r.state, r.fileIndex} +} + +// Seek restores the line table reader to a position returned by Tell. +// +// The argument pos must have been returned by a call to Tell on this +// line table. +func (r *LineReader) Seek(pos LineReaderPos) { + r.buf.off = pos.off + r.buf.data = r.section[r.buf.off:r.endOffset] + r.fileEntries = r.fileEntries[:pos.numFileEntries] + r.state = pos.state + r.fileIndex = pos.fileIndex +} + +// Reset repositions the line table reader at the beginning of the +// line table. +func (r *LineReader) Reset() { + // Reset buffer to the line number program offset. + r.buf.off = r.programOffset + r.buf.data = r.section[r.buf.off:r.endOffset] + + // Reset file entries list. + r.fileEntries = r.fileEntries[:r.initialFileEntries] + + // Reset line number program state. + r.resetState() +} + +// resetState resets r.state to its default values +func (r *LineReader) resetState() { + // Reset the state machine registers to the defaults given in + // [DWARF4 6.2.2]. + r.state = LineEntry{ + Address: 0, + OpIndex: 0, + File: nil, + Line: 1, + Column: 0, + IsStmt: r.defaultIsStmt, + BasicBlock: false, + PrologueEnd: false, + EpilogueBegin: false, + ISA: 0, + Discriminator: 0, + } + r.fileIndex = 1 + r.updateFile() +} + +// Files returns the file name table of this compilation unit as of +// the current position in the line table. The file name table may be +// referenced from attributes in this compilation unit such as +// AttrDeclFile. +// +// Entry 0 is always nil, since file index 0 represents "no file". +// +// The file name table of a compilation unit is not fixed. Files +// returns the file table as of the current position in the line +// table. This may contain more entries than the file table at an +// earlier position in the line table, though existing entries never +// change. +func (r *LineReader) Files() []*LineFile { + return r.fileEntries +} + +// ErrUnknownPC is the error returned by LineReader.ScanPC when the +// seek PC is not covered by any entry in the line table. +var ErrUnknownPC = errors.New("ErrUnknownPC") + +// SeekPC sets *entry to the LineEntry that includes pc and positions +// the reader on the next entry in the line table. If necessary, this +// will seek backwards to find pc. +// +// If pc is not covered by any entry in this line table, SeekPC +// returns ErrUnknownPC. In this case, *entry and the final seek +// position are unspecified. +// +// Note that DWARF line tables only permit sequential, forward scans. +// Hence, in the worst case, this takes time linear in the size of the +// line table. If the caller wishes to do repeated fast PC lookups, it +// should build an appropriate index of the line table. +func (r *LineReader) SeekPC(pc uint64, entry *LineEntry) error { + if err := r.Next(entry); err != nil { + return err + } + if entry.Address > pc { + // We're too far. Start at the beginning of the table. + r.Reset() + if err := r.Next(entry); err != nil { + return err + } + if entry.Address > pc { + // The whole table starts after pc. + r.Reset() + return ErrUnknownPC + } + } + + // Scan until we pass pc, then back up one. + for { + var next LineEntry + pos := r.Tell() + if err := r.Next(&next); err != nil { + if err == io.EOF { + return ErrUnknownPC + } + return err + } + if next.Address > pc { + if entry.EndSequence { + // pc is in a hole in the table. + return ErrUnknownPC + } + // entry is the desired entry. Back up the + // cursor to "next" and return success. + r.Seek(pos) + return nil + } + *entry = next + } +} + +// pathIsAbs reports whether path is an absolute path (or "full path +// name" in DWARF parlance). This is in "whatever form makes sense for +// the host system", so this accepts both UNIX-style and DOS-style +// absolute paths. We avoid the filepath package because we want this +// to behave the same regardless of our host system and because we +// don't know what system the paths came from. +func pathIsAbs(path string) bool { + _, path = splitDrive(path) + return len(path) > 0 && (path[0] == '/' || path[0] == '\\') +} + +// pathJoin joins dirname and filename. filename must be relative. +// DWARF paths can be UNIX-style or DOS-style, so this handles both. +func pathJoin(dirname, filename string) string { + if len(dirname) == 0 { + return filename + } + // dirname should be absolute, which means we can determine + // whether it's a DOS path reasonably reliably by looking for + // a drive letter or UNC path. + drive, dirname := splitDrive(dirname) + if drive == "" { + // UNIX-style path. + return path.Join(dirname, filename) + } + // DOS-style path. + drive2, filename := splitDrive(filename) + if drive2 != "" { + if !strings.EqualFold(drive, drive2) { + // Different drives. There's not much we can + // do here, so just ignore the directory. + return drive2 + filename + } + // Drives are the same. Ignore drive on filename. + } + if !(strings.HasSuffix(dirname, "/") || strings.HasSuffix(dirname, `\`)) && dirname != "" { + sep := `\` + if strings.HasPrefix(dirname, "/") { + sep = `/` + } + dirname += sep + } + return drive + dirname + filename +} + +// splitDrive splits the DOS drive letter or UNC share point from +// path, if any. path == drive + rest +func splitDrive(path string) (drive, rest string) { + if len(path) >= 2 && path[1] == ':' { + if c := path[0]; 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' { + return path[:2], path[2:] + } + } + if len(path) > 3 && (path[0] == '\\' || path[0] == '/') && (path[1] == '\\' || path[1] == '/') { + // Normalize the path so we can search for just \ below. + npath := strings.Replace(path, "/", `\`, -1) + // Get the host part, which must be non-empty. + slash1 := strings.IndexByte(npath[2:], '\\') + 2 + if slash1 > 2 { + // Get the mount-point part, which must be non-empty. + slash2 := strings.IndexByte(npath[slash1+1:], '\\') + slash1 + 1 + if slash2 > slash1 { + return path[:slash2], path[slash2:] + } + } + } + return "", path +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/open.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/open.go new file mode 100644 index 00000000..994b7262 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/open.go @@ -0,0 +1,140 @@ +// 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 dwarf provides access to DWARF debugging information loaded from +executable files, as defined in the DWARF 2.0 Standard at +http://dwarfstd.org/doc/dwarf-2.0.0.pdf. + +# Security + +This package is not designed to be hardened against adversarial inputs, and is +outside the scope of https://go.dev/security/policy. In particular, only basic +validation is done when parsing object files. As such, care should be taken when +parsing untrusted inputs, as parsing malformed files may consume significant +resources, or cause panics. +*/ +package dwarf + +import ( + "encoding/binary" + "errors" +) + +// Data represents the DWARF debugging information +// loaded from an executable file (for example, an ELF or Mach-O executable). +type Data struct { + // raw data + abbrev []byte + aranges []byte + frame []byte + info []byte + line []byte + pubnames []byte + ranges []byte + str []byte + + // New sections added in DWARF 5. + addr []byte + lineStr []byte + strOffsets []byte + rngLists []byte + + // parsed data + abbrevCache map[uint64]abbrevTable + bigEndian bool + order binary.ByteOrder + typeCache map[Offset]Type + typeSigs map[uint64]*typeUnit + unit []unit +} + +var errSegmentSelector = errors.New("non-zero segment_selector size not supported") + +// New returns a new Data object initialized from the given parameters. +// Rather than calling this function directly, clients should typically use +// the DWARF method of the File type of the appropriate package debug/elf, +// debug/macho, or debug/pe. +// +// The []byte arguments are the data from the corresponding debug section +// in the object file; for example, for an ELF object, abbrev is the contents of +// the ".debug_abbrev" section. +func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) { + d := &Data{ + abbrev: abbrev, + aranges: aranges, + frame: frame, + info: info, + line: line, + pubnames: pubnames, + ranges: ranges, + str: str, + abbrevCache: make(map[uint64]abbrevTable), + typeCache: make(map[Offset]Type), + typeSigs: make(map[uint64]*typeUnit), + } + + // Sniff .debug_info to figure out byte order. + // 32-bit DWARF: 4 byte length, 2 byte version. + // 64-bit DWARf: 4 bytes of 0xff, 8 byte length, 2 byte version. + if len(d.info) < 6 { + return nil, DecodeError{"info", Offset(len(d.info)), "too short"} + } + offset := 4 + if d.info[0] == 0xff && d.info[1] == 0xff && d.info[2] == 0xff && d.info[3] == 0xff { + if len(d.info) < 14 { + return nil, DecodeError{"info", Offset(len(d.info)), "too short"} + } + offset = 12 + } + // Fetch the version, a tiny 16-bit number (1, 2, 3, 4, 5). + x, y := d.info[offset], d.info[offset+1] + switch { + case x == 0 && y == 0: + return nil, DecodeError{"info", 4, "unsupported version 0"} + case x == 0: + d.bigEndian = true + d.order = binary.BigEndian + case y == 0: + d.bigEndian = false + d.order = binary.LittleEndian + default: + return nil, DecodeError{"info", 4, "cannot determine byte order"} + } + + u, err := d.parseUnits() + if err != nil { + return nil, err + } + d.unit = u + return d, nil +} + +// AddTypes will add one .debug_types section to the DWARF data. A +// typical object with DWARF version 4 debug info will have multiple +// .debug_types sections. The name is used for error reporting only, +// and serves to distinguish one .debug_types section from another. +func (d *Data) AddTypes(name string, types []byte) error { + return d.parseTypes(name, types) +} + +// AddSection adds another DWARF section by name. The name should be a +// DWARF section name such as ".debug_addr", ".debug_str_offsets", and +// so forth. This approach is used for new DWARF sections added in +// DWARF 5 and later. +func (d *Data) AddSection(name string, contents []byte) error { + var err error + switch name { + case ".debug_addr": + d.addr = contents + case ".debug_line_str": + d.lineStr = contents + case ".debug_str_offsets": + d.strOffsets = contents + case ".debug_rnglists": + d.rngLists = contents + } + // Just ignore names that we don't yet support. + return err +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/tag_string.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/tag_string.go new file mode 100644 index 00000000..b79ea175 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/tag_string.go @@ -0,0 +1,119 @@ +// Code generated by "stringer -type Tag -trimprefix=Tag"; DO NOT EDIT. + +package dwarf + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[TagArrayType-1] + _ = x[TagClassType-2] + _ = x[TagEntryPoint-3] + _ = x[TagEnumerationType-4] + _ = x[TagFormalParameter-5] + _ = x[TagImportedDeclaration-8] + _ = x[TagLabel-10] + _ = x[TagLexDwarfBlock-11] + _ = x[TagMember-13] + _ = x[TagPointerType-15] + _ = x[TagReferenceType-16] + _ = x[TagCompileUnit-17] + _ = x[TagStringType-18] + _ = x[TagStructType-19] + _ = x[TagSubroutineType-21] + _ = x[TagTypedef-22] + _ = x[TagUnionType-23] + _ = x[TagUnspecifiedParameters-24] + _ = x[TagVariant-25] + _ = x[TagCommonDwarfBlock-26] + _ = x[TagCommonInclusion-27] + _ = x[TagInheritance-28] + _ = x[TagInlinedSubroutine-29] + _ = x[TagModule-30] + _ = x[TagPtrToMemberType-31] + _ = x[TagSetType-32] + _ = x[TagSubrangeType-33] + _ = x[TagWithStmt-34] + _ = x[TagAccessDeclaration-35] + _ = x[TagBaseType-36] + _ = x[TagCatchDwarfBlock-37] + _ = x[TagConstType-38] + _ = x[TagConstant-39] + _ = x[TagEnumerator-40] + _ = x[TagFileType-41] + _ = x[TagFriend-42] + _ = x[TagNamelist-43] + _ = x[TagNamelistItem-44] + _ = x[TagPackedType-45] + _ = x[TagSubprogram-46] + _ = x[TagTemplateTypeParameter-47] + _ = x[TagTemplateValueParameter-48] + _ = x[TagThrownType-49] + _ = x[TagTryDwarfBlock-50] + _ = x[TagVariantPart-51] + _ = x[TagVariable-52] + _ = x[TagVolatileType-53] + _ = x[TagDwarfProcedure-54] + _ = x[TagRestrictType-55] + _ = x[TagInterfaceType-56] + _ = x[TagNamespace-57] + _ = x[TagImportedModule-58] + _ = x[TagUnspecifiedType-59] + _ = x[TagPartialUnit-60] + _ = x[TagImportedUnit-61] + _ = x[TagMutableType-62] + _ = x[TagCondition-63] + _ = x[TagSharedType-64] + _ = x[TagTypeUnit-65] + _ = x[TagRvalueReferenceType-66] + _ = x[TagTemplateAlias-67] + _ = x[TagCoarrayType-68] + _ = x[TagGenericSubrange-69] + _ = x[TagDynamicType-70] + _ = x[TagAtomicType-71] + _ = x[TagCallSite-72] + _ = x[TagCallSiteParameter-73] + _ = x[TagSkeletonUnit-74] + _ = x[TagImmutableType-75] +} + +const ( + _Tag_name_0 = "ArrayTypeClassTypeEntryPointEnumerationTypeFormalParameter" + _Tag_name_1 = "ImportedDeclaration" + _Tag_name_2 = "LabelLexDwarfBlock" + _Tag_name_3 = "Member" + _Tag_name_4 = "PointerTypeReferenceTypeCompileUnitStringTypeStructType" + _Tag_name_5 = "SubroutineTypeTypedefUnionTypeUnspecifiedParametersVariantCommonDwarfBlockCommonInclusionInheritanceInlinedSubroutineModulePtrToMemberTypeSetTypeSubrangeTypeWithStmtAccessDeclarationBaseTypeCatchDwarfBlockConstTypeConstantEnumeratorFileTypeFriendNamelistNamelistItemPackedTypeSubprogramTemplateTypeParameterTemplateValueParameterThrownTypeTryDwarfBlockVariantPartVariableVolatileTypeDwarfProcedureRestrictTypeInterfaceTypeNamespaceImportedModuleUnspecifiedTypePartialUnitImportedUnitMutableTypeConditionSharedTypeTypeUnitRvalueReferenceTypeTemplateAliasCoarrayTypeGenericSubrangeDynamicTypeAtomicTypeCallSiteCallSiteParameterSkeletonUnitImmutableType" +) + +var ( + _Tag_index_0 = [...]uint8{0, 9, 18, 28, 43, 58} + _Tag_index_2 = [...]uint8{0, 5, 18} + _Tag_index_4 = [...]uint8{0, 11, 24, 35, 45, 55} + _Tag_index_5 = [...]uint16{0, 14, 21, 30, 51, 58, 74, 89, 100, 117, 123, 138, 145, 157, 165, 182, 190, 205, 214, 222, 232, 240, 246, 254, 266, 276, 286, 307, 329, 339, 352, 363, 371, 383, 397, 409, 422, 431, 445, 460, 471, 483, 494, 503, 513, 521, 540, 553, 564, 579, 590, 600, 608, 625, 637, 650} +) + +func (i Tag) String() string { + switch { + case 1 <= i && i <= 5: + i -= 1 + return _Tag_name_0[_Tag_index_0[i]:_Tag_index_0[i+1]] + case i == 8: + return _Tag_name_1 + case 10 <= i && i <= 11: + i -= 10 + return _Tag_name_2[_Tag_index_2[i]:_Tag_index_2[i+1]] + case i == 13: + return _Tag_name_3 + case 15 <= i && i <= 19: + i -= 15 + return _Tag_name_4[_Tag_index_4[i]:_Tag_index_4[i+1]] + case 21 <= i && i <= 75: + i -= 21 + return _Tag_name_5[_Tag_index_5[i]:_Tag_index_5[i+1]] + default: + return "Tag(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/type.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/type.go new file mode 100644 index 00000000..a95c4c73 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/type.go @@ -0,0 +1,870 @@ +// 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. + +// DWARF type information structures. +// The format is heavily biased toward C, but for simplicity +// the String methods use a pseudo-Go syntax. + +package dwarf + +import "strconv" + +// A Type conventionally represents a pointer to any of the +// specific Type structures (CharType, StructType, etc.). +type Type interface { + Common() *CommonType + String() string + Size() int64 +} + +// A CommonType holds fields common to multiple types. +// If a field is not known or not applicable for a given type, +// the zero value is used. +type CommonType struct { + ByteSize int64 // size of value of this type, in bytes + Name string // name that can be used to refer to type +} + +func (c *CommonType) Common() *CommonType { return c } + +func (c *CommonType) Size() int64 { return c.ByteSize } + +// Basic types + +// A BasicType holds fields common to all basic types. +// +// See the documentation for StructField for more info on the interpretation of +// the BitSize/BitOffset/DataBitOffset fields. +type BasicType struct { + CommonType + BitSize int64 + BitOffset int64 + DataBitOffset int64 +} + +func (b *BasicType) Basic() *BasicType { return b } + +func (t *BasicType) String() string { + if t.Name != "" { + return t.Name + } + return "?" +} + +// A CharType represents a signed character type. +type CharType struct { + BasicType +} + +// A UcharType represents an unsigned character type. +type UcharType struct { + BasicType +} + +// An IntType represents a signed integer type. +type IntType struct { + BasicType +} + +// A UintType represents an unsigned integer type. +type UintType struct { + BasicType +} + +// A FloatType represents a floating point type. +type FloatType struct { + BasicType +} + +// A ComplexType represents a complex floating point type. +type ComplexType struct { + BasicType +} + +// A BoolType represents a boolean type. +type BoolType struct { + BasicType +} + +// An AddrType represents a machine address type. +type AddrType struct { + BasicType +} + +// An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type. +type UnspecifiedType struct { + BasicType +} + +// qualifiers + +// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier. +type QualType struct { + CommonType + Qual string + Type Type +} + +func (t *QualType) String() string { return t.Qual + " " + t.Type.String() } + +func (t *QualType) Size() int64 { return t.Type.Size() } + +// An ArrayType represents a fixed size array type. +type ArrayType struct { + CommonType + Type Type + StrideBitSize int64 // if > 0, number of bits to hold each element + Count int64 // if == -1, an incomplete array, like char x[]. +} + +func (t *ArrayType) String() string { + return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String() +} + +func (t *ArrayType) Size() int64 { + if t.Count == -1 { + return 0 + } + return t.Count * t.Type.Size() +} + +// A VoidType represents the C void type. +type VoidType struct { + CommonType +} + +func (t *VoidType) String() string { return "void" } + +// A PtrType represents a pointer type. +type PtrType struct { + CommonType + Type Type +} + +func (t *PtrType) String() string { return "*" + t.Type.String() } + +// A StructType represents a struct, union, or C++ class type. +type StructType struct { + CommonType + StructName string + Kind string // "struct", "union", or "class". + Field []*StructField + Incomplete bool // if true, struct, union, class is declared but not defined +} + +// A StructField represents a field in a struct, union, or C++ class type. +// +// # Bit Fields +// +// The BitSize, BitOffset, and DataBitOffset fields describe the bit +// size and offset of data members declared as bit fields in C/C++ +// struct/union/class types. +// +// BitSize is the number of bits in the bit field. +// +// DataBitOffset, if non-zero, is the number of bits from the start of +// the enclosing entity (e.g. containing struct/class/union) to the +// start of the bit field. This corresponds to the DW_AT_data_bit_offset +// DWARF attribute that was introduced in DWARF 4. +// +// BitOffset, if non-zero, is the number of bits between the most +// significant bit of the storage unit holding the bit field to the +// most significant bit of the bit field. Here "storage unit" is the +// type name before the bit field (for a field "unsigned x:17", the +// storage unit is "unsigned"). BitOffset values can vary depending on +// the endianness of the system. BitOffset corresponds to the +// DW_AT_bit_offset DWARF attribute that was deprecated in DWARF 4 and +// removed in DWARF 5. +// +// At most one of DataBitOffset and BitOffset will be non-zero; +// DataBitOffset/BitOffset will only be non-zero if BitSize is +// non-zero. Whether a C compiler uses one or the other +// will depend on compiler vintage and command line options. +// +// Here is an example of C/C++ bit field use, along with what to +// expect in terms of DWARF bit offset info. Consider this code: +// +// struct S { +// int q; +// int j:5; +// int k:6; +// int m:5; +// int n:8; +// } s; +// +// For the code above, one would expect to see the following for +// DW_AT_bit_offset values (using GCC 8): +// +// Little | Big +// Endian | Endian +// | +// "j": 27 | 0 +// "k": 21 | 5 +// "m": 16 | 11 +// "n": 8 | 16 +// +// Note that in the above the offsets are purely with respect to the +// containing storage unit for j/k/m/n -- these values won't vary based +// on the size of prior data members in the containing struct. +// +// If the compiler emits DW_AT_data_bit_offset, the expected values +// would be: +// +// "j": 32 +// "k": 37 +// "m": 43 +// "n": 48 +// +// Here the value 32 for "j" reflects the fact that the bit field is +// preceded by other data members (recall that DW_AT_data_bit_offset +// values are relative to the start of the containing struct). Hence +// DW_AT_data_bit_offset values can be quite large for structs with +// many fields. +// +// DWARF also allow for the possibility of base types that have +// non-zero bit size and bit offset, so this information is also +// captured for base types, but it is worth noting that it is not +// possible to trigger this behavior using mainstream languages. +type StructField struct { + Name string + Type Type + ByteOffset int64 + ByteSize int64 // usually zero; use Type.Size() for normal fields + BitOffset int64 + DataBitOffset int64 + BitSize int64 // zero if not a bit field +} + +func (t *StructType) String() string { + if t.StructName != "" { + return t.Kind + " " + t.StructName + } + return t.Defn() +} + +func (f *StructField) bitOffset() int64 { + if f.BitOffset != 0 { + return f.BitOffset + } + return f.DataBitOffset +} + +func (t *StructType) Defn() string { + s := t.Kind + if t.StructName != "" { + s += " " + t.StructName + } + if t.Incomplete { + s += " /*incomplete*/" + return s + } + s += " {" + for i, f := range t.Field { + if i > 0 { + s += "; " + } + s += f.Name + " " + f.Type.String() + s += "@" + strconv.FormatInt(f.ByteOffset, 10) + if f.BitSize > 0 { + s += " : " + strconv.FormatInt(f.BitSize, 10) + s += "@" + strconv.FormatInt(f.bitOffset(), 10) + } + } + s += "}" + return s +} + +// An EnumType represents an enumerated type. +// The only indication of its native integer type is its ByteSize +// (inside CommonType). +type EnumType struct { + CommonType + EnumName string + Val []*EnumValue +} + +// An EnumValue represents a single enumeration value. +type EnumValue struct { + Name string + Val int64 +} + +func (t *EnumType) String() string { + s := "enum" + if t.EnumName != "" { + s += " " + t.EnumName + } + s += " {" + for i, v := range t.Val { + if i > 0 { + s += "; " + } + s += v.Name + "=" + strconv.FormatInt(v.Val, 10) + } + s += "}" + return s +} + +// A FuncType represents a function type. +type FuncType struct { + CommonType + ReturnType Type + ParamType []Type +} + +func (t *FuncType) String() string { + s := "func(" + for i, t := range t.ParamType { + if i > 0 { + s += ", " + } + s += t.String() + } + s += ")" + if t.ReturnType != nil { + s += " " + t.ReturnType.String() + } + return s +} + +// A DotDotDotType represents the variadic ... function parameter. +type DotDotDotType struct { + CommonType +} + +func (t *DotDotDotType) String() string { return "..." } + +// A TypedefType represents a named type. +type TypedefType struct { + CommonType + Type Type +} + +func (t *TypedefType) String() string { return t.Name } + +func (t *TypedefType) Size() int64 { return t.Type.Size() } + +// An UnsupportedType is a placeholder returned in situations where we +// encounter a type that isn't supported. +type UnsupportedType struct { + CommonType + Tag Tag +} + +func (t *UnsupportedType) String() string { + if t.Name != "" { + return t.Name + } + return t.Name + "(unsupported type " + t.Tag.String() + ")" +} + +// typeReader is used to read from either the info section or the +// types section. +type typeReader interface { + Seek(Offset) + Next() (*Entry, error) + clone() typeReader + offset() Offset + // AddressSize returns the size in bytes of addresses in the current + // compilation unit. + AddressSize() int +} + +// Type reads the type at off in the DWARF “info” section. +func (d *Data) Type(off Offset) (Type, error) { + return d.readType("info", d.Reader(), off, d.typeCache, nil) +} + +type typeFixer struct { + typedefs []*TypedefType + arraytypes []*Type +} + +func (tf *typeFixer) recordArrayType(t *Type) { + if t == nil { + return + } + _, ok := (*t).(*ArrayType) + if ok { + tf.arraytypes = append(tf.arraytypes, t) + } +} + +func (tf *typeFixer) apply() { + for _, t := range tf.typedefs { + t.Common().ByteSize = t.Type.Size() + } + for _, t := range tf.arraytypes { + zeroArray(t) + } +} + +// readType reads a type from r at off of name. It adds types to the +// type cache, appends new typedef types to typedefs, and computes the +// sizes of types. Callers should pass nil for typedefs; this is used +// for internal recursion. +func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type, fixups *typeFixer) (Type, error) { + if t, ok := typeCache[off]; ok { + return t, nil + } + r.Seek(off) + e, err := r.Next() + if err != nil { + return nil, err + } + addressSize := r.AddressSize() + if e == nil || e.Offset != off { + return nil, DecodeError{name, off, "no type at offset"} + } + + // If this is the root of the recursion, prepare to resolve + // typedef sizes and perform other fixups once the recursion is + // done. This must be done after the type graph is constructed + // because it may need to resolve cycles in a different order than + // readType encounters them. + if fixups == nil { + var fixer typeFixer + defer func() { + fixer.apply() + }() + fixups = &fixer + } + + // Parse type from Entry. + // Must always set typeCache[off] before calling + // d.readType recursively, to handle circular types correctly. + var typ Type + + nextDepth := 0 + + // Get next child; set err if error happens. + next := func() *Entry { + if !e.Children { + return nil + } + // Only return direct children. + // Skip over composite entries that happen to be nested + // inside this one. Most DWARF generators wouldn't generate + // such a thing, but clang does. + // See golang.org/issue/6472. + for { + kid, err1 := r.Next() + if err1 != nil { + err = err1 + return nil + } + if kid == nil { + err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"} + return nil + } + if kid.Tag == 0 { + if nextDepth > 0 { + nextDepth-- + continue + } + return nil + } + if kid.Children { + nextDepth++ + } + if nextDepth > 0 { + continue + } + return kid + } + } + + // Get Type referred to by Entry's AttrType field. + // Set err if error happens. Not having a type is an error. + typeOf := func(e *Entry) Type { + tval := e.Val(AttrType) + var t Type + switch toff := tval.(type) { + case Offset: + if t, err = d.readType(name, r.clone(), toff, typeCache, fixups); err != nil { + return nil + } + case uint64: + if t, err = d.sigToType(toff); err != nil { + return nil + } + default: + // It appears that no Type means "void". + return new(VoidType) + } + return t + } + + switch e.Tag { + case TagArrayType: + // Multi-dimensional array. (DWARF v2 §5.4) + // Attributes: + // AttrType:subtype [required] + // AttrStrideSize: size in bits of each element of the array + // AttrByteSize: size of entire array + // Children: + // TagSubrangeType or TagEnumerationType giving one dimension. + // dimensions are in left to right order. + t := new(ArrayType) + typ = t + typeCache[off] = t + if t.Type = typeOf(e); err != nil { + goto Error + } + t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64) + + // Accumulate dimensions, + var dims []int64 + for kid := next(); kid != nil; kid = next() { + // TODO(rsc): Can also be TagEnumerationType + // but haven't seen that in the wild yet. + switch kid.Tag { + case TagSubrangeType: + count, ok := kid.Val(AttrCount).(int64) + if !ok { + // Old binaries may have an upper bound instead. + count, ok = kid.Val(AttrUpperBound).(int64) + if ok { + count++ // Length is one more than upper bound. + } else if len(dims) == 0 { + count = -1 // As in x[]. + } + } + dims = append(dims, count) + case TagEnumerationType: + err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"} + goto Error + } + } + if len(dims) == 0 { + // LLVM generates this for x[]. + dims = []int64{-1} + } + + t.Count = dims[0] + for i := len(dims) - 1; i >= 1; i-- { + t.Type = &ArrayType{Type: t.Type, Count: dims[i]} + } + + case TagBaseType: + // Basic type. (DWARF v2 §5.1) + // Attributes: + // AttrName: name of base type in programming language of the compilation unit [required] + // AttrEncoding: encoding value for type (encFloat etc) [required] + // AttrByteSize: size of type in bytes [required] + // AttrBitOffset: bit offset of value within containing storage unit + // AttrDataBitOffset: bit offset of value within containing storage unit + // AttrBitSize: size in bits + // + // For most languages BitOffset/DataBitOffset/BitSize will not be present + // for base types. + name, _ := e.Val(AttrName).(string) + enc, ok := e.Val(AttrEncoding).(int64) + if !ok { + err = DecodeError{name, e.Offset, "missing encoding attribute for " + name} + goto Error + } + switch enc { + default: + err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"} + goto Error + + case encAddress: + typ = new(AddrType) + case encBoolean: + typ = new(BoolType) + case encComplexFloat: + typ = new(ComplexType) + if name == "complex" { + // clang writes out 'complex' instead of 'complex float' or 'complex double'. + // clang also writes out a byte size that we can use to distinguish. + // See issue 8694. + switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize { + case 8: + name = "complex float" + case 16: + name = "complex double" + } + } + case encFloat: + typ = new(FloatType) + case encSigned: + typ = new(IntType) + case encUnsigned: + typ = new(UintType) + case encSignedChar: + typ = new(CharType) + case encUnsignedChar: + typ = new(UcharType) + } + typeCache[off] = typ + t := typ.(interface { + Basic() *BasicType + }).Basic() + t.Name = name + t.BitSize, _ = e.Val(AttrBitSize).(int64) + haveBitOffset := false + haveDataBitOffset := false + t.BitOffset, haveBitOffset = e.Val(AttrBitOffset).(int64) + t.DataBitOffset, haveDataBitOffset = e.Val(AttrDataBitOffset).(int64) + if haveBitOffset && haveDataBitOffset { + err = DecodeError{name, e.Offset, "duplicate bit offset attributes"} + goto Error + } + + case TagClassType, TagStructType, TagUnionType: + // Structure, union, or class type. (DWARF v2 §5.5) + // Attributes: + // AttrName: name of struct, union, or class + // AttrByteSize: byte size [required] + // AttrDeclaration: if true, struct/union/class is incomplete + // Children: + // TagMember to describe one member. + // AttrName: name of member [required] + // AttrType: type of member [required] + // AttrByteSize: size in bytes + // AttrBitOffset: bit offset within bytes for bit fields + // AttrDataBitOffset: field bit offset relative to struct start + // AttrBitSize: bit size for bit fields + // AttrDataMemberLoc: location within struct [required for struct, class] + // There is much more to handle C++, all ignored for now. + t := new(StructType) + typ = t + typeCache[off] = t + switch e.Tag { + case TagClassType: + t.Kind = "class" + case TagStructType: + t.Kind = "struct" + case TagUnionType: + t.Kind = "union" + } + t.StructName, _ = e.Val(AttrName).(string) + t.Incomplete = e.Val(AttrDeclaration) != nil + t.Field = make([]*StructField, 0, 8) + var lastFieldType *Type + var lastFieldBitSize int64 + var lastFieldByteOffset int64 + for kid := next(); kid != nil; kid = next() { + if kid.Tag != TagMember { + continue + } + f := new(StructField) + if f.Type = typeOf(kid); err != nil { + goto Error + } + switch loc := kid.Val(AttrDataMemberLoc).(type) { + case []byte: + // TODO: Should have original compilation + // unit here, not unknownFormat. + b := makeBuf(d, unknownFormat{}, "location", 0, loc) + if b.uint8() != opPlusUconst { + err = DecodeError{name, kid.Offset, "unexpected opcode"} + goto Error + } + f.ByteOffset = int64(b.uint()) + if b.err != nil { + err = b.err + goto Error + } + case int64: + f.ByteOffset = loc + } + + f.Name, _ = kid.Val(AttrName).(string) + f.ByteSize, _ = kid.Val(AttrByteSize).(int64) + haveBitOffset := false + haveDataBitOffset := false + f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64) + f.DataBitOffset, haveDataBitOffset = kid.Val(AttrDataBitOffset).(int64) + if haveBitOffset && haveDataBitOffset { + err = DecodeError{name, e.Offset, "duplicate bit offset attributes"} + goto Error + } + f.BitSize, _ = kid.Val(AttrBitSize).(int64) + t.Field = append(t.Field, f) + + if lastFieldBitSize == 0 && lastFieldByteOffset == f.ByteOffset && t.Kind != "union" { + // Last field was zero width. Fix array length. + // (DWARF writes out 0-length arrays as if they were 1-length arrays.) + fixups.recordArrayType(lastFieldType) + } + lastFieldType = &f.Type + lastFieldByteOffset = f.ByteOffset + lastFieldBitSize = f.BitSize + } + if t.Kind != "union" { + b, ok := e.Val(AttrByteSize).(int64) + if ok && b == lastFieldByteOffset { + // Final field must be zero width. Fix array length. + fixups.recordArrayType(lastFieldType) + } + } + + case TagConstType, TagVolatileType, TagRestrictType: + // Type modifier (DWARF v2 §5.2) + // Attributes: + // AttrType: subtype + t := new(QualType) + typ = t + typeCache[off] = t + if t.Type = typeOf(e); err != nil { + goto Error + } + switch e.Tag { + case TagConstType: + t.Qual = "const" + case TagRestrictType: + t.Qual = "restrict" + case TagVolatileType: + t.Qual = "volatile" + } + + case TagEnumerationType: + // Enumeration type (DWARF v2 §5.6) + // Attributes: + // AttrName: enum name if any + // AttrByteSize: bytes required to represent largest value + // Children: + // TagEnumerator: + // AttrName: name of constant + // AttrConstValue: value of constant + t := new(EnumType) + typ = t + typeCache[off] = t + t.EnumName, _ = e.Val(AttrName).(string) + t.Val = make([]*EnumValue, 0, 8) + for kid := next(); kid != nil; kid = next() { + if kid.Tag == TagEnumerator { + f := new(EnumValue) + f.Name, _ = kid.Val(AttrName).(string) + f.Val, _ = kid.Val(AttrConstValue).(int64) + n := len(t.Val) + if n >= cap(t.Val) { + val := make([]*EnumValue, n, n*2) + copy(val, t.Val) + t.Val = val + } + t.Val = t.Val[0 : n+1] + t.Val[n] = f + } + } + + case TagPointerType: + // Type modifier (DWARF v2 §5.2) + // Attributes: + // AttrType: subtype [not required! void* has no AttrType] + // AttrAddrClass: address class [ignored] + t := new(PtrType) + typ = t + typeCache[off] = t + if e.Val(AttrType) == nil { + t.Type = &VoidType{} + break + } + t.Type = typeOf(e) + + case TagSubroutineType: + // Subroutine type. (DWARF v2 §5.7) + // Attributes: + // AttrType: type of return value if any + // AttrName: possible name of type [ignored] + // AttrPrototyped: whether used ANSI C prototype [ignored] + // Children: + // TagFormalParameter: typed parameter + // AttrType: type of parameter + // TagUnspecifiedParameter: final ... + t := new(FuncType) + typ = t + typeCache[off] = t + if t.ReturnType = typeOf(e); err != nil { + goto Error + } + t.ParamType = make([]Type, 0, 8) + for kid := next(); kid != nil; kid = next() { + var tkid Type + switch kid.Tag { + default: + continue + case TagFormalParameter: + if tkid = typeOf(kid); err != nil { + goto Error + } + case TagUnspecifiedParameters: + tkid = &DotDotDotType{} + } + t.ParamType = append(t.ParamType, tkid) + } + + case TagTypedef: + // Typedef (DWARF v2 §5.3) + // Attributes: + // AttrName: name [required] + // AttrType: type definition [required] + t := new(TypedefType) + typ = t + typeCache[off] = t + t.Name, _ = e.Val(AttrName).(string) + t.Type = typeOf(e) + + case TagUnspecifiedType: + // Unspecified type (DWARF v3 §5.2) + // Attributes: + // AttrName: name + t := new(UnspecifiedType) + typ = t + typeCache[off] = t + t.Name, _ = e.Val(AttrName).(string) + + default: + // This is some other type DIE that we're currently not + // equipped to handle. Return an abstract "unsupported type" + // object in such cases. + t := new(UnsupportedType) + typ = t + typeCache[off] = t + t.Tag = e.Tag + t.Name, _ = e.Val(AttrName).(string) + } + + if err != nil { + goto Error + } + + { + b, ok := e.Val(AttrByteSize).(int64) + if !ok { + b = -1 + switch t := typ.(type) { + case *TypedefType: + // Record that we need to resolve this + // type's size once the type graph is + // constructed. + fixups.typedefs = append(fixups.typedefs, t) + case *PtrType: + b = int64(addressSize) + } + } + typ.Common().ByteSize = b + } + return typ, nil + +Error: + // If the parse fails, take the type out of the cache + // so that the next call with this offset doesn't hit + // the cache and return success. + delete(typeCache, off) + return nil, err +} + +func zeroArray(t *Type) { + at := (*t).(*ArrayType) + if at.Type.Size() == 0 { + return + } + // Make a copy to avoid invalidating typeCache. + tt := *at + tt.Count = 0 + *t = &tt +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/typeunit.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/typeunit.go new file mode 100644 index 00000000..27aa0784 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/typeunit.go @@ -0,0 +1,160 @@ +// 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 dwarf + +import ( + "fmt" + "strconv" +) + +// Parse the type units stored in a DWARF4 .debug_types section. Each +// type unit defines a single primary type and an 8-byte signature. +// Other sections may then use formRefSig8 to refer to the type. + +// The typeUnit format is a single type with a signature. It holds +// the same data as a compilation unit. +type typeUnit struct { + unit + toff Offset // Offset to signature type within data. + name string // Name of .debug_type section. + cache Type // Cache the type, nil to start. +} + +// Parse a .debug_types section. +func (d *Data) parseTypes(name string, types []byte) error { + b := makeBuf(d, unknownFormat{}, name, 0, types) + for len(b.data) > 0 { + base := b.off + n, dwarf64 := b.unitLength() + if n != Offset(uint32(n)) { + b.error("type unit length overflow") + return b.err + } + hdroff := b.off + vers := int(b.uint16()) + if vers != 4 { + b.error("unsupported DWARF version " + strconv.Itoa(vers)) + return b.err + } + var ao uint64 + if !dwarf64 { + ao = uint64(b.uint32()) + } else { + ao = b.uint64() + } + atable, err := d.parseAbbrev(ao, vers) + if err != nil { + return err + } + asize := b.uint8() + sig := b.uint64() + + var toff uint32 + if !dwarf64 { + toff = b.uint32() + } else { + to64 := b.uint64() + if to64 != uint64(uint32(to64)) { + b.error("type unit type offset overflow") + return b.err + } + toff = uint32(to64) + } + + boff := b.off + d.typeSigs[sig] = &typeUnit{ + unit: unit{ + base: base, + off: boff, + data: b.bytes(int(n - (b.off - hdroff))), + atable: atable, + asize: int(asize), + vers: vers, + is64: dwarf64, + }, + toff: Offset(toff), + name: name, + } + if b.err != nil { + return b.err + } + } + return nil +} + +// Return the type for a type signature. +func (d *Data) sigToType(sig uint64) (Type, error) { + tu := d.typeSigs[sig] + if tu == nil { + return nil, fmt.Errorf("no type unit with signature %v", sig) + } + if tu.cache != nil { + return tu.cache, nil + } + + b := makeBuf(d, tu, tu.name, tu.off, tu.data) + r := &typeUnitReader{d: d, tu: tu, b: b} + t, err := d.readType(tu.name, r, tu.toff, make(map[Offset]Type), nil) + if err != nil { + return nil, err + } + + tu.cache = t + return t, nil +} + +// typeUnitReader is a typeReader for a tagTypeUnit. +type typeUnitReader struct { + d *Data + tu *typeUnit + b buf + err error +} + +// Seek to a new position in the type unit. +func (tur *typeUnitReader) Seek(off Offset) { + tur.err = nil + doff := off - tur.tu.off + if doff < 0 || doff >= Offset(len(tur.tu.data)) { + tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data)) + return + } + tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:]) +} + +// AddressSize returns the size in bytes of addresses in the current type unit. +func (tur *typeUnitReader) AddressSize() int { + return tur.tu.unit.asize +} + +// Next reads the next Entry from the type unit. +func (tur *typeUnitReader) Next() (*Entry, error) { + if tur.err != nil { + return nil, tur.err + } + if len(tur.tu.data) == 0 { + return nil, nil + } + e := tur.b.entry(nil, tur.tu.atable, tur.tu.base, tur.tu.vers) + if tur.b.err != nil { + tur.err = tur.b.err + return nil, tur.err + } + return e, nil +} + +// clone returns a new reader for the type unit. +func (tur *typeUnitReader) clone() typeReader { + return &typeUnitReader{ + d: tur.d, + tu: tur.tu, + b: makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data), + } +} + +// offset returns the current offset. +func (tur *typeUnitReader) offset() Offset { + return tur.b.off +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/dwarf/unit.go b/vendor/github.com/mandiant/GoReSym/debug/dwarf/unit.go new file mode 100644 index 00000000..8b810d0a --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/dwarf/unit.go @@ -0,0 +1,137 @@ +// 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 dwarf + +import ( + "sort" + "strconv" +) + +// DWARF debug info is split into a sequence of compilation units. +// Each unit has its own abbreviation table and address size. + +type unit struct { + base Offset // byte offset of header within the aggregate info + off Offset // byte offset of data within the aggregate info + data []byte + atable abbrevTable + asize int + vers int + utype uint8 // DWARF 5 unit type + is64 bool // True for 64-bit DWARF format +} + +// Implement the dataFormat interface. + +func (u *unit) version() int { + return u.vers +} + +func (u *unit) dwarf64() (bool, bool) { + return u.is64, true +} + +func (u *unit) addrsize() int { + return u.asize +} + +func (d *Data) parseUnits() ([]unit, error) { + // Count units. + nunit := 0 + b := makeBuf(d, unknownFormat{}, "info", 0, d.info) + for len(b.data) > 0 { + len, _ := b.unitLength() + if len != Offset(uint32(len)) { + b.error("unit length overflow") + break + } + b.skip(int(len)) + if len > 0 { + nunit++ + } + } + if b.err != nil { + return nil, b.err + } + + // Again, this time writing them down. + b = makeBuf(d, unknownFormat{}, "info", 0, d.info) + units := make([]unit, nunit) + for i := range units { + u := &units[i] + u.base = b.off + var n Offset + if b.err != nil { + return nil, b.err + } + for n == 0 { + n, u.is64 = b.unitLength() + } + dataOff := b.off + vers := b.uint16() + if vers < 2 || vers > 5 { + b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) + break + } + u.vers = int(vers) + if vers >= 5 { + u.utype = b.uint8() + u.asize = int(b.uint8()) + } + var abbrevOff uint64 + if u.is64 { + abbrevOff = b.uint64() + } else { + abbrevOff = uint64(b.uint32()) + } + atable, err := d.parseAbbrev(abbrevOff, u.vers) + if err != nil { + if b.err == nil { + b.err = err + } + break + } + u.atable = atable + if vers < 5 { + u.asize = int(b.uint8()) + } + + switch u.utype { + case utSkeleton, utSplitCompile: + b.uint64() // unit ID + case utType, utSplitType: + b.uint64() // type signature + if u.is64 { // type offset + b.uint64() + } else { + b.uint32() + } + } + + u.off = b.off + u.data = b.bytes(int(n - (b.off - dataOff))) + } + if b.err != nil { + return nil, b.err + } + return units, nil +} + +// offsetToUnit returns the index of the unit containing offset off. +// It returns -1 if no unit contains this offset. +func (d *Data) offsetToUnit(off Offset) int { + // Find the unit after off + next := sort.Search(len(d.unit), func(i int) bool { + return d.unit[i].off > off + }) + if next == 0 { + return -1 + } + u := &d.unit[next-1] + if u.off <= off && off < u.off+Offset(len(u.data)) { + return next - 1 + } + return -1 +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/elf/elf.go b/vendor/github.com/mandiant/GoReSym/debug/elf/elf.go new file mode 100644 index 00000000..e99d42f3 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/elf/elf.go @@ -0,0 +1,3176 @@ +/* + * ELF constants and data structures + * + * Derived from: + * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $ + * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $ + * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $ + * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $ + * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $ + * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $ + * "System V ABI" (http://www.sco.com/developers/gabi/latest/ch4.eheader.html) + * "ELF for the ARM® 64-bit Architecture (AArch64)" (ARM IHI 0056B) + * "RISC-V ELF psABI specification" (https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md) + * llvm/BinaryFormat/ELF.h - ELF constants and structures + * + * Copyright (c) 1996-1998 John D. Polstra. All rights reserved. + * Copyright (c) 2001 David E. O'Brien + * Portions Copyright 2009 The Go Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package elf + +import "strconv" + +/* + * Constants + */ + +// Indexes into the Header.Ident array. +const ( + EI_CLASS = 4 /* Class of machine. */ + EI_DATA = 5 /* Data format. */ + EI_VERSION = 6 /* ELF format version. */ + EI_OSABI = 7 /* Operating system / ABI identification */ + EI_ABIVERSION = 8 /* ABI version */ + EI_PAD = 9 /* Start of padding (per SVR4 ABI). */ + EI_NIDENT = 16 /* Size of e_ident array. */ +) + +// Initial magic number for ELF files. +const ELFMAG = "\177ELF" + +// Version is found in Header.Ident[EI_VERSION] and Header.Version. +type Version byte + +const ( + EV_NONE Version = 0 + EV_CURRENT Version = 1 +) + +var versionStrings = []intName{ + {0, "EV_NONE"}, + {1, "EV_CURRENT"}, +} + +func (i Version) String() string { return stringName(uint32(i), versionStrings, false) } +func (i Version) GoString() string { return stringName(uint32(i), versionStrings, true) } + +// Class is found in Header.Ident[EI_CLASS] and Header.Class. +type Class byte + +const ( + ELFCLASSNONE Class = 0 /* Unknown class. */ + ELFCLASS32 Class = 1 /* 32-bit architecture. */ + ELFCLASS64 Class = 2 /* 64-bit architecture. */ +) + +var classStrings = []intName{ + {0, "ELFCLASSNONE"}, + {1, "ELFCLASS32"}, + {2, "ELFCLASS64"}, +} + +func (i Class) String() string { return stringName(uint32(i), classStrings, false) } +func (i Class) GoString() string { return stringName(uint32(i), classStrings, true) } + +// Data is found in Header.Ident[EI_DATA] and Header.Data. +type Data byte + +const ( + ELFDATANONE Data = 0 /* Unknown data format. */ + ELFDATA2LSB Data = 1 /* 2's complement little-endian. */ + ELFDATA2MSB Data = 2 /* 2's complement big-endian. */ +) + +var dataStrings = []intName{ + {0, "ELFDATANONE"}, + {1, "ELFDATA2LSB"}, + {2, "ELFDATA2MSB"}, +} + +func (i Data) String() string { return stringName(uint32(i), dataStrings, false) } +func (i Data) GoString() string { return stringName(uint32(i), dataStrings, true) } + +// OSABI is found in Header.Ident[EI_OSABI] and Header.OSABI. +type OSABI byte + +const ( + ELFOSABI_NONE OSABI = 0 /* UNIX System V ABI */ + ELFOSABI_HPUX OSABI = 1 /* HP-UX operating system */ + ELFOSABI_NETBSD OSABI = 2 /* NetBSD */ + ELFOSABI_LINUX OSABI = 3 /* GNU/Linux */ + ELFOSABI_HURD OSABI = 4 /* GNU/Hurd */ + ELFOSABI_86OPEN OSABI = 5 /* 86Open common IA32 ABI */ + ELFOSABI_SOLARIS OSABI = 6 /* Solaris */ + ELFOSABI_AIX OSABI = 7 /* AIX */ + ELFOSABI_IRIX OSABI = 8 /* IRIX */ + ELFOSABI_FREEBSD OSABI = 9 /* FreeBSD */ + ELFOSABI_TRU64 OSABI = 10 /* TRU64 UNIX */ + ELFOSABI_MODESTO OSABI = 11 /* Novell Modesto */ + ELFOSABI_OPENBSD OSABI = 12 /* OpenBSD */ + ELFOSABI_OPENVMS OSABI = 13 /* Open VMS */ + ELFOSABI_NSK OSABI = 14 /* HP Non-Stop Kernel */ + ELFOSABI_AROS OSABI = 15 /* Amiga Research OS */ + ELFOSABI_FENIXOS OSABI = 16 /* The FenixOS highly scalable multi-core OS */ + ELFOSABI_CLOUDABI OSABI = 17 /* Nuxi CloudABI */ + ELFOSABI_ARM OSABI = 97 /* ARM */ + ELFOSABI_STANDALONE OSABI = 255 /* Standalone (embedded) application */ +) + +var osabiStrings = []intName{ + {0, "ELFOSABI_NONE"}, + {1, "ELFOSABI_HPUX"}, + {2, "ELFOSABI_NETBSD"}, + {3, "ELFOSABI_LINUX"}, + {4, "ELFOSABI_HURD"}, + {5, "ELFOSABI_86OPEN"}, + {6, "ELFOSABI_SOLARIS"}, + {7, "ELFOSABI_AIX"}, + {8, "ELFOSABI_IRIX"}, + {9, "ELFOSABI_FREEBSD"}, + {10, "ELFOSABI_TRU64"}, + {11, "ELFOSABI_MODESTO"}, + {12, "ELFOSABI_OPENBSD"}, + {13, "ELFOSABI_OPENVMS"}, + {14, "ELFOSABI_NSK"}, + {15, "ELFOSABI_AROS"}, + {16, "ELFOSABI_FENIXOS"}, + {17, "ELFOSABI_CLOUDABI"}, + {97, "ELFOSABI_ARM"}, + {255, "ELFOSABI_STANDALONE"}, +} + +func (i OSABI) String() string { return stringName(uint32(i), osabiStrings, false) } +func (i OSABI) GoString() string { return stringName(uint32(i), osabiStrings, true) } + +// Type is found in Header.Type. +type Type uint16 + +const ( + ET_NONE Type = 0 /* Unknown type. */ + ET_REL Type = 1 /* Relocatable. */ + ET_EXEC Type = 2 /* Executable. */ + ET_DYN Type = 3 /* Shared object. */ + ET_CORE Type = 4 /* Core file. */ + ET_LOOS Type = 0xfe00 /* First operating system specific. */ + ET_HIOS Type = 0xfeff /* Last operating system-specific. */ + ET_LOPROC Type = 0xff00 /* First processor-specific. */ + ET_HIPROC Type = 0xffff /* Last processor-specific. */ +) + +var typeStrings = []intName{ + {0, "ET_NONE"}, + {1, "ET_REL"}, + {2, "ET_EXEC"}, + {3, "ET_DYN"}, + {4, "ET_CORE"}, + {0xfe00, "ET_LOOS"}, + {0xfeff, "ET_HIOS"}, + {0xff00, "ET_LOPROC"}, + {0xffff, "ET_HIPROC"}, +} + +func (i Type) String() string { return stringName(uint32(i), typeStrings, false) } +func (i Type) GoString() string { return stringName(uint32(i), typeStrings, true) } + +// Machine is found in Header.Machine. +type Machine uint16 + +const ( + EM_NONE Machine = 0 /* Unknown machine. */ + EM_M32 Machine = 1 /* AT&T WE32100. */ + EM_SPARC Machine = 2 /* Sun SPARC. */ + EM_386 Machine = 3 /* Intel i386. */ + EM_68K Machine = 4 /* Motorola 68000. */ + EM_88K Machine = 5 /* Motorola 88000. */ + EM_860 Machine = 7 /* Intel i860. */ + EM_MIPS Machine = 8 /* MIPS R3000 Big-Endian only. */ + EM_S370 Machine = 9 /* IBM System/370. */ + EM_MIPS_RS3_LE Machine = 10 /* MIPS R3000 Little-Endian. */ + EM_PARISC Machine = 15 /* HP PA-RISC. */ + EM_VPP500 Machine = 17 /* Fujitsu VPP500. */ + EM_SPARC32PLUS Machine = 18 /* SPARC v8plus. */ + EM_960 Machine = 19 /* Intel 80960. */ + EM_PPC Machine = 20 /* PowerPC 32-bit. */ + EM_PPC64 Machine = 21 /* PowerPC 64-bit. */ + EM_S390 Machine = 22 /* IBM System/390. */ + EM_V800 Machine = 36 /* NEC V800. */ + EM_FR20 Machine = 37 /* Fujitsu FR20. */ + EM_RH32 Machine = 38 /* TRW RH-32. */ + EM_RCE Machine = 39 /* Motorola RCE. */ + EM_ARM Machine = 40 /* ARM. */ + EM_SH Machine = 42 /* Hitachi SH. */ + EM_SPARCV9 Machine = 43 /* SPARC v9 64-bit. */ + EM_TRICORE Machine = 44 /* Siemens TriCore embedded processor. */ + EM_ARC Machine = 45 /* Argonaut RISC Core. */ + EM_H8_300 Machine = 46 /* Hitachi H8/300. */ + EM_H8_300H Machine = 47 /* Hitachi H8/300H. */ + EM_H8S Machine = 48 /* Hitachi H8S. */ + EM_H8_500 Machine = 49 /* Hitachi H8/500. */ + EM_IA_64 Machine = 50 /* Intel IA-64 Processor. */ + EM_MIPS_X Machine = 51 /* Stanford MIPS-X. */ + EM_COLDFIRE Machine = 52 /* Motorola ColdFire. */ + EM_68HC12 Machine = 53 /* Motorola M68HC12. */ + EM_MMA Machine = 54 /* Fujitsu MMA. */ + EM_PCP Machine = 55 /* Siemens PCP. */ + EM_NCPU Machine = 56 /* Sony nCPU. */ + EM_NDR1 Machine = 57 /* Denso NDR1 microprocessor. */ + EM_STARCORE Machine = 58 /* Motorola Star*Core processor. */ + EM_ME16 Machine = 59 /* Toyota ME16 processor. */ + EM_ST100 Machine = 60 /* STMicroelectronics ST100 processor. */ + EM_TINYJ Machine = 61 /* Advanced Logic Corp. TinyJ processor. */ + EM_X86_64 Machine = 62 /* Advanced Micro Devices x86-64 */ + EM_PDSP Machine = 63 /* Sony DSP Processor */ + EM_PDP10 Machine = 64 /* Digital Equipment Corp. PDP-10 */ + EM_PDP11 Machine = 65 /* Digital Equipment Corp. PDP-11 */ + EM_FX66 Machine = 66 /* Siemens FX66 microcontroller */ + EM_ST9PLUS Machine = 67 /* STMicroelectronics ST9+ 8/16 bit microcontroller */ + EM_ST7 Machine = 68 /* STMicroelectronics ST7 8-bit microcontroller */ + EM_68HC16 Machine = 69 /* Motorola MC68HC16 Microcontroller */ + EM_68HC11 Machine = 70 /* Motorola MC68HC11 Microcontroller */ + EM_68HC08 Machine = 71 /* Motorola MC68HC08 Microcontroller */ + EM_68HC05 Machine = 72 /* Motorola MC68HC05 Microcontroller */ + EM_SVX Machine = 73 /* Silicon Graphics SVx */ + EM_ST19 Machine = 74 /* STMicroelectronics ST19 8-bit microcontroller */ + EM_VAX Machine = 75 /* Digital VAX */ + EM_CRIS Machine = 76 /* Axis Communications 32-bit embedded processor */ + EM_JAVELIN Machine = 77 /* Infineon Technologies 32-bit embedded processor */ + EM_FIREPATH Machine = 78 /* Element 14 64-bit DSP Processor */ + EM_ZSP Machine = 79 /* LSI Logic 16-bit DSP Processor */ + EM_MMIX Machine = 80 /* Donald Knuth's educational 64-bit processor */ + EM_HUANY Machine = 81 /* Harvard University machine-independent object files */ + EM_PRISM Machine = 82 /* SiTera Prism */ + EM_AVR Machine = 83 /* Atmel AVR 8-bit microcontroller */ + EM_FR30 Machine = 84 /* Fujitsu FR30 */ + EM_D10V Machine = 85 /* Mitsubishi D10V */ + EM_D30V Machine = 86 /* Mitsubishi D30V */ + EM_V850 Machine = 87 /* NEC v850 */ + EM_M32R Machine = 88 /* Mitsubishi M32R */ + EM_MN10300 Machine = 89 /* Matsushita MN10300 */ + EM_MN10200 Machine = 90 /* Matsushita MN10200 */ + EM_PJ Machine = 91 /* picoJava */ + EM_OPENRISC Machine = 92 /* OpenRISC 32-bit embedded processor */ + EM_ARC_COMPACT Machine = 93 /* ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5) */ + EM_XTENSA Machine = 94 /* Tensilica Xtensa Architecture */ + EM_VIDEOCORE Machine = 95 /* Alphamosaic VideoCore processor */ + EM_TMM_GPP Machine = 96 /* Thompson Multimedia General Purpose Processor */ + EM_NS32K Machine = 97 /* National Semiconductor 32000 series */ + EM_TPC Machine = 98 /* Tenor Network TPC processor */ + EM_SNP1K Machine = 99 /* Trebia SNP 1000 processor */ + EM_ST200 Machine = 100 /* STMicroelectronics (www.st.com) ST200 microcontroller */ + EM_IP2K Machine = 101 /* Ubicom IP2xxx microcontroller family */ + EM_MAX Machine = 102 /* MAX Processor */ + EM_CR Machine = 103 /* National Semiconductor CompactRISC microprocessor */ + EM_F2MC16 Machine = 104 /* Fujitsu F2MC16 */ + EM_MSP430 Machine = 105 /* Texas Instruments embedded microcontroller msp430 */ + EM_BLACKFIN Machine = 106 /* Analog Devices Blackfin (DSP) processor */ + EM_SE_C33 Machine = 107 /* S1C33 Family of Seiko Epson processors */ + EM_SEP Machine = 108 /* Sharp embedded microprocessor */ + EM_ARCA Machine = 109 /* Arca RISC Microprocessor */ + EM_UNICORE Machine = 110 /* Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University */ + EM_EXCESS Machine = 111 /* eXcess: 16/32/64-bit configurable embedded CPU */ + EM_DXP Machine = 112 /* Icera Semiconductor Inc. Deep Execution Processor */ + EM_ALTERA_NIOS2 Machine = 113 /* Altera Nios II soft-core processor */ + EM_CRX Machine = 114 /* National Semiconductor CompactRISC CRX microprocessor */ + EM_XGATE Machine = 115 /* Motorola XGATE embedded processor */ + EM_C166 Machine = 116 /* Infineon C16x/XC16x processor */ + EM_M16C Machine = 117 /* Renesas M16C series microprocessors */ + EM_DSPIC30F Machine = 118 /* Microchip Technology dsPIC30F Digital Signal Controller */ + EM_CE Machine = 119 /* Freescale Communication Engine RISC core */ + EM_M32C Machine = 120 /* Renesas M32C series microprocessors */ + EM_TSK3000 Machine = 131 /* Altium TSK3000 core */ + EM_RS08 Machine = 132 /* Freescale RS08 embedded processor */ + EM_SHARC Machine = 133 /* Analog Devices SHARC family of 32-bit DSP processors */ + EM_ECOG2 Machine = 134 /* Cyan Technology eCOG2 microprocessor */ + EM_SCORE7 Machine = 135 /* Sunplus S+core7 RISC processor */ + EM_DSP24 Machine = 136 /* New Japan Radio (NJR) 24-bit DSP Processor */ + EM_VIDEOCORE3 Machine = 137 /* Broadcom VideoCore III processor */ + EM_LATTICEMICO32 Machine = 138 /* RISC processor for Lattice FPGA architecture */ + EM_SE_C17 Machine = 139 /* Seiko Epson C17 family */ + EM_TI_C6000 Machine = 140 /* The Texas Instruments TMS320C6000 DSP family */ + EM_TI_C2000 Machine = 141 /* The Texas Instruments TMS320C2000 DSP family */ + EM_TI_C5500 Machine = 142 /* The Texas Instruments TMS320C55x DSP family */ + EM_TI_ARP32 Machine = 143 /* Texas Instruments Application Specific RISC Processor, 32bit fetch */ + EM_TI_PRU Machine = 144 /* Texas Instruments Programmable Realtime Unit */ + EM_MMDSP_PLUS Machine = 160 /* STMicroelectronics 64bit VLIW Data Signal Processor */ + EM_CYPRESS_M8C Machine = 161 /* Cypress M8C microprocessor */ + EM_R32C Machine = 162 /* Renesas R32C series microprocessors */ + EM_TRIMEDIA Machine = 163 /* NXP Semiconductors TriMedia architecture family */ + EM_QDSP6 Machine = 164 /* QUALCOMM DSP6 Processor */ + EM_8051 Machine = 165 /* Intel 8051 and variants */ + EM_STXP7X Machine = 166 /* STMicroelectronics STxP7x family of configurable and extensible RISC processors */ + EM_NDS32 Machine = 167 /* Andes Technology compact code size embedded RISC processor family */ + EM_ECOG1 Machine = 168 /* Cyan Technology eCOG1X family */ + EM_ECOG1X Machine = 168 /* Cyan Technology eCOG1X family */ + EM_MAXQ30 Machine = 169 /* Dallas Semiconductor MAXQ30 Core Micro-controllers */ + EM_XIMO16 Machine = 170 /* New Japan Radio (NJR) 16-bit DSP Processor */ + EM_MANIK Machine = 171 /* M2000 Reconfigurable RISC Microprocessor */ + EM_CRAYNV2 Machine = 172 /* Cray Inc. NV2 vector architecture */ + EM_RX Machine = 173 /* Renesas RX family */ + EM_METAG Machine = 174 /* Imagination Technologies META processor architecture */ + EM_MCST_ELBRUS Machine = 175 /* MCST Elbrus general purpose hardware architecture */ + EM_ECOG16 Machine = 176 /* Cyan Technology eCOG16 family */ + EM_CR16 Machine = 177 /* National Semiconductor CompactRISC CR16 16-bit microprocessor */ + EM_ETPU Machine = 178 /* Freescale Extended Time Processing Unit */ + EM_SLE9X Machine = 179 /* Infineon Technologies SLE9X core */ + EM_L10M Machine = 180 /* Intel L10M */ + EM_K10M Machine = 181 /* Intel K10M */ + EM_AARCH64 Machine = 183 /* ARM 64-bit Architecture (AArch64) */ + EM_AVR32 Machine = 185 /* Atmel Corporation 32-bit microprocessor family */ + EM_STM8 Machine = 186 /* STMicroeletronics STM8 8-bit microcontroller */ + EM_TILE64 Machine = 187 /* Tilera TILE64 multicore architecture family */ + EM_TILEPRO Machine = 188 /* Tilera TILEPro multicore architecture family */ + EM_MICROBLAZE Machine = 189 /* Xilinx MicroBlaze 32-bit RISC soft processor core */ + EM_CUDA Machine = 190 /* NVIDIA CUDA architecture */ + EM_TILEGX Machine = 191 /* Tilera TILE-Gx multicore architecture family */ + EM_CLOUDSHIELD Machine = 192 /* CloudShield architecture family */ + EM_COREA_1ST Machine = 193 /* KIPO-KAIST Core-A 1st generation processor family */ + EM_COREA_2ND Machine = 194 /* KIPO-KAIST Core-A 2nd generation processor family */ + EM_ARC_COMPACT2 Machine = 195 /* Synopsys ARCompact V2 */ + EM_OPEN8 Machine = 196 /* Open8 8-bit RISC soft processor core */ + EM_RL78 Machine = 197 /* Renesas RL78 family */ + EM_VIDEOCORE5 Machine = 198 /* Broadcom VideoCore V processor */ + EM_78KOR Machine = 199 /* Renesas 78KOR family */ + EM_56800EX Machine = 200 /* Freescale 56800EX Digital Signal Controller (DSC) */ + EM_BA1 Machine = 201 /* Beyond BA1 CPU architecture */ + EM_BA2 Machine = 202 /* Beyond BA2 CPU architecture */ + EM_XCORE Machine = 203 /* XMOS xCORE processor family */ + EM_MCHP_PIC Machine = 204 /* Microchip 8-bit PIC(r) family */ + EM_INTEL205 Machine = 205 /* Reserved by Intel */ + EM_INTEL206 Machine = 206 /* Reserved by Intel */ + EM_INTEL207 Machine = 207 /* Reserved by Intel */ + EM_INTEL208 Machine = 208 /* Reserved by Intel */ + EM_INTEL209 Machine = 209 /* Reserved by Intel */ + EM_KM32 Machine = 210 /* KM211 KM32 32-bit processor */ + EM_KMX32 Machine = 211 /* KM211 KMX32 32-bit processor */ + EM_KMX16 Machine = 212 /* KM211 KMX16 16-bit processor */ + EM_KMX8 Machine = 213 /* KM211 KMX8 8-bit processor */ + EM_KVARC Machine = 214 /* KM211 KVARC processor */ + EM_CDP Machine = 215 /* Paneve CDP architecture family */ + EM_COGE Machine = 216 /* Cognitive Smart Memory Processor */ + EM_COOL Machine = 217 /* Bluechip Systems CoolEngine */ + EM_NORC Machine = 218 /* Nanoradio Optimized RISC */ + EM_CSR_KALIMBA Machine = 219 /* CSR Kalimba architecture family */ + EM_Z80 Machine = 220 /* Zilog Z80 */ + EM_VISIUM Machine = 221 /* Controls and Data Services VISIUMcore processor */ + EM_FT32 Machine = 222 /* FTDI Chip FT32 high performance 32-bit RISC architecture */ + EM_MOXIE Machine = 223 /* Moxie processor family */ + EM_AMDGPU Machine = 224 /* AMD GPU architecture */ + EM_RISCV Machine = 243 /* RISC-V */ + EM_LANAI Machine = 244 /* Lanai 32-bit processor */ + EM_BPF Machine = 247 /* Linux BPF – in-kernel virtual machine */ + + /* Non-standard or deprecated. */ + EM_486 Machine = 6 /* Intel i486. */ + EM_MIPS_RS4_BE Machine = 10 /* MIPS R4000 Big-Endian */ + EM_ALPHA_STD Machine = 41 /* Digital Alpha (standard value). */ + EM_ALPHA Machine = 0x9026 /* Alpha (written in the absence of an ABI) */ +) + +var machineStrings = []intName{ + {0, "EM_NONE"}, + {1, "EM_M32"}, + {2, "EM_SPARC"}, + {3, "EM_386"}, + {4, "EM_68K"}, + {5, "EM_88K"}, + {7, "EM_860"}, + {8, "EM_MIPS"}, + {9, "EM_S370"}, + {10, "EM_MIPS_RS3_LE"}, + {15, "EM_PARISC"}, + {17, "EM_VPP500"}, + {18, "EM_SPARC32PLUS"}, + {19, "EM_960"}, + {20, "EM_PPC"}, + {21, "EM_PPC64"}, + {22, "EM_S390"}, + {36, "EM_V800"}, + {37, "EM_FR20"}, + {38, "EM_RH32"}, + {39, "EM_RCE"}, + {40, "EM_ARM"}, + {42, "EM_SH"}, + {43, "EM_SPARCV9"}, + {44, "EM_TRICORE"}, + {45, "EM_ARC"}, + {46, "EM_H8_300"}, + {47, "EM_H8_300H"}, + {48, "EM_H8S"}, + {49, "EM_H8_500"}, + {50, "EM_IA_64"}, + {51, "EM_MIPS_X"}, + {52, "EM_COLDFIRE"}, + {53, "EM_68HC12"}, + {54, "EM_MMA"}, + {55, "EM_PCP"}, + {56, "EM_NCPU"}, + {57, "EM_NDR1"}, + {58, "EM_STARCORE"}, + {59, "EM_ME16"}, + {60, "EM_ST100"}, + {61, "EM_TINYJ"}, + {62, "EM_X86_64"}, + {63, "EM_PDSP"}, + {64, "EM_PDP10"}, + {65, "EM_PDP11"}, + {66, "EM_FX66"}, + {67, "EM_ST9PLUS"}, + {68, "EM_ST7"}, + {69, "EM_68HC16"}, + {70, "EM_68HC11"}, + {71, "EM_68HC08"}, + {72, "EM_68HC05"}, + {73, "EM_SVX"}, + {74, "EM_ST19"}, + {75, "EM_VAX"}, + {76, "EM_CRIS"}, + {77, "EM_JAVELIN"}, + {78, "EM_FIREPATH"}, + {79, "EM_ZSP"}, + {80, "EM_MMIX"}, + {81, "EM_HUANY"}, + {82, "EM_PRISM"}, + {83, "EM_AVR"}, + {84, "EM_FR30"}, + {85, "EM_D10V"}, + {86, "EM_D30V"}, + {87, "EM_V850"}, + {88, "EM_M32R"}, + {89, "EM_MN10300"}, + {90, "EM_MN10200"}, + {91, "EM_PJ"}, + {92, "EM_OPENRISC"}, + {93, "EM_ARC_COMPACT"}, + {94, "EM_XTENSA"}, + {95, "EM_VIDEOCORE"}, + {96, "EM_TMM_GPP"}, + {97, "EM_NS32K"}, + {98, "EM_TPC"}, + {99, "EM_SNP1K"}, + {100, "EM_ST200"}, + {101, "EM_IP2K"}, + {102, "EM_MAX"}, + {103, "EM_CR"}, + {104, "EM_F2MC16"}, + {105, "EM_MSP430"}, + {106, "EM_BLACKFIN"}, + {107, "EM_SE_C33"}, + {108, "EM_SEP"}, + {109, "EM_ARCA"}, + {110, "EM_UNICORE"}, + {111, "EM_EXCESS"}, + {112, "EM_DXP"}, + {113, "EM_ALTERA_NIOS2"}, + {114, "EM_CRX"}, + {115, "EM_XGATE"}, + {116, "EM_C166"}, + {117, "EM_M16C"}, + {118, "EM_DSPIC30F"}, + {119, "EM_CE"}, + {120, "EM_M32C"}, + {131, "EM_TSK3000"}, + {132, "EM_RS08"}, + {133, "EM_SHARC"}, + {134, "EM_ECOG2"}, + {135, "EM_SCORE7"}, + {136, "EM_DSP24"}, + {137, "EM_VIDEOCORE3"}, + {138, "EM_LATTICEMICO32"}, + {139, "EM_SE_C17"}, + {140, "EM_TI_C6000"}, + {141, "EM_TI_C2000"}, + {142, "EM_TI_C5500"}, + {143, "EM_TI_ARP32"}, + {144, "EM_TI_PRU"}, + {160, "EM_MMDSP_PLUS"}, + {161, "EM_CYPRESS_M8C"}, + {162, "EM_R32C"}, + {163, "EM_TRIMEDIA"}, + {164, "EM_QDSP6"}, + {165, "EM_8051"}, + {166, "EM_STXP7X"}, + {167, "EM_NDS32"}, + {168, "EM_ECOG1"}, + {168, "EM_ECOG1X"}, + {169, "EM_MAXQ30"}, + {170, "EM_XIMO16"}, + {171, "EM_MANIK"}, + {172, "EM_CRAYNV2"}, + {173, "EM_RX"}, + {174, "EM_METAG"}, + {175, "EM_MCST_ELBRUS"}, + {176, "EM_ECOG16"}, + {177, "EM_CR16"}, + {178, "EM_ETPU"}, + {179, "EM_SLE9X"}, + {180, "EM_L10M"}, + {181, "EM_K10M"}, + {183, "EM_AARCH64"}, + {185, "EM_AVR32"}, + {186, "EM_STM8"}, + {187, "EM_TILE64"}, + {188, "EM_TILEPRO"}, + {189, "EM_MICROBLAZE"}, + {190, "EM_CUDA"}, + {191, "EM_TILEGX"}, + {192, "EM_CLOUDSHIELD"}, + {193, "EM_COREA_1ST"}, + {194, "EM_COREA_2ND"}, + {195, "EM_ARC_COMPACT2"}, + {196, "EM_OPEN8"}, + {197, "EM_RL78"}, + {198, "EM_VIDEOCORE5"}, + {199, "EM_78KOR"}, + {200, "EM_56800EX"}, + {201, "EM_BA1"}, + {202, "EM_BA2"}, + {203, "EM_XCORE"}, + {204, "EM_MCHP_PIC"}, + {205, "EM_INTEL205"}, + {206, "EM_INTEL206"}, + {207, "EM_INTEL207"}, + {208, "EM_INTEL208"}, + {209, "EM_INTEL209"}, + {210, "EM_KM32"}, + {211, "EM_KMX32"}, + {212, "EM_KMX16"}, + {213, "EM_KMX8"}, + {214, "EM_KVARC"}, + {215, "EM_CDP"}, + {216, "EM_COGE"}, + {217, "EM_COOL"}, + {218, "EM_NORC"}, + {219, "EM_CSR_KALIMBA "}, + {220, "EM_Z80 "}, + {221, "EM_VISIUM "}, + {222, "EM_FT32 "}, + {223, "EM_MOXIE"}, + {224, "EM_AMDGPU"}, + {243, "EM_RISCV"}, + {244, "EM_LANAI"}, + {247, "EM_BPF"}, + + /* Non-standard or deprecated. */ + {6, "EM_486"}, + {10, "EM_MIPS_RS4_BE"}, + {41, "EM_ALPHA_STD"}, + {0x9026, "EM_ALPHA"}, +} + +func (i Machine) String() string { return stringName(uint32(i), machineStrings, false) } +func (i Machine) GoString() string { return stringName(uint32(i), machineStrings, true) } + +// Special section indices. +type SectionIndex int + +const ( + SHN_UNDEF SectionIndex = 0 /* Undefined, missing, irrelevant. */ + SHN_LORESERVE SectionIndex = 0xff00 /* First of reserved range. */ + SHN_LOPROC SectionIndex = 0xff00 /* First processor-specific. */ + SHN_HIPROC SectionIndex = 0xff1f /* Last processor-specific. */ + SHN_LOOS SectionIndex = 0xff20 /* First operating system-specific. */ + SHN_HIOS SectionIndex = 0xff3f /* Last operating system-specific. */ + SHN_ABS SectionIndex = 0xfff1 /* Absolute values. */ + SHN_COMMON SectionIndex = 0xfff2 /* Common data. */ + SHN_XINDEX SectionIndex = 0xffff /* Escape; index stored elsewhere. */ + SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */ +) + +var shnStrings = []intName{ + {0, "SHN_UNDEF"}, + {0xff00, "SHN_LOPROC"}, + {0xff20, "SHN_LOOS"}, + {0xfff1, "SHN_ABS"}, + {0xfff2, "SHN_COMMON"}, + {0xffff, "SHN_XINDEX"}, +} + +func (i SectionIndex) String() string { return stringName(uint32(i), shnStrings, false) } +func (i SectionIndex) GoString() string { return stringName(uint32(i), shnStrings, true) } + +// Section type. +type SectionType uint32 + +const ( + SHT_NULL SectionType = 0 /* inactive */ + SHT_PROGBITS SectionType = 1 /* program defined information */ + SHT_SYMTAB SectionType = 2 /* symbol table section */ + SHT_STRTAB SectionType = 3 /* string table section */ + SHT_RELA SectionType = 4 /* relocation section with addends */ + SHT_HASH SectionType = 5 /* symbol hash table section */ + SHT_DYNAMIC SectionType = 6 /* dynamic section */ + SHT_NOTE SectionType = 7 /* note section */ + SHT_NOBITS SectionType = 8 /* no space section */ + SHT_REL SectionType = 9 /* relocation section - no addends */ + SHT_SHLIB SectionType = 10 /* reserved - purpose unknown */ + SHT_DYNSYM SectionType = 11 /* dynamic symbol table section */ + SHT_INIT_ARRAY SectionType = 14 /* Initialization function pointers. */ + SHT_FINI_ARRAY SectionType = 15 /* Termination function pointers. */ + SHT_PREINIT_ARRAY SectionType = 16 /* Pre-initialization function ptrs. */ + SHT_GROUP SectionType = 17 /* Section group. */ + SHT_SYMTAB_SHNDX SectionType = 18 /* Section indexes (see SHN_XINDEX). */ + SHT_LOOS SectionType = 0x60000000 /* First of OS specific semantics */ + SHT_GNU_ATTRIBUTES SectionType = 0x6ffffff5 /* GNU object attributes */ + SHT_GNU_HASH SectionType = 0x6ffffff6 /* GNU hash table */ + SHT_GNU_LIBLIST SectionType = 0x6ffffff7 /* GNU prelink library list */ + SHT_GNU_VERDEF SectionType = 0x6ffffffd /* GNU version definition section */ + SHT_GNU_VERNEED SectionType = 0x6ffffffe /* GNU version needs section */ + SHT_GNU_VERSYM SectionType = 0x6fffffff /* GNU version symbol table */ + SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */ + SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */ + SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */ + SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */ + SHT_HIUSER SectionType = 0xffffffff /* specific indexes */ +) + +var shtStrings = []intName{ + {0, "SHT_NULL"}, + {1, "SHT_PROGBITS"}, + {2, "SHT_SYMTAB"}, + {3, "SHT_STRTAB"}, + {4, "SHT_RELA"}, + {5, "SHT_HASH"}, + {6, "SHT_DYNAMIC"}, + {7, "SHT_NOTE"}, + {8, "SHT_NOBITS"}, + {9, "SHT_REL"}, + {10, "SHT_SHLIB"}, + {11, "SHT_DYNSYM"}, + {14, "SHT_INIT_ARRAY"}, + {15, "SHT_FINI_ARRAY"}, + {16, "SHT_PREINIT_ARRAY"}, + {17, "SHT_GROUP"}, + {18, "SHT_SYMTAB_SHNDX"}, + {0x60000000, "SHT_LOOS"}, + {0x6ffffff5, "SHT_GNU_ATTRIBUTES"}, + {0x6ffffff6, "SHT_GNU_HASH"}, + {0x6ffffff7, "SHT_GNU_LIBLIST"}, + {0x6ffffffd, "SHT_GNU_VERDEF"}, + {0x6ffffffe, "SHT_GNU_VERNEED"}, + {0x6fffffff, "SHT_GNU_VERSYM"}, + {0x70000000, "SHT_LOPROC"}, + {0x7fffffff, "SHT_HIPROC"}, + {0x80000000, "SHT_LOUSER"}, + {0xffffffff, "SHT_HIUSER"}, +} + +func (i SectionType) String() string { return stringName(uint32(i), shtStrings, false) } +func (i SectionType) GoString() string { return stringName(uint32(i), shtStrings, true) } + +// Section flags. +type SectionFlag uint32 + +const ( + SHF_WRITE SectionFlag = 0x1 /* Section contains writable data. */ + SHF_ALLOC SectionFlag = 0x2 /* Section occupies memory. */ + SHF_EXECINSTR SectionFlag = 0x4 /* Section contains instructions. */ + SHF_MERGE SectionFlag = 0x10 /* Section may be merged. */ + SHF_STRINGS SectionFlag = 0x20 /* Section contains strings. */ + SHF_INFO_LINK SectionFlag = 0x40 /* sh_info holds section index. */ + SHF_LINK_ORDER SectionFlag = 0x80 /* Special ordering requirements. */ + SHF_OS_NONCONFORMING SectionFlag = 0x100 /* OS-specific processing required. */ + SHF_GROUP SectionFlag = 0x200 /* Member of section group. */ + SHF_TLS SectionFlag = 0x400 /* Section contains TLS data. */ + SHF_COMPRESSED SectionFlag = 0x800 /* Section is compressed. */ + SHF_MASKOS SectionFlag = 0x0ff00000 /* OS-specific semantics. */ + SHF_MASKPROC SectionFlag = 0xf0000000 /* Processor-specific semantics. */ +) + +var shfStrings = []intName{ + {0x1, "SHF_WRITE"}, + {0x2, "SHF_ALLOC"}, + {0x4, "SHF_EXECINSTR"}, + {0x10, "SHF_MERGE"}, + {0x20, "SHF_STRINGS"}, + {0x40, "SHF_INFO_LINK"}, + {0x80, "SHF_LINK_ORDER"}, + {0x100, "SHF_OS_NONCONFORMING"}, + {0x200, "SHF_GROUP"}, + {0x400, "SHF_TLS"}, + {0x800, "SHF_COMPRESSED"}, +} + +func (i SectionFlag) String() string { return flagName(uint32(i), shfStrings, false) } +func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) } + +// Section compression type. +type CompressionType int + +const ( + COMPRESS_ZLIB CompressionType = 1 /* ZLIB compression. */ + COMPRESS_LOOS CompressionType = 0x60000000 /* First OS-specific. */ + COMPRESS_HIOS CompressionType = 0x6fffffff /* Last OS-specific. */ + COMPRESS_LOPROC CompressionType = 0x70000000 /* First processor-specific type. */ + COMPRESS_HIPROC CompressionType = 0x7fffffff /* Last processor-specific type. */ +) + +var compressionStrings = []intName{ + {1, "COMPRESS_ZLIB"}, + {0x60000000, "COMPRESS_LOOS"}, + {0x6fffffff, "COMPRESS_HIOS"}, + {0x70000000, "COMPRESS_LOPROC"}, + {0x7fffffff, "COMPRESS_HIPROC"}, +} + +func (i CompressionType) String() string { return stringName(uint32(i), compressionStrings, false) } +func (i CompressionType) GoString() string { return stringName(uint32(i), compressionStrings, true) } + +// Prog.Type +type ProgType int + +const ( + PT_NULL ProgType = 0 /* Unused entry. */ + PT_LOAD ProgType = 1 /* Loadable segment. */ + PT_DYNAMIC ProgType = 2 /* Dynamic linking information segment. */ + PT_INTERP ProgType = 3 /* Pathname of interpreter. */ + PT_NOTE ProgType = 4 /* Auxiliary information. */ + PT_SHLIB ProgType = 5 /* Reserved (not used). */ + PT_PHDR ProgType = 6 /* Location of program header itself. */ + PT_TLS ProgType = 7 /* Thread local storage segment */ + + PT_LOOS ProgType = 0x60000000 /* First OS-specific. */ + + PT_GNU_EH_FRAME ProgType = 0x6474e550 /* Frame unwind information */ + PT_GNU_STACK ProgType = 0x6474e551 /* Stack flags */ + PT_GNU_RELRO ProgType = 0x6474e552 /* Read only after relocs */ + PT_GNU_PROPERTY ProgType = 0x6474e553 /* GNU property */ + PT_GNU_MBIND_LO ProgType = 0x6474e555 /* Mbind segments start */ + PT_GNU_MBIND_HI ProgType = 0x6474f554 /* Mbind segments finish */ + + PT_PAX_FLAGS ProgType = 0x65041580 /* PAX flags */ + + PT_OPENBSD_RANDOMIZE ProgType = 0x65a3dbe6 /* Random data */ + PT_OPENBSD_WXNEEDED ProgType = 0x65a3dbe7 /* W^X violations */ + PT_OPENBSD_BOOTDATA ProgType = 0x65a41be6 /* Boot arguments */ + + PT_SUNW_EH_FRAME ProgType = 0x6474e550 /* Frame unwind information */ + PT_SUNWSTACK ProgType = 0x6ffffffb /* Stack segment */ + + PT_HIOS ProgType = 0x6fffffff /* Last OS-specific. */ + + PT_LOPROC ProgType = 0x70000000 /* First processor-specific type. */ + + PT_ARM_ARCHEXT ProgType = 0x70000000 /* Architecture compatibility */ + PT_ARM_EXIDX ProgType = 0x70000001 /* Exception unwind tables */ + + PT_AARCH64_ARCHEXT ProgType = 0x70000000 /* Architecture compatibility */ + PT_AARCH64_UNWIND ProgType = 0x70000001 /* Exception unwind tables */ + + PT_MIPS_REGINFO ProgType = 0x70000000 /* Register usage */ + PT_MIPS_RTPROC ProgType = 0x70000001 /* Runtime procedures */ + PT_MIPS_OPTIONS ProgType = 0x70000002 /* Options */ + PT_MIPS_ABIFLAGS ProgType = 0x70000003 /* ABI flags */ + + PT_S390_PGSTE ProgType = 0x70000000 /* 4k page table size */ + + PT_HIPROC ProgType = 0x7fffffff /* Last processor-specific type. */ +) + +var ptStrings = []intName{ + {0, "PT_NULL"}, + {1, "PT_LOAD"}, + {2, "PT_DYNAMIC"}, + {3, "PT_INTERP"}, + {4, "PT_NOTE"}, + {5, "PT_SHLIB"}, + {6, "PT_PHDR"}, + {7, "PT_TLS"}, + {0x60000000, "PT_LOOS"}, + {0x6474e550, "PT_GNU_EH_FRAME"}, + {0x6474e551, "PT_GNU_STACK"}, + {0x6474e552, "PT_GNU_RELRO"}, + {0x6474e553, "PT_GNU_PROPERTY"}, + {0x65041580, "PT_PAX_FLAGS"}, + {0x65a3dbe6, "PT_OPENBSD_RANDOMIZE"}, + {0x65a3dbe7, "PT_OPENBSD_WXNEEDED"}, + {0x65a41be6, "PT_OPENBSD_BOOTDATA"}, + {0x6ffffffb, "PT_SUNWSTACK"}, + {0x6fffffff, "PT_HIOS"}, + {0x70000000, "PT_LOPROC"}, + // We don't list the processor-dependent ProgTypes, + // as the values overlap. + {0x7fffffff, "PT_HIPROC"}, +} + +func (i ProgType) String() string { return stringName(uint32(i), ptStrings, false) } +func (i ProgType) GoString() string { return stringName(uint32(i), ptStrings, true) } + +// Prog.Flag +type ProgFlag uint32 + +const ( + PF_X ProgFlag = 0x1 /* Executable. */ + PF_W ProgFlag = 0x2 /* Writable. */ + PF_R ProgFlag = 0x4 /* Readable. */ + PF_MASKOS ProgFlag = 0x0ff00000 /* Operating system-specific. */ + PF_MASKPROC ProgFlag = 0xf0000000 /* Processor-specific. */ +) + +var pfStrings = []intName{ + {0x1, "PF_X"}, + {0x2, "PF_W"}, + {0x4, "PF_R"}, +} + +func (i ProgFlag) String() string { return flagName(uint32(i), pfStrings, false) } +func (i ProgFlag) GoString() string { return flagName(uint32(i), pfStrings, true) } + +// Dyn.Tag +type DynTag int + +const ( + DT_NULL DynTag = 0 /* Terminating entry. */ + DT_NEEDED DynTag = 1 /* String table offset of a needed shared library. */ + DT_PLTRELSZ DynTag = 2 /* Total size in bytes of PLT relocations. */ + DT_PLTGOT DynTag = 3 /* Processor-dependent address. */ + DT_HASH DynTag = 4 /* Address of symbol hash table. */ + DT_STRTAB DynTag = 5 /* Address of string table. */ + DT_SYMTAB DynTag = 6 /* Address of symbol table. */ + DT_RELA DynTag = 7 /* Address of ElfNN_Rela relocations. */ + DT_RELASZ DynTag = 8 /* Total size of ElfNN_Rela relocations. */ + DT_RELAENT DynTag = 9 /* Size of each ElfNN_Rela relocation entry. */ + DT_STRSZ DynTag = 10 /* Size of string table. */ + DT_SYMENT DynTag = 11 /* Size of each symbol table entry. */ + DT_INIT DynTag = 12 /* Address of initialization function. */ + DT_FINI DynTag = 13 /* Address of finalization function. */ + DT_SONAME DynTag = 14 /* String table offset of shared object name. */ + DT_RPATH DynTag = 15 /* String table offset of library path. [sup] */ + DT_SYMBOLIC DynTag = 16 /* Indicates "symbolic" linking. [sup] */ + DT_REL DynTag = 17 /* Address of ElfNN_Rel relocations. */ + DT_RELSZ DynTag = 18 /* Total size of ElfNN_Rel relocations. */ + DT_RELENT DynTag = 19 /* Size of each ElfNN_Rel relocation. */ + DT_PLTREL DynTag = 20 /* Type of relocation used for PLT. */ + DT_DEBUG DynTag = 21 /* Reserved (not used). */ + DT_TEXTREL DynTag = 22 /* Indicates there may be relocations in non-writable segments. [sup] */ + DT_JMPREL DynTag = 23 /* Address of PLT relocations. */ + DT_BIND_NOW DynTag = 24 /* [sup] */ + DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */ + DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */ + DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */ + DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of termination functions. */ + DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */ + DT_FLAGS DynTag = 30 /* Object specific flag values. */ + DT_ENCODING DynTag = 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ + DT_PREINIT_ARRAY DynTag = 32 /* Address of the array of pointers to pre-initialization functions. */ + DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */ + DT_SYMTAB_SHNDX DynTag = 34 /* Address of SHT_SYMTAB_SHNDX section. */ + + DT_LOOS DynTag = 0x6000000d /* First OS-specific */ + DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */ + + DT_VALRNGLO DynTag = 0x6ffffd00 + DT_GNU_PRELINKED DynTag = 0x6ffffdf5 + DT_GNU_CONFLICTSZ DynTag = 0x6ffffdf6 + DT_GNU_LIBLISTSZ DynTag = 0x6ffffdf7 + DT_CHECKSUM DynTag = 0x6ffffdf8 + DT_PLTPADSZ DynTag = 0x6ffffdf9 + DT_MOVEENT DynTag = 0x6ffffdfa + DT_MOVESZ DynTag = 0x6ffffdfb + DT_FEATURE DynTag = 0x6ffffdfc + DT_POSFLAG_1 DynTag = 0x6ffffdfd + DT_SYMINSZ DynTag = 0x6ffffdfe + DT_SYMINENT DynTag = 0x6ffffdff + DT_VALRNGHI DynTag = 0x6ffffdff + + DT_ADDRRNGLO DynTag = 0x6ffffe00 + DT_GNU_HASH DynTag = 0x6ffffef5 + DT_TLSDESC_PLT DynTag = 0x6ffffef6 + DT_TLSDESC_GOT DynTag = 0x6ffffef7 + DT_GNU_CONFLICT DynTag = 0x6ffffef8 + DT_GNU_LIBLIST DynTag = 0x6ffffef9 + DT_CONFIG DynTag = 0x6ffffefa + DT_DEPAUDIT DynTag = 0x6ffffefb + DT_AUDIT DynTag = 0x6ffffefc + DT_PLTPAD DynTag = 0x6ffffefd + DT_MOVETAB DynTag = 0x6ffffefe + DT_SYMINFO DynTag = 0x6ffffeff + DT_ADDRRNGHI DynTag = 0x6ffffeff + + DT_VERSYM DynTag = 0x6ffffff0 + DT_RELACOUNT DynTag = 0x6ffffff9 + DT_RELCOUNT DynTag = 0x6ffffffa + DT_FLAGS_1 DynTag = 0x6ffffffb + DT_VERDEF DynTag = 0x6ffffffc + DT_VERDEFNUM DynTag = 0x6ffffffd + DT_VERNEED DynTag = 0x6ffffffe + DT_VERNEEDNUM DynTag = 0x6fffffff + + DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */ + + DT_MIPS_RLD_VERSION DynTag = 0x70000001 + DT_MIPS_TIME_STAMP DynTag = 0x70000002 + DT_MIPS_ICHECKSUM DynTag = 0x70000003 + DT_MIPS_IVERSION DynTag = 0x70000004 + DT_MIPS_FLAGS DynTag = 0x70000005 + DT_MIPS_BASE_ADDRESS DynTag = 0x70000006 + DT_MIPS_MSYM DynTag = 0x70000007 + DT_MIPS_CONFLICT DynTag = 0x70000008 + DT_MIPS_LIBLIST DynTag = 0x70000009 + DT_MIPS_LOCAL_GOTNO DynTag = 0x7000000a + DT_MIPS_CONFLICTNO DynTag = 0x7000000b + DT_MIPS_LIBLISTNO DynTag = 0x70000010 + DT_MIPS_SYMTABNO DynTag = 0x70000011 + DT_MIPS_UNREFEXTNO DynTag = 0x70000012 + DT_MIPS_GOTSYM DynTag = 0x70000013 + DT_MIPS_HIPAGENO DynTag = 0x70000014 + DT_MIPS_RLD_MAP DynTag = 0x70000016 + DT_MIPS_DELTA_CLASS DynTag = 0x70000017 + DT_MIPS_DELTA_CLASS_NO DynTag = 0x70000018 + DT_MIPS_DELTA_INSTANCE DynTag = 0x70000019 + DT_MIPS_DELTA_INSTANCE_NO DynTag = 0x7000001a + DT_MIPS_DELTA_RELOC DynTag = 0x7000001b + DT_MIPS_DELTA_RELOC_NO DynTag = 0x7000001c + DT_MIPS_DELTA_SYM DynTag = 0x7000001d + DT_MIPS_DELTA_SYM_NO DynTag = 0x7000001e + DT_MIPS_DELTA_CLASSSYM DynTag = 0x70000020 + DT_MIPS_DELTA_CLASSSYM_NO DynTag = 0x70000021 + DT_MIPS_CXX_FLAGS DynTag = 0x70000022 + DT_MIPS_PIXIE_INIT DynTag = 0x70000023 + DT_MIPS_SYMBOL_LIB DynTag = 0x70000024 + DT_MIPS_LOCALPAGE_GOTIDX DynTag = 0x70000025 + DT_MIPS_LOCAL_GOTIDX DynTag = 0x70000026 + DT_MIPS_HIDDEN_GOTIDX DynTag = 0x70000027 + DT_MIPS_PROTECTED_GOTIDX DynTag = 0x70000028 + DT_MIPS_OPTIONS DynTag = 0x70000029 + DT_MIPS_INTERFACE DynTag = 0x7000002a + DT_MIPS_DYNSTR_ALIGN DynTag = 0x7000002b + DT_MIPS_INTERFACE_SIZE DynTag = 0x7000002c + DT_MIPS_RLD_TEXT_RESOLVE_ADDR DynTag = 0x7000002d + DT_MIPS_PERF_SUFFIX DynTag = 0x7000002e + DT_MIPS_COMPACT_SIZE DynTag = 0x7000002f + DT_MIPS_GP_VALUE DynTag = 0x70000030 + DT_MIPS_AUX_DYNAMIC DynTag = 0x70000031 + DT_MIPS_PLTGOT DynTag = 0x70000032 + DT_MIPS_RWPLT DynTag = 0x70000034 + DT_MIPS_RLD_MAP_REL DynTag = 0x70000035 + + DT_PPC_GOT DynTag = 0x70000000 + DT_PPC_OPT DynTag = 0x70000001 + + DT_PPC64_GLINK DynTag = 0x70000000 + DT_PPC64_OPD DynTag = 0x70000001 + DT_PPC64_OPDSZ DynTag = 0x70000002 + DT_PPC64_OPT DynTag = 0x70000003 + + DT_SPARC_REGISTER DynTag = 0x70000001 + + DT_AUXILIARY DynTag = 0x7ffffffd + DT_USED DynTag = 0x7ffffffe + DT_FILTER DynTag = 0x7fffffff + + DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */ +) + +var dtStrings = []intName{ + {0, "DT_NULL"}, + {1, "DT_NEEDED"}, + {2, "DT_PLTRELSZ"}, + {3, "DT_PLTGOT"}, + {4, "DT_HASH"}, + {5, "DT_STRTAB"}, + {6, "DT_SYMTAB"}, + {7, "DT_RELA"}, + {8, "DT_RELASZ"}, + {9, "DT_RELAENT"}, + {10, "DT_STRSZ"}, + {11, "DT_SYMENT"}, + {12, "DT_INIT"}, + {13, "DT_FINI"}, + {14, "DT_SONAME"}, + {15, "DT_RPATH"}, + {16, "DT_SYMBOLIC"}, + {17, "DT_REL"}, + {18, "DT_RELSZ"}, + {19, "DT_RELENT"}, + {20, "DT_PLTREL"}, + {21, "DT_DEBUG"}, + {22, "DT_TEXTREL"}, + {23, "DT_JMPREL"}, + {24, "DT_BIND_NOW"}, + {25, "DT_INIT_ARRAY"}, + {26, "DT_FINI_ARRAY"}, + {27, "DT_INIT_ARRAYSZ"}, + {28, "DT_FINI_ARRAYSZ"}, + {29, "DT_RUNPATH"}, + {30, "DT_FLAGS"}, + {32, "DT_ENCODING"}, + {32, "DT_PREINIT_ARRAY"}, + {33, "DT_PREINIT_ARRAYSZ"}, + {34, "DT_SYMTAB_SHNDX"}, + {0x6000000d, "DT_LOOS"}, + {0x6ffff000, "DT_HIOS"}, + {0x6ffffd00, "DT_VALRNGLO"}, + {0x6ffffdf5, "DT_GNU_PRELINKED"}, + {0x6ffffdf6, "DT_GNU_CONFLICTSZ"}, + {0x6ffffdf7, "DT_GNU_LIBLISTSZ"}, + {0x6ffffdf8, "DT_CHECKSUM"}, + {0x6ffffdf9, "DT_PLTPADSZ"}, + {0x6ffffdfa, "DT_MOVEENT"}, + {0x6ffffdfb, "DT_MOVESZ"}, + {0x6ffffdfc, "DT_FEATURE"}, + {0x6ffffdfd, "DT_POSFLAG_1"}, + {0x6ffffdfe, "DT_SYMINSZ"}, + {0x6ffffdff, "DT_SYMINENT"}, + {0x6ffffdff, "DT_VALRNGHI"}, + {0x6ffffe00, "DT_ADDRRNGLO"}, + {0x6ffffef5, "DT_GNU_HASH"}, + {0x6ffffef6, "DT_TLSDESC_PLT"}, + {0x6ffffef7, "DT_TLSDESC_GOT"}, + {0x6ffffef8, "DT_GNU_CONFLICT"}, + {0x6ffffef9, "DT_GNU_LIBLIST"}, + {0x6ffffefa, "DT_CONFIG"}, + {0x6ffffefb, "DT_DEPAUDIT"}, + {0x6ffffefc, "DT_AUDIT"}, + {0x6ffffefd, "DT_PLTPAD"}, + {0x6ffffefe, "DT_MOVETAB"}, + {0x6ffffeff, "DT_SYMINFO"}, + {0x6ffffeff, "DT_ADDRRNGHI"}, + {0x6ffffff0, "DT_VERSYM"}, + {0x6ffffff9, "DT_RELACOUNT"}, + {0x6ffffffa, "DT_RELCOUNT"}, + {0x6ffffffb, "DT_FLAGS_1"}, + {0x6ffffffc, "DT_VERDEF"}, + {0x6ffffffd, "DT_VERDEFNUM"}, + {0x6ffffffe, "DT_VERNEED"}, + {0x6fffffff, "DT_VERNEEDNUM"}, + {0x70000000, "DT_LOPROC"}, + // We don't list the processor-dependent DynTags, + // as the values overlap. + {0x7ffffffd, "DT_AUXILIARY"}, + {0x7ffffffe, "DT_USED"}, + {0x7fffffff, "DT_FILTER"}, +} + +func (i DynTag) String() string { return stringName(uint32(i), dtStrings, false) } +func (i DynTag) GoString() string { return stringName(uint32(i), dtStrings, true) } + +// DT_FLAGS values. +type DynFlag int + +const ( + DF_ORIGIN DynFlag = 0x0001 /* Indicates that the object being loaded may + make reference to the + $ORIGIN substitution string */ + DF_SYMBOLIC DynFlag = 0x0002 /* Indicates "symbolic" linking. */ + DF_TEXTREL DynFlag = 0x0004 /* Indicates there may be relocations in non-writable segments. */ + DF_BIND_NOW DynFlag = 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ + DF_STATIC_TLS DynFlag = 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ +) + +var dflagStrings = []intName{ + {0x0001, "DF_ORIGIN"}, + {0x0002, "DF_SYMBOLIC"}, + {0x0004, "DF_TEXTREL"}, + {0x0008, "DF_BIND_NOW"}, + {0x0010, "DF_STATIC_TLS"}, +} + +func (i DynFlag) String() string { return flagName(uint32(i), dflagStrings, false) } +func (i DynFlag) GoString() string { return flagName(uint32(i), dflagStrings, true) } + +// NType values; used in core files. +type NType int + +const ( + NT_PRSTATUS NType = 1 /* Process status. */ + NT_FPREGSET NType = 2 /* Floating point registers. */ + NT_PRPSINFO NType = 3 /* Process state info. */ +) + +var ntypeStrings = []intName{ + {1, "NT_PRSTATUS"}, + {2, "NT_FPREGSET"}, + {3, "NT_PRPSINFO"}, +} + +func (i NType) String() string { return stringName(uint32(i), ntypeStrings, false) } +func (i NType) GoString() string { return stringName(uint32(i), ntypeStrings, true) } + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +type SymBind int + +const ( + STB_LOCAL SymBind = 0 /* Local symbol */ + STB_GLOBAL SymBind = 1 /* Global symbol */ + STB_WEAK SymBind = 2 /* like global - lower precedence */ + STB_LOOS SymBind = 10 /* Reserved range for operating system */ + STB_HIOS SymBind = 12 /* specific semantics. */ + STB_LOPROC SymBind = 13 /* reserved range for processor */ + STB_HIPROC SymBind = 15 /* specific semantics. */ +) + +var stbStrings = []intName{ + {0, "STB_LOCAL"}, + {1, "STB_GLOBAL"}, + {2, "STB_WEAK"}, + {10, "STB_LOOS"}, + {12, "STB_HIOS"}, + {13, "STB_LOPROC"}, + {15, "STB_HIPROC"}, +} + +func (i SymBind) String() string { return stringName(uint32(i), stbStrings, false) } +func (i SymBind) GoString() string { return stringName(uint32(i), stbStrings, true) } + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +type SymType int + +const ( + STT_NOTYPE SymType = 0 /* Unspecified type. */ + STT_OBJECT SymType = 1 /* Data object. */ + STT_FUNC SymType = 2 /* Function. */ + STT_SECTION SymType = 3 /* Section. */ + STT_FILE SymType = 4 /* Source file. */ + STT_COMMON SymType = 5 /* Uninitialized common block. */ + STT_TLS SymType = 6 /* TLS object. */ + STT_LOOS SymType = 10 /* Reserved range for operating system */ + STT_HIOS SymType = 12 /* specific semantics. */ + STT_LOPROC SymType = 13 /* reserved range for processor */ + STT_HIPROC SymType = 15 /* specific semantics. */ +) + +var sttStrings = []intName{ + {0, "STT_NOTYPE"}, + {1, "STT_OBJECT"}, + {2, "STT_FUNC"}, + {3, "STT_SECTION"}, + {4, "STT_FILE"}, + {5, "STT_COMMON"}, + {6, "STT_TLS"}, + {10, "STT_LOOS"}, + {12, "STT_HIOS"}, + {13, "STT_LOPROC"}, + {15, "STT_HIPROC"}, +} + +func (i SymType) String() string { return stringName(uint32(i), sttStrings, false) } +func (i SymType) GoString() string { return stringName(uint32(i), sttStrings, true) } + +/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ +type SymVis int + +const ( + STV_DEFAULT SymVis = 0x0 /* Default visibility (see binding). */ + STV_INTERNAL SymVis = 0x1 /* Special meaning in relocatable objects. */ + STV_HIDDEN SymVis = 0x2 /* Not visible. */ + STV_PROTECTED SymVis = 0x3 /* Visible but not preemptible. */ +) + +var stvStrings = []intName{ + {0x0, "STV_DEFAULT"}, + {0x1, "STV_INTERNAL"}, + {0x2, "STV_HIDDEN"}, + {0x3, "STV_PROTECTED"}, +} + +func (i SymVis) String() string { return stringName(uint32(i), stvStrings, false) } +func (i SymVis) GoString() string { return stringName(uint32(i), stvStrings, true) } + +/* + * Relocation types. + */ + +// Relocation types for x86-64. +type R_X86_64 int + +const ( + R_X86_64_NONE R_X86_64 = 0 /* No relocation. */ + R_X86_64_64 R_X86_64 = 1 /* Add 64 bit symbol value. */ + R_X86_64_PC32 R_X86_64 = 2 /* PC-relative 32 bit signed sym value. */ + R_X86_64_GOT32 R_X86_64 = 3 /* PC-relative 32 bit GOT offset. */ + R_X86_64_PLT32 R_X86_64 = 4 /* PC-relative 32 bit PLT offset. */ + R_X86_64_COPY R_X86_64 = 5 /* Copy data from shared object. */ + R_X86_64_GLOB_DAT R_X86_64 = 6 /* Set GOT entry to data address. */ + R_X86_64_JMP_SLOT R_X86_64 = 7 /* Set GOT entry to code address. */ + R_X86_64_RELATIVE R_X86_64 = 8 /* Add load address of shared object. */ + R_X86_64_GOTPCREL R_X86_64 = 9 /* Add 32 bit signed pcrel offset to GOT. */ + R_X86_64_32 R_X86_64 = 10 /* Add 32 bit zero extended symbol value */ + R_X86_64_32S R_X86_64 = 11 /* Add 32 bit sign extended symbol value */ + R_X86_64_16 R_X86_64 = 12 /* Add 16 bit zero extended symbol value */ + R_X86_64_PC16 R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */ + R_X86_64_8 R_X86_64 = 14 /* Add 8 bit zero extended symbol value */ + R_X86_64_PC8 R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */ + R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */ + R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */ + R_X86_64_TPOFF64 R_X86_64 = 18 /* Offset in static TLS block */ + R_X86_64_TLSGD R_X86_64 = 19 /* PC relative offset to GD GOT entry */ + R_X86_64_TLSLD R_X86_64 = 20 /* PC relative offset to LD GOT entry */ + R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */ + R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */ + R_X86_64_TPOFF32 R_X86_64 = 23 /* Offset in static TLS block */ + R_X86_64_PC64 R_X86_64 = 24 /* PC relative 64-bit sign extended symbol value. */ + R_X86_64_GOTOFF64 R_X86_64 = 25 + R_X86_64_GOTPC32 R_X86_64 = 26 + R_X86_64_GOT64 R_X86_64 = 27 + R_X86_64_GOTPCREL64 R_X86_64 = 28 + R_X86_64_GOTPC64 R_X86_64 = 29 + R_X86_64_GOTPLT64 R_X86_64 = 30 + R_X86_64_PLTOFF64 R_X86_64 = 31 + R_X86_64_SIZE32 R_X86_64 = 32 + R_X86_64_SIZE64 R_X86_64 = 33 + R_X86_64_GOTPC32_TLSDESC R_X86_64 = 34 + R_X86_64_TLSDESC_CALL R_X86_64 = 35 + R_X86_64_TLSDESC R_X86_64 = 36 + R_X86_64_IRELATIVE R_X86_64 = 37 + R_X86_64_RELATIVE64 R_X86_64 = 38 + R_X86_64_PC32_BND R_X86_64 = 39 + R_X86_64_PLT32_BND R_X86_64 = 40 + R_X86_64_GOTPCRELX R_X86_64 = 41 + R_X86_64_REX_GOTPCRELX R_X86_64 = 42 +) + +var rx86_64Strings = []intName{ + {0, "R_X86_64_NONE"}, + {1, "R_X86_64_64"}, + {2, "R_X86_64_PC32"}, + {3, "R_X86_64_GOT32"}, + {4, "R_X86_64_PLT32"}, + {5, "R_X86_64_COPY"}, + {6, "R_X86_64_GLOB_DAT"}, + {7, "R_X86_64_JMP_SLOT"}, + {8, "R_X86_64_RELATIVE"}, + {9, "R_X86_64_GOTPCREL"}, + {10, "R_X86_64_32"}, + {11, "R_X86_64_32S"}, + {12, "R_X86_64_16"}, + {13, "R_X86_64_PC16"}, + {14, "R_X86_64_8"}, + {15, "R_X86_64_PC8"}, + {16, "R_X86_64_DTPMOD64"}, + {17, "R_X86_64_DTPOFF64"}, + {18, "R_X86_64_TPOFF64"}, + {19, "R_X86_64_TLSGD"}, + {20, "R_X86_64_TLSLD"}, + {21, "R_X86_64_DTPOFF32"}, + {22, "R_X86_64_GOTTPOFF"}, + {23, "R_X86_64_TPOFF32"}, + {24, "R_X86_64_PC64"}, + {25, "R_X86_64_GOTOFF64"}, + {26, "R_X86_64_GOTPC32"}, + {27, "R_X86_64_GOT64"}, + {28, "R_X86_64_GOTPCREL64"}, + {29, "R_X86_64_GOTPC64"}, + {30, "R_X86_64_GOTPLT64"}, + {31, "R_X86_64_PLTOFF64"}, + {32, "R_X86_64_SIZE32"}, + {33, "R_X86_64_SIZE64"}, + {34, "R_X86_64_GOTPC32_TLSDESC"}, + {35, "R_X86_64_TLSDESC_CALL"}, + {36, "R_X86_64_TLSDESC"}, + {37, "R_X86_64_IRELATIVE"}, + {38, "R_X86_64_RELATIVE64"}, + {39, "R_X86_64_PC32_BND"}, + {40, "R_X86_64_PLT32_BND"}, + {41, "R_X86_64_GOTPCRELX"}, + {42, "R_X86_64_REX_GOTPCRELX"}, +} + +func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) } +func (i R_X86_64) GoString() string { return stringName(uint32(i), rx86_64Strings, true) } + +// Relocation types for AArch64 (aka arm64) +type R_AARCH64 int + +const ( + R_AARCH64_NONE R_AARCH64 = 0 + R_AARCH64_P32_ABS32 R_AARCH64 = 1 + R_AARCH64_P32_ABS16 R_AARCH64 = 2 + R_AARCH64_P32_PREL32 R_AARCH64 = 3 + R_AARCH64_P32_PREL16 R_AARCH64 = 4 + R_AARCH64_P32_MOVW_UABS_G0 R_AARCH64 = 5 + R_AARCH64_P32_MOVW_UABS_G0_NC R_AARCH64 = 6 + R_AARCH64_P32_MOVW_UABS_G1 R_AARCH64 = 7 + R_AARCH64_P32_MOVW_SABS_G0 R_AARCH64 = 8 + R_AARCH64_P32_LD_PREL_LO19 R_AARCH64 = 9 + R_AARCH64_P32_ADR_PREL_LO21 R_AARCH64 = 10 + R_AARCH64_P32_ADR_PREL_PG_HI21 R_AARCH64 = 11 + R_AARCH64_P32_ADD_ABS_LO12_NC R_AARCH64 = 12 + R_AARCH64_P32_LDST8_ABS_LO12_NC R_AARCH64 = 13 + R_AARCH64_P32_LDST16_ABS_LO12_NC R_AARCH64 = 14 + R_AARCH64_P32_LDST32_ABS_LO12_NC R_AARCH64 = 15 + R_AARCH64_P32_LDST64_ABS_LO12_NC R_AARCH64 = 16 + R_AARCH64_P32_LDST128_ABS_LO12_NC R_AARCH64 = 17 + R_AARCH64_P32_TSTBR14 R_AARCH64 = 18 + R_AARCH64_P32_CONDBR19 R_AARCH64 = 19 + R_AARCH64_P32_JUMP26 R_AARCH64 = 20 + R_AARCH64_P32_CALL26 R_AARCH64 = 21 + R_AARCH64_P32_GOT_LD_PREL19 R_AARCH64 = 25 + R_AARCH64_P32_ADR_GOT_PAGE R_AARCH64 = 26 + R_AARCH64_P32_LD32_GOT_LO12_NC R_AARCH64 = 27 + R_AARCH64_P32_TLSGD_ADR_PAGE21 R_AARCH64 = 81 + R_AARCH64_P32_TLSGD_ADD_LO12_NC R_AARCH64 = 82 + R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21 R_AARCH64 = 103 + R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC R_AARCH64 = 104 + R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19 R_AARCH64 = 105 + R_AARCH64_P32_TLSLE_MOVW_TPREL_G1 R_AARCH64 = 106 + R_AARCH64_P32_TLSLE_MOVW_TPREL_G0 R_AARCH64 = 107 + R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC R_AARCH64 = 108 + R_AARCH64_P32_TLSLE_ADD_TPREL_HI12 R_AARCH64 = 109 + R_AARCH64_P32_TLSLE_ADD_TPREL_LO12 R_AARCH64 = 110 + R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC R_AARCH64 = 111 + R_AARCH64_P32_TLSDESC_LD_PREL19 R_AARCH64 = 122 + R_AARCH64_P32_TLSDESC_ADR_PREL21 R_AARCH64 = 123 + R_AARCH64_P32_TLSDESC_ADR_PAGE21 R_AARCH64 = 124 + R_AARCH64_P32_TLSDESC_LD32_LO12_NC R_AARCH64 = 125 + R_AARCH64_P32_TLSDESC_ADD_LO12_NC R_AARCH64 = 126 + R_AARCH64_P32_TLSDESC_CALL R_AARCH64 = 127 + R_AARCH64_P32_COPY R_AARCH64 = 180 + R_AARCH64_P32_GLOB_DAT R_AARCH64 = 181 + R_AARCH64_P32_JUMP_SLOT R_AARCH64 = 182 + R_AARCH64_P32_RELATIVE R_AARCH64 = 183 + R_AARCH64_P32_TLS_DTPMOD R_AARCH64 = 184 + R_AARCH64_P32_TLS_DTPREL R_AARCH64 = 185 + R_AARCH64_P32_TLS_TPREL R_AARCH64 = 186 + R_AARCH64_P32_TLSDESC R_AARCH64 = 187 + R_AARCH64_P32_IRELATIVE R_AARCH64 = 188 + R_AARCH64_NULL R_AARCH64 = 256 + R_AARCH64_ABS64 R_AARCH64 = 257 + R_AARCH64_ABS32 R_AARCH64 = 258 + R_AARCH64_ABS16 R_AARCH64 = 259 + R_AARCH64_PREL64 R_AARCH64 = 260 + R_AARCH64_PREL32 R_AARCH64 = 261 + R_AARCH64_PREL16 R_AARCH64 = 262 + R_AARCH64_MOVW_UABS_G0 R_AARCH64 = 263 + R_AARCH64_MOVW_UABS_G0_NC R_AARCH64 = 264 + R_AARCH64_MOVW_UABS_G1 R_AARCH64 = 265 + R_AARCH64_MOVW_UABS_G1_NC R_AARCH64 = 266 + R_AARCH64_MOVW_UABS_G2 R_AARCH64 = 267 + R_AARCH64_MOVW_UABS_G2_NC R_AARCH64 = 268 + R_AARCH64_MOVW_UABS_G3 R_AARCH64 = 269 + R_AARCH64_MOVW_SABS_G0 R_AARCH64 = 270 + R_AARCH64_MOVW_SABS_G1 R_AARCH64 = 271 + R_AARCH64_MOVW_SABS_G2 R_AARCH64 = 272 + R_AARCH64_LD_PREL_LO19 R_AARCH64 = 273 + R_AARCH64_ADR_PREL_LO21 R_AARCH64 = 274 + R_AARCH64_ADR_PREL_PG_HI21 R_AARCH64 = 275 + R_AARCH64_ADR_PREL_PG_HI21_NC R_AARCH64 = 276 + R_AARCH64_ADD_ABS_LO12_NC R_AARCH64 = 277 + R_AARCH64_LDST8_ABS_LO12_NC R_AARCH64 = 278 + R_AARCH64_TSTBR14 R_AARCH64 = 279 + R_AARCH64_CONDBR19 R_AARCH64 = 280 + R_AARCH64_JUMP26 R_AARCH64 = 282 + R_AARCH64_CALL26 R_AARCH64 = 283 + R_AARCH64_LDST16_ABS_LO12_NC R_AARCH64 = 284 + R_AARCH64_LDST32_ABS_LO12_NC R_AARCH64 = 285 + R_AARCH64_LDST64_ABS_LO12_NC R_AARCH64 = 286 + R_AARCH64_LDST128_ABS_LO12_NC R_AARCH64 = 299 + R_AARCH64_GOT_LD_PREL19 R_AARCH64 = 309 + R_AARCH64_LD64_GOTOFF_LO15 R_AARCH64 = 310 + R_AARCH64_ADR_GOT_PAGE R_AARCH64 = 311 + R_AARCH64_LD64_GOT_LO12_NC R_AARCH64 = 312 + R_AARCH64_LD64_GOTPAGE_LO15 R_AARCH64 = 313 + R_AARCH64_TLSGD_ADR_PREL21 R_AARCH64 = 512 + R_AARCH64_TLSGD_ADR_PAGE21 R_AARCH64 = 513 + R_AARCH64_TLSGD_ADD_LO12_NC R_AARCH64 = 514 + R_AARCH64_TLSGD_MOVW_G1 R_AARCH64 = 515 + R_AARCH64_TLSGD_MOVW_G0_NC R_AARCH64 = 516 + R_AARCH64_TLSLD_ADR_PREL21 R_AARCH64 = 517 + R_AARCH64_TLSLD_ADR_PAGE21 R_AARCH64 = 518 + R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 R_AARCH64 = 539 + R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC R_AARCH64 = 540 + R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 R_AARCH64 = 541 + R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC R_AARCH64 = 542 + R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 R_AARCH64 = 543 + R_AARCH64_TLSLE_MOVW_TPREL_G2 R_AARCH64 = 544 + R_AARCH64_TLSLE_MOVW_TPREL_G1 R_AARCH64 = 545 + R_AARCH64_TLSLE_MOVW_TPREL_G1_NC R_AARCH64 = 546 + R_AARCH64_TLSLE_MOVW_TPREL_G0 R_AARCH64 = 547 + R_AARCH64_TLSLE_MOVW_TPREL_G0_NC R_AARCH64 = 548 + R_AARCH64_TLSLE_ADD_TPREL_HI12 R_AARCH64 = 549 + R_AARCH64_TLSLE_ADD_TPREL_LO12 R_AARCH64 = 550 + R_AARCH64_TLSLE_ADD_TPREL_LO12_NC R_AARCH64 = 551 + R_AARCH64_TLSDESC_LD_PREL19 R_AARCH64 = 560 + R_AARCH64_TLSDESC_ADR_PREL21 R_AARCH64 = 561 + R_AARCH64_TLSDESC_ADR_PAGE21 R_AARCH64 = 562 + R_AARCH64_TLSDESC_LD64_LO12_NC R_AARCH64 = 563 + R_AARCH64_TLSDESC_ADD_LO12_NC R_AARCH64 = 564 + R_AARCH64_TLSDESC_OFF_G1 R_AARCH64 = 565 + R_AARCH64_TLSDESC_OFF_G0_NC R_AARCH64 = 566 + R_AARCH64_TLSDESC_LDR R_AARCH64 = 567 + R_AARCH64_TLSDESC_ADD R_AARCH64 = 568 + R_AARCH64_TLSDESC_CALL R_AARCH64 = 569 + R_AARCH64_TLSLE_LDST128_TPREL_LO12 R_AARCH64 = 570 + R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC R_AARCH64 = 571 + R_AARCH64_TLSLD_LDST128_DTPREL_LO12 R_AARCH64 = 572 + R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC R_AARCH64 = 573 + R_AARCH64_COPY R_AARCH64 = 1024 + R_AARCH64_GLOB_DAT R_AARCH64 = 1025 + R_AARCH64_JUMP_SLOT R_AARCH64 = 1026 + R_AARCH64_RELATIVE R_AARCH64 = 1027 + R_AARCH64_TLS_DTPMOD64 R_AARCH64 = 1028 + R_AARCH64_TLS_DTPREL64 R_AARCH64 = 1029 + R_AARCH64_TLS_TPREL64 R_AARCH64 = 1030 + R_AARCH64_TLSDESC R_AARCH64 = 1031 + R_AARCH64_IRELATIVE R_AARCH64 = 1032 +) + +var raarch64Strings = []intName{ + {0, "R_AARCH64_NONE"}, + {1, "R_AARCH64_P32_ABS32"}, + {2, "R_AARCH64_P32_ABS16"}, + {3, "R_AARCH64_P32_PREL32"}, + {4, "R_AARCH64_P32_PREL16"}, + {5, "R_AARCH64_P32_MOVW_UABS_G0"}, + {6, "R_AARCH64_P32_MOVW_UABS_G0_NC"}, + {7, "R_AARCH64_P32_MOVW_UABS_G1"}, + {8, "R_AARCH64_P32_MOVW_SABS_G0"}, + {9, "R_AARCH64_P32_LD_PREL_LO19"}, + {10, "R_AARCH64_P32_ADR_PREL_LO21"}, + {11, "R_AARCH64_P32_ADR_PREL_PG_HI21"}, + {12, "R_AARCH64_P32_ADD_ABS_LO12_NC"}, + {13, "R_AARCH64_P32_LDST8_ABS_LO12_NC"}, + {14, "R_AARCH64_P32_LDST16_ABS_LO12_NC"}, + {15, "R_AARCH64_P32_LDST32_ABS_LO12_NC"}, + {16, "R_AARCH64_P32_LDST64_ABS_LO12_NC"}, + {17, "R_AARCH64_P32_LDST128_ABS_LO12_NC"}, + {18, "R_AARCH64_P32_TSTBR14"}, + {19, "R_AARCH64_P32_CONDBR19"}, + {20, "R_AARCH64_P32_JUMP26"}, + {21, "R_AARCH64_P32_CALL26"}, + {25, "R_AARCH64_P32_GOT_LD_PREL19"}, + {26, "R_AARCH64_P32_ADR_GOT_PAGE"}, + {27, "R_AARCH64_P32_LD32_GOT_LO12_NC"}, + {81, "R_AARCH64_P32_TLSGD_ADR_PAGE21"}, + {82, "R_AARCH64_P32_TLSGD_ADD_LO12_NC"}, + {103, "R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21"}, + {104, "R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC"}, + {105, "R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19"}, + {106, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G1"}, + {107, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0"}, + {108, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC"}, + {109, "R_AARCH64_P32_TLSLE_ADD_TPREL_HI12"}, + {110, "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12"}, + {111, "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC"}, + {122, "R_AARCH64_P32_TLSDESC_LD_PREL19"}, + {123, "R_AARCH64_P32_TLSDESC_ADR_PREL21"}, + {124, "R_AARCH64_P32_TLSDESC_ADR_PAGE21"}, + {125, "R_AARCH64_P32_TLSDESC_LD32_LO12_NC"}, + {126, "R_AARCH64_P32_TLSDESC_ADD_LO12_NC"}, + {127, "R_AARCH64_P32_TLSDESC_CALL"}, + {180, "R_AARCH64_P32_COPY"}, + {181, "R_AARCH64_P32_GLOB_DAT"}, + {182, "R_AARCH64_P32_JUMP_SLOT"}, + {183, "R_AARCH64_P32_RELATIVE"}, + {184, "R_AARCH64_P32_TLS_DTPMOD"}, + {185, "R_AARCH64_P32_TLS_DTPREL"}, + {186, "R_AARCH64_P32_TLS_TPREL"}, + {187, "R_AARCH64_P32_TLSDESC"}, + {188, "R_AARCH64_P32_IRELATIVE"}, + {256, "R_AARCH64_NULL"}, + {257, "R_AARCH64_ABS64"}, + {258, "R_AARCH64_ABS32"}, + {259, "R_AARCH64_ABS16"}, + {260, "R_AARCH64_PREL64"}, + {261, "R_AARCH64_PREL32"}, + {262, "R_AARCH64_PREL16"}, + {263, "R_AARCH64_MOVW_UABS_G0"}, + {264, "R_AARCH64_MOVW_UABS_G0_NC"}, + {265, "R_AARCH64_MOVW_UABS_G1"}, + {266, "R_AARCH64_MOVW_UABS_G1_NC"}, + {267, "R_AARCH64_MOVW_UABS_G2"}, + {268, "R_AARCH64_MOVW_UABS_G2_NC"}, + {269, "R_AARCH64_MOVW_UABS_G3"}, + {270, "R_AARCH64_MOVW_SABS_G0"}, + {271, "R_AARCH64_MOVW_SABS_G1"}, + {272, "R_AARCH64_MOVW_SABS_G2"}, + {273, "R_AARCH64_LD_PREL_LO19"}, + {274, "R_AARCH64_ADR_PREL_LO21"}, + {275, "R_AARCH64_ADR_PREL_PG_HI21"}, + {276, "R_AARCH64_ADR_PREL_PG_HI21_NC"}, + {277, "R_AARCH64_ADD_ABS_LO12_NC"}, + {278, "R_AARCH64_LDST8_ABS_LO12_NC"}, + {279, "R_AARCH64_TSTBR14"}, + {280, "R_AARCH64_CONDBR19"}, + {282, "R_AARCH64_JUMP26"}, + {283, "R_AARCH64_CALL26"}, + {284, "R_AARCH64_LDST16_ABS_LO12_NC"}, + {285, "R_AARCH64_LDST32_ABS_LO12_NC"}, + {286, "R_AARCH64_LDST64_ABS_LO12_NC"}, + {299, "R_AARCH64_LDST128_ABS_LO12_NC"}, + {309, "R_AARCH64_GOT_LD_PREL19"}, + {310, "R_AARCH64_LD64_GOTOFF_LO15"}, + {311, "R_AARCH64_ADR_GOT_PAGE"}, + {312, "R_AARCH64_LD64_GOT_LO12_NC"}, + {313, "R_AARCH64_LD64_GOTPAGE_LO15"}, + {512, "R_AARCH64_TLSGD_ADR_PREL21"}, + {513, "R_AARCH64_TLSGD_ADR_PAGE21"}, + {514, "R_AARCH64_TLSGD_ADD_LO12_NC"}, + {515, "R_AARCH64_TLSGD_MOVW_G1"}, + {516, "R_AARCH64_TLSGD_MOVW_G0_NC"}, + {517, "R_AARCH64_TLSLD_ADR_PREL21"}, + {518, "R_AARCH64_TLSLD_ADR_PAGE21"}, + {539, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1"}, + {540, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC"}, + {541, "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21"}, + {542, "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC"}, + {543, "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19"}, + {544, "R_AARCH64_TLSLE_MOVW_TPREL_G2"}, + {545, "R_AARCH64_TLSLE_MOVW_TPREL_G1"}, + {546, "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC"}, + {547, "R_AARCH64_TLSLE_MOVW_TPREL_G0"}, + {548, "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC"}, + {549, "R_AARCH64_TLSLE_ADD_TPREL_HI12"}, + {550, "R_AARCH64_TLSLE_ADD_TPREL_LO12"}, + {551, "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC"}, + {560, "R_AARCH64_TLSDESC_LD_PREL19"}, + {561, "R_AARCH64_TLSDESC_ADR_PREL21"}, + {562, "R_AARCH64_TLSDESC_ADR_PAGE21"}, + {563, "R_AARCH64_TLSDESC_LD64_LO12_NC"}, + {564, "R_AARCH64_TLSDESC_ADD_LO12_NC"}, + {565, "R_AARCH64_TLSDESC_OFF_G1"}, + {566, "R_AARCH64_TLSDESC_OFF_G0_NC"}, + {567, "R_AARCH64_TLSDESC_LDR"}, + {568, "R_AARCH64_TLSDESC_ADD"}, + {569, "R_AARCH64_TLSDESC_CALL"}, + {570, "R_AARCH64_TLSLE_LDST128_TPREL_LO12"}, + {571, "R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC"}, + {572, "R_AARCH64_TLSLD_LDST128_DTPREL_LO12"}, + {573, "R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC"}, + {1024, "R_AARCH64_COPY"}, + {1025, "R_AARCH64_GLOB_DAT"}, + {1026, "R_AARCH64_JUMP_SLOT"}, + {1027, "R_AARCH64_RELATIVE"}, + {1028, "R_AARCH64_TLS_DTPMOD64"}, + {1029, "R_AARCH64_TLS_DTPREL64"}, + {1030, "R_AARCH64_TLS_TPREL64"}, + {1031, "R_AARCH64_TLSDESC"}, + {1032, "R_AARCH64_IRELATIVE"}, +} + +func (i R_AARCH64) String() string { return stringName(uint32(i), raarch64Strings, false) } +func (i R_AARCH64) GoString() string { return stringName(uint32(i), raarch64Strings, true) } + +// Relocation types for Alpha. +type R_ALPHA int + +const ( + R_ALPHA_NONE R_ALPHA = 0 /* No reloc */ + R_ALPHA_REFLONG R_ALPHA = 1 /* Direct 32 bit */ + R_ALPHA_REFQUAD R_ALPHA = 2 /* Direct 64 bit */ + R_ALPHA_GPREL32 R_ALPHA = 3 /* GP relative 32 bit */ + R_ALPHA_LITERAL R_ALPHA = 4 /* GP relative 16 bit w/optimization */ + R_ALPHA_LITUSE R_ALPHA = 5 /* Optimization hint for LITERAL */ + R_ALPHA_GPDISP R_ALPHA = 6 /* Add displacement to GP */ + R_ALPHA_BRADDR R_ALPHA = 7 /* PC+4 relative 23 bit shifted */ + R_ALPHA_HINT R_ALPHA = 8 /* PC+4 relative 16 bit shifted */ + R_ALPHA_SREL16 R_ALPHA = 9 /* PC relative 16 bit */ + R_ALPHA_SREL32 R_ALPHA = 10 /* PC relative 32 bit */ + R_ALPHA_SREL64 R_ALPHA = 11 /* PC relative 64 bit */ + R_ALPHA_OP_PUSH R_ALPHA = 12 /* OP stack push */ + R_ALPHA_OP_STORE R_ALPHA = 13 /* OP stack pop and store */ + R_ALPHA_OP_PSUB R_ALPHA = 14 /* OP stack subtract */ + R_ALPHA_OP_PRSHIFT R_ALPHA = 15 /* OP stack right shift */ + R_ALPHA_GPVALUE R_ALPHA = 16 + R_ALPHA_GPRELHIGH R_ALPHA = 17 + R_ALPHA_GPRELLOW R_ALPHA = 18 + R_ALPHA_IMMED_GP_16 R_ALPHA = 19 + R_ALPHA_IMMED_GP_HI32 R_ALPHA = 20 + R_ALPHA_IMMED_SCN_HI32 R_ALPHA = 21 + R_ALPHA_IMMED_BR_HI32 R_ALPHA = 22 + R_ALPHA_IMMED_LO32 R_ALPHA = 23 + R_ALPHA_COPY R_ALPHA = 24 /* Copy symbol at runtime */ + R_ALPHA_GLOB_DAT R_ALPHA = 25 /* Create GOT entry */ + R_ALPHA_JMP_SLOT R_ALPHA = 26 /* Create PLT entry */ + R_ALPHA_RELATIVE R_ALPHA = 27 /* Adjust by program base */ +) + +var ralphaStrings = []intName{ + {0, "R_ALPHA_NONE"}, + {1, "R_ALPHA_REFLONG"}, + {2, "R_ALPHA_REFQUAD"}, + {3, "R_ALPHA_GPREL32"}, + {4, "R_ALPHA_LITERAL"}, + {5, "R_ALPHA_LITUSE"}, + {6, "R_ALPHA_GPDISP"}, + {7, "R_ALPHA_BRADDR"}, + {8, "R_ALPHA_HINT"}, + {9, "R_ALPHA_SREL16"}, + {10, "R_ALPHA_SREL32"}, + {11, "R_ALPHA_SREL64"}, + {12, "R_ALPHA_OP_PUSH"}, + {13, "R_ALPHA_OP_STORE"}, + {14, "R_ALPHA_OP_PSUB"}, + {15, "R_ALPHA_OP_PRSHIFT"}, + {16, "R_ALPHA_GPVALUE"}, + {17, "R_ALPHA_GPRELHIGH"}, + {18, "R_ALPHA_GPRELLOW"}, + {19, "R_ALPHA_IMMED_GP_16"}, + {20, "R_ALPHA_IMMED_GP_HI32"}, + {21, "R_ALPHA_IMMED_SCN_HI32"}, + {22, "R_ALPHA_IMMED_BR_HI32"}, + {23, "R_ALPHA_IMMED_LO32"}, + {24, "R_ALPHA_COPY"}, + {25, "R_ALPHA_GLOB_DAT"}, + {26, "R_ALPHA_JMP_SLOT"}, + {27, "R_ALPHA_RELATIVE"}, +} + +func (i R_ALPHA) String() string { return stringName(uint32(i), ralphaStrings, false) } +func (i R_ALPHA) GoString() string { return stringName(uint32(i), ralphaStrings, true) } + +// Relocation types for ARM. +type R_ARM int + +const ( + R_ARM_NONE R_ARM = 0 /* No relocation. */ + R_ARM_PC24 R_ARM = 1 + R_ARM_ABS32 R_ARM = 2 + R_ARM_REL32 R_ARM = 3 + R_ARM_PC13 R_ARM = 4 + R_ARM_ABS16 R_ARM = 5 + R_ARM_ABS12 R_ARM = 6 + R_ARM_THM_ABS5 R_ARM = 7 + R_ARM_ABS8 R_ARM = 8 + R_ARM_SBREL32 R_ARM = 9 + R_ARM_THM_PC22 R_ARM = 10 + R_ARM_THM_PC8 R_ARM = 11 + R_ARM_AMP_VCALL9 R_ARM = 12 + R_ARM_SWI24 R_ARM = 13 + R_ARM_THM_SWI8 R_ARM = 14 + R_ARM_XPC25 R_ARM = 15 + R_ARM_THM_XPC22 R_ARM = 16 + R_ARM_TLS_DTPMOD32 R_ARM = 17 + R_ARM_TLS_DTPOFF32 R_ARM = 18 + R_ARM_TLS_TPOFF32 R_ARM = 19 + R_ARM_COPY R_ARM = 20 /* Copy data from shared object. */ + R_ARM_GLOB_DAT R_ARM = 21 /* Set GOT entry to data address. */ + R_ARM_JUMP_SLOT R_ARM = 22 /* Set GOT entry to code address. */ + R_ARM_RELATIVE R_ARM = 23 /* Add load address of shared object. */ + R_ARM_GOTOFF R_ARM = 24 /* Add GOT-relative symbol address. */ + R_ARM_GOTPC R_ARM = 25 /* Add PC-relative GOT table address. */ + R_ARM_GOT32 R_ARM = 26 /* Add PC-relative GOT offset. */ + R_ARM_PLT32 R_ARM = 27 /* Add PC-relative PLT offset. */ + R_ARM_CALL R_ARM = 28 + R_ARM_JUMP24 R_ARM = 29 + R_ARM_THM_JUMP24 R_ARM = 30 + R_ARM_BASE_ABS R_ARM = 31 + R_ARM_ALU_PCREL_7_0 R_ARM = 32 + R_ARM_ALU_PCREL_15_8 R_ARM = 33 + R_ARM_ALU_PCREL_23_15 R_ARM = 34 + R_ARM_LDR_SBREL_11_10_NC R_ARM = 35 + R_ARM_ALU_SBREL_19_12_NC R_ARM = 36 + R_ARM_ALU_SBREL_27_20_CK R_ARM = 37 + R_ARM_TARGET1 R_ARM = 38 + R_ARM_SBREL31 R_ARM = 39 + R_ARM_V4BX R_ARM = 40 + R_ARM_TARGET2 R_ARM = 41 + R_ARM_PREL31 R_ARM = 42 + R_ARM_MOVW_ABS_NC R_ARM = 43 + R_ARM_MOVT_ABS R_ARM = 44 + R_ARM_MOVW_PREL_NC R_ARM = 45 + R_ARM_MOVT_PREL R_ARM = 46 + R_ARM_THM_MOVW_ABS_NC R_ARM = 47 + R_ARM_THM_MOVT_ABS R_ARM = 48 + R_ARM_THM_MOVW_PREL_NC R_ARM = 49 + R_ARM_THM_MOVT_PREL R_ARM = 50 + R_ARM_THM_JUMP19 R_ARM = 51 + R_ARM_THM_JUMP6 R_ARM = 52 + R_ARM_THM_ALU_PREL_11_0 R_ARM = 53 + R_ARM_THM_PC12 R_ARM = 54 + R_ARM_ABS32_NOI R_ARM = 55 + R_ARM_REL32_NOI R_ARM = 56 + R_ARM_ALU_PC_G0_NC R_ARM = 57 + R_ARM_ALU_PC_G0 R_ARM = 58 + R_ARM_ALU_PC_G1_NC R_ARM = 59 + R_ARM_ALU_PC_G1 R_ARM = 60 + R_ARM_ALU_PC_G2 R_ARM = 61 + R_ARM_LDR_PC_G1 R_ARM = 62 + R_ARM_LDR_PC_G2 R_ARM = 63 + R_ARM_LDRS_PC_G0 R_ARM = 64 + R_ARM_LDRS_PC_G1 R_ARM = 65 + R_ARM_LDRS_PC_G2 R_ARM = 66 + R_ARM_LDC_PC_G0 R_ARM = 67 + R_ARM_LDC_PC_G1 R_ARM = 68 + R_ARM_LDC_PC_G2 R_ARM = 69 + R_ARM_ALU_SB_G0_NC R_ARM = 70 + R_ARM_ALU_SB_G0 R_ARM = 71 + R_ARM_ALU_SB_G1_NC R_ARM = 72 + R_ARM_ALU_SB_G1 R_ARM = 73 + R_ARM_ALU_SB_G2 R_ARM = 74 + R_ARM_LDR_SB_G0 R_ARM = 75 + R_ARM_LDR_SB_G1 R_ARM = 76 + R_ARM_LDR_SB_G2 R_ARM = 77 + R_ARM_LDRS_SB_G0 R_ARM = 78 + R_ARM_LDRS_SB_G1 R_ARM = 79 + R_ARM_LDRS_SB_G2 R_ARM = 80 + R_ARM_LDC_SB_G0 R_ARM = 81 + R_ARM_LDC_SB_G1 R_ARM = 82 + R_ARM_LDC_SB_G2 R_ARM = 83 + R_ARM_MOVW_BREL_NC R_ARM = 84 + R_ARM_MOVT_BREL R_ARM = 85 + R_ARM_MOVW_BREL R_ARM = 86 + R_ARM_THM_MOVW_BREL_NC R_ARM = 87 + R_ARM_THM_MOVT_BREL R_ARM = 88 + R_ARM_THM_MOVW_BREL R_ARM = 89 + R_ARM_TLS_GOTDESC R_ARM = 90 + R_ARM_TLS_CALL R_ARM = 91 + R_ARM_TLS_DESCSEQ R_ARM = 92 + R_ARM_THM_TLS_CALL R_ARM = 93 + R_ARM_PLT32_ABS R_ARM = 94 + R_ARM_GOT_ABS R_ARM = 95 + R_ARM_GOT_PREL R_ARM = 96 + R_ARM_GOT_BREL12 R_ARM = 97 + R_ARM_GOTOFF12 R_ARM = 98 + R_ARM_GOTRELAX R_ARM = 99 + R_ARM_GNU_VTENTRY R_ARM = 100 + R_ARM_GNU_VTINHERIT R_ARM = 101 + R_ARM_THM_JUMP11 R_ARM = 102 + R_ARM_THM_JUMP8 R_ARM = 103 + R_ARM_TLS_GD32 R_ARM = 104 + R_ARM_TLS_LDM32 R_ARM = 105 + R_ARM_TLS_LDO32 R_ARM = 106 + R_ARM_TLS_IE32 R_ARM = 107 + R_ARM_TLS_LE32 R_ARM = 108 + R_ARM_TLS_LDO12 R_ARM = 109 + R_ARM_TLS_LE12 R_ARM = 110 + R_ARM_TLS_IE12GP R_ARM = 111 + R_ARM_PRIVATE_0 R_ARM = 112 + R_ARM_PRIVATE_1 R_ARM = 113 + R_ARM_PRIVATE_2 R_ARM = 114 + R_ARM_PRIVATE_3 R_ARM = 115 + R_ARM_PRIVATE_4 R_ARM = 116 + R_ARM_PRIVATE_5 R_ARM = 117 + R_ARM_PRIVATE_6 R_ARM = 118 + R_ARM_PRIVATE_7 R_ARM = 119 + R_ARM_PRIVATE_8 R_ARM = 120 + R_ARM_PRIVATE_9 R_ARM = 121 + R_ARM_PRIVATE_10 R_ARM = 122 + R_ARM_PRIVATE_11 R_ARM = 123 + R_ARM_PRIVATE_12 R_ARM = 124 + R_ARM_PRIVATE_13 R_ARM = 125 + R_ARM_PRIVATE_14 R_ARM = 126 + R_ARM_PRIVATE_15 R_ARM = 127 + R_ARM_ME_TOO R_ARM = 128 + R_ARM_THM_TLS_DESCSEQ16 R_ARM = 129 + R_ARM_THM_TLS_DESCSEQ32 R_ARM = 130 + R_ARM_THM_GOT_BREL12 R_ARM = 131 + R_ARM_THM_ALU_ABS_G0_NC R_ARM = 132 + R_ARM_THM_ALU_ABS_G1_NC R_ARM = 133 + R_ARM_THM_ALU_ABS_G2_NC R_ARM = 134 + R_ARM_THM_ALU_ABS_G3 R_ARM = 135 + R_ARM_IRELATIVE R_ARM = 160 + R_ARM_RXPC25 R_ARM = 249 + R_ARM_RSBREL32 R_ARM = 250 + R_ARM_THM_RPC22 R_ARM = 251 + R_ARM_RREL32 R_ARM = 252 + R_ARM_RABS32 R_ARM = 253 + R_ARM_RPC24 R_ARM = 254 + R_ARM_RBASE R_ARM = 255 +) + +var rarmStrings = []intName{ + {0, "R_ARM_NONE"}, + {1, "R_ARM_PC24"}, + {2, "R_ARM_ABS32"}, + {3, "R_ARM_REL32"}, + {4, "R_ARM_PC13"}, + {5, "R_ARM_ABS16"}, + {6, "R_ARM_ABS12"}, + {7, "R_ARM_THM_ABS5"}, + {8, "R_ARM_ABS8"}, + {9, "R_ARM_SBREL32"}, + {10, "R_ARM_THM_PC22"}, + {11, "R_ARM_THM_PC8"}, + {12, "R_ARM_AMP_VCALL9"}, + {13, "R_ARM_SWI24"}, + {14, "R_ARM_THM_SWI8"}, + {15, "R_ARM_XPC25"}, + {16, "R_ARM_THM_XPC22"}, + {17, "R_ARM_TLS_DTPMOD32"}, + {18, "R_ARM_TLS_DTPOFF32"}, + {19, "R_ARM_TLS_TPOFF32"}, + {20, "R_ARM_COPY"}, + {21, "R_ARM_GLOB_DAT"}, + {22, "R_ARM_JUMP_SLOT"}, + {23, "R_ARM_RELATIVE"}, + {24, "R_ARM_GOTOFF"}, + {25, "R_ARM_GOTPC"}, + {26, "R_ARM_GOT32"}, + {27, "R_ARM_PLT32"}, + {28, "R_ARM_CALL"}, + {29, "R_ARM_JUMP24"}, + {30, "R_ARM_THM_JUMP24"}, + {31, "R_ARM_BASE_ABS"}, + {32, "R_ARM_ALU_PCREL_7_0"}, + {33, "R_ARM_ALU_PCREL_15_8"}, + {34, "R_ARM_ALU_PCREL_23_15"}, + {35, "R_ARM_LDR_SBREL_11_10_NC"}, + {36, "R_ARM_ALU_SBREL_19_12_NC"}, + {37, "R_ARM_ALU_SBREL_27_20_CK"}, + {38, "R_ARM_TARGET1"}, + {39, "R_ARM_SBREL31"}, + {40, "R_ARM_V4BX"}, + {41, "R_ARM_TARGET2"}, + {42, "R_ARM_PREL31"}, + {43, "R_ARM_MOVW_ABS_NC"}, + {44, "R_ARM_MOVT_ABS"}, + {45, "R_ARM_MOVW_PREL_NC"}, + {46, "R_ARM_MOVT_PREL"}, + {47, "R_ARM_THM_MOVW_ABS_NC"}, + {48, "R_ARM_THM_MOVT_ABS"}, + {49, "R_ARM_THM_MOVW_PREL_NC"}, + {50, "R_ARM_THM_MOVT_PREL"}, + {51, "R_ARM_THM_JUMP19"}, + {52, "R_ARM_THM_JUMP6"}, + {53, "R_ARM_THM_ALU_PREL_11_0"}, + {54, "R_ARM_THM_PC12"}, + {55, "R_ARM_ABS32_NOI"}, + {56, "R_ARM_REL32_NOI"}, + {57, "R_ARM_ALU_PC_G0_NC"}, + {58, "R_ARM_ALU_PC_G0"}, + {59, "R_ARM_ALU_PC_G1_NC"}, + {60, "R_ARM_ALU_PC_G1"}, + {61, "R_ARM_ALU_PC_G2"}, + {62, "R_ARM_LDR_PC_G1"}, + {63, "R_ARM_LDR_PC_G2"}, + {64, "R_ARM_LDRS_PC_G0"}, + {65, "R_ARM_LDRS_PC_G1"}, + {66, "R_ARM_LDRS_PC_G2"}, + {67, "R_ARM_LDC_PC_G0"}, + {68, "R_ARM_LDC_PC_G1"}, + {69, "R_ARM_LDC_PC_G2"}, + {70, "R_ARM_ALU_SB_G0_NC"}, + {71, "R_ARM_ALU_SB_G0"}, + {72, "R_ARM_ALU_SB_G1_NC"}, + {73, "R_ARM_ALU_SB_G1"}, + {74, "R_ARM_ALU_SB_G2"}, + {75, "R_ARM_LDR_SB_G0"}, + {76, "R_ARM_LDR_SB_G1"}, + {77, "R_ARM_LDR_SB_G2"}, + {78, "R_ARM_LDRS_SB_G0"}, + {79, "R_ARM_LDRS_SB_G1"}, + {80, "R_ARM_LDRS_SB_G2"}, + {81, "R_ARM_LDC_SB_G0"}, + {82, "R_ARM_LDC_SB_G1"}, + {83, "R_ARM_LDC_SB_G2"}, + {84, "R_ARM_MOVW_BREL_NC"}, + {85, "R_ARM_MOVT_BREL"}, + {86, "R_ARM_MOVW_BREL"}, + {87, "R_ARM_THM_MOVW_BREL_NC"}, + {88, "R_ARM_THM_MOVT_BREL"}, + {89, "R_ARM_THM_MOVW_BREL"}, + {90, "R_ARM_TLS_GOTDESC"}, + {91, "R_ARM_TLS_CALL"}, + {92, "R_ARM_TLS_DESCSEQ"}, + {93, "R_ARM_THM_TLS_CALL"}, + {94, "R_ARM_PLT32_ABS"}, + {95, "R_ARM_GOT_ABS"}, + {96, "R_ARM_GOT_PREL"}, + {97, "R_ARM_GOT_BREL12"}, + {98, "R_ARM_GOTOFF12"}, + {99, "R_ARM_GOTRELAX"}, + {100, "R_ARM_GNU_VTENTRY"}, + {101, "R_ARM_GNU_VTINHERIT"}, + {102, "R_ARM_THM_JUMP11"}, + {103, "R_ARM_THM_JUMP8"}, + {104, "R_ARM_TLS_GD32"}, + {105, "R_ARM_TLS_LDM32"}, + {106, "R_ARM_TLS_LDO32"}, + {107, "R_ARM_TLS_IE32"}, + {108, "R_ARM_TLS_LE32"}, + {109, "R_ARM_TLS_LDO12"}, + {110, "R_ARM_TLS_LE12"}, + {111, "R_ARM_TLS_IE12GP"}, + {112, "R_ARM_PRIVATE_0"}, + {113, "R_ARM_PRIVATE_1"}, + {114, "R_ARM_PRIVATE_2"}, + {115, "R_ARM_PRIVATE_3"}, + {116, "R_ARM_PRIVATE_4"}, + {117, "R_ARM_PRIVATE_5"}, + {118, "R_ARM_PRIVATE_6"}, + {119, "R_ARM_PRIVATE_7"}, + {120, "R_ARM_PRIVATE_8"}, + {121, "R_ARM_PRIVATE_9"}, + {122, "R_ARM_PRIVATE_10"}, + {123, "R_ARM_PRIVATE_11"}, + {124, "R_ARM_PRIVATE_12"}, + {125, "R_ARM_PRIVATE_13"}, + {126, "R_ARM_PRIVATE_14"}, + {127, "R_ARM_PRIVATE_15"}, + {128, "R_ARM_ME_TOO"}, + {129, "R_ARM_THM_TLS_DESCSEQ16"}, + {130, "R_ARM_THM_TLS_DESCSEQ32"}, + {131, "R_ARM_THM_GOT_BREL12"}, + {132, "R_ARM_THM_ALU_ABS_G0_NC"}, + {133, "R_ARM_THM_ALU_ABS_G1_NC"}, + {134, "R_ARM_THM_ALU_ABS_G2_NC"}, + {135, "R_ARM_THM_ALU_ABS_G3"}, + {160, "R_ARM_IRELATIVE"}, + {249, "R_ARM_RXPC25"}, + {250, "R_ARM_RSBREL32"}, + {251, "R_ARM_THM_RPC22"}, + {252, "R_ARM_RREL32"}, + {253, "R_ARM_RABS32"}, + {254, "R_ARM_RPC24"}, + {255, "R_ARM_RBASE"}, +} + +func (i R_ARM) String() string { return stringName(uint32(i), rarmStrings, false) } +func (i R_ARM) GoString() string { return stringName(uint32(i), rarmStrings, true) } + +// Relocation types for 386. +type R_386 int + +const ( + R_386_NONE R_386 = 0 /* No relocation. */ + R_386_32 R_386 = 1 /* Add symbol value. */ + R_386_PC32 R_386 = 2 /* Add PC-relative symbol value. */ + R_386_GOT32 R_386 = 3 /* Add PC-relative GOT offset. */ + R_386_PLT32 R_386 = 4 /* Add PC-relative PLT offset. */ + R_386_COPY R_386 = 5 /* Copy data from shared object. */ + R_386_GLOB_DAT R_386 = 6 /* Set GOT entry to data address. */ + R_386_JMP_SLOT R_386 = 7 /* Set GOT entry to code address. */ + R_386_RELATIVE R_386 = 8 /* Add load address of shared object. */ + R_386_GOTOFF R_386 = 9 /* Add GOT-relative symbol address. */ + R_386_GOTPC R_386 = 10 /* Add PC-relative GOT table address. */ + R_386_32PLT R_386 = 11 + R_386_TLS_TPOFF R_386 = 14 /* Negative offset in static TLS block */ + R_386_TLS_IE R_386 = 15 /* Absolute address of GOT for -ve static TLS */ + R_386_TLS_GOTIE R_386 = 16 /* GOT entry for negative static TLS block */ + R_386_TLS_LE R_386 = 17 /* Negative offset relative to static TLS */ + R_386_TLS_GD R_386 = 18 /* 32 bit offset to GOT (index,off) pair */ + R_386_TLS_LDM R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */ + R_386_16 R_386 = 20 + R_386_PC16 R_386 = 21 + R_386_8 R_386 = 22 + R_386_PC8 R_386 = 23 + R_386_TLS_GD_32 R_386 = 24 /* 32 bit offset to GOT (index,off) pair */ + R_386_TLS_GD_PUSH R_386 = 25 /* pushl instruction for Sun ABI GD sequence */ + R_386_TLS_GD_CALL R_386 = 26 /* call instruction for Sun ABI GD sequence */ + R_386_TLS_GD_POP R_386 = 27 /* popl instruction for Sun ABI GD sequence */ + R_386_TLS_LDM_32 R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */ + R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */ + R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */ + R_386_TLS_LDM_POP R_386 = 31 /* popl instruction for Sun ABI LD sequence */ + R_386_TLS_LDO_32 R_386 = 32 /* 32 bit offset from start of TLS block */ + R_386_TLS_IE_32 R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */ + R_386_TLS_LE_32 R_386 = 34 /* 32 bit offset within static TLS block */ + R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */ + R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */ + R_386_TLS_TPOFF32 R_386 = 37 /* GOT entry of -ve static TLS offset */ + R_386_SIZE32 R_386 = 38 + R_386_TLS_GOTDESC R_386 = 39 + R_386_TLS_DESC_CALL R_386 = 40 + R_386_TLS_DESC R_386 = 41 + R_386_IRELATIVE R_386 = 42 + R_386_GOT32X R_386 = 43 +) + +var r386Strings = []intName{ + {0, "R_386_NONE"}, + {1, "R_386_32"}, + {2, "R_386_PC32"}, + {3, "R_386_GOT32"}, + {4, "R_386_PLT32"}, + {5, "R_386_COPY"}, + {6, "R_386_GLOB_DAT"}, + {7, "R_386_JMP_SLOT"}, + {8, "R_386_RELATIVE"}, + {9, "R_386_GOTOFF"}, + {10, "R_386_GOTPC"}, + {11, "R_386_32PLT"}, + {14, "R_386_TLS_TPOFF"}, + {15, "R_386_TLS_IE"}, + {16, "R_386_TLS_GOTIE"}, + {17, "R_386_TLS_LE"}, + {18, "R_386_TLS_GD"}, + {19, "R_386_TLS_LDM"}, + {20, "R_386_16"}, + {21, "R_386_PC16"}, + {22, "R_386_8"}, + {23, "R_386_PC8"}, + {24, "R_386_TLS_GD_32"}, + {25, "R_386_TLS_GD_PUSH"}, + {26, "R_386_TLS_GD_CALL"}, + {27, "R_386_TLS_GD_POP"}, + {28, "R_386_TLS_LDM_32"}, + {29, "R_386_TLS_LDM_PUSH"}, + {30, "R_386_TLS_LDM_CALL"}, + {31, "R_386_TLS_LDM_POP"}, + {32, "R_386_TLS_LDO_32"}, + {33, "R_386_TLS_IE_32"}, + {34, "R_386_TLS_LE_32"}, + {35, "R_386_TLS_DTPMOD32"}, + {36, "R_386_TLS_DTPOFF32"}, + {37, "R_386_TLS_TPOFF32"}, + {38, "R_386_SIZE32"}, + {39, "R_386_TLS_GOTDESC"}, + {40, "R_386_TLS_DESC_CALL"}, + {41, "R_386_TLS_DESC"}, + {42, "R_386_IRELATIVE"}, + {43, "R_386_GOT32X"}, +} + +func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) } +func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) } + +// Relocation types for MIPS. +type R_MIPS int + +const ( + R_MIPS_NONE R_MIPS = 0 + R_MIPS_16 R_MIPS = 1 + R_MIPS_32 R_MIPS = 2 + R_MIPS_REL32 R_MIPS = 3 + R_MIPS_26 R_MIPS = 4 + R_MIPS_HI16 R_MIPS = 5 /* high 16 bits of symbol value */ + R_MIPS_LO16 R_MIPS = 6 /* low 16 bits of symbol value */ + R_MIPS_GPREL16 R_MIPS = 7 /* GP-relative reference */ + R_MIPS_LITERAL R_MIPS = 8 /* Reference to literal section */ + R_MIPS_GOT16 R_MIPS = 9 /* Reference to global offset table */ + R_MIPS_PC16 R_MIPS = 10 /* 16 bit PC relative reference */ + R_MIPS_CALL16 R_MIPS = 11 /* 16 bit call through glbl offset tbl */ + R_MIPS_GPREL32 R_MIPS = 12 + R_MIPS_SHIFT5 R_MIPS = 16 + R_MIPS_SHIFT6 R_MIPS = 17 + R_MIPS_64 R_MIPS = 18 + R_MIPS_GOT_DISP R_MIPS = 19 + R_MIPS_GOT_PAGE R_MIPS = 20 + R_MIPS_GOT_OFST R_MIPS = 21 + R_MIPS_GOT_HI16 R_MIPS = 22 + R_MIPS_GOT_LO16 R_MIPS = 23 + R_MIPS_SUB R_MIPS = 24 + R_MIPS_INSERT_A R_MIPS = 25 + R_MIPS_INSERT_B R_MIPS = 26 + R_MIPS_DELETE R_MIPS = 27 + R_MIPS_HIGHER R_MIPS = 28 + R_MIPS_HIGHEST R_MIPS = 29 + R_MIPS_CALL_HI16 R_MIPS = 30 + R_MIPS_CALL_LO16 R_MIPS = 31 + R_MIPS_SCN_DISP R_MIPS = 32 + R_MIPS_REL16 R_MIPS = 33 + R_MIPS_ADD_IMMEDIATE R_MIPS = 34 + R_MIPS_PJUMP R_MIPS = 35 + R_MIPS_RELGOT R_MIPS = 36 + R_MIPS_JALR R_MIPS = 37 + + R_MIPS_TLS_DTPMOD32 R_MIPS = 38 /* Module number 32 bit */ + R_MIPS_TLS_DTPREL32 R_MIPS = 39 /* Module-relative offset 32 bit */ + R_MIPS_TLS_DTPMOD64 R_MIPS = 40 /* Module number 64 bit */ + R_MIPS_TLS_DTPREL64 R_MIPS = 41 /* Module-relative offset 64 bit */ + R_MIPS_TLS_GD R_MIPS = 42 /* 16 bit GOT offset for GD */ + R_MIPS_TLS_LDM R_MIPS = 43 /* 16 bit GOT offset for LDM */ + R_MIPS_TLS_DTPREL_HI16 R_MIPS = 44 /* Module-relative offset, high 16 bits */ + R_MIPS_TLS_DTPREL_LO16 R_MIPS = 45 /* Module-relative offset, low 16 bits */ + R_MIPS_TLS_GOTTPREL R_MIPS = 46 /* 16 bit GOT offset for IE */ + R_MIPS_TLS_TPREL32 R_MIPS = 47 /* TP-relative offset, 32 bit */ + R_MIPS_TLS_TPREL64 R_MIPS = 48 /* TP-relative offset, 64 bit */ + R_MIPS_TLS_TPREL_HI16 R_MIPS = 49 /* TP-relative offset, high 16 bits */ + R_MIPS_TLS_TPREL_LO16 R_MIPS = 50 /* TP-relative offset, low 16 bits */ +) + +var rmipsStrings = []intName{ + {0, "R_MIPS_NONE"}, + {1, "R_MIPS_16"}, + {2, "R_MIPS_32"}, + {3, "R_MIPS_REL32"}, + {4, "R_MIPS_26"}, + {5, "R_MIPS_HI16"}, + {6, "R_MIPS_LO16"}, + {7, "R_MIPS_GPREL16"}, + {8, "R_MIPS_LITERAL"}, + {9, "R_MIPS_GOT16"}, + {10, "R_MIPS_PC16"}, + {11, "R_MIPS_CALL16"}, + {12, "R_MIPS_GPREL32"}, + {16, "R_MIPS_SHIFT5"}, + {17, "R_MIPS_SHIFT6"}, + {18, "R_MIPS_64"}, + {19, "R_MIPS_GOT_DISP"}, + {20, "R_MIPS_GOT_PAGE"}, + {21, "R_MIPS_GOT_OFST"}, + {22, "R_MIPS_GOT_HI16"}, + {23, "R_MIPS_GOT_LO16"}, + {24, "R_MIPS_SUB"}, + {25, "R_MIPS_INSERT_A"}, + {26, "R_MIPS_INSERT_B"}, + {27, "R_MIPS_DELETE"}, + {28, "R_MIPS_HIGHER"}, + {29, "R_MIPS_HIGHEST"}, + {30, "R_MIPS_CALL_HI16"}, + {31, "R_MIPS_CALL_LO16"}, + {32, "R_MIPS_SCN_DISP"}, + {33, "R_MIPS_REL16"}, + {34, "R_MIPS_ADD_IMMEDIATE"}, + {35, "R_MIPS_PJUMP"}, + {36, "R_MIPS_RELGOT"}, + {37, "R_MIPS_JALR"}, + {38, "R_MIPS_TLS_DTPMOD32"}, + {39, "R_MIPS_TLS_DTPREL32"}, + {40, "R_MIPS_TLS_DTPMOD64"}, + {41, "R_MIPS_TLS_DTPREL64"}, + {42, "R_MIPS_TLS_GD"}, + {43, "R_MIPS_TLS_LDM"}, + {44, "R_MIPS_TLS_DTPREL_HI16"}, + {45, "R_MIPS_TLS_DTPREL_LO16"}, + {46, "R_MIPS_TLS_GOTTPREL"}, + {47, "R_MIPS_TLS_TPREL32"}, + {48, "R_MIPS_TLS_TPREL64"}, + {49, "R_MIPS_TLS_TPREL_HI16"}, + {50, "R_MIPS_TLS_TPREL_LO16"}, +} + +func (i R_MIPS) String() string { return stringName(uint32(i), rmipsStrings, false) } +func (i R_MIPS) GoString() string { return stringName(uint32(i), rmipsStrings, true) } + +// Relocation types for PowerPC. +// +// Values that are shared by both R_PPC and R_PPC64 are prefixed with +// R_POWERPC_ in the ELF standard. For the R_PPC type, the relevant +// shared relocations have been renamed with the prefix R_PPC_. +// The original name follows the value in a comment. +type R_PPC int + +const ( + R_PPC_NONE R_PPC = 0 // R_POWERPC_NONE + R_PPC_ADDR32 R_PPC = 1 // R_POWERPC_ADDR32 + R_PPC_ADDR24 R_PPC = 2 // R_POWERPC_ADDR24 + R_PPC_ADDR16 R_PPC = 3 // R_POWERPC_ADDR16 + R_PPC_ADDR16_LO R_PPC = 4 // R_POWERPC_ADDR16_LO + R_PPC_ADDR16_HI R_PPC = 5 // R_POWERPC_ADDR16_HI + R_PPC_ADDR16_HA R_PPC = 6 // R_POWERPC_ADDR16_HA + R_PPC_ADDR14 R_PPC = 7 // R_POWERPC_ADDR14 + R_PPC_ADDR14_BRTAKEN R_PPC = 8 // R_POWERPC_ADDR14_BRTAKEN + R_PPC_ADDR14_BRNTAKEN R_PPC = 9 // R_POWERPC_ADDR14_BRNTAKEN + R_PPC_REL24 R_PPC = 10 // R_POWERPC_REL24 + R_PPC_REL14 R_PPC = 11 // R_POWERPC_REL14 + R_PPC_REL14_BRTAKEN R_PPC = 12 // R_POWERPC_REL14_BRTAKEN + R_PPC_REL14_BRNTAKEN R_PPC = 13 // R_POWERPC_REL14_BRNTAKEN + R_PPC_GOT16 R_PPC = 14 // R_POWERPC_GOT16 + R_PPC_GOT16_LO R_PPC = 15 // R_POWERPC_GOT16_LO + R_PPC_GOT16_HI R_PPC = 16 // R_POWERPC_GOT16_HI + R_PPC_GOT16_HA R_PPC = 17 // R_POWERPC_GOT16_HA + R_PPC_PLTREL24 R_PPC = 18 + R_PPC_COPY R_PPC = 19 // R_POWERPC_COPY + R_PPC_GLOB_DAT R_PPC = 20 // R_POWERPC_GLOB_DAT + R_PPC_JMP_SLOT R_PPC = 21 // R_POWERPC_JMP_SLOT + R_PPC_RELATIVE R_PPC = 22 // R_POWERPC_RELATIVE + R_PPC_LOCAL24PC R_PPC = 23 + R_PPC_UADDR32 R_PPC = 24 // R_POWERPC_UADDR32 + R_PPC_UADDR16 R_PPC = 25 // R_POWERPC_UADDR16 + R_PPC_REL32 R_PPC = 26 // R_POWERPC_REL32 + R_PPC_PLT32 R_PPC = 27 // R_POWERPC_PLT32 + R_PPC_PLTREL32 R_PPC = 28 // R_POWERPC_PLTREL32 + R_PPC_PLT16_LO R_PPC = 29 // R_POWERPC_PLT16_LO + R_PPC_PLT16_HI R_PPC = 30 // R_POWERPC_PLT16_HI + R_PPC_PLT16_HA R_PPC = 31 // R_POWERPC_PLT16_HA + R_PPC_SDAREL16 R_PPC = 32 + R_PPC_SECTOFF R_PPC = 33 // R_POWERPC_SECTOFF + R_PPC_SECTOFF_LO R_PPC = 34 // R_POWERPC_SECTOFF_LO + R_PPC_SECTOFF_HI R_PPC = 35 // R_POWERPC_SECTOFF_HI + R_PPC_SECTOFF_HA R_PPC = 36 // R_POWERPC_SECTOFF_HA + R_PPC_TLS R_PPC = 67 // R_POWERPC_TLS + R_PPC_DTPMOD32 R_PPC = 68 // R_POWERPC_DTPMOD32 + R_PPC_TPREL16 R_PPC = 69 // R_POWERPC_TPREL16 + R_PPC_TPREL16_LO R_PPC = 70 // R_POWERPC_TPREL16_LO + R_PPC_TPREL16_HI R_PPC = 71 // R_POWERPC_TPREL16_HI + R_PPC_TPREL16_HA R_PPC = 72 // R_POWERPC_TPREL16_HA + R_PPC_TPREL32 R_PPC = 73 // R_POWERPC_TPREL32 + R_PPC_DTPREL16 R_PPC = 74 // R_POWERPC_DTPREL16 + R_PPC_DTPREL16_LO R_PPC = 75 // R_POWERPC_DTPREL16_LO + R_PPC_DTPREL16_HI R_PPC = 76 // R_POWERPC_DTPREL16_HI + R_PPC_DTPREL16_HA R_PPC = 77 // R_POWERPC_DTPREL16_HA + R_PPC_DTPREL32 R_PPC = 78 // R_POWERPC_DTPREL32 + R_PPC_GOT_TLSGD16 R_PPC = 79 // R_POWERPC_GOT_TLSGD16 + R_PPC_GOT_TLSGD16_LO R_PPC = 80 // R_POWERPC_GOT_TLSGD16_LO + R_PPC_GOT_TLSGD16_HI R_PPC = 81 // R_POWERPC_GOT_TLSGD16_HI + R_PPC_GOT_TLSGD16_HA R_PPC = 82 // R_POWERPC_GOT_TLSGD16_HA + R_PPC_GOT_TLSLD16 R_PPC = 83 // R_POWERPC_GOT_TLSLD16 + R_PPC_GOT_TLSLD16_LO R_PPC = 84 // R_POWERPC_GOT_TLSLD16_LO + R_PPC_GOT_TLSLD16_HI R_PPC = 85 // R_POWERPC_GOT_TLSLD16_HI + R_PPC_GOT_TLSLD16_HA R_PPC = 86 // R_POWERPC_GOT_TLSLD16_HA + R_PPC_GOT_TPREL16 R_PPC = 87 // R_POWERPC_GOT_TPREL16 + R_PPC_GOT_TPREL16_LO R_PPC = 88 // R_POWERPC_GOT_TPREL16_LO + R_PPC_GOT_TPREL16_HI R_PPC = 89 // R_POWERPC_GOT_TPREL16_HI + R_PPC_GOT_TPREL16_HA R_PPC = 90 // R_POWERPC_GOT_TPREL16_HA + R_PPC_EMB_NADDR32 R_PPC = 101 + R_PPC_EMB_NADDR16 R_PPC = 102 + R_PPC_EMB_NADDR16_LO R_PPC = 103 + R_PPC_EMB_NADDR16_HI R_PPC = 104 + R_PPC_EMB_NADDR16_HA R_PPC = 105 + R_PPC_EMB_SDAI16 R_PPC = 106 + R_PPC_EMB_SDA2I16 R_PPC = 107 + R_PPC_EMB_SDA2REL R_PPC = 108 + R_PPC_EMB_SDA21 R_PPC = 109 + R_PPC_EMB_MRKREF R_PPC = 110 + R_PPC_EMB_RELSEC16 R_PPC = 111 + R_PPC_EMB_RELST_LO R_PPC = 112 + R_PPC_EMB_RELST_HI R_PPC = 113 + R_PPC_EMB_RELST_HA R_PPC = 114 + R_PPC_EMB_BIT_FLD R_PPC = 115 + R_PPC_EMB_RELSDA R_PPC = 116 +) + +var rppcStrings = []intName{ + {0, "R_PPC_NONE"}, + {1, "R_PPC_ADDR32"}, + {2, "R_PPC_ADDR24"}, + {3, "R_PPC_ADDR16"}, + {4, "R_PPC_ADDR16_LO"}, + {5, "R_PPC_ADDR16_HI"}, + {6, "R_PPC_ADDR16_HA"}, + {7, "R_PPC_ADDR14"}, + {8, "R_PPC_ADDR14_BRTAKEN"}, + {9, "R_PPC_ADDR14_BRNTAKEN"}, + {10, "R_PPC_REL24"}, + {11, "R_PPC_REL14"}, + {12, "R_PPC_REL14_BRTAKEN"}, + {13, "R_PPC_REL14_BRNTAKEN"}, + {14, "R_PPC_GOT16"}, + {15, "R_PPC_GOT16_LO"}, + {16, "R_PPC_GOT16_HI"}, + {17, "R_PPC_GOT16_HA"}, + {18, "R_PPC_PLTREL24"}, + {19, "R_PPC_COPY"}, + {20, "R_PPC_GLOB_DAT"}, + {21, "R_PPC_JMP_SLOT"}, + {22, "R_PPC_RELATIVE"}, + {23, "R_PPC_LOCAL24PC"}, + {24, "R_PPC_UADDR32"}, + {25, "R_PPC_UADDR16"}, + {26, "R_PPC_REL32"}, + {27, "R_PPC_PLT32"}, + {28, "R_PPC_PLTREL32"}, + {29, "R_PPC_PLT16_LO"}, + {30, "R_PPC_PLT16_HI"}, + {31, "R_PPC_PLT16_HA"}, + {32, "R_PPC_SDAREL16"}, + {33, "R_PPC_SECTOFF"}, + {34, "R_PPC_SECTOFF_LO"}, + {35, "R_PPC_SECTOFF_HI"}, + {36, "R_PPC_SECTOFF_HA"}, + {67, "R_PPC_TLS"}, + {68, "R_PPC_DTPMOD32"}, + {69, "R_PPC_TPREL16"}, + {70, "R_PPC_TPREL16_LO"}, + {71, "R_PPC_TPREL16_HI"}, + {72, "R_PPC_TPREL16_HA"}, + {73, "R_PPC_TPREL32"}, + {74, "R_PPC_DTPREL16"}, + {75, "R_PPC_DTPREL16_LO"}, + {76, "R_PPC_DTPREL16_HI"}, + {77, "R_PPC_DTPREL16_HA"}, + {78, "R_PPC_DTPREL32"}, + {79, "R_PPC_GOT_TLSGD16"}, + {80, "R_PPC_GOT_TLSGD16_LO"}, + {81, "R_PPC_GOT_TLSGD16_HI"}, + {82, "R_PPC_GOT_TLSGD16_HA"}, + {83, "R_PPC_GOT_TLSLD16"}, + {84, "R_PPC_GOT_TLSLD16_LO"}, + {85, "R_PPC_GOT_TLSLD16_HI"}, + {86, "R_PPC_GOT_TLSLD16_HA"}, + {87, "R_PPC_GOT_TPREL16"}, + {88, "R_PPC_GOT_TPREL16_LO"}, + {89, "R_PPC_GOT_TPREL16_HI"}, + {90, "R_PPC_GOT_TPREL16_HA"}, + {101, "R_PPC_EMB_NADDR32"}, + {102, "R_PPC_EMB_NADDR16"}, + {103, "R_PPC_EMB_NADDR16_LO"}, + {104, "R_PPC_EMB_NADDR16_HI"}, + {105, "R_PPC_EMB_NADDR16_HA"}, + {106, "R_PPC_EMB_SDAI16"}, + {107, "R_PPC_EMB_SDA2I16"}, + {108, "R_PPC_EMB_SDA2REL"}, + {109, "R_PPC_EMB_SDA21"}, + {110, "R_PPC_EMB_MRKREF"}, + {111, "R_PPC_EMB_RELSEC16"}, + {112, "R_PPC_EMB_RELST_LO"}, + {113, "R_PPC_EMB_RELST_HI"}, + {114, "R_PPC_EMB_RELST_HA"}, + {115, "R_PPC_EMB_BIT_FLD"}, + {116, "R_PPC_EMB_RELSDA"}, +} + +func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) } +func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) } + +// Relocation types for 64-bit PowerPC or Power Architecture processors. +// +// Values that are shared by both R_PPC and R_PPC64 are prefixed with +// R_POWERPC_ in the ELF standard. For the R_PPC64 type, the relevant +// shared relocations have been renamed with the prefix R_PPC64_. +// The original name follows the value in a comment. +type R_PPC64 int + +const ( + R_PPC64_NONE R_PPC64 = 0 // R_POWERPC_NONE + R_PPC64_ADDR32 R_PPC64 = 1 // R_POWERPC_ADDR32 + R_PPC64_ADDR24 R_PPC64 = 2 // R_POWERPC_ADDR24 + R_PPC64_ADDR16 R_PPC64 = 3 // R_POWERPC_ADDR16 + R_PPC64_ADDR16_LO R_PPC64 = 4 // R_POWERPC_ADDR16_LO + R_PPC64_ADDR16_HI R_PPC64 = 5 // R_POWERPC_ADDR16_HI + R_PPC64_ADDR16_HA R_PPC64 = 6 // R_POWERPC_ADDR16_HA + R_PPC64_ADDR14 R_PPC64 = 7 // R_POWERPC_ADDR14 + R_PPC64_ADDR14_BRTAKEN R_PPC64 = 8 // R_POWERPC_ADDR14_BRTAKEN + R_PPC64_ADDR14_BRNTAKEN R_PPC64 = 9 // R_POWERPC_ADDR14_BRNTAKEN + R_PPC64_REL24 R_PPC64 = 10 // R_POWERPC_REL24 + R_PPC64_REL14 R_PPC64 = 11 // R_POWERPC_REL14 + R_PPC64_REL14_BRTAKEN R_PPC64 = 12 // R_POWERPC_REL14_BRTAKEN + R_PPC64_REL14_BRNTAKEN R_PPC64 = 13 // R_POWERPC_REL14_BRNTAKEN + R_PPC64_GOT16 R_PPC64 = 14 // R_POWERPC_GOT16 + R_PPC64_GOT16_LO R_PPC64 = 15 // R_POWERPC_GOT16_LO + R_PPC64_GOT16_HI R_PPC64 = 16 // R_POWERPC_GOT16_HI + R_PPC64_GOT16_HA R_PPC64 = 17 // R_POWERPC_GOT16_HA + R_PPC64_JMP_SLOT R_PPC64 = 21 // R_POWERPC_JMP_SLOT + R_PPC64_REL32 R_PPC64 = 26 // R_POWERPC_REL32 + R_PPC64_ADDR64 R_PPC64 = 38 + R_PPC64_ADDR16_HIGHER R_PPC64 = 39 + R_PPC64_ADDR16_HIGHERA R_PPC64 = 40 + R_PPC64_ADDR16_HIGHEST R_PPC64 = 41 + R_PPC64_ADDR16_HIGHESTA R_PPC64 = 42 + R_PPC64_REL64 R_PPC64 = 44 + R_PPC64_TOC16 R_PPC64 = 47 + R_PPC64_TOC16_LO R_PPC64 = 48 + R_PPC64_TOC16_HI R_PPC64 = 49 + R_PPC64_TOC16_HA R_PPC64 = 50 + R_PPC64_TOC R_PPC64 = 51 + R_PPC64_PLTGOT16 R_PPC64 = 52 + R_PPC64_PLTGOT16_LO R_PPC64 = 53 + R_PPC64_PLTGOT16_HI R_PPC64 = 54 + R_PPC64_PLTGOT16_HA R_PPC64 = 55 + R_PPC64_ADDR16_DS R_PPC64 = 56 + R_PPC64_ADDR16_LO_DS R_PPC64 = 57 + R_PPC64_GOT16_DS R_PPC64 = 58 + R_PPC64_GOT16_LO_DS R_PPC64 = 59 + R_PPC64_PLT16_LO_DS R_PPC64 = 60 + R_PPC64_SECTOFF_DS R_PPC64 = 61 + R_PPC64_SECTOFF_LO_DS R_PPC64 = 61 + R_PPC64_TOC16_DS R_PPC64 = 63 + R_PPC64_TOC16_LO_DS R_PPC64 = 64 + R_PPC64_PLTGOT16_DS R_PPC64 = 65 + R_PPC64_PLTGOT_LO_DS R_PPC64 = 66 + R_PPC64_TLS R_PPC64 = 67 // R_POWERPC_TLS + R_PPC64_DTPMOD64 R_PPC64 = 68 // R_POWERPC_DTPMOD64 + R_PPC64_TPREL16 R_PPC64 = 69 // R_POWERPC_TPREL16 + R_PPC64_TPREL16_LO R_PPC64 = 70 // R_POWERPC_TPREL16_LO + R_PPC64_TPREL16_HI R_PPC64 = 71 // R_POWERPC_TPREL16_HI + R_PPC64_TPREL16_HA R_PPC64 = 72 // R_POWERPC_TPREL16_HA + R_PPC64_TPREL64 R_PPC64 = 73 // R_POWERPC_TPREL64 + R_PPC64_DTPREL16 R_PPC64 = 74 // R_POWERPC_DTPREL16 + R_PPC64_DTPREL16_LO R_PPC64 = 75 // R_POWERPC_DTPREL16_LO + R_PPC64_DTPREL16_HI R_PPC64 = 76 // R_POWERPC_DTPREL16_HI + R_PPC64_DTPREL16_HA R_PPC64 = 77 // R_POWERPC_DTPREL16_HA + R_PPC64_DTPREL64 R_PPC64 = 78 // R_POWERPC_DTPREL64 + R_PPC64_GOT_TLSGD16 R_PPC64 = 79 // R_POWERPC_GOT_TLSGD16 + R_PPC64_GOT_TLSGD16_LO R_PPC64 = 80 // R_POWERPC_GOT_TLSGD16_LO + R_PPC64_GOT_TLSGD16_HI R_PPC64 = 81 // R_POWERPC_GOT_TLSGD16_HI + R_PPC64_GOT_TLSGD16_HA R_PPC64 = 82 // R_POWERPC_GOT_TLSGD16_HA + R_PPC64_GOT_TLSLD16 R_PPC64 = 83 // R_POWERPC_GOT_TLSLD16 + R_PPC64_GOT_TLSLD16_LO R_PPC64 = 84 // R_POWERPC_GOT_TLSLD16_LO + R_PPC64_GOT_TLSLD16_HI R_PPC64 = 85 // R_POWERPC_GOT_TLSLD16_HI + R_PPC64_GOT_TLSLD16_HA R_PPC64 = 86 // R_POWERPC_GOT_TLSLD16_HA + R_PPC64_GOT_TPREL16_DS R_PPC64 = 87 // R_POWERPC_GOT_TPREL16_DS + R_PPC64_GOT_TPREL16_LO_DS R_PPC64 = 88 // R_POWERPC_GOT_TPREL16_LO_DS + R_PPC64_GOT_TPREL16_HI R_PPC64 = 89 // R_POWERPC_GOT_TPREL16_HI + R_PPC64_GOT_TPREL16_HA R_PPC64 = 90 // R_POWERPC_GOT_TPREL16_HA + R_PPC64_GOT_DTPREL16_DS R_PPC64 = 91 // R_POWERPC_GOT_DTPREL16_DS + R_PPC64_GOT_DTPREL16_LO_DS R_PPC64 = 92 // R_POWERPC_GOT_DTPREL16_LO_DS + R_PPC64_GOT_DTPREL16_HI R_PPC64 = 93 // R_POWERPC_GOT_DTPREL16_HI + R_PPC64_GOT_DTPREL16_HA R_PPC64 = 94 // R_POWERPC_GOT_DTPREL16_HA + R_PPC64_TPREL16_DS R_PPC64 = 95 + R_PPC64_TPREL16_LO_DS R_PPC64 = 96 + R_PPC64_TPREL16_HIGHER R_PPC64 = 97 + R_PPC64_TPREL16_HIGHERA R_PPC64 = 98 + R_PPC64_TPREL16_HIGHEST R_PPC64 = 99 + R_PPC64_TPREL16_HIGHESTA R_PPC64 = 100 + R_PPC64_DTPREL16_DS R_PPC64 = 101 + R_PPC64_DTPREL16_LO_DS R_PPC64 = 102 + R_PPC64_DTPREL16_HIGHER R_PPC64 = 103 + R_PPC64_DTPREL16_HIGHERA R_PPC64 = 104 + R_PPC64_DTPREL16_HIGHEST R_PPC64 = 105 + R_PPC64_DTPREL16_HIGHESTA R_PPC64 = 106 + R_PPC64_TLSGD R_PPC64 = 107 + R_PPC64_TLSLD R_PPC64 = 108 + R_PPC64_TOCSAVE R_PPC64 = 109 + R_PPC64_ADDR16_HIGH R_PPC64 = 110 + R_PPC64_ADDR16_HIGHA R_PPC64 = 111 + R_PPC64_TPREL16_HIGH R_PPC64 = 112 + R_PPC64_TPREL16_HIGHA R_PPC64 = 113 + R_PPC64_DTPREL16_HIGH R_PPC64 = 114 + R_PPC64_DTPREL16_HIGHA R_PPC64 = 115 + R_PPC64_REL24_NOTOC R_PPC64 = 116 + R_PPC64_ADDR64_LOCAL R_PPC64 = 117 + R_PPC64_ENTRY R_PPC64 = 118 + R_PPC64_REL16DX_HA R_PPC64 = 246 // R_POWERPC_REL16DX_HA + R_PPC64_JMP_IREL R_PPC64 = 247 + R_PPC64_IRELATIVE R_PPC64 = 248 // R_POWERPC_IRELATIVE + R_PPC64_REL16 R_PPC64 = 249 // R_POWERPC_REL16 + R_PPC64_REL16_LO R_PPC64 = 250 // R_POWERPC_REL16_LO + R_PPC64_REL16_HI R_PPC64 = 251 // R_POWERPC_REL16_HI + R_PPC64_REL16_HA R_PPC64 = 252 // R_POWERPC_REL16_HA +) + +var rppc64Strings = []intName{ + {0, "R_PPC64_NONE"}, + {1, "R_PPC64_ADDR32"}, + {2, "R_PPC64_ADDR24"}, + {3, "R_PPC64_ADDR16"}, + {4, "R_PPC64_ADDR16_LO"}, + {5, "R_PPC64_ADDR16_HI"}, + {6, "R_PPC64_ADDR16_HA"}, + {7, "R_PPC64_ADDR14"}, + {8, "R_PPC64_ADDR14_BRTAKEN"}, + {9, "R_PPC64_ADDR14_BRNTAKEN"}, + {10, "R_PPC64_REL24"}, + {11, "R_PPC64_REL14"}, + {12, "R_PPC64_REL14_BRTAKEN"}, + {13, "R_PPC64_REL14_BRNTAKEN"}, + {14, "R_PPC64_GOT16"}, + {15, "R_PPC64_GOT16_LO"}, + {16, "R_PPC64_GOT16_HI"}, + {17, "R_PPC64_GOT16_HA"}, + {21, "R_PPC64_JMP_SLOT"}, + {26, "R_PPC64_REL32"}, + {38, "R_PPC64_ADDR64"}, + {39, "R_PPC64_ADDR16_HIGHER"}, + {40, "R_PPC64_ADDR16_HIGHERA"}, + {41, "R_PPC64_ADDR16_HIGHEST"}, + {42, "R_PPC64_ADDR16_HIGHESTA"}, + {44, "R_PPC64_REL64"}, + {47, "R_PPC64_TOC16"}, + {48, "R_PPC64_TOC16_LO"}, + {49, "R_PPC64_TOC16_HI"}, + {50, "R_PPC64_TOC16_HA"}, + {51, "R_PPC64_TOC"}, + {52, "R_PPC64_PLTGOT16"}, + {53, "R_PPC64_PLTGOT16_LO"}, + {54, "R_PPC64_PLTGOT16_HI"}, + {55, "R_PPC64_PLTGOT16_HA"}, + {56, "R_PPC64_ADDR16_DS"}, + {57, "R_PPC64_ADDR16_LO_DS"}, + {58, "R_PPC64_GOT16_DS"}, + {59, "R_PPC64_GOT16_LO_DS"}, + {60, "R_PPC64_PLT16_LO_DS"}, + {61, "R_PPC64_SECTOFF_DS"}, + {61, "R_PPC64_SECTOFF_LO_DS"}, + {63, "R_PPC64_TOC16_DS"}, + {64, "R_PPC64_TOC16_LO_DS"}, + {65, "R_PPC64_PLTGOT16_DS"}, + {66, "R_PPC64_PLTGOT_LO_DS"}, + {67, "R_PPC64_TLS"}, + {68, "R_PPC64_DTPMOD64"}, + {69, "R_PPC64_TPREL16"}, + {70, "R_PPC64_TPREL16_LO"}, + {71, "R_PPC64_TPREL16_HI"}, + {72, "R_PPC64_TPREL16_HA"}, + {73, "R_PPC64_TPREL64"}, + {74, "R_PPC64_DTPREL16"}, + {75, "R_PPC64_DTPREL16_LO"}, + {76, "R_PPC64_DTPREL16_HI"}, + {77, "R_PPC64_DTPREL16_HA"}, + {78, "R_PPC64_DTPREL64"}, + {79, "R_PPC64_GOT_TLSGD16"}, + {80, "R_PPC64_GOT_TLSGD16_LO"}, + {81, "R_PPC64_GOT_TLSGD16_HI"}, + {82, "R_PPC64_GOT_TLSGD16_HA"}, + {83, "R_PPC64_GOT_TLSLD16"}, + {84, "R_PPC64_GOT_TLSLD16_LO"}, + {85, "R_PPC64_GOT_TLSLD16_HI"}, + {86, "R_PPC64_GOT_TLSLD16_HA"}, + {87, "R_PPC64_GOT_TPREL16_DS"}, + {88, "R_PPC64_GOT_TPREL16_LO_DS"}, + {89, "R_PPC64_GOT_TPREL16_HI"}, + {90, "R_PPC64_GOT_TPREL16_HA"}, + {91, "R_PPC64_GOT_DTPREL16_DS"}, + {92, "R_PPC64_GOT_DTPREL16_LO_DS"}, + {93, "R_PPC64_GOT_DTPREL16_HI"}, + {94, "R_PPC64_GOT_DTPREL16_HA"}, + {95, "R_PPC64_TPREL16_DS"}, + {96, "R_PPC64_TPREL16_LO_DS"}, + {97, "R_PPC64_TPREL16_HIGHER"}, + {98, "R_PPC64_TPREL16_HIGHERA"}, + {99, "R_PPC64_TPREL16_HIGHEST"}, + {100, "R_PPC64_TPREL16_HIGHESTA"}, + {101, "R_PPC64_DTPREL16_DS"}, + {102, "R_PPC64_DTPREL16_LO_DS"}, + {103, "R_PPC64_DTPREL16_HIGHER"}, + {104, "R_PPC64_DTPREL16_HIGHERA"}, + {105, "R_PPC64_DTPREL16_HIGHEST"}, + {106, "R_PPC64_DTPREL16_HIGHESTA"}, + {107, "R_PPC64_TLSGD"}, + {108, "R_PPC64_TLSLD"}, + {109, "R_PPC64_TOCSAVE"}, + {110, "R_PPC64_ADDR16_HIGH"}, + {111, "R_PPC64_ADDR16_HIGHA"}, + {112, "R_PPC64_TPREL16_HIGH"}, + {113, "R_PPC64_TPREL16_HIGHA"}, + {114, "R_PPC64_DTPREL16_HIGH"}, + {115, "R_PPC64_DTPREL16_HIGHA"}, + {116, "R_PPC64_REL24_NOTOC"}, + {117, "R_PPC64_ADDR64_LOCAL"}, + {118, "R_PPC64_ENTRY"}, + {246, "R_PPC64_REL16DX_HA"}, + {247, "R_PPC64_JMP_IREL"}, + {248, "R_PPC64_IRELATIVE"}, + {249, "R_PPC64_REL16"}, + {250, "R_PPC64_REL16_LO"}, + {251, "R_PPC64_REL16_HI"}, + {252, "R_PPC64_REL16_HA"}, +} + +func (i R_PPC64) String() string { return stringName(uint32(i), rppc64Strings, false) } +func (i R_PPC64) GoString() string { return stringName(uint32(i), rppc64Strings, true) } + +// Relocation types for RISC-V processors. +type R_RISCV int + +const ( + R_RISCV_NONE R_RISCV = 0 /* No relocation. */ + R_RISCV_32 R_RISCV = 1 /* Add 32 bit zero extended symbol value */ + R_RISCV_64 R_RISCV = 2 /* Add 64 bit symbol value. */ + R_RISCV_RELATIVE R_RISCV = 3 /* Add load address of shared object. */ + R_RISCV_COPY R_RISCV = 4 /* Copy data from shared object. */ + R_RISCV_JUMP_SLOT R_RISCV = 5 /* Set GOT entry to code address. */ + R_RISCV_TLS_DTPMOD32 R_RISCV = 6 /* 32 bit ID of module containing symbol */ + R_RISCV_TLS_DTPMOD64 R_RISCV = 7 /* ID of module containing symbol */ + R_RISCV_TLS_DTPREL32 R_RISCV = 8 /* 32 bit relative offset in TLS block */ + R_RISCV_TLS_DTPREL64 R_RISCV = 9 /* Relative offset in TLS block */ + R_RISCV_TLS_TPREL32 R_RISCV = 10 /* 32 bit relative offset in static TLS block */ + R_RISCV_TLS_TPREL64 R_RISCV = 11 /* Relative offset in static TLS block */ + R_RISCV_BRANCH R_RISCV = 16 /* PC-relative branch */ + R_RISCV_JAL R_RISCV = 17 /* PC-relative jump */ + R_RISCV_CALL R_RISCV = 18 /* PC-relative call */ + R_RISCV_CALL_PLT R_RISCV = 19 /* PC-relative call (PLT) */ + R_RISCV_GOT_HI20 R_RISCV = 20 /* PC-relative GOT reference */ + R_RISCV_TLS_GOT_HI20 R_RISCV = 21 /* PC-relative TLS IE GOT offset */ + R_RISCV_TLS_GD_HI20 R_RISCV = 22 /* PC-relative TLS GD reference */ + R_RISCV_PCREL_HI20 R_RISCV = 23 /* PC-relative reference */ + R_RISCV_PCREL_LO12_I R_RISCV = 24 /* PC-relative reference */ + R_RISCV_PCREL_LO12_S R_RISCV = 25 /* PC-relative reference */ + R_RISCV_HI20 R_RISCV = 26 /* Absolute address */ + R_RISCV_LO12_I R_RISCV = 27 /* Absolute address */ + R_RISCV_LO12_S R_RISCV = 28 /* Absolute address */ + R_RISCV_TPREL_HI20 R_RISCV = 29 /* TLS LE thread offset */ + R_RISCV_TPREL_LO12_I R_RISCV = 30 /* TLS LE thread offset */ + R_RISCV_TPREL_LO12_S R_RISCV = 31 /* TLS LE thread offset */ + R_RISCV_TPREL_ADD R_RISCV = 32 /* TLS LE thread usage */ + R_RISCV_ADD8 R_RISCV = 33 /* 8-bit label addition */ + R_RISCV_ADD16 R_RISCV = 34 /* 16-bit label addition */ + R_RISCV_ADD32 R_RISCV = 35 /* 32-bit label addition */ + R_RISCV_ADD64 R_RISCV = 36 /* 64-bit label addition */ + R_RISCV_SUB8 R_RISCV = 37 /* 8-bit label subtraction */ + R_RISCV_SUB16 R_RISCV = 38 /* 16-bit label subtraction */ + R_RISCV_SUB32 R_RISCV = 39 /* 32-bit label subtraction */ + R_RISCV_SUB64 R_RISCV = 40 /* 64-bit label subtraction */ + R_RISCV_GNU_VTINHERIT R_RISCV = 41 /* GNU C++ vtable hierarchy */ + R_RISCV_GNU_VTENTRY R_RISCV = 42 /* GNU C++ vtable member usage */ + R_RISCV_ALIGN R_RISCV = 43 /* Alignment statement */ + R_RISCV_RVC_BRANCH R_RISCV = 44 /* PC-relative branch offset */ + R_RISCV_RVC_JUMP R_RISCV = 45 /* PC-relative jump offset */ + R_RISCV_RVC_LUI R_RISCV = 46 /* Absolute address */ + R_RISCV_GPREL_I R_RISCV = 47 /* GP-relative reference */ + R_RISCV_GPREL_S R_RISCV = 48 /* GP-relative reference */ + R_RISCV_TPREL_I R_RISCV = 49 /* TP-relative TLS LE load */ + R_RISCV_TPREL_S R_RISCV = 50 /* TP-relative TLS LE store */ + R_RISCV_RELAX R_RISCV = 51 /* Instruction pair can be relaxed */ + R_RISCV_SUB6 R_RISCV = 52 /* Local label subtraction */ + R_RISCV_SET6 R_RISCV = 53 /* Local label subtraction */ + R_RISCV_SET8 R_RISCV = 54 /* Local label subtraction */ + R_RISCV_SET16 R_RISCV = 55 /* Local label subtraction */ + R_RISCV_SET32 R_RISCV = 56 /* Local label subtraction */ + R_RISCV_32_PCREL R_RISCV = 57 /* 32-bit PC relative */ +) + +var rriscvStrings = []intName{ + {0, "R_RISCV_NONE"}, + {1, "R_RISCV_32"}, + {2, "R_RISCV_64"}, + {3, "R_RISCV_RELATIVE"}, + {4, "R_RISCV_COPY"}, + {5, "R_RISCV_JUMP_SLOT"}, + {6, "R_RISCV_TLS_DTPMOD32"}, + {7, "R_RISCV_TLS_DTPMOD64"}, + {8, "R_RISCV_TLS_DTPREL32"}, + {9, "R_RISCV_TLS_DTPREL64"}, + {10, "R_RISCV_TLS_TPREL32"}, + {11, "R_RISCV_TLS_TPREL64"}, + {16, "R_RISCV_BRANCH"}, + {17, "R_RISCV_JAL"}, + {18, "R_RISCV_CALL"}, + {19, "R_RISCV_CALL_PLT"}, + {20, "R_RISCV_GOT_HI20"}, + {21, "R_RISCV_TLS_GOT_HI20"}, + {22, "R_RISCV_TLS_GD_HI20"}, + {23, "R_RISCV_PCREL_HI20"}, + {24, "R_RISCV_PCREL_LO12_I"}, + {25, "R_RISCV_PCREL_LO12_S"}, + {26, "R_RISCV_HI20"}, + {27, "R_RISCV_LO12_I"}, + {28, "R_RISCV_LO12_S"}, + {29, "R_RISCV_TPREL_HI20"}, + {30, "R_RISCV_TPREL_LO12_I"}, + {31, "R_RISCV_TPREL_LO12_S"}, + {32, "R_RISCV_TPREL_ADD"}, + {33, "R_RISCV_ADD8"}, + {34, "R_RISCV_ADD16"}, + {35, "R_RISCV_ADD32"}, + {36, "R_RISCV_ADD64"}, + {37, "R_RISCV_SUB8"}, + {38, "R_RISCV_SUB16"}, + {39, "R_RISCV_SUB32"}, + {40, "R_RISCV_SUB64"}, + {41, "R_RISCV_GNU_VTINHERIT"}, + {42, "R_RISCV_GNU_VTENTRY"}, + {43, "R_RISCV_ALIGN"}, + {44, "R_RISCV_RVC_BRANCH"}, + {45, "R_RISCV_RVC_JUMP"}, + {46, "R_RISCV_RVC_LUI"}, + {47, "R_RISCV_GPREL_I"}, + {48, "R_RISCV_GPREL_S"}, + {49, "R_RISCV_TPREL_I"}, + {50, "R_RISCV_TPREL_S"}, + {51, "R_RISCV_RELAX"}, + {52, "R_RISCV_SUB6"}, + {53, "R_RISCV_SET6"}, + {54, "R_RISCV_SET8"}, + {55, "R_RISCV_SET16"}, + {56, "R_RISCV_SET32"}, + {57, "R_RISCV_32_PCREL"}, +} + +func (i R_RISCV) String() string { return stringName(uint32(i), rriscvStrings, false) } +func (i R_RISCV) GoString() string { return stringName(uint32(i), rriscvStrings, true) } + +// Relocation types for s390x processors. +type R_390 int + +const ( + R_390_NONE R_390 = 0 + R_390_8 R_390 = 1 + R_390_12 R_390 = 2 + R_390_16 R_390 = 3 + R_390_32 R_390 = 4 + R_390_PC32 R_390 = 5 + R_390_GOT12 R_390 = 6 + R_390_GOT32 R_390 = 7 + R_390_PLT32 R_390 = 8 + R_390_COPY R_390 = 9 + R_390_GLOB_DAT R_390 = 10 + R_390_JMP_SLOT R_390 = 11 + R_390_RELATIVE R_390 = 12 + R_390_GOTOFF R_390 = 13 + R_390_GOTPC R_390 = 14 + R_390_GOT16 R_390 = 15 + R_390_PC16 R_390 = 16 + R_390_PC16DBL R_390 = 17 + R_390_PLT16DBL R_390 = 18 + R_390_PC32DBL R_390 = 19 + R_390_PLT32DBL R_390 = 20 + R_390_GOTPCDBL R_390 = 21 + R_390_64 R_390 = 22 + R_390_PC64 R_390 = 23 + R_390_GOT64 R_390 = 24 + R_390_PLT64 R_390 = 25 + R_390_GOTENT R_390 = 26 + R_390_GOTOFF16 R_390 = 27 + R_390_GOTOFF64 R_390 = 28 + R_390_GOTPLT12 R_390 = 29 + R_390_GOTPLT16 R_390 = 30 + R_390_GOTPLT32 R_390 = 31 + R_390_GOTPLT64 R_390 = 32 + R_390_GOTPLTENT R_390 = 33 + R_390_GOTPLTOFF16 R_390 = 34 + R_390_GOTPLTOFF32 R_390 = 35 + R_390_GOTPLTOFF64 R_390 = 36 + R_390_TLS_LOAD R_390 = 37 + R_390_TLS_GDCALL R_390 = 38 + R_390_TLS_LDCALL R_390 = 39 + R_390_TLS_GD32 R_390 = 40 + R_390_TLS_GD64 R_390 = 41 + R_390_TLS_GOTIE12 R_390 = 42 + R_390_TLS_GOTIE32 R_390 = 43 + R_390_TLS_GOTIE64 R_390 = 44 + R_390_TLS_LDM32 R_390 = 45 + R_390_TLS_LDM64 R_390 = 46 + R_390_TLS_IE32 R_390 = 47 + R_390_TLS_IE64 R_390 = 48 + R_390_TLS_IEENT R_390 = 49 + R_390_TLS_LE32 R_390 = 50 + R_390_TLS_LE64 R_390 = 51 + R_390_TLS_LDO32 R_390 = 52 + R_390_TLS_LDO64 R_390 = 53 + R_390_TLS_DTPMOD R_390 = 54 + R_390_TLS_DTPOFF R_390 = 55 + R_390_TLS_TPOFF R_390 = 56 + R_390_20 R_390 = 57 + R_390_GOT20 R_390 = 58 + R_390_GOTPLT20 R_390 = 59 + R_390_TLS_GOTIE20 R_390 = 60 +) + +var r390Strings = []intName{ + {0, "R_390_NONE"}, + {1, "R_390_8"}, + {2, "R_390_12"}, + {3, "R_390_16"}, + {4, "R_390_32"}, + {5, "R_390_PC32"}, + {6, "R_390_GOT12"}, + {7, "R_390_GOT32"}, + {8, "R_390_PLT32"}, + {9, "R_390_COPY"}, + {10, "R_390_GLOB_DAT"}, + {11, "R_390_JMP_SLOT"}, + {12, "R_390_RELATIVE"}, + {13, "R_390_GOTOFF"}, + {14, "R_390_GOTPC"}, + {15, "R_390_GOT16"}, + {16, "R_390_PC16"}, + {17, "R_390_PC16DBL"}, + {18, "R_390_PLT16DBL"}, + {19, "R_390_PC32DBL"}, + {20, "R_390_PLT32DBL"}, + {21, "R_390_GOTPCDBL"}, + {22, "R_390_64"}, + {23, "R_390_PC64"}, + {24, "R_390_GOT64"}, + {25, "R_390_PLT64"}, + {26, "R_390_GOTENT"}, + {27, "R_390_GOTOFF16"}, + {28, "R_390_GOTOFF64"}, + {29, "R_390_GOTPLT12"}, + {30, "R_390_GOTPLT16"}, + {31, "R_390_GOTPLT32"}, + {32, "R_390_GOTPLT64"}, + {33, "R_390_GOTPLTENT"}, + {34, "R_390_GOTPLTOFF16"}, + {35, "R_390_GOTPLTOFF32"}, + {36, "R_390_GOTPLTOFF64"}, + {37, "R_390_TLS_LOAD"}, + {38, "R_390_TLS_GDCALL"}, + {39, "R_390_TLS_LDCALL"}, + {40, "R_390_TLS_GD32"}, + {41, "R_390_TLS_GD64"}, + {42, "R_390_TLS_GOTIE12"}, + {43, "R_390_TLS_GOTIE32"}, + {44, "R_390_TLS_GOTIE64"}, + {45, "R_390_TLS_LDM32"}, + {46, "R_390_TLS_LDM64"}, + {47, "R_390_TLS_IE32"}, + {48, "R_390_TLS_IE64"}, + {49, "R_390_TLS_IEENT"}, + {50, "R_390_TLS_LE32"}, + {51, "R_390_TLS_LE64"}, + {52, "R_390_TLS_LDO32"}, + {53, "R_390_TLS_LDO64"}, + {54, "R_390_TLS_DTPMOD"}, + {55, "R_390_TLS_DTPOFF"}, + {56, "R_390_TLS_TPOFF"}, + {57, "R_390_20"}, + {58, "R_390_GOT20"}, + {59, "R_390_GOTPLT20"}, + {60, "R_390_TLS_GOTIE20"}, +} + +func (i R_390) String() string { return stringName(uint32(i), r390Strings, false) } +func (i R_390) GoString() string { return stringName(uint32(i), r390Strings, true) } + +// Relocation types for SPARC. +type R_SPARC int + +const ( + R_SPARC_NONE R_SPARC = 0 + R_SPARC_8 R_SPARC = 1 + R_SPARC_16 R_SPARC = 2 + R_SPARC_32 R_SPARC = 3 + R_SPARC_DISP8 R_SPARC = 4 + R_SPARC_DISP16 R_SPARC = 5 + R_SPARC_DISP32 R_SPARC = 6 + R_SPARC_WDISP30 R_SPARC = 7 + R_SPARC_WDISP22 R_SPARC = 8 + R_SPARC_HI22 R_SPARC = 9 + R_SPARC_22 R_SPARC = 10 + R_SPARC_13 R_SPARC = 11 + R_SPARC_LO10 R_SPARC = 12 + R_SPARC_GOT10 R_SPARC = 13 + R_SPARC_GOT13 R_SPARC = 14 + R_SPARC_GOT22 R_SPARC = 15 + R_SPARC_PC10 R_SPARC = 16 + R_SPARC_PC22 R_SPARC = 17 + R_SPARC_WPLT30 R_SPARC = 18 + R_SPARC_COPY R_SPARC = 19 + R_SPARC_GLOB_DAT R_SPARC = 20 + R_SPARC_JMP_SLOT R_SPARC = 21 + R_SPARC_RELATIVE R_SPARC = 22 + R_SPARC_UA32 R_SPARC = 23 + R_SPARC_PLT32 R_SPARC = 24 + R_SPARC_HIPLT22 R_SPARC = 25 + R_SPARC_LOPLT10 R_SPARC = 26 + R_SPARC_PCPLT32 R_SPARC = 27 + R_SPARC_PCPLT22 R_SPARC = 28 + R_SPARC_PCPLT10 R_SPARC = 29 + R_SPARC_10 R_SPARC = 30 + R_SPARC_11 R_SPARC = 31 + R_SPARC_64 R_SPARC = 32 + R_SPARC_OLO10 R_SPARC = 33 + R_SPARC_HH22 R_SPARC = 34 + R_SPARC_HM10 R_SPARC = 35 + R_SPARC_LM22 R_SPARC = 36 + R_SPARC_PC_HH22 R_SPARC = 37 + R_SPARC_PC_HM10 R_SPARC = 38 + R_SPARC_PC_LM22 R_SPARC = 39 + R_SPARC_WDISP16 R_SPARC = 40 + R_SPARC_WDISP19 R_SPARC = 41 + R_SPARC_GLOB_JMP R_SPARC = 42 + R_SPARC_7 R_SPARC = 43 + R_SPARC_5 R_SPARC = 44 + R_SPARC_6 R_SPARC = 45 + R_SPARC_DISP64 R_SPARC = 46 + R_SPARC_PLT64 R_SPARC = 47 + R_SPARC_HIX22 R_SPARC = 48 + R_SPARC_LOX10 R_SPARC = 49 + R_SPARC_H44 R_SPARC = 50 + R_SPARC_M44 R_SPARC = 51 + R_SPARC_L44 R_SPARC = 52 + R_SPARC_REGISTER R_SPARC = 53 + R_SPARC_UA64 R_SPARC = 54 + R_SPARC_UA16 R_SPARC = 55 +) + +var rsparcStrings = []intName{ + {0, "R_SPARC_NONE"}, + {1, "R_SPARC_8"}, + {2, "R_SPARC_16"}, + {3, "R_SPARC_32"}, + {4, "R_SPARC_DISP8"}, + {5, "R_SPARC_DISP16"}, + {6, "R_SPARC_DISP32"}, + {7, "R_SPARC_WDISP30"}, + {8, "R_SPARC_WDISP22"}, + {9, "R_SPARC_HI22"}, + {10, "R_SPARC_22"}, + {11, "R_SPARC_13"}, + {12, "R_SPARC_LO10"}, + {13, "R_SPARC_GOT10"}, + {14, "R_SPARC_GOT13"}, + {15, "R_SPARC_GOT22"}, + {16, "R_SPARC_PC10"}, + {17, "R_SPARC_PC22"}, + {18, "R_SPARC_WPLT30"}, + {19, "R_SPARC_COPY"}, + {20, "R_SPARC_GLOB_DAT"}, + {21, "R_SPARC_JMP_SLOT"}, + {22, "R_SPARC_RELATIVE"}, + {23, "R_SPARC_UA32"}, + {24, "R_SPARC_PLT32"}, + {25, "R_SPARC_HIPLT22"}, + {26, "R_SPARC_LOPLT10"}, + {27, "R_SPARC_PCPLT32"}, + {28, "R_SPARC_PCPLT22"}, + {29, "R_SPARC_PCPLT10"}, + {30, "R_SPARC_10"}, + {31, "R_SPARC_11"}, + {32, "R_SPARC_64"}, + {33, "R_SPARC_OLO10"}, + {34, "R_SPARC_HH22"}, + {35, "R_SPARC_HM10"}, + {36, "R_SPARC_LM22"}, + {37, "R_SPARC_PC_HH22"}, + {38, "R_SPARC_PC_HM10"}, + {39, "R_SPARC_PC_LM22"}, + {40, "R_SPARC_WDISP16"}, + {41, "R_SPARC_WDISP19"}, + {42, "R_SPARC_GLOB_JMP"}, + {43, "R_SPARC_7"}, + {44, "R_SPARC_5"}, + {45, "R_SPARC_6"}, + {46, "R_SPARC_DISP64"}, + {47, "R_SPARC_PLT64"}, + {48, "R_SPARC_HIX22"}, + {49, "R_SPARC_LOX10"}, + {50, "R_SPARC_H44"}, + {51, "R_SPARC_M44"}, + {52, "R_SPARC_L44"}, + {53, "R_SPARC_REGISTER"}, + {54, "R_SPARC_UA64"}, + {55, "R_SPARC_UA16"}, +} + +func (i R_SPARC) String() string { return stringName(uint32(i), rsparcStrings, false) } +func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings, true) } + +// Magic number for the elf trampoline, chosen wisely to be an immediate value. +const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003 + +// ELF32 File header. +type Header32 struct { + Ident [EI_NIDENT]byte /* File identification. */ + Type uint16 /* File type. */ + Machine uint16 /* Machine architecture. */ + Version uint32 /* ELF format version. */ + Entry uint32 /* Entry point. */ + Phoff uint32 /* Program header file offset. */ + Shoff uint32 /* Section header file offset. */ + Flags uint32 /* Architecture-specific flags. */ + Ehsize uint16 /* Size of ELF header in bytes. */ + Phentsize uint16 /* Size of program header entry. */ + Phnum uint16 /* Number of program header entries. */ + Shentsize uint16 /* Size of section header entry. */ + Shnum uint16 /* Number of section header entries. */ + Shstrndx uint16 /* Section name strings section. */ +} + +// ELF32 Section header. +type Section32 struct { + Name uint32 /* Section name (index into the section header string table). */ + Type uint32 /* Section type. */ + Flags uint32 /* Section flags. */ + Addr uint32 /* Address in memory image. */ + Off uint32 /* Offset in file. */ + Size uint32 /* Size in bytes. */ + Link uint32 /* Index of a related section. */ + Info uint32 /* Depends on section type. */ + Addralign uint32 /* Alignment in bytes. */ + Entsize uint32 /* Size of each entry in section. */ +} + +// ELF32 Program header. +type Prog32 struct { + Type uint32 /* Entry type. */ + Off uint32 /* File offset of contents. */ + Vaddr uint32 /* Virtual address in memory image. */ + Paddr uint32 /* Physical address (not used). */ + Filesz uint32 /* Size of contents in file. */ + Memsz uint32 /* Size of contents in memory. */ + Flags uint32 /* Access permission flags. */ + Align uint32 /* Alignment in memory and file. */ +} + +// ELF32 Dynamic structure. The ".dynamic" section contains an array of them. +type Dyn32 struct { + Tag int32 /* Entry type. */ + Val uint32 /* Integer/Address value. */ +} + +// ELF32 Compression header. +type Chdr32 struct { + Type uint32 + Size uint32 + Addralign uint32 +} + +/* + * Relocation entries. + */ + +// ELF32 Relocations that don't need an addend field. +type Rel32 struct { + Off uint32 /* Location to be relocated. */ + Info uint32 /* Relocation type and symbol index. */ +} + +// ELF32 Relocations that need an addend field. +type Rela32 struct { + Off uint32 /* Location to be relocated. */ + Info uint32 /* Relocation type and symbol index. */ + Addend int32 /* Addend. */ +} + +func R_SYM32(info uint32) uint32 { return info >> 8 } +func R_TYPE32(info uint32) uint32 { return info & 0xff } +func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ } + +// ELF32 Symbol. +type Sym32 struct { + Name uint32 + Value uint32 + Size uint32 + Info uint8 + Other uint8 + Shndx uint16 +} + +const Sym32Size = 16 + +func ST_BIND(info uint8) SymBind { return SymBind(info >> 4) } +func ST_TYPE(info uint8) SymType { return SymType(info & 0xF) } +func ST_INFO(bind SymBind, typ SymType) uint8 { + return uint8(bind)<<4 | uint8(typ)&0xf +} +func ST_VISIBILITY(other uint8) SymVis { return SymVis(other & 3) } + +/* + * ELF64 + */ + +// ELF64 file header. +type Header64 struct { + Ident [EI_NIDENT]byte /* File identification. */ + Type uint16 /* File type. */ + Machine uint16 /* Machine architecture. */ + Version uint32 /* ELF format version. */ + Entry uint64 /* Entry point. */ + Phoff uint64 /* Program header file offset. */ + Shoff uint64 /* Section header file offset. */ + Flags uint32 /* Architecture-specific flags. */ + Ehsize uint16 /* Size of ELF header in bytes. */ + Phentsize uint16 /* Size of program header entry. */ + Phnum uint16 /* Number of program header entries. */ + Shentsize uint16 /* Size of section header entry. */ + Shnum uint16 /* Number of section header entries. */ + Shstrndx uint16 /* Section name strings section. */ +} + +// ELF64 Section header. +type Section64 struct { + Name uint32 /* Section name (index into the section header string table). */ + Type uint32 /* Section type. */ + Flags uint64 /* Section flags. */ + Addr uint64 /* Address in memory image. */ + Off uint64 /* Offset in file. */ + Size uint64 /* Size in bytes. */ + Link uint32 /* Index of a related section. */ + Info uint32 /* Depends on section type. */ + Addralign uint64 /* Alignment in bytes. */ + Entsize uint64 /* Size of each entry in section. */ +} + +// ELF64 Program header. +type Prog64 struct { + Type uint32 /* Entry type. */ + Flags uint32 /* Access permission flags. */ + Off uint64 /* File offset of contents. */ + Vaddr uint64 /* Virtual address in memory image. */ + Paddr uint64 /* Physical address (not used). */ + Filesz uint64 /* Size of contents in file. */ + Memsz uint64 /* Size of contents in memory. */ + Align uint64 /* Alignment in memory and file. */ +} + +// ELF64 Dynamic structure. The ".dynamic" section contains an array of them. +type Dyn64 struct { + Tag int64 /* Entry type. */ + Val uint64 /* Integer/address value */ +} + +// ELF64 Compression header. +type Chdr64 struct { + Type uint32 + _ uint32 /* Reserved. */ + Size uint64 + Addralign uint64 +} + +/* + * Relocation entries. + */ + +/* ELF64 relocations that don't need an addend field. */ +type Rel64 struct { + Off uint64 /* Location to be relocated. */ + Info uint64 /* Relocation type and symbol index. */ +} + +/* ELF64 relocations that need an addend field. */ +type Rela64 struct { + Off uint64 /* Location to be relocated. */ + Info uint64 /* Relocation type and symbol index. */ + Addend int64 /* Addend. */ +} + +func R_SYM64(info uint64) uint32 { return uint32(info >> 32) } +func R_TYPE64(info uint64) uint32 { return uint32(info) } +func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) } + +// ELF64 symbol table entries. +type Sym64 struct { + Name uint32 /* String table index of name. */ + Info uint8 /* Type and binding information. */ + Other uint8 /* Reserved (not used). */ + Shndx uint16 /* Section index of symbol. */ + Value uint64 /* Symbol value. */ + Size uint64 /* Size of associated object. */ +} + +const Sym64Size = 24 + +type intName struct { + i uint32 + s string +} + +func stringName(i uint32, names []intName, goSyntax bool) string { + for _, n := range names { + if n.i == i { + if goSyntax { + return "elf." + n.s + } + return n.s + } + } + + // second pass - look for smaller to add with. + // assume sorted already + for j := len(names) - 1; j >= 0; j-- { + n := names[j] + if n.i < i { + s := n.s + if goSyntax { + s = "elf." + s + } + return s + "+" + strconv.FormatUint(uint64(i-n.i), 10) + } + } + + return strconv.FormatUint(uint64(i), 10) +} + +func flagName(i uint32, names []intName, goSyntax bool) string { + s := "" + for _, n := range names { + if n.i&i == n.i { + if len(s) > 0 { + s += "+" + } + if goSyntax { + s += "elf." + } + s += n.s + i -= n.i + } + } + if len(s) == 0 { + return "0x" + strconv.FormatUint(uint64(i), 16) + } + if i != 0 { + s += "+0x" + strconv.FormatUint(uint64(i), 16) + } + return s +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/elf/file.go b/vendor/github.com/mandiant/GoReSym/debug/elf/file.go new file mode 100644 index 00000000..11bcc782 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/elf/file.go @@ -0,0 +1,1578 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Package elf implements access to ELF object files. +package elf + +import ( + "bytes" + "compress/zlib" + "encoding/binary" + "errors" + "fmt" + "io" + "os" + "strings" + + "github.com/mandiant/GoReSym/debug/dwarf" + "github.com/mandiant/GoReSym/saferio" +) + +// seekStart, seekCurrent, seekEnd are copies of +// io.SeekStart, io.SeekCurrent, and io.SeekEnd. +// We can't use the ones from package io because +// we want this code to build with Go 1.4 during +// cmd/dist bootstrap. +const ( + seekStart int = 0 + seekCurrent int = 1 + seekEnd int = 2 +) + +// TODO: error reporting detail + +/* + * Internal ELF representation + */ + +// A FileHeader represents an ELF file header. +type FileHeader struct { + Class Class + Data Data + Version Version + OSABI OSABI + ABIVersion uint8 + ByteOrder binary.ByteOrder + Type Type + Machine Machine + Entry uint64 +} + +// A File represents an open ELF file. +type File struct { + FileHeader + Sections []*Section + Progs []*Prog + closer io.Closer + gnuNeed []verneed + gnuVersym []byte + + dataAfterSectionCache map[uint64][]byte // secVA -> dataAfterSection +} + +// A SectionHeader represents a single ELF section header. +type SectionHeader struct { + Name string + Type SectionType + Flags SectionFlag + Addr uint64 + Offset uint64 + Size uint64 + Link uint32 + Info uint32 + Addralign uint64 + Entsize uint64 + + // FileSize is the size of this section in the file in bytes. + // If a section is compressed, FileSize is the size of the + // compressed data, while Size (above) is the size of the + // uncompressed data. + FileSize uint64 +} + +// A Section represents a single section in an ELF file. +type Section struct { + SectionHeader + + // Embed ReaderAt for ReadAt method. + // Do not embed SectionReader directly + // to avoid having Read and Seek. + // If a client wants Read and Seek it must use + // Open() to avoid fighting over the seek offset + // with other clients. + // + // ReaderAt may be nil if the section is not easily available + // in a random-access form. For example, a compressed section + // may have a nil ReaderAt. + io.ReaderAt + sr *io.SectionReader + + compressionType CompressionType + compressionOffset int64 +} + +// Data reads and returns the contents of the ELF section. +// Even if the section is stored compressed in the ELF file, +// Data returns uncompressed data. +func (s *Section) Data() ([]byte, error) { + dat := make([]byte, s.Size) + n, err := io.ReadFull(s.Open(), dat) + return dat[0:n], err +} + +// stringTable reads and returns the string table given by the +// specified link value. +func (f *File) stringTable(link uint32) ([]byte, error) { + if link <= 0 || link >= uint32(len(f.Sections)) { + return nil, errors.New("section has invalid string table link") + } + return f.Sections[link].Data() +} + +// Open returns a new ReadSeeker reading the ELF section. +// Even if the section is stored compressed in the ELF file, +// the ReadSeeker reads uncompressed data. +func (s *Section) Open() io.ReadSeeker { + if s.Flags&SHF_COMPRESSED == 0 { + return io.NewSectionReader(s.sr, 0, 1<<63-1) + } + if s.compressionType == COMPRESS_ZLIB { + return &readSeekerFromReader{ + reset: func() (io.Reader, error) { + fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset) + return zlib.NewReader(fr) + }, + size: int64(s.Size), + } + } + err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType} + return errorReader{err} +} + +// A ProgHeader represents a single ELF program header. +type ProgHeader struct { + Type ProgType + Flags ProgFlag + Off uint64 + Vaddr uint64 + Paddr uint64 + Filesz uint64 + Memsz uint64 + Align uint64 +} + +// A Prog represents a single ELF program header in an ELF binary. +type Prog struct { + ProgHeader + + // Embed ReaderAt for ReadAt method. + // Do not embed SectionReader directly + // to avoid having Read and Seek. + // If a client wants Read and Seek it must use + // Open() to avoid fighting over the seek offset + // with other clients. + io.ReaderAt + sr *io.SectionReader +} + +// Open returns a new ReadSeeker reading the ELF program body. +func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } + +// A Symbol represents an entry in an ELF symbol table section. +type Symbol struct { + Name string + Info, Other byte + Section SectionIndex + Value, Size uint64 + + // Version and Library are present only for the dynamic symbol + // table. + Version string + Library string +} + +/* + * ELF reader + */ + +type FormatError struct { + off int64 + msg string + val interface{} +} + +func (e *FormatError) Error() string { + msg := e.msg + if e.val != nil { + msg += fmt.Sprintf(" '%v' ", e.val) + } + msg += fmt.Sprintf("in record at byte %#x", e.off) + return msg +} + +// Open opens the named file using os.Open and prepares it for use as an ELF binary. +func Open(name string) (*File, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + ff, err := NewFile(f) + if err != nil { + f.Close() + return nil, err + } + ff.closer = f + return ff, nil +} + +// Close closes the File. +// If the File was created using NewFile directly instead of Open, +// Close has no effect. +func (f *File) Close() error { + var err error + if f.closer != nil { + err = f.closer.Close() + f.closer = nil + } + return err +} + +// SectionByType returns the first section in f with the +// given type, or nil if there is no such section. +func (f *File) SectionByType(typ SectionType) *Section { + for _, s := range f.Sections { + if s.Type == typ { + return s + } + } + return nil +} + +// NewFile creates a new File for accessing an ELF binary in an underlying reader. +// The ELF binary is expected to start at position 0 in the ReaderAt. +func NewFile(r io.ReaderAt) (*File, error) { + + sr := io.NewSectionReader(r, 0, 1<<63-1) + // Read and decode ELF identifier + var ident [16]uint8 + if _, err := r.ReadAt(ident[0:], 0); err != nil { + return nil, err + } + if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { + return nil, &FormatError{0, "bad magic number", ident[0:4]} + } + + f := new(File) + f.dataAfterSectionCache = make(map[uint64][]byte) + f.Class = Class(ident[EI_CLASS]) + switch f.Class { + case ELFCLASS32: + case ELFCLASS64: + // ok + default: + return nil, &FormatError{0, "unknown ELF class", f.Class} + } + + f.Data = Data(ident[EI_DATA]) + switch f.Data { + case ELFDATA2LSB: + f.ByteOrder = binary.LittleEndian + case ELFDATA2MSB: + f.ByteOrder = binary.BigEndian + default: + return nil, &FormatError{0, "unknown ELF data encoding", f.Data} + } + + f.Version = Version(ident[EI_VERSION]) + if f.Version != EV_CURRENT { + return nil, &FormatError{0, "unknown ELF version", f.Version} + } + + f.OSABI = OSABI(ident[EI_OSABI]) + f.ABIVersion = ident[EI_ABIVERSION] + + // Read ELF file header + var phoff int64 + var phentsize, phnum int + var shoff int64 + var shentsize, shnum, shstrndx int + switch f.Class { + case ELFCLASS32: + hdr := new(Header32) + sr.Seek(0, seekStart) + if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { + return nil, err + } + f.Type = Type(hdr.Type) + f.Machine = Machine(hdr.Machine) + f.Entry = uint64(hdr.Entry) + if v := Version(hdr.Version); v != f.Version { + return nil, &FormatError{0, "mismatched ELF version", v} + } + phoff = int64(hdr.Phoff) + phentsize = int(hdr.Phentsize) + phnum = int(hdr.Phnum) + shoff = int64(hdr.Shoff) + shentsize = int(hdr.Shentsize) + shnum = int(hdr.Shnum) + shstrndx = int(hdr.Shstrndx) + case ELFCLASS64: + hdr := new(Header64) + sr.Seek(0, seekStart) + if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { + return nil, err + } + f.Type = Type(hdr.Type) + f.Machine = Machine(hdr.Machine) + f.Entry = hdr.Entry + if v := Version(hdr.Version); v != f.Version { + return nil, &FormatError{0, "mismatched ELF version", v} + } + phoff = int64(hdr.Phoff) + phentsize = int(hdr.Phentsize) + phnum = int(hdr.Phnum) + shoff = int64(hdr.Shoff) + shentsize = int(hdr.Shentsize) + shnum = int(hdr.Shnum) + shstrndx = int(hdr.Shstrndx) + } + + if shoff < 0 { + return nil, &FormatError{0, "invalid shoff", shoff} + } + if phoff < 0 { + return nil, &FormatError{0, "invalid phoff", phoff} + } + + if shoff == 0 && shnum != 0 { + return nil, &FormatError{0, "invalid ELF shnum for shoff=0", shnum} + } + + if shnum > 0 && shstrndx >= shnum { + return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} + } + + var wantPhentsize, wantShentsize int + switch f.Class { + case ELFCLASS32: + wantPhentsize = 8 * 4 + wantShentsize = 10 * 4 + case ELFCLASS64: + wantPhentsize = 2*4 + 6*8 + wantShentsize = 4*4 + 6*8 + } + if phnum > 0 && phentsize < wantPhentsize { + return nil, &FormatError{0, "invalid ELF phentsize", phentsize} + } + + // Read program headers + f.Progs = make([]*Prog, phnum) + for i := 0; i < phnum; i++ { + off := phoff + int64(i)*int64(phentsize) + sr.Seek(off, seekStart) + p := new(Prog) + switch f.Class { + case ELFCLASS32: + ph := new(Prog32) + if err := binary.Read(sr, f.ByteOrder, ph); err != nil { + return nil, err + } + p.ProgHeader = ProgHeader{ + Type: ProgType(ph.Type), + Flags: ProgFlag(ph.Flags), + Off: uint64(ph.Off), + Vaddr: uint64(ph.Vaddr), + Paddr: uint64(ph.Paddr), + Filesz: uint64(ph.Filesz), + Memsz: uint64(ph.Memsz), + Align: uint64(ph.Align), + } + case ELFCLASS64: + ph := new(Prog64) + if err := binary.Read(sr, f.ByteOrder, ph); err != nil { + return nil, err + } + p.ProgHeader = ProgHeader{ + Type: ProgType(ph.Type), + Flags: ProgFlag(ph.Flags), + Off: ph.Off, + Vaddr: ph.Vaddr, + Paddr: ph.Paddr, + Filesz: ph.Filesz, + Memsz: ph.Memsz, + Align: ph.Align, + } + } + if int64(p.Off) < 0 { + return nil, &FormatError{off, "invalid program header offset", p.Off} + } + if int64(p.Filesz) < 0 { + return nil, &FormatError{off, "invalid program header file size", p.Filesz} + } + p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) + p.ReaderAt = p.sr + f.Progs[i] = p + } + + // If the number of sections is greater than or equal to SHN_LORESERVE + // (0xff00), shnum has the value zero and the actual number of section + // header table entries is contained in the sh_size field of the section + // header at index 0. + if shoff > 0 && shnum == 0 { + var typ, link uint32 + sr.Seek(shoff, seekStart) + switch f.Class { + case ELFCLASS32: + sh := new(Section32) + if err := binary.Read(sr, f.ByteOrder, sh); err != nil { + return nil, err + } + shnum = int(sh.Size) + typ = sh.Type + link = sh.Link + case ELFCLASS64: + sh := new(Section64) + if err := binary.Read(sr, f.ByteOrder, sh); err != nil { + return nil, err + } + shnum = int(sh.Size) + typ = sh.Type + link = sh.Link + } + if SectionType(typ) != SHT_NULL { + return nil, &FormatError{shoff, "invalid type of the initial section", SectionType(typ)} + } + + if shnum < int(SHN_LORESERVE) { + return nil, &FormatError{shoff, "invalid ELF shnum contained in sh_size", shnum} + } + + // If the section name string table section index is greater than or + // equal to SHN_LORESERVE (0xff00), this member has the value + // SHN_XINDEX (0xffff) and the actual index of the section name + // string table section is contained in the sh_link field of the + // section header at index 0. + if shstrndx == int(SHN_XINDEX) { + shstrndx = int(link) + if shstrndx < int(SHN_LORESERVE) { + return nil, &FormatError{shoff, "invalid ELF shstrndx contained in sh_link", shstrndx} + } + } + } + + if shnum > 0 && shentsize < wantShentsize { + return nil, &FormatError{0, "invalid ELF shentsize", shentsize} + } + + // Read section headers + c := saferio.SliceCap((*Section)(nil), uint64(shnum)) + if c < 0 { + return nil, &FormatError{0, "too many sections", shnum} + } + f.Sections = make([]*Section, 0, c) + names := make([]uint32, 0, c) + for i := 0; i < shnum; i++ { + off := shoff + int64(i)*int64(shentsize) + sr.Seek(off, seekStart) + s := new(Section) + switch f.Class { + case ELFCLASS32: + sh := new(Section32) + if err := binary.Read(sr, f.ByteOrder, sh); err != nil { + return nil, err + } + names = append(names, sh.Name) + s.SectionHeader = SectionHeader{ + Type: SectionType(sh.Type), + Flags: SectionFlag(sh.Flags), + Addr: uint64(sh.Addr), + Offset: uint64(sh.Off), + FileSize: uint64(sh.Size), + Link: sh.Link, + Info: sh.Info, + Addralign: uint64(sh.Addralign), + Entsize: uint64(sh.Entsize), + } + case ELFCLASS64: + sh := new(Section64) + if err := binary.Read(sr, f.ByteOrder, sh); err != nil { + return nil, err + } + names = append(names, sh.Name) + s.SectionHeader = SectionHeader{ + Type: SectionType(sh.Type), + Flags: SectionFlag(sh.Flags), + Offset: sh.Off, + FileSize: sh.Size, + Addr: sh.Addr, + Link: sh.Link, + Info: sh.Info, + Addralign: sh.Addralign, + Entsize: sh.Entsize, + } + } + if int64(s.Offset) < 0 { + return nil, &FormatError{off, "invalid section offset", int64(s.Offset)} + } + if int64(s.FileSize) < 0 { + return nil, &FormatError{off, "invalid section size", int64(s.FileSize)} + } + s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize)) + + if s.Flags&SHF_COMPRESSED == 0 { + s.ReaderAt = s.sr + s.Size = s.FileSize + } else { + // Read the compression header. + switch f.Class { + case ELFCLASS32: + ch := new(Chdr32) + if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { + return nil, err + } + s.compressionType = CompressionType(ch.Type) + s.Size = uint64(ch.Size) + s.Addralign = uint64(ch.Addralign) + s.compressionOffset = int64(binary.Size(ch)) + case ELFCLASS64: + ch := new(Chdr64) + if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { + return nil, err + } + s.compressionType = CompressionType(ch.Type) + s.Size = ch.Size + s.Addralign = ch.Addralign + s.compressionOffset = int64(binary.Size(ch)) + } + } + + f.Sections = append(f.Sections, s) + } + + if len(f.Sections) == 0 { + return f, nil + } + + // Load section header string table. + if shstrndx == 0 { + // If the file has no section name string table, + // shstrndx holds the value SHN_UNDEF (0). + return f, nil + } + shstr := f.Sections[shstrndx] + if shstr.Type != SHT_STRTAB { + return nil, &FormatError{shoff + int64(shstrndx*shentsize), "invalid ELF section name string table type", shstr.Type} + } + shstrtab, err := shstr.Data() + if err != nil { + return nil, err + } + for i, s := range f.Sections { + var ok bool + s.Name, ok = getString(shstrtab, int(names[i])) + if !ok { + return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} + } + } + return f, nil +} + +// getSymbols returns a slice of Symbols from parsing the symbol table +// with the given type, along with the associated string table. +func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { + switch f.Class { + case ELFCLASS64: + return f.getSymbols64(typ) + + case ELFCLASS32: + return f.getSymbols32(typ) + } + + return nil, nil, errors.New("not implemented") +} + +// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols +// if there is no such section in the File. +var ErrNoSymbols = errors.New("no symbol section") + +func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { + symtabSection := f.SectionByType(typ) + if symtabSection == nil { + return nil, nil, ErrNoSymbols + } + + data, err := symtabSection.Data() + if err != nil { + return nil, nil, errors.New("cannot load symbol section") + } + symtab := bytes.NewReader(data) + if symtab.Len()%Sym32Size != 0 { + return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") + } + + strdata, err := f.stringTable(symtabSection.Link) + if err != nil { + return nil, nil, errors.New("cannot load string table section") + } + + // The first entry is all zeros. + var skip [Sym32Size]byte + symtab.Read(skip[:]) + + symbols := make([]Symbol, symtab.Len()/Sym32Size) + + i := 0 + var sym Sym32 + for symtab.Len() > 0 { + binary.Read(symtab, f.ByteOrder, &sym) + str, _ := getString(strdata, int(sym.Name)) + symbols[i].Name = str + symbols[i].Info = sym.Info + symbols[i].Other = sym.Other + symbols[i].Section = SectionIndex(sym.Shndx) + symbols[i].Value = uint64(sym.Value) + symbols[i].Size = uint64(sym.Size) + i++ + } + + return symbols, strdata, nil +} + +func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { + symtabSection := f.SectionByType(typ) + if symtabSection == nil { + return nil, nil, ErrNoSymbols + } + + data, err := symtabSection.Data() + if err != nil { + return nil, nil, errors.New("cannot load symbol section") + } + symtab := bytes.NewReader(data) + if symtab.Len()%Sym64Size != 0 { + return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") + } + + strdata, err := f.stringTable(symtabSection.Link) + if err != nil { + return nil, nil, errors.New("cannot load string table section") + } + + // The first entry is all zeros. + var skip [Sym64Size]byte + symtab.Read(skip[:]) + + symbols := make([]Symbol, symtab.Len()/Sym64Size) + + i := 0 + var sym Sym64 + for symtab.Len() > 0 { + binary.Read(symtab, f.ByteOrder, &sym) + str, _ := getString(strdata, int(sym.Name)) + symbols[i].Name = str + symbols[i].Info = sym.Info + symbols[i].Other = sym.Other + symbols[i].Section = SectionIndex(sym.Shndx) + symbols[i].Value = sym.Value + symbols[i].Size = sym.Size + i++ + } + + return symbols, strdata, nil +} + +// getString extracts a string from an ELF string table. +func getString(section []byte, start int) (string, bool) { + if start < 0 || start >= len(section) { + return "", false + } + + for end := start; end < len(section); end++ { + if section[end] == 0 { + return string(section[start:end]), true + } + } + return "", false +} + +func (f *File) DataAfterSection(target *Section) []byte { + if cached, ok := f.dataAfterSectionCache[uint64(target.Addr)]; ok { + return cached + } + + data := []byte{} + found := false + for _, s := range f.Sections { + if s.Addr == target.Addr && s.Name == target.Name { + found = true + } + + if found { + raw, err := s.Data() + if raw != nil { + data = append(data, raw[:]...) + } + + if err != nil { + break + } + } + } + + f.dataAfterSectionCache[uint64(target.Addr)] = data + return data +} + +// Section returns a section with the given name, or nil if no such +// section exists. +func (f *File) Section(name string) *Section { + for _, s := range f.Sections { + if s.Name == name { + return s + } + } + return nil +} + +// applyRelocations applies relocations to dst. rels is a relocations section +// in REL or RELA format. +func (f *File) applyRelocations(dst []byte, rels []byte) error { + switch { + case f.Class == ELFCLASS64 && f.Machine == EM_X86_64: + return f.applyRelocationsAMD64(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_386: + return f.applyRelocations386(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_ARM: + return f.applyRelocationsARM(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64: + return f.applyRelocationsARM64(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_PPC: + return f.applyRelocationsPPC(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_PPC64: + return f.applyRelocationsPPC64(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_MIPS: + return f.applyRelocationsMIPS(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_MIPS: + return f.applyRelocationsMIPS64(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_RISCV: + return f.applyRelocationsRISCV64(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_S390: + return f.applyRelocationss390x(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9: + return f.applyRelocationsSPARC64(dst, rels) + default: + return errors.New("applyRelocations: not implemented") + } +} + +// canApplyRelocation reports whether we should try to apply a +// relocation to a DWARF data section, given a pointer to the symbol +// targeted by the relocation. +// Most relocations in DWARF data tend to be section-relative, but +// some target non-section symbols (for example, low_PC attrs on +// subprogram or compilation unit DIEs that target function symbols). +func canApplyRelocation(sym *Symbol) bool { + return sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE +} + +func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_X86_64(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if !canApplyRelocation(sym) { + continue + } + + // There are relocations, so this must be a normal + // object file. The code below handles only basic relocations + // of the form S + A (symbol plus addend). + + switch t { + case R_X86_64_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val64 := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) + case R_X86_64_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + +func (f *File) applyRelocations386(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_386(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + if t == R_386_32 { + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + +func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_ARM(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + switch t { + case R_ARM_ABS32: + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + +func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_AARCH64(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if !canApplyRelocation(sym) { + continue + } + + // There are relocations, so this must be a normal + // object file. The code below handles only basic relocations + // of the form S + A (symbol plus addend). + + switch t { + case R_AARCH64_ABS64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val64 := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) + case R_AARCH64_ABS32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + +func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { + // 12 is the size of Rela32. + if len(rels)%12 != 0 { + return errors.New("length of relocation section is not a multiple of 12") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 8 + t := R_PPC(rela.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if !canApplyRelocation(sym) { + continue + } + + switch t { + case R_PPC_ADDR32: + if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + +func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_PPC64(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if !canApplyRelocation(sym) { + continue + } + + switch t { + case R_PPC64_ADDR64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val64 := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) + case R_PPC64_ADDR32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + +func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_MIPS(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + switch t { + case R_MIPS_32: + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + +func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + var symNo uint64 + var t R_MIPS + if f.ByteOrder == binary.BigEndian { + symNo = rela.Info >> 32 + t = R_MIPS(rela.Info & 0xff) + } else { + symNo = rela.Info & 0xffffffff + t = R_MIPS(rela.Info >> 56) + } + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if !canApplyRelocation(sym) { + continue + } + + switch t { + case R_MIPS_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val64 := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) + case R_MIPS_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + +func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_RISCV(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if !canApplyRelocation(sym) { + continue + } + + switch t { + case R_RISCV_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val64 := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) + case R_RISCV_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + +func (f *File) applyRelocationss390x(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_390(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if !canApplyRelocation(sym) { + continue + } + + switch t { + case R_390_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val64 := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) + case R_390_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + +func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_SPARC(rela.Info & 0xff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if !canApplyRelocation(sym) { + continue + } + + switch t { + case R_SPARC_64, R_SPARC_UA64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val64 := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64) + case R_SPARC_32, R_SPARC_UA32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + +func (f *File) DWARF() (*dwarf.Data, error) { + dwarfSuffix := func(s *Section) string { + switch { + case strings.HasPrefix(s.Name, ".debug_"): + return s.Name[7:] + case strings.HasPrefix(s.Name, ".zdebug_"): + return s.Name[8:] + default: + return "" + } + + } + // sectionData gets the data for s, checks its size, and + // applies any applicable relations. + sectionData := func(i int, s *Section) ([]byte, error) { + b, err := s.Data() + if err != nil && uint64(len(b)) < s.Size { + return nil, err + } + + if len(b) >= 12 && string(b[:4]) == "ZLIB" { + dlen := binary.BigEndian.Uint64(b[4:12]) + dbuf := make([]byte, dlen) + r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) + if err != nil { + return nil, err + } + if _, err := io.ReadFull(r, dbuf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } + b = dbuf + } + + for _, r := range f.Sections { + if r.Type != SHT_RELA && r.Type != SHT_REL { + continue + } + if int(r.Info) != i { + continue + } + rd, err := r.Data() + if err != nil { + return nil, err + } + err = f.applyRelocations(b, rd) + if err != nil { + return nil, err + } + } + return b, nil + } + + // There are many DWARf sections, but these are the ones + // the debug/dwarf package started with. + var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix == "" { + continue + } + if _, ok := dat[suffix]; !ok { + continue + } + b, err := sectionData(i, s) + if err != nil { + return nil, err + } + dat[suffix] = b + } + + d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) + if err != nil { + return nil, err + } + + // Look for DWARF4 .debug_types sections and DWARF5 sections. + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix == "" { + continue + } + if _, ok := dat[suffix]; ok { + // Already handled. + continue + } + + b, err := sectionData(i, s) + if err != nil { + return nil, err + } + + if suffix == "types" { + if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil { + return nil, err + } + } else { + if err := d.AddSection(".debug_"+suffix, b); err != nil { + return nil, err + } + } + } + + return d, nil +} + +// Symbols returns the symbol table for f. The symbols will be listed in the order +// they appear in f. +// +// For compatibility with Go 1.0, Symbols omits the null symbol at index 0. +// After retrieving the symbols as symtab, an externally supplied index x +// corresponds to symtab[x-1], not symtab[x]. +func (f *File) Symbols() ([]Symbol, error) { + sym, _, err := f.getSymbols(SHT_SYMTAB) + return sym, err +} + +// DynamicSymbols returns the dynamic symbol table for f. The symbols +// will be listed in the order they appear in f. +// +// If f has a symbol version table, the returned Symbols will have +// initialized Version and Library fields. +// +// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. +// After retrieving the symbols as symtab, an externally supplied index x +// corresponds to symtab[x-1], not symtab[x]. +func (f *File) DynamicSymbols() ([]Symbol, error) { + sym, str, err := f.getSymbols(SHT_DYNSYM) + if err != nil { + return nil, err + } + if f.gnuVersionInit(str) { + for i := range sym { + sym[i].Library, sym[i].Version = f.gnuVersion(i) + } + } + return sym, nil +} + +type ImportedSymbol struct { + Name string + Version string + Library string +} + +// ImportedSymbols returns the names of all symbols +// referred to by the binary f that are expected to be +// satisfied by other libraries at dynamic load time. +// It does not return weak symbols. +func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { + sym, str, err := f.getSymbols(SHT_DYNSYM) + if err != nil { + return nil, err + } + f.gnuVersionInit(str) + var all []ImportedSymbol + for i, s := range sym { + if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { + all = append(all, ImportedSymbol{Name: s.Name}) + sym := &all[len(all)-1] + sym.Library, sym.Version = f.gnuVersion(i) + } + } + return all, nil +} + +type verneed struct { + File string + Name string +} + +// gnuVersionInit parses the GNU version tables +// for use by calls to gnuVersion. +func (f *File) gnuVersionInit(str []byte) bool { + if f.gnuNeed != nil { + // Already initialized + return true + } + + // Accumulate verneed information. + vn := f.SectionByType(SHT_GNU_VERNEED) + if vn == nil { + return false + } + d, _ := vn.Data() + + var need []verneed + i := 0 + for { + if i+16 > len(d) { + break + } + vers := f.ByteOrder.Uint16(d[i : i+2]) + if vers != 1 { + break + } + cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) + fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) + aux := f.ByteOrder.Uint32(d[i+8 : i+12]) + next := f.ByteOrder.Uint32(d[i+12 : i+16]) + file, _ := getString(str, int(fileoff)) + + var name string + j := i + int(aux) + for c := 0; c < int(cnt); c++ { + if j+16 > len(d) { + break + } + // hash := f.ByteOrder.Uint32(d[j:j+4]) + // flags := f.ByteOrder.Uint16(d[j+4:j+6]) + other := f.ByteOrder.Uint16(d[j+6 : j+8]) + nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) + next := f.ByteOrder.Uint32(d[j+12 : j+16]) + name, _ = getString(str, int(nameoff)) + ndx := int(other) + if ndx >= len(need) { + a := make([]verneed, 2*(ndx+1)) + copy(a, need) + need = a + } + + need[ndx] = verneed{file, name} + if next == 0 { + break + } + j += int(next) + } + + if next == 0 { + break + } + i += int(next) + } + + // Versym parallels symbol table, indexing into verneed. + vs := f.SectionByType(SHT_GNU_VERSYM) + if vs == nil { + return false + } + d, _ = vs.Data() + + f.gnuNeed = need + f.gnuVersym = d + return true +} + +// gnuVersion adds Library and Version information to sym, +// which came from offset i of the symbol table. +func (f *File) gnuVersion(i int) (library string, version string) { + // Each entry is two bytes. + i = (i + 1) * 2 + if i >= len(f.gnuVersym) { + return + } + j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) + if j < 2 || j >= len(f.gnuNeed) { + return + } + n := &f.gnuNeed[j] + return n.File, n.Name +} + +// ImportedLibraries returns the names of all libraries +// referred to by the binary f that are expected to be +// linked with the binary at dynamic link time. +func (f *File) ImportedLibraries() ([]string, error) { + return f.DynString(DT_NEEDED) +} + +// DynString returns the strings listed for the given tag in the file's dynamic +// section. +// +// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or +// DT_RUNPATH. +func (f *File) DynString(tag DynTag) ([]string, error) { + switch tag { + case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: + default: + return nil, fmt.Errorf("non-string-valued tag %v", tag) + } + ds := f.SectionByType(SHT_DYNAMIC) + if ds == nil { + // not dynamic, so no libraries + return nil, nil + } + d, err := ds.Data() + if err != nil { + return nil, err + } + str, err := f.stringTable(ds.Link) + if err != nil { + return nil, err + } + var all []string + for len(d) > 0 { + var t DynTag + var v uint64 + switch f.Class { + case ELFCLASS32: + t = DynTag(f.ByteOrder.Uint32(d[0:4])) + v = uint64(f.ByteOrder.Uint32(d[4:8])) + d = d[8:] + case ELFCLASS64: + t = DynTag(f.ByteOrder.Uint64(d[0:8])) + v = f.ByteOrder.Uint64(d[8:16]) + d = d[16:] + } + if t == tag { + s, ok := getString(str, int(v)) + if ok { + all = append(all, s) + } + } + } + return all, nil +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/elf/reader.go b/vendor/github.com/mandiant/GoReSym/debug/elf/reader.go new file mode 100644 index 00000000..8de2d3c7 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/elf/reader.go @@ -0,0 +1,110 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package elf + +import ( + "io" + "os" +) + +// errorReader returns error from all operations. +type errorReader struct { + error +} + +func (r errorReader) Read(p []byte) (n int, err error) { + return 0, r.error +} + +func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) { + return 0, r.error +} + +func (r errorReader) Seek(offset int64, whence int) (int64, error) { + return 0, r.error +} + +func (r errorReader) Close() error { + return r.error +} + +// readSeekerFromReader converts an io.Reader into an io.ReadSeeker. +// In general Seek may not be efficient, but it is optimized for +// common cases such as seeking to the end to find the length of the +// data. +type readSeekerFromReader struct { + reset func() (io.Reader, error) + r io.Reader + size int64 + offset int64 +} + +func (r *readSeekerFromReader) start() { + x, err := r.reset() + if err != nil { + r.r = errorReader{err} + } else { + r.r = x + } + r.offset = 0 +} + +func (r *readSeekerFromReader) Read(p []byte) (n int, err error) { + if r.r == nil { + r.start() + } + n, err = r.r.Read(p) + r.offset += int64(n) + return n, err +} + +func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) { + var newOffset int64 + switch whence { + case seekStart: + newOffset = offset + case seekCurrent: + newOffset = r.offset + offset + case seekEnd: + newOffset = r.size + offset + default: + return 0, os.ErrInvalid + } + + switch { + case newOffset == r.offset: + return newOffset, nil + + case newOffset < 0, newOffset > r.size: + return 0, os.ErrInvalid + + case newOffset == 0: + r.r = nil + + case newOffset == r.size: + r.r = errorReader{io.EOF} + + default: + if newOffset < r.offset { + // Restart at the beginning. + r.start() + } + // Read until we reach offset. + var buf [512]byte + for r.offset < newOffset { + b := buf[:] + if newOffset-r.offset < int64(len(buf)) { + b = buf[:newOffset-r.offset] + } + if _, err := r.Read(b); err != nil { + return 0, err + } + } + } + r.offset = newOffset + return r.offset, nil +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/gosym/pclntab.go b/vendor/github.com/mandiant/GoReSym/debug/gosym/pclntab.go new file mode 100644 index 00000000..ce36b074 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/gosym/pclntab.go @@ -0,0 +1,746 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +/* + * Line tables + */ + +package gosym + +import ( + "bytes" + "encoding/binary" + "fmt" + "sort" + "strings" + "sync" +) + +// version of the pclntab +type version int + +const ( + verUnknown version = iota + ver11 + ver12 + ver116 + ver118 + ver120 +) + +func (v version) String() string { + switch v { + case verUnknown: + return "Unknown" + case ver11: + return "1.1" + case ver12: + return "1.2" + case ver116: + return "1.16" + case ver118: + return "1.18" + case ver120: + return "1.20" + default: + return fmt.Sprintf("ERROR Unknown ID number %d", int(v)) + } +} + +// A LineTable is a data structure mapping program counters to line numbers. +// +// In Go 1.1 and earlier, each function (represented by a Func) had its own LineTable, +// and the line number corresponded to a numbering of all source lines in the +// program, across all files. That absolute line number would then have to be +// converted separately to a file name and line number within the file. +// +// In Go 1.2, the format of the data changed so that there is a single LineTable +// for the entire program, shared by all Funcs, and there are no absolute line +// numbers, just line numbers within specific files. +// +// For the most part, LineTable's methods should be treated as an internal +// detail of the package; callers should use the methods on Table instead. +type LineTable struct { + Data []byte + PC uint64 + Line int + + // This mutex is used to keep parsing of pclntab synchronous. + mu sync.Mutex + + // Contains the version of the pclntab section. + Version version + + // Go 1.2/1.16/1.18 state + Binary binary.ByteOrder + Quantum uint32 + Ptrsize uint32 + textStart uint64 // address of runtime.text symbol (1.18+) + funcnametab []byte + cutab []byte + funcdata []byte + functab []byte + nfunctab uint32 + filetab []byte + pctab []byte // points to the pctables. + nfiletab uint32 + funcNames map[uint32]string // cache the function names + strings map[uint32]string // interned substrings of Data, keyed by offset + // fileMap varies depending on the version of the object file. + // For ver12, it maps the name to the index in the file table. + // For ver116, it maps the name to the offset in filetab. + fileMap map[string]uint32 +} + +// NOTE(rsc): This is wrong for GOARCH=arm, which uses a quantum of 4, +// but we have no idea whether we're using arm or not. This only +// matters in the old (pre-Go 1.2) symbol table format, so it's not worth +// fixing. +const oldQuantum = 1 + +func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) { + // The PC/line table can be thought of as a sequence of + // * + // batches. Each update batch results in a (pc, line) pair, + // where line applies to every PC from pc up to but not + // including the pc of the next pair. + // + // Here we process each update individually, which simplifies + // the code, but makes the corner cases more confusing. + b, pc, line = t.Data, t.PC, t.Line + for pc <= targetPC && line != targetLine && len(b) > 0 { + code := b[0] + b = b[1:] + switch { + case code == 0: + if len(b) < 4 { + b = b[0:0] + break + } + val := binary.BigEndian.Uint32(b) + b = b[4:] + line += int(val) + case code <= 64: + line += int(code) + case code <= 128: + line -= int(code - 64) + default: + pc += oldQuantum * uint64(code-128) + continue + } + pc += oldQuantum + } + return b, pc, line +} + +func (t *LineTable) slice(pc uint64) *LineTable { + data, pc, line := t.parse(pc, -1) + return &LineTable{Data: data, PC: pc, Line: line} +} + +// PCToLine returns the line number for the given program counter. +// +// Deprecated: Use Table's PCToLine method instead. +func (t *LineTable) PCToLine(pc uint64) int { + if t.isGo12("") { + return t.go12PCToLine(pc) + } + _, _, line := t.parse(pc, -1) + return line +} + +// LineToPC returns the program counter for the given line number, +// considering only program counters before maxpc. +// +// Deprecated: Use Table's LineToPC method instead. +func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 { + if t.isGo12("") { + return 0 + } + _, pc, line1 := t.parse(maxpc, line) + if line1 != line { + return 0 + } + // Subtract quantum from PC to account for post-line increment + return pc - oldQuantum +} + +// NewLineTable returns a new PC/line table +// corresponding to the encoded data. +// Text must be the start address of the +// corresponding text segment. +func NewLineTable(data []byte, text uint64) *LineTable { + return &LineTable{Data: data, PC: text, Line: 0, funcNames: make(map[uint32]string), strings: make(map[uint32]string)} +} + +// Go 1.2 symbol table format. +// See golang.org/s/go12symtab. +// +// A general note about the methods here: rather than try to avoid +// index out of bounds errors, we trust Go to detect them, and then +// we recover from the panics and treat them as indicative of a malformed +// or incomplete table. +// +// The methods called by symtab.go, which begin with "go12" prefixes, +// are expected to have that recovery logic. + +// isGo12 reports whether this is a Go 1.2 (or later) symbol table. +func (t *LineTable) isGo12(versionOverride string) bool { + t.parsePclnTab(versionOverride) + return t.Version >= ver12 +} + +const ( + go12magic = 0xfffffffb + go116magic = 0xfffffffa + go118magic = 0xfffffff0 + go120magic = 0xfffffff1 +) + +// uintptr returns the pointer-sized value encoded at b. +// The pointer size is dictated by the table being read. +func (t *LineTable) uintptr(b []byte) uint64 { + if t.Ptrsize == 4 { + return uint64(t.Binary.Uint32(b)) + } + return t.Binary.Uint64(b) +} + +// parsePclnTab parses the pclntab, setting the version. +func (t *LineTable) parsePclnTab(versionOverride string) { + t.mu.Lock() + defer t.mu.Unlock() + if t.Version != verUnknown { + return + } + + // Note that during this function, setting the version is the last thing we do. + // If we set the version too early, and parsing failed (likely as a panic on + // slice lookups), we'd have a mistaken version. + // + // Error paths through this code will default the version to 1.1. + t.Version = ver11 + + if !disableRecover { + defer func() { + // If we panic parsing, assume it's a Go 1.1 pclntab. + recover() + }() + } + + // Check header: 4-byte magic, two zeros, pc quantum, pointer size. + if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 || + (t.Data[6] != 1 && t.Data[6] != 2 && t.Data[6] != 4) || // pc quantum + (t.Data[7] != 4 && t.Data[7] != 8) { // pointer size + return + } + + var possibleVersion version + leMagic := binary.LittleEndian.Uint32(t.Data) + beMagic := binary.BigEndian.Uint32(t.Data) + switch { + case leMagic == go12magic: + t.Binary, possibleVersion = binary.LittleEndian, ver12 + case beMagic == go12magic: + t.Binary, possibleVersion = binary.BigEndian, ver12 + case leMagic == go116magic: + t.Binary, possibleVersion = binary.LittleEndian, ver116 + case beMagic == go116magic: + t.Binary, possibleVersion = binary.BigEndian, ver116 + case leMagic == go118magic: + t.Binary, possibleVersion = binary.LittleEndian, ver118 + case beMagic == go118magic: + t.Binary, possibleVersion = binary.BigEndian, ver118 + case leMagic == go120magic: + t.Binary, possibleVersion = binary.LittleEndian, ver120 + case beMagic == go120magic: + t.Binary, possibleVersion = binary.BigEndian, ver120 + default: + return + } + t.Version = possibleVersion + + if len(versionOverride) > 0 { + if strings.Contains(versionOverride, "1.20") { + t.Version = ver120 + } else if strings.Contains(versionOverride, "1.19") { + t.Version = ver118 + } else if strings.Contains(versionOverride, "1.18") { + t.Version = ver118 + } else if strings.Contains(versionOverride, "1.17") { + t.Version = ver116 + } else if strings.Contains(versionOverride, "1.16") { + t.Version = ver116 + } else if strings.Contains(versionOverride, "1.15") { + t.Version = ver12 + } else if strings.Contains(versionOverride, "1.14") { + t.Version = ver12 + } else if strings.Contains(versionOverride, "1.13") { + t.Version = ver12 + } else if strings.Contains(versionOverride, "1.12") { + t.Version = ver12 + } else if strings.Contains(versionOverride, "1.11") { + t.Version = ver11 + } else { + t.Version = ver11 + } + } + + // quantum and ptrSize are the same between 1.2, 1.16, and 1.18 + t.Quantum = uint32(t.Data[6]) + t.Ptrsize = uint32(t.Data[7]) + + offset := func(word uint32) uint64 { + return t.uintptr(t.Data[8+word*t.Ptrsize:]) + } + data := func(word uint32) []byte { + return t.Data[offset(word):] + } + + switch t.Version { + case ver118, ver120: + t.nfunctab = uint32(offset(0)) + t.nfiletab = uint32(offset(1)) + t.textStart = t.PC // use the start PC instead of reading from the table, which may be unrelocated + t.funcnametab = data(3) + t.cutab = data(4) + t.filetab = data(5) + t.pctab = data(6) + t.funcdata = data(7) + t.functab = data(7) + functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize() + t.functab = t.functab[:functabsize] + case ver116: + t.nfunctab = uint32(offset(0)) + t.nfiletab = uint32(offset(1)) + t.funcnametab = data(2) + t.cutab = data(3) + t.filetab = data(4) + t.pctab = data(5) + t.funcdata = data(6) + t.functab = data(6) + functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize() + t.functab = t.functab[:functabsize] + case ver12: + t.nfunctab = uint32(t.uintptr(t.Data[8:])) + t.funcdata = t.Data + t.funcnametab = t.Data + t.functab = t.Data[8+t.Ptrsize:] + t.pctab = t.Data + functabsize := (int(t.nfunctab)*2 + 1) * t.functabFieldSize() + fileoff := t.Binary.Uint32(t.functab[functabsize:]) + t.functab = t.functab[:functabsize] + t.filetab = t.Data[fileoff:] + t.nfiletab = t.Binary.Uint32(t.filetab) + t.filetab = t.filetab[:t.nfiletab*4] + default: + panic("unreachable") + } +} + +// go12Funcs returns a slice of Funcs derived from the Go 1.2+ pcln table. +func (t *LineTable) go12Funcs() []Func { + // Assume it is malformed and return nil on error. + if !disableRecover { + defer func() { + recover() + }() + } + + // avoid OOM error on corrupt binaries + // empirically gathered. Most binaries are <= UINT16_MAX, but some truly huge have >= 100000 functions + ft := t.funcTab() + if ft.Count() >= 350000 { + return make([]Func, 0) + } + + funcs := make([]Func, ft.Count()) + syms := make([]Sym, len(funcs)) + for i := range funcs { + f := &funcs[i] + f.Entry = ft.pc(i) + f.End = ft.pc(i + 1) + info := t.funcData(uint32(i)) + f.LineTable = t + f.FrameSize = int(info.deferreturn()) + syms[i] = Sym{ + Value: f.Entry, + Type: 'T', + Name: t.funcName(info.nameoff()), + GoType: 0, + Func: f, + GoVersion: t.Version, + } + f.Sym = &syms[i] + } + return funcs +} + +// findFunc returns the funcData corresponding to the given program counter. +func (t *LineTable) findFunc(pc uint64) funcData { + ft := t.funcTab() + if pc < ft.pc(0) || pc >= ft.pc(ft.Count()) { + return funcData{} + } + idx := sort.Search(int(t.nfunctab), func(i int) bool { + return ft.pc(i) > pc + }) + idx-- + return t.funcData(uint32(idx)) +} + +// readvarint reads, removes, and returns a varint from *pp. +func (t *LineTable) readvarint(pp *[]byte) uint32 { + var v, shift uint32 + p := *pp + for shift = 0; ; shift += 7 { + b := p[0] + p = p[1:] + v |= (uint32(b) & 0x7F) << shift + if b&0x80 == 0 { + break + } + } + *pp = p + return v +} + +// funcName returns the name of the function found at off. +func (t *LineTable) funcName(off uint32) string { + if s, ok := t.funcNames[off]; ok { + return s + } + i := bytes.IndexByte(t.funcnametab[off:], 0) + s := string(t.funcnametab[off : off+uint32(i)]) + t.funcNames[off] = s + return s +} + +// stringFrom returns a Go string found at off from a position. +func (t *LineTable) stringFrom(arr []byte, off uint32) string { + if s, ok := t.strings[off]; ok { + return s + } + i := bytes.IndexByte(arr[off:], 0) + s := string(arr[off : off+uint32(i)]) + t.strings[off] = s + return s +} + +// string returns a Go string found at off. +func (t *LineTable) string(off uint32) string { + return t.stringFrom(t.funcdata, off) +} + +// functabFieldSize returns the size in bytes of a single functab field. +func (t *LineTable) functabFieldSize() int { + if t.Version >= ver118 { + return 4 + } + return int(t.Ptrsize) +} + +// funcTab returns t's funcTab. +func (t *LineTable) funcTab() funcTab { + return funcTab{LineTable: t, sz: t.functabFieldSize()} +} + +// funcTab is memory corresponding to a slice of functab structs, followed by an invalid PC. +// A functab struct is a PC and a func offset. +type funcTab struct { + *LineTable + sz int // cached result of t.functabFieldSize +} + +// Count returns the number of func entries in f. +func (f funcTab) Count() int { + return int(f.nfunctab) +} + +// pc returns the PC of the i'th func in f. +func (f funcTab) pc(i int) uint64 { + u := f.uint(f.functab[2*i*f.sz:]) + if f.Version >= ver118 { + u += f.textStart + } + return u +} + +// funcOff returns the funcdata offset of the i'th func in f. +func (f funcTab) funcOff(i int) uint64 { + return f.uint(f.functab[(2*i+1)*f.sz:]) +} + +// uint returns the uint stored at b. +func (f funcTab) uint(b []byte) uint64 { + if f.sz == 4 { + return uint64(f.Binary.Uint32(b)) + } + return f.Binary.Uint64(b) +} + +// funcData is memory corresponding to an _func struct. +type funcData struct { + t *LineTable // LineTable this data is a part of + data []byte // raw memory for the function +} + +// funcData returns the ith funcData in t.functab. +func (t *LineTable) funcData(i uint32) funcData { + data := t.funcdata[t.funcTab().funcOff(int(i)):] + return funcData{t: t, data: data} +} + +// IsZero reports whether f is the zero value. +func (f funcData) IsZero() bool { + return f.t == nil && f.data == nil +} + +// entryPC returns the func's entry PC. +func (f *funcData) entryPC() uint64 { + // In Go 1.18, the first field of _func changed + // from a uintptr entry PC to a uint32 entry offset. + if f.t.Version >= ver118 { + // TODO: support multiple text sections. + // See runtime/symtab.go:(*moduledata).textAddr. + return uint64(f.t.Binary.Uint32(f.data)) + f.t.textStart + } + return f.t.uintptr(f.data) +} + +func (f funcData) nameoff() uint32 { return f.field(1) } +func (f funcData) deferreturn() uint32 { return f.field(3) } +func (f funcData) pcfile() uint32 { return f.field(5) } +func (f funcData) pcln() uint32 { return f.field(6) } +func (f funcData) cuOffset() uint32 { return f.field(8) } + +// field returns the nth field of the _func struct. +// It panics if n == 0 or n > 9; for n == 0, call f.entryPC. +// Most callers should use a named field accessor (just above). +func (f funcData) field(n uint32) uint32 { + if n == 0 || n > 9 { + panic("bad funcdata field") + } + // In Go 1.18, the first field of _func changed + // from a uintptr entry PC to a uint32 entry offset. + sz0 := f.t.Ptrsize + if f.t.Version >= ver118 { + sz0 = 4 + } + off := sz0 + (n-1)*4 // subsequent fields are 4 bytes each + data := f.data[off:] + return f.t.Binary.Uint32(data) +} + +// step advances to the next pc, value pair in the encoded table. +func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool { + uvdelta := t.readvarint(p) + if uvdelta == 0 && !first { + return false + } + if uvdelta&1 != 0 { + uvdelta = ^(uvdelta >> 1) + } else { + uvdelta >>= 1 + } + vdelta := int32(uvdelta) + pcdelta := t.readvarint(p) * t.Quantum + *pc += uint64(pcdelta) + *val += vdelta + return true +} + +// pcvalue reports the value associated with the target pc. +// off is the offset to the beginning of the pc-value table, +// and entry is the start PC for the corresponding function. +func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 { + p := t.pctab[off:] + + val := int32(-1) + pc := entry + for t.step(&p, &pc, &val, pc == entry) { + if targetpc < pc { + return val + } + } + return -1 +} + +// findFileLine scans one function in the binary looking for a +// program counter in the given file on the given line. +// It does so by running the pc-value tables mapping program counter +// to file number. Since most functions come from a single file, these +// are usually short and quick to scan. If a file match is found, then the +// code goes to the expense of looking for a simultaneous line number match. +func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32, cutab []byte) uint64 { + if filetab == 0 || linetab == 0 { + return 0 + } + + fp := t.pctab[filetab:] + fl := t.pctab[linetab:] + fileVal := int32(-1) + filePC := entry + lineVal := int32(-1) + linePC := entry + fileStartPC := filePC + for t.step(&fp, &filePC, &fileVal, filePC == entry) { + fileIndex := fileVal + if t.Version == ver116 || t.Version == ver118 || t.Version == ver120 { + fileIndex = int32(t.Binary.Uint32(cutab[fileVal*4:])) + } + if fileIndex == filenum && fileStartPC < filePC { + // fileIndex is in effect starting at fileStartPC up to + // but not including filePC, and it's the file we want. + // Run the PC table looking for a matching line number + // or until we reach filePC. + lineStartPC := linePC + for linePC < filePC && t.step(&fl, &linePC, &lineVal, linePC == entry) { + // lineVal is in effect until linePC, and lineStartPC < filePC. + if lineVal == line { + if fileStartPC <= lineStartPC { + return lineStartPC + } + if fileStartPC < linePC { + return fileStartPC + } + } + lineStartPC = linePC + } + } + fileStartPC = filePC + } + return 0 +} + +// go12PCToLine maps program counter to line number for the Go 1.2+ pcln table. +func (t *LineTable) go12PCToLine(pc uint64) (line int) { + defer func() { + if !disableRecover && recover() != nil { + line = -1 + } + }() + + f := t.findFunc(pc) + if f.IsZero() { + return -1 + } + entry := f.entryPC() + linetab := f.pcln() + return int(t.pcvalue(linetab, entry, pc)) +} + +// go12PCToFile maps program counter to file name for the Go 1.2+ pcln table. +func (t *LineTable) go12PCToFile(pc uint64) (file string) { + defer func() { + if !disableRecover && recover() != nil { + file = "" + } + }() + + f := t.findFunc(pc) + if f.IsZero() { + return "" + } + entry := f.entryPC() + filetab := f.pcfile() + fno := t.pcvalue(filetab, entry, pc) + if t.Version == ver12 { + if fno <= 0 { + return "" + } + return t.string(t.Binary.Uint32(t.filetab[4*fno:])) + } + // Go ≥ 1.16 + if fno < 0 { // 0 is valid for ≥ 1.16 + return "" + } + cuoff := f.cuOffset() + if fnoff := t.Binary.Uint32(t.cutab[(cuoff+uint32(fno))*4:]); fnoff != ^uint32(0) { + return t.stringFrom(t.filetab, fnoff) + } + return "" +} + +// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2+ pcln table. +func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) { + defer func() { + if !disableRecover && recover() != nil { + pc = 0 + } + }() + + t.initFileMap() + filenum, ok := t.fileMap[file] + if !ok { + return 0 + } + + // Scan all functions. + // If this turns out to be a bottleneck, we could build a map[int32][]int32 + // mapping file number to a list of functions with code from that file. + var cutab []byte + for i := uint32(0); i < t.nfunctab; i++ { + f := t.funcData(i) + entry := f.entryPC() + filetab := f.pcfile() + linetab := f.pcln() + if t.Version == ver116 || t.Version == ver118 || t.Version == ver120 { + cutab = t.cutab[f.cuOffset()*4:] + } + pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line), cutab) + if pc != 0 { + return pc + } + } + return 0 +} + +// initFileMap initializes the map from file name to file number. +func (t *LineTable) initFileMap() { + t.mu.Lock() + defer t.mu.Unlock() + + if t.fileMap != nil { + return + } + m := make(map[string]uint32) + + if t.Version == ver12 { + for i := uint32(1); i < t.nfiletab; i++ { + s := t.string(t.Binary.Uint32(t.filetab[4*i:])) + m[s] = i + } + } else { + var pos uint32 + for i := uint32(0); i < t.nfiletab; i++ { + s := t.stringFrom(t.filetab, pos) + m[s] = pos + pos += uint32(len(s) + 1) + } + } + t.fileMap = m +} + +// go12MapFiles adds to m a key for every file in the Go 1.2 LineTable. +// Every key maps to obj. That's not a very interesting map, but it provides +// a way for callers to obtain the list of files in the program. +func (t *LineTable) go12MapFiles(m map[string]*Obj, obj *Obj) { + if !disableRecover { + defer func() { + recover() + }() + } + + t.initFileMap() + for file := range t.fileMap { + m[file] = obj + } +} + +// disableRecover causes this package not to swallow panics. +// This is useful when making changes. +const disableRecover = false diff --git a/vendor/github.com/mandiant/GoReSym/debug/gosym/symtab.go b/vendor/github.com/mandiant/GoReSym/debug/gosym/symtab.go new file mode 100644 index 00000000..7014a069 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/gosym/symtab.go @@ -0,0 +1,775 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Package gosym implements access to the Go symbol +// and line number tables embedded in Go binaries generated +// by the gc compilers. +package gosym + +import ( + "bytes" + "encoding/binary" + "fmt" + "strconv" + "strings" +) + +/* + * Symbols + */ + +// A Sym represents a single symbol table entry. +type Sym struct { + Value uint64 + Type byte + Name string + GoType uint64 + // If this symbol is a function symbol, the corresponding Func + Func *Func + GoVersion version +} + +// Static reports whether this symbol is static (not visible outside its file). +func (s *Sym) Static() bool { return s.Type >= 'a' } + +// nameWithoutInst returns s.Name if s.Name has no brackets (does not reference an +// instantiated type, function, or method). If s.Name contains brackets, then it +// returns s.Name with all the contents between (and including) the outermost left +// and right bracket removed. This is useful to ignore any extra slashes or dots +// inside the brackets from the string searches below, where needed. +func (s *Sym) nameWithoutInst() string { + start := strings.Index(s.Name, "[") + if start < 0 { + return s.Name + } + end := strings.LastIndex(s.Name, "]") + if end < 0 { + // Malformed name, should contain closing bracket too. + return s.Name + } + return s.Name[0:start] + s.Name[end+1:] +} + +// PackageName returns the package part of the symbol name, +// or the empty string if there is none. +func (s *Sym) PackageName() string { + name := s.nameWithoutInst() + + // Since go1.20, a prefix of "type:" and "go:" is a compiler-generated symbol, + // they do not belong to any package. + // + // See cmd/compile/internal/base/link.go:ReservedImports variable. + if s.GoVersion >= ver120 && (strings.HasPrefix(name, "go:") || strings.HasPrefix(name, "type:")) { + return "" + } + + // For go1.18 and below, the prefix are "type." and "go." instead. + if s.GoVersion <= ver118 && (strings.HasPrefix(name, "go.") || strings.HasPrefix(name, "type.")) { + return "" + } + + pathend := strings.LastIndex(name, "/") + if pathend < 0 { + pathend = 0 + } + + if i := strings.Index(name[pathend:], "."); i != -1 { + return name[:pathend+i] + } + return "" +} + +// ReceiverName returns the receiver type name of this symbol, +// or the empty string if there is none. A receiver name is only detected in +// the case that s.Name is fully-specified with a package name. +func (s *Sym) ReceiverName() string { + name := s.nameWithoutInst() + // If we find a slash in name, it should precede any bracketed expression + // that was removed, so pathend will apply correctly to name and s.Name. + pathend := strings.LastIndex(name, "/") + if pathend < 0 { + pathend = 0 + } + // Find the first dot after pathend (or from the beginning, if there was + // no slash in name). + l := strings.Index(name[pathend:], ".") + // Find the last dot after pathend (or the beginnng). + r := strings.LastIndex(name[pathend:], ".") + if l == -1 || r == -1 || l == r { + // There is no receiver if we didn't find two distinct dots after pathend. + return "" + } + // Given there is a trailing '.' that is in name, find it now in s.Name. + // pathend+l should apply to s.Name, because it should be the dot in the + // package name. + r = strings.LastIndex(s.Name[pathend:], ".") + return s.Name[pathend+l+1 : pathend+r] +} + +// BaseName returns the symbol name without the package or receiver name. +func (s *Sym) BaseName() string { + name := s.nameWithoutInst() + if i := strings.LastIndex(name, "."); i != -1 { + if s.Name != name { + brack := strings.Index(s.Name, "[") + if i > brack { + // BaseName is a method name after the brackets, so + // recalculate for s.Name. Otherwise, i applies + // correctly to s.Name, since it is before the + // brackets. + i = strings.LastIndex(s.Name, ".") + } + } + return s.Name[i+1:] + } + return s.Name +} + +// A Func collects information about a single function. +type Func struct { + Entry uint64 + *Sym + End uint64 + Params []*Sym // nil for Go 1.3 and later binaries + Locals []*Sym // nil for Go 1.3 and later binaries + FrameSize int + LineTable *LineTable + Obj *Obj +} + +// An Obj represents a collection of functions in a symbol table. +// +// The exact method of division of a binary into separate Objs is an internal detail +// of the symbol table format. +// +// In early versions of Go each source file became a different Obj. +// +// In Go 1 and Go 1.1, each package produced one Obj for all Go sources +// and one Obj per C source file. +// +// In Go 1.2, there is a single Obj for the entire program. +type Obj struct { + // Funcs is a list of functions in the Obj. + Funcs []Func + + // In Go 1.1 and earlier, Paths is a list of symbols corresponding + // to the source file names that produced the Obj. + // In Go 1.2, Paths is nil. + // Use the keys of Table.Files to obtain a list of source files. + Paths []Sym // meta +} + +/* + * Symbol tables + */ + +// Table represents a Go symbol table. It stores all of the +// symbols decoded from the program and provides methods to translate +// between symbols, names, and addresses. +type Table struct { + Syms []Sym // nil for Go 1.3 and later binaries + Funcs []Func + Files map[string]*Obj // for Go 1.2 and later all files map to one Obj + Objs []Obj // for Go 1.2 and later only one Obj in slice + + Go12line *LineTable // Go 1.2 line number table +} + +type sym struct { + value uint64 + gotype uint64 + typ byte + name []byte +} + +var ( + littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00} + bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00} + oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00} +) + +func walksymtab(data []byte, fn func(sym) error) error { + if len(data) == 0 { // missing symtab is okay + return nil + } + var order binary.ByteOrder = binary.BigEndian + newTable := false + switch { + case bytes.HasPrefix(data, oldLittleEndianSymtab): + // Same as Go 1.0, but little endian. + // Format was used during interim development between Go 1.0 and Go 1.1. + // Should not be widespread, but easy to support. + data = data[6:] + order = binary.LittleEndian + case bytes.HasPrefix(data, bigEndianSymtab): + newTable = true + case bytes.HasPrefix(data, littleEndianSymtab): + newTable = true + order = binary.LittleEndian + } + var ptrsz int + if newTable { + if len(data) < 8 { + return &DecodingError{len(data), "unexpected EOF", nil} + } + ptrsz = int(data[7]) + if ptrsz != 4 && ptrsz != 8 { + return &DecodingError{7, "invalid pointer size", ptrsz} + } + data = data[8:] + } + var s sym + p := data + for len(p) >= 4 { + var typ byte + if newTable { + // Symbol type, value, Go type. + typ = p[0] & 0x3F + wideValue := p[0]&0x40 != 0 + goType := p[0]&0x80 != 0 + if typ < 26 { + typ += 'A' + } else { + typ += 'a' - 26 + } + s.typ = typ + p = p[1:] + if wideValue { + if len(p) < ptrsz { + return &DecodingError{len(data), "unexpected EOF", nil} + } + // fixed-width value + if ptrsz == 8 { + s.value = order.Uint64(p[0:8]) + p = p[8:] + } else { + s.value = uint64(order.Uint32(p[0:4])) + p = p[4:] + } + } else { + // varint value + s.value = 0 + shift := uint(0) + for len(p) > 0 && p[0]&0x80 != 0 { + s.value |= uint64(p[0]&0x7F) << shift + shift += 7 + p = p[1:] + } + if len(p) == 0 { + return &DecodingError{len(data), "unexpected EOF", nil} + } + s.value |= uint64(p[0]) << shift + p = p[1:] + } + if goType { + if len(p) < ptrsz { + return &DecodingError{len(data), "unexpected EOF", nil} + } + // fixed-width go type + if ptrsz == 8 { + s.gotype = order.Uint64(p[0:8]) + p = p[8:] + } else { + s.gotype = uint64(order.Uint32(p[0:4])) + p = p[4:] + } + } + } else { + // Value, symbol type. + s.value = uint64(order.Uint32(p[0:4])) + if len(p) < 5 { + return &DecodingError{len(data), "unexpected EOF", nil} + } + typ = p[4] + if typ&0x80 == 0 { + return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ} + } + typ &^= 0x80 + s.typ = typ + p = p[5:] + } + + // Name. + var i int + var nnul int + for i = 0; i < len(p); i++ { + if p[i] == 0 { + nnul = 1 + break + } + } + switch typ { + case 'z', 'Z': + p = p[i+nnul:] + for i = 0; i+2 <= len(p); i += 2 { + if p[i] == 0 && p[i+1] == 0 { + nnul = 2 + break + } + } + } + if len(p) < i+nnul { + return &DecodingError{len(data), "unexpected EOF", nil} + } + s.name = p[0:i] + i += nnul + p = p[i:] + + if !newTable { + if len(p) < 4 { + return &DecodingError{len(data), "unexpected EOF", nil} + } + // Go type. + s.gotype = uint64(order.Uint32(p[:4])) + p = p[4:] + } + fn(s) + } + return nil +} + +// NewTable decodes the Go symbol table (the ".gosymtab" section in ELF), +// returning an in-memory representation. +// Starting with Go 1.3, the Go symbol table no longer includes symbol data. +func NewTable(symtab []byte, pcln *LineTable, versionOverride string) (*Table, error) { + var n int + err := walksymtab(symtab, func(s sym) error { + n++ + return nil + }) + if err != nil { + return nil, err + } + + var t Table + if pcln.isGo12(versionOverride) { + t.Go12line = pcln + } + fname := make(map[uint16]string) + t.Syms = make([]Sym, 0, n) + nf := 0 + nz := 0 + lasttyp := uint8(0) + err = walksymtab(symtab, func(s sym) error { + n := len(t.Syms) + t.Syms = t.Syms[0 : n+1] + ts := &t.Syms[n] + ts.Type = s.typ + ts.Value = s.value + ts.GoType = s.gotype + ts.GoVersion = pcln.Version + switch s.typ { + default: + // rewrite name to use . instead of · (c2 b7) + w := 0 + b := s.name + for i := 0; i < len(b); i++ { + if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 { + i++ + b[i] = '.' + } + b[w] = b[i] + w++ + } + ts.Name = string(s.name[0:w]) + case 'z', 'Z': + if lasttyp != 'z' && lasttyp != 'Z' { + nz++ + } + for i := 0; i < len(s.name); i += 2 { + eltIdx := binary.BigEndian.Uint16(s.name[i : i+2]) + elt, ok := fname[eltIdx] + if !ok { + return &DecodingError{-1, "bad filename code", eltIdx} + } + if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' { + ts.Name += "/" + } + ts.Name += elt + } + } + switch s.typ { + case 'T', 't', 'L', 'l': + nf++ + case 'f': + fname[uint16(s.value)] = ts.Name + } + lasttyp = s.typ + return nil + }) + if err != nil { + return nil, err + } + + t.Funcs = make([]Func, 0, nf) + t.Files = make(map[string]*Obj) + + var obj *Obj + if t.Go12line != nil { + // Put all functions into one Obj. + t.Objs = make([]Obj, 1) + obj = &t.Objs[0] + t.Go12line.go12MapFiles(t.Files, obj) + } else { + t.Objs = make([]Obj, 0, nz) + } + + // Count text symbols and attach frame sizes, parameters, and + // locals to them. Also, find object file boundaries. + lastf := 0 + for i := 0; i < len(t.Syms); i++ { + sym := &t.Syms[i] + switch sym.Type { + case 'Z', 'z': // path symbol + if t.Go12line != nil { + // Go 1.2 binaries have the file information elsewhere. Ignore. + break + } + // Finish the current object + if obj != nil { + obj.Funcs = t.Funcs[lastf:] + } + lastf = len(t.Funcs) + + // Start new object + n := len(t.Objs) + t.Objs = t.Objs[0 : n+1] + obj = &t.Objs[n] + + // Count & copy path symbols + var end int + for end = i + 1; end < len(t.Syms); end++ { + if c := t.Syms[end].Type; c != 'Z' && c != 'z' { + break + } + } + obj.Paths = t.Syms[i:end] + i = end - 1 // loop will i++ + + // Record file names + depth := 0 + for j := range obj.Paths { + s := &obj.Paths[j] + if s.Name == "" { + depth-- + } else { + if depth == 0 { + t.Files[s.Name] = obj + } + depth++ + } + } + + case 'T', 't', 'L', 'l': // text symbol + if n := len(t.Funcs); n > 0 { + t.Funcs[n-1].End = sym.Value + } + if sym.Name == "runtime.etext" || sym.Name == "etext" { + continue + } + + // Count parameter and local (auto) syms + var np, na int + var end int + countloop: + for end = i + 1; end < len(t.Syms); end++ { + switch t.Syms[end].Type { + case 'T', 't', 'L', 'l', 'Z', 'z': + break countloop + case 'p': + np++ + case 'a': + na++ + } + } + + // Fill in the function symbol + n := len(t.Funcs) + t.Funcs = t.Funcs[0 : n+1] + fn := &t.Funcs[n] + sym.Func = fn + fn.Params = make([]*Sym, 0, np) + fn.Locals = make([]*Sym, 0, na) + fn.Sym = sym + fn.Entry = sym.Value + fn.Obj = obj + if t.Go12line != nil { + // All functions share the same line table. + // It knows how to narrow down to a specific + // function quickly. + fn.LineTable = t.Go12line + } else if pcln != nil { + fn.LineTable = pcln.slice(fn.Entry) + pcln = fn.LineTable + } + for j := i; j < end; j++ { + s := &t.Syms[j] + switch s.Type { + case 'm': + fn.FrameSize = int(s.Value) + case 'p': + n := len(fn.Params) + fn.Params = fn.Params[0 : n+1] + fn.Params[n] = s + case 'a': + n := len(fn.Locals) + fn.Locals = fn.Locals[0 : n+1] + fn.Locals[n] = s + } + } + i = end - 1 // loop will i++ + } + } + + if t.Go12line != nil && nf == 0 { + t.Funcs = t.Go12line.go12Funcs() + } + if obj != nil { + obj.Funcs = t.Funcs[lastf:] + } + return &t, nil +} + +// PCToFunc returns the function containing the program counter pc, +// or nil if there is no such function. +func (t *Table) PCToFunc(pc uint64) *Func { + funcs := t.Funcs + for len(funcs) > 0 { + m := len(funcs) / 2 + fn := &funcs[m] + switch { + case pc < fn.Entry: + funcs = funcs[0:m] + case fn.Entry <= pc && pc < fn.End: + return fn + default: + funcs = funcs[m+1:] + } + } + return nil +} + +// PCToLine looks up line number information for a program counter. +// If there is no information, it returns fn == nil. +func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) { + if fn = t.PCToFunc(pc); fn == nil { + return + } + if t.Go12line != nil { + file = t.Go12line.go12PCToFile(pc) + line = t.Go12line.go12PCToLine(pc) + } else { + file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc)) + } + return +} + +// LineToPC looks up the first program counter on the given line in +// the named file. It returns UnknownPathError or UnknownLineError if +// there is an error looking up this line. +func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) { + obj, ok := t.Files[file] + if !ok { + return 0, nil, UnknownFileError(file) + } + + if t.Go12line != nil { + pc := t.Go12line.go12LineToPC(file, line) + if pc == 0 { + return 0, nil, &UnknownLineError{file, line} + } + return pc, t.PCToFunc(pc), nil + } + + abs, err := obj.alineFromLine(file, line) + if err != nil { + return + } + for i := range obj.Funcs { + f := &obj.Funcs[i] + pc := f.LineTable.LineToPC(abs, f.End) + if pc != 0 { + return pc, f, nil + } + } + return 0, nil, &UnknownLineError{file, line} +} + +// LookupSym returns the text, data, or bss symbol with the given name, +// or nil if no such symbol is found. +func (t *Table) LookupSym(name string) *Sym { + // TODO(austin) Maybe make a map + for i := range t.Syms { + s := &t.Syms[i] + switch s.Type { + case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b': + if s.Name == name { + return s + } + } + } + return nil +} + +// LookupFunc returns the text, data, or bss symbol with the given name, +// or nil if no such symbol is found. +func (t *Table) LookupFunc(name string) *Func { + for i := range t.Funcs { + f := &t.Funcs[i] + if f.Sym.Name == name { + return f + } + } + return nil +} + +// SymByAddr returns the text, data, or bss symbol starting at the given address. +func (t *Table) SymByAddr(addr uint64) *Sym { + for i := range t.Syms { + s := &t.Syms[i] + switch s.Type { + case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b': + if s.Value == addr { + return s + } + } + } + return nil +} + +/* + * Object files + */ + +// This is legacy code for Go 1.1 and earlier, which used the +// Plan 9 format for pc-line tables. This code was never quite +// correct. It's probably very close, and it's usually correct, but +// we never quite found all the corner cases. +// +// Go 1.2 and later use a simpler format, documented at golang.org/s/go12symtab. + +func (o *Obj) lineFromAline(aline int) (string, int) { + type stackEnt struct { + path string + start int + offset int + prev *stackEnt + } + + noPath := &stackEnt{"", 0, 0, nil} + tos := noPath + +pathloop: + for _, s := range o.Paths { + val := int(s.Value) + switch { + case val > aline: + break pathloop + + case val == 1: + // Start a new stack + tos = &stackEnt{s.Name, val, 0, noPath} + + case s.Name == "": + // Pop + if tos == noPath { + return "", 0 + } + tos.prev.offset += val - tos.start + tos = tos.prev + + default: + // Push + tos = &stackEnt{s.Name, val, 0, tos} + } + } + + if tos == noPath { + return "", 0 + } + return tos.path, aline - tos.start - tos.offset + 1 +} + +func (o *Obj) alineFromLine(path string, line int) (int, error) { + if line < 1 { + return 0, &UnknownLineError{path, line} + } + + for i, s := range o.Paths { + // Find this path + if s.Name != path { + continue + } + + // Find this line at this stack level + depth := 0 + var incstart int + line += int(s.Value) + pathloop: + for _, s := range o.Paths[i:] { + val := int(s.Value) + switch { + case depth == 1 && val >= line: + return line - 1, nil + + case s.Name == "": + depth-- + if depth == 0 { + break pathloop + } else if depth == 1 { + line += val - incstart + } + + default: + if depth == 1 { + incstart = val + } + depth++ + } + } + return 0, &UnknownLineError{path, line} + } + return 0, UnknownFileError(path) +} + +/* + * Errors + */ + +// UnknownFileError represents a failure to find the specific file in +// the symbol table. +type UnknownFileError string + +func (e UnknownFileError) Error() string { return "unknown file: " + string(e) } + +// UnknownLineError represents a failure to map a line to a program +// counter, either because the line is beyond the bounds of the file +// or because there is no code on the given line. +type UnknownLineError struct { + File string + Line int +} + +func (e *UnknownLineError) Error() string { + return "no code at " + e.File + ":" + strconv.Itoa(e.Line) +} + +// DecodingError represents an error during the decoding of +// the symbol table. +type DecodingError struct { + off int + msg string + val interface{} +} + +func (e *DecodingError) Error() string { + msg := e.msg + if e.val != nil { + msg += fmt.Sprintf(" '%v'", e.val) + } + msg += fmt.Sprintf(" at byte %#x", e.off) + return msg +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/macho/fat.go b/vendor/github.com/mandiant/GoReSym/debug/macho/fat.go new file mode 100644 index 00000000..08bc85ce --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/macho/fat.go @@ -0,0 +1,148 @@ +// Copyright 2014 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package macho + +import ( + "encoding/binary" + "fmt" + "io" + "os" +) + +// A FatFile is a Mach-O universal binary that contains at least one architecture. +type FatFile struct { + Magic uint32 + Arches []FatArch + closer io.Closer +} + +// A FatArchHeader represents a fat header for a specific image architecture. +type FatArchHeader struct { + Cpu Cpu + SubCpu uint32 + Offset uint32 + Size uint32 + Align uint32 +} + +const fatArchHeaderSize = 5 * 4 + +// A FatArch is a Mach-O File inside a FatFile. +type FatArch struct { + FatArchHeader + *File +} + +// ErrNotFat is returned from NewFatFile or OpenFat when the file is not a +// universal binary but may be a thin binary, based on its magic number. +var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil} + +// NewFatFile creates a new FatFile for accessing all the Mach-O images in a +// universal binary. The Mach-O binary is expected to start at position 0 in +// the ReaderAt. +func NewFatFile(r io.ReaderAt) (*FatFile, error) { + var ff FatFile + sr := io.NewSectionReader(r, 0, 1<<63-1) + + // Read the fat_header struct, which is always in big endian. + // Start with the magic number. + err := binary.Read(sr, binary.BigEndian, &ff.Magic) + if err != nil { + return nil, &FormatError{0, "error reading magic number", nil} + } else if ff.Magic != MagicFat { + // See if this is a Mach-O file via its magic number. The magic + // must be converted to little endian first though. + var buf [4]byte + binary.BigEndian.PutUint32(buf[:], ff.Magic) + leMagic := binary.LittleEndian.Uint32(buf[:]) + if leMagic == Magic32 || leMagic == Magic64 { + return nil, ErrNotFat + } else { + return nil, &FormatError{0, "invalid magic number", nil} + } + } + offset := int64(4) + + // Read the number of FatArchHeaders that come after the fat_header. + var narch uint32 + err = binary.Read(sr, binary.BigEndian, &narch) + if err != nil { + return nil, &FormatError{offset, "invalid fat_header", nil} + } + offset += 4 + + if narch < 1 { + return nil, &FormatError{offset, "file contains no images", nil} + } + + // Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure + // there are not duplicate architectures. + seenArches := make(map[uint64]bool, narch) + // Make sure that all images are for the same MH_ type. + var machoType Type + + // Following the fat_header comes narch fat_arch structs that index + // Mach-O images further in the file. + ff.Arches = make([]FatArch, narch) + for i := uint32(0); i < narch; i++ { + fa := &ff.Arches[i] + err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader) + if err != nil { + return nil, &FormatError{offset, "invalid fat_arch header", nil} + } + offset += fatArchHeaderSize + + fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size)) + fa.File, err = NewFile(fr) + if err != nil { + return nil, err + } + + // Make sure the architecture for this image is not duplicate. + seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu) + if o, k := seenArches[seenArch]; o || k { + return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil} + } + seenArches[seenArch] = true + + // Make sure the Mach-O type matches that of the first image. + if i == 0 { + machoType = fa.Type + } else { + if fa.Type != machoType { + return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil} + } + } + } + + return &ff, nil +} + +// OpenFat opens the named file using os.Open and prepares it for use as a Mach-O +// universal binary. +func OpenFat(name string) (*FatFile, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + ff, err := NewFatFile(f) + if err != nil { + f.Close() + return nil, err + } + ff.closer = f + return ff, nil +} + +func (ff *FatFile) Close() error { + var err error + if ff.closer != nil { + err = ff.closer.Close() + ff.closer = nil + } + return err +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/macho/file.go b/vendor/github.com/mandiant/GoReSym/debug/macho/file.go new file mode 100644 index 00000000..564a9217 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/macho/file.go @@ -0,0 +1,725 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Package macho implements access to Mach-O object files. +package macho + +// High level access to low level data structures. + +import ( + "bytes" + "compress/zlib" + "encoding/binary" + "fmt" + "io" + "os" + "strings" + + "github.com/mandiant/GoReSym/debug/dwarf" +) + +// A File represents an open Mach-O file. +type File struct { + FileHeader + ByteOrder binary.ByteOrder + Loads []Load + Sections []*Section + + Symtab *Symtab + Dysymtab *Dysymtab + + closer io.Closer + dataAfterSectionCache map[uint64][]byte // secVA -> dataAfterSection +} + +// A Load represents any Mach-O load command. +type Load interface { + Raw() []byte +} + +// A LoadBytes is the uninterpreted bytes of a Mach-O load command. +type LoadBytes []byte + +func (b LoadBytes) Raw() []byte { return b } + +// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command. +type SegmentHeader struct { + Cmd LoadCmd + Len uint32 + Name string + Addr uint64 + Memsz uint64 + Offset uint64 + Filesz uint64 + Maxprot uint32 + Prot uint32 + Nsect uint32 + Flag uint32 +} + +// A Segment represents a Mach-O 32-bit or 64-bit load segment command. +type Segment struct { + LoadBytes + SegmentHeader + + // Embed ReaderAt for ReadAt method. + // Do not embed SectionReader directly + // to avoid having Read and Seek. + // If a client wants Read and Seek it must use + // Open() to avoid fighting over the seek offset + // with other clients. + io.ReaderAt + sr *io.SectionReader +} + +// Data reads and returns the contents of the segment. +func (s *Segment) Data() ([]byte, error) { + dat := make([]byte, s.sr.Size()) + n, err := s.sr.ReadAt(dat, 0) + if n == len(dat) { + err = nil + } + return dat[0:n], err +} + +// Open returns a new ReadSeeker reading the segment. +func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } + +type SectionHeader struct { + Name string + Seg string + Addr uint64 + Size uint64 + Offset uint32 + Align uint32 + Reloff uint32 + Nreloc uint32 + Flags uint32 +} + +// A Reloc represents a Mach-O relocation. +type Reloc struct { + Addr uint32 + Value uint32 + // when Scattered == false && Extern == true, Value is the symbol number. + // when Scattered == false && Extern == false, Value is the section number. + // when Scattered == true, Value is the value that this reloc refers to. + Type uint8 + Len uint8 // 0=byte, 1=word, 2=long, 3=quad + Pcrel bool + Extern bool // valid if Scattered == false + Scattered bool +} + +type Section struct { + SectionHeader + Relocs []Reloc + + // Embed ReaderAt for ReadAt method. + // Do not embed SectionReader directly + // to avoid having Read and Seek. + // If a client wants Read and Seek it must use + // Open() to avoid fighting over the seek offset + // with other clients. + io.ReaderAt + sr *io.SectionReader +} + +// Data reads and returns the contents of the Mach-O section. +func (s *Section) Data() ([]byte, error) { + dat := make([]byte, s.sr.Size()) + n, err := s.sr.ReadAt(dat, 0) + if n == len(dat) { + err = nil + } + return dat[0:n], err +} + +// Open returns a new ReadSeeker reading the Mach-O section. +func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } + +// A Dylib represents a Mach-O load dynamic library command. +type Dylib struct { + LoadBytes + Name string + Time uint32 + CurrentVersion uint32 + CompatVersion uint32 +} + +// A Symtab represents a Mach-O symbol table command. +type Symtab struct { + LoadBytes + SymtabCmd + Syms []Symbol +} + +// A Dysymtab represents a Mach-O dynamic symbol table command. +type Dysymtab struct { + LoadBytes + DysymtabCmd + IndirectSyms []uint32 // indices into Symtab.Syms +} + +// A Rpath represents a Mach-O rpath command. +type Rpath struct { + LoadBytes + Path string +} + +// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry. +type Symbol struct { + Name string + Type uint8 + Sect uint8 + Desc uint16 + Value uint64 +} + +/* + * Mach-O reader + */ + +// FormatError is returned by some operations if the data does +// not have the correct format for an object file. +type FormatError struct { + off int64 + msg string + val interface{} +} + +func (e *FormatError) Error() string { + msg := e.msg + if e.val != nil { + msg += fmt.Sprintf(" '%v'", e.val) + } + msg += fmt.Sprintf(" in record at byte %#x", e.off) + return msg +} + +// Open opens the named file using os.Open and prepares it for use as a Mach-O binary. +func Open(name string) (*File, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + ff, err := NewFile(f) + if err != nil { + f.Close() + return nil, err + } + ff.closer = f + return ff, nil +} + +// Close closes the File. +// If the File was created using NewFile directly instead of Open, +// Close has no effect. +func (f *File) Close() error { + var err error + if f.closer != nil { + err = f.closer.Close() + f.closer = nil + } + return err +} + +// NewFile creates a new File for accessing a Mach-O binary in an underlying reader. +// The Mach-O binary is expected to start at position 0 in the ReaderAt. +func NewFile(r io.ReaderAt) (*File, error) { + f := new(File) + f.dataAfterSectionCache = make(map[uint64][]byte) + sr := io.NewSectionReader(r, 0, 1<<63-1) + + // Read and decode Mach magic to determine byte order, size. + // Magic32 and Magic64 differ only in the bottom bit. + var ident [4]byte + if _, err := r.ReadAt(ident[0:], 0); err != nil { + return nil, err + } + be := binary.BigEndian.Uint32(ident[0:]) + le := binary.LittleEndian.Uint32(ident[0:]) + switch Magic32 &^ 1 { + case be &^ 1: + f.ByteOrder = binary.BigEndian + f.Magic = be + case le &^ 1: + f.ByteOrder = binary.LittleEndian + f.Magic = le + default: + return nil, &FormatError{0, "invalid magic number", nil} + } + + // Read entire file header. + if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil { + return nil, err + } + + // Then load commands. + offset := int64(fileHeaderSize32) + if f.Magic == Magic64 { + offset = fileHeaderSize64 + } + dat := make([]byte, f.Cmdsz) + if _, err := r.ReadAt(dat, offset); err != nil { + return nil, err + } + f.Loads = make([]Load, f.Ncmd) + bo := f.ByteOrder + for i := range f.Loads { + // Each load command begins with uint32 command and length. + if len(dat) < 8 { + return nil, &FormatError{offset, "command block too small", nil} + } + cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8]) + if siz < 8 || siz > uint32(len(dat)) { + return nil, &FormatError{offset, "invalid command block size", nil} + } + var cmddat []byte + cmddat, dat = dat[0:siz], dat[siz:] + offset += int64(siz) + var s *Segment + switch cmd { + default: + f.Loads[i] = LoadBytes(cmddat) + + case LoadCmdRpath: + var hdr RpathCmd + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + l := new(Rpath) + if hdr.Path >= uint32(len(cmddat)) { + return nil, &FormatError{offset, "invalid path in rpath command", hdr.Path} + } + l.Path = cstring(cmddat[hdr.Path:]) + l.LoadBytes = LoadBytes(cmddat) + f.Loads[i] = l + + case LoadCmdDylib: + var hdr DylibCmd + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + l := new(Dylib) + if hdr.Name >= uint32(len(cmddat)) { + return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name} + } + l.Name = cstring(cmddat[hdr.Name:]) + l.Time = hdr.Time + l.CurrentVersion = hdr.CurrentVersion + l.CompatVersion = hdr.CompatVersion + l.LoadBytes = LoadBytes(cmddat) + f.Loads[i] = l + + case LoadCmdSymtab: + var hdr SymtabCmd + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + strtab := make([]byte, hdr.Strsize) + if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil { + return nil, err + } + var symsz int + if f.Magic == Magic64 { + symsz = 16 + } else { + symsz = 12 + } + symdat := make([]byte, int(hdr.Nsyms)*symsz) + if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil { + return nil, err + } + st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset) + if err != nil { + return nil, err + } + f.Loads[i] = st + f.Symtab = st + + case LoadCmdDysymtab: + var hdr DysymtabCmd + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &hdr); err != nil { + return nil, err + } + dat := make([]byte, hdr.Nindirectsyms*4) + if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil { + return nil, err + } + x := make([]uint32, hdr.Nindirectsyms) + if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil { + return nil, err + } + st := new(Dysymtab) + st.LoadBytes = LoadBytes(cmddat) + st.DysymtabCmd = hdr + st.IndirectSyms = x + f.Loads[i] = st + f.Dysymtab = st + + case LoadCmdSegment: + var seg32 Segment32 + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &seg32); err != nil { + return nil, err + } + s = new(Segment) + s.LoadBytes = cmddat + s.Cmd = cmd + s.Len = siz + s.Name = cstring(seg32.Name[0:]) + s.Addr = uint64(seg32.Addr) + s.Memsz = uint64(seg32.Memsz) + s.Offset = uint64(seg32.Offset) + s.Filesz = uint64(seg32.Filesz) + s.Maxprot = seg32.Maxprot + s.Prot = seg32.Prot + s.Nsect = seg32.Nsect + s.Flag = seg32.Flag + f.Loads[i] = s + for i := 0; i < int(s.Nsect); i++ { + var sh32 Section32 + if err := binary.Read(b, bo, &sh32); err != nil { + return nil, err + } + sh := new(Section) + sh.Name = cstring(sh32.Name[0:]) + sh.Seg = cstring(sh32.Seg[0:]) + sh.Addr = uint64(sh32.Addr) + sh.Size = uint64(sh32.Size) + sh.Offset = sh32.Offset + sh.Align = sh32.Align + sh.Reloff = sh32.Reloff + sh.Nreloc = sh32.Nreloc + sh.Flags = sh32.Flags + if err := f.pushSection(sh, r); err != nil { + return nil, err + } + } + + case LoadCmdSegment64: + var seg64 Segment64 + b := bytes.NewReader(cmddat) + if err := binary.Read(b, bo, &seg64); err != nil { + return nil, err + } + s = new(Segment) + s.LoadBytes = cmddat + s.Cmd = cmd + s.Len = siz + s.Name = cstring(seg64.Name[0:]) + s.Addr = seg64.Addr + s.Memsz = seg64.Memsz + s.Offset = seg64.Offset + s.Filesz = seg64.Filesz + s.Maxprot = seg64.Maxprot + s.Prot = seg64.Prot + s.Nsect = seg64.Nsect + s.Flag = seg64.Flag + f.Loads[i] = s + for i := 0; i < int(s.Nsect); i++ { + var sh64 Section64 + if err := binary.Read(b, bo, &sh64); err != nil { + return nil, err + } + sh := new(Section) + sh.Name = cstring(sh64.Name[0:]) + sh.Seg = cstring(sh64.Seg[0:]) + sh.Addr = sh64.Addr + sh.Size = sh64.Size + sh.Offset = sh64.Offset + sh.Align = sh64.Align + sh.Reloff = sh64.Reloff + sh.Nreloc = sh64.Nreloc + sh.Flags = sh64.Flags + if err := f.pushSection(sh, r); err != nil { + return nil, err + } + } + } + if s != nil { + s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz)) + s.ReaderAt = s.sr + } + } + return f, nil +} + +func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) { + bo := f.ByteOrder + symtab := make([]Symbol, hdr.Nsyms) + b := bytes.NewReader(symdat) + for i := range symtab { + var n Nlist64 + if f.Magic == Magic64 { + if err := binary.Read(b, bo, &n); err != nil { + return nil, err + } + } else { + var n32 Nlist32 + if err := binary.Read(b, bo, &n32); err != nil { + return nil, err + } + n.Name = n32.Name + n.Type = n32.Type + n.Sect = n32.Sect + n.Desc = n32.Desc + n.Value = uint64(n32.Value) + } + sym := &symtab[i] + if n.Name >= uint32(len(strtab)) { + return nil, &FormatError{offset, "invalid name in symbol table", n.Name} + } + // We add "_" to Go symbols. Strip it here. See issue 33808. + name := cstring(strtab[n.Name:]) + if strings.Contains(name, ".") && name[0] == '_' { + name = name[1:] + } + sym.Name = name + sym.Type = n.Type + sym.Sect = n.Sect + sym.Desc = n.Desc + sym.Value = n.Value + } + st := new(Symtab) + st.LoadBytes = LoadBytes(cmddat) + st.Syms = symtab + return st, nil +} + +type relocInfo struct { + Addr uint32 + Symnum uint32 +} + +func (f *File) pushSection(sh *Section, r io.ReaderAt) error { + f.Sections = append(f.Sections, sh) + sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size)) + sh.ReaderAt = sh.sr + + if sh.Nreloc > 0 { + reldat := make([]byte, int(sh.Nreloc)*8) + if _, err := r.ReadAt(reldat, int64(sh.Reloff)); err != nil { + return err + } + b := bytes.NewReader(reldat) + + bo := f.ByteOrder + + sh.Relocs = make([]Reloc, sh.Nreloc) + for i := range sh.Relocs { + rel := &sh.Relocs[i] + + var ri relocInfo + if err := binary.Read(b, bo, &ri); err != nil { + return err + } + + if ri.Addr&(1<<31) != 0 { // scattered + rel.Addr = ri.Addr & (1<<24 - 1) + rel.Type = uint8((ri.Addr >> 24) & (1<<4 - 1)) + rel.Len = uint8((ri.Addr >> 28) & (1<<2 - 1)) + rel.Pcrel = ri.Addr&(1<<30) != 0 + rel.Value = ri.Symnum + rel.Scattered = true + } else { + switch bo { + case binary.LittleEndian: + rel.Addr = ri.Addr + rel.Value = ri.Symnum & (1<<24 - 1) + rel.Pcrel = ri.Symnum&(1<<24) != 0 + rel.Len = uint8((ri.Symnum >> 25) & (1<<2 - 1)) + rel.Extern = ri.Symnum&(1<<27) != 0 + rel.Type = uint8((ri.Symnum >> 28) & (1<<4 - 1)) + case binary.BigEndian: + rel.Addr = ri.Addr + rel.Value = ri.Symnum >> 8 + rel.Pcrel = ri.Symnum&(1<<7) != 0 + rel.Len = uint8((ri.Symnum >> 5) & (1<<2 - 1)) + rel.Extern = ri.Symnum&(1<<4) != 0 + rel.Type = uint8(ri.Symnum & (1<<4 - 1)) + default: + panic("unreachable") + } + } + } + } + + return nil +} + +func cstring(b []byte) string { + i := bytes.IndexByte(b, 0) + if i == -1 { + i = len(b) + } + return string(b[0:i]) +} + +// Segment returns the first Segment with the given name, or nil if no such segment exists. +func (f *File) Segment(name string) *Segment { + for _, l := range f.Loads { + if s, ok := l.(*Segment); ok && s.Name == name { + return s + } + } + return nil +} + +func (f *File) DataAfterSection(target *Section) []byte { + if cached, ok := f.dataAfterSectionCache[target.Addr]; ok { + return cached + } + + data := []byte{} + found := false + for _, s := range f.Sections { + if s.Addr == target.Addr && s.Name == target.Name { + found = true + } + + if found { + raw, err := s.Data() + if raw != nil { + data = append(data, raw[:]...) + } + + if err != nil { + break + } + } + } + f.dataAfterSectionCache[target.Addr] = data + return data +} + +// Section returns the first section with the given name, or nil if no such +// section exists. +func (f *File) Section(name string) *Section { + for _, s := range f.Sections { + if s.Name == name { + return s + } + } + return nil +} + +// DWARF returns the DWARF debug information for the Mach-O file. +func (f *File) DWARF() (*dwarf.Data, error) { + dwarfSuffix := func(s *Section) string { + switch { + case strings.HasPrefix(s.Name, "__debug_"): + return s.Name[8:] + case strings.HasPrefix(s.Name, "__zdebug_"): + return s.Name[9:] + default: + return "" + } + + } + sectionData := func(s *Section) ([]byte, error) { + b, err := s.Data() + if err != nil && uint64(len(b)) < s.Size { + return nil, err + } + + if len(b) >= 12 && string(b[:4]) == "ZLIB" { + dlen := binary.BigEndian.Uint64(b[4:12]) + dbuf := make([]byte, dlen) + r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) + if err != nil { + return nil, err + } + if _, err := io.ReadFull(r, dbuf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } + b = dbuf + } + return b, nil + } + + // There are many other DWARF sections, but these + // are the ones the debug/dwarf package uses. + // Don't bother loading others. + var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} + for _, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix == "" { + continue + } + if _, ok := dat[suffix]; !ok { + continue + } + b, err := sectionData(s) + if err != nil { + return nil, err + } + dat[suffix] = b + } + + d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) + if err != nil { + return nil, err + } + + // Look for DWARF4 .debug_types sections. + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix != "types" { + continue + } + + b, err := sectionData(s) + if err != nil { + return nil, err + } + + err = d.AddTypes(fmt.Sprintf("types-%d", i), b) + if err != nil { + return nil, err + } + } + + return d, nil +} + +// ImportedSymbols returns the names of all symbols +// referred to by the binary f that are expected to be +// satisfied by other libraries at dynamic load time. +func (f *File) ImportedSymbols() ([]string, error) { + if f.Dysymtab == nil || f.Symtab == nil { + return nil, &FormatError{0, "missing symbol table", nil} + } + + st := f.Symtab + dt := f.Dysymtab + var all []string + for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] { + all = append(all, s.Name) + } + return all, nil +} + +// ImportedLibraries returns the paths of all libraries +// referred to by the binary f that are expected to be +// linked with the binary at dynamic link time. +func (f *File) ImportedLibraries() ([]string, error) { + var all []string + for _, l := range f.Loads { + if lib, ok := l.(*Dylib); ok { + all = append(all, lib.Name) + } + } + return all, nil +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/macho/macho.go b/vendor/github.com/mandiant/GoReSym/debug/macho/macho.go new file mode 100644 index 00000000..8a3c05b5 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/macho/macho.go @@ -0,0 +1,343 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Mach-O header data structures +// Originally at: +// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html (since deleted by Apply) +// Archived copy at: +// https://web.archive.org/web/20090819232456/http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/index.html +// For cloned PDF see: +// https://github.com/aidansteele/osx-abi-macho-file-format-reference + +package macho + +import "strconv" + +// A FileHeader represents a Mach-O file header. +type FileHeader struct { + Magic uint32 + Cpu Cpu + SubCpu uint32 + Type Type + Ncmd uint32 + Cmdsz uint32 + Flags uint32 +} + +const ( + fileHeaderSize32 = 7 * 4 + fileHeaderSize64 = 8 * 4 +) + +const ( + Magic32 uint32 = 0xfeedface + Magic64 uint32 = 0xfeedfacf + MagicFat uint32 = 0xcafebabe +) + +// A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library. +type Type uint32 + +const ( + TypeObj Type = 1 + TypeExec Type = 2 + TypeDylib Type = 6 + TypeBundle Type = 8 +) + +var typeStrings = []intName{ + {uint32(TypeObj), "Obj"}, + {uint32(TypeExec), "Exec"}, + {uint32(TypeDylib), "Dylib"}, + {uint32(TypeBundle), "Bundle"}, +} + +func (t Type) String() string { return stringName(uint32(t), typeStrings, false) } +func (t Type) GoString() string { return stringName(uint32(t), typeStrings, true) } + +// A Cpu is a Mach-O cpu type. +type Cpu uint32 + +const cpuArch64 = 0x01000000 + +const ( + Cpu386 Cpu = 7 + CpuAmd64 Cpu = Cpu386 | cpuArch64 + CpuArm Cpu = 12 + CpuArm64 Cpu = CpuArm | cpuArch64 + CpuPpc Cpu = 18 + CpuPpc64 Cpu = CpuPpc | cpuArch64 +) + +var cpuStrings = []intName{ + {uint32(Cpu386), "Cpu386"}, + {uint32(CpuAmd64), "CpuAmd64"}, + {uint32(CpuArm), "CpuArm"}, + {uint32(CpuArm64), "CpuArm64"}, + {uint32(CpuPpc), "CpuPpc"}, + {uint32(CpuPpc64), "CpuPpc64"}, +} + +func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) } +func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) } + +// A LoadCmd is a Mach-O load command. +type LoadCmd uint32 + +const ( + LoadCmdSegment LoadCmd = 0x1 + LoadCmdSymtab LoadCmd = 0x2 + LoadCmdThread LoadCmd = 0x4 + LoadCmdUnixThread LoadCmd = 0x5 // thread+stack + LoadCmdDysymtab LoadCmd = 0xb + LoadCmdDylib LoadCmd = 0xc // load dylib command + LoadCmdDylinker LoadCmd = 0xf // id dylinker command (not load dylinker command) + LoadCmdSegment64 LoadCmd = 0x19 + LoadCmdRpath LoadCmd = 0x8000001c +) + +var cmdStrings = []intName{ + {uint32(LoadCmdSegment), "LoadCmdSegment"}, + {uint32(LoadCmdThread), "LoadCmdThread"}, + {uint32(LoadCmdUnixThread), "LoadCmdUnixThread"}, + {uint32(LoadCmdDylib), "LoadCmdDylib"}, + {uint32(LoadCmdSegment64), "LoadCmdSegment64"}, + {uint32(LoadCmdRpath), "LoadCmdRpath"}, +} + +func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) } +func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) } + +type ( + // A Segment32 is a 32-bit Mach-O segment load command. + Segment32 struct { + Cmd LoadCmd + Len uint32 + Name [16]byte + Addr uint32 + Memsz uint32 + Offset uint32 + Filesz uint32 + Maxprot uint32 + Prot uint32 + Nsect uint32 + Flag uint32 + } + + // A Segment64 is a 64-bit Mach-O segment load command. + Segment64 struct { + Cmd LoadCmd + Len uint32 + Name [16]byte + Addr uint64 + Memsz uint64 + Offset uint64 + Filesz uint64 + Maxprot uint32 + Prot uint32 + Nsect uint32 + Flag uint32 + } + + // A SymtabCmd is a Mach-O symbol table command. + SymtabCmd struct { + Cmd LoadCmd + Len uint32 + Symoff uint32 + Nsyms uint32 + Stroff uint32 + Strsize uint32 + } + + // A DysymtabCmd is a Mach-O dynamic symbol table command. + DysymtabCmd struct { + Cmd LoadCmd + Len uint32 + Ilocalsym uint32 + Nlocalsym uint32 + Iextdefsym uint32 + Nextdefsym uint32 + Iundefsym uint32 + Nundefsym uint32 + Tocoffset uint32 + Ntoc uint32 + Modtaboff uint32 + Nmodtab uint32 + Extrefsymoff uint32 + Nextrefsyms uint32 + Indirectsymoff uint32 + Nindirectsyms uint32 + Extreloff uint32 + Nextrel uint32 + Locreloff uint32 + Nlocrel uint32 + } + + // A DylibCmd is a Mach-O load dynamic library command. + DylibCmd struct { + Cmd LoadCmd + Len uint32 + Name uint32 + Time uint32 + CurrentVersion uint32 + CompatVersion uint32 + } + + // A RpathCmd is a Mach-O rpath command. + RpathCmd struct { + Cmd LoadCmd + Len uint32 + Path uint32 + } + + // A Thread is a Mach-O thread state command. + Thread struct { + Cmd LoadCmd + Len uint32 + Type uint32 + Data []uint32 + } +) + +const ( + FlagNoUndefs uint32 = 0x1 + FlagIncrLink uint32 = 0x2 + FlagDyldLink uint32 = 0x4 + FlagBindAtLoad uint32 = 0x8 + FlagPrebound uint32 = 0x10 + FlagSplitSegs uint32 = 0x20 + FlagLazyInit uint32 = 0x40 + FlagTwoLevel uint32 = 0x80 + FlagForceFlat uint32 = 0x100 + FlagNoMultiDefs uint32 = 0x200 + FlagNoFixPrebinding uint32 = 0x400 + FlagPrebindable uint32 = 0x800 + FlagAllModsBound uint32 = 0x1000 + FlagSubsectionsViaSymbols uint32 = 0x2000 + FlagCanonical uint32 = 0x4000 + FlagWeakDefines uint32 = 0x8000 + FlagBindsToWeak uint32 = 0x10000 + FlagAllowStackExecution uint32 = 0x20000 + FlagRootSafe uint32 = 0x40000 + FlagSetuidSafe uint32 = 0x80000 + FlagNoReexportedDylibs uint32 = 0x100000 + FlagPIE uint32 = 0x200000 + FlagDeadStrippableDylib uint32 = 0x400000 + FlagHasTLVDescriptors uint32 = 0x800000 + FlagNoHeapExecution uint32 = 0x1000000 + FlagAppExtensionSafe uint32 = 0x2000000 +) + +// A Section32 is a 32-bit Mach-O section header. +type Section32 struct { + Name [16]byte + Seg [16]byte + Addr uint32 + Size uint32 + Offset uint32 + Align uint32 + Reloff uint32 + Nreloc uint32 + Flags uint32 + Reserve1 uint32 + Reserve2 uint32 +} + +// A Section64 is a 64-bit Mach-O section header. +type Section64 struct { + Name [16]byte + Seg [16]byte + Addr uint64 + Size uint64 + Offset uint32 + Align uint32 + Reloff uint32 + Nreloc uint32 + Flags uint32 + Reserve1 uint32 + Reserve2 uint32 + Reserve3 uint32 +} + +// An Nlist32 is a Mach-O 32-bit symbol table entry. +type Nlist32 struct { + Name uint32 + Type uint8 + Sect uint8 + Desc uint16 + Value uint32 +} + +// An Nlist64 is a Mach-O 64-bit symbol table entry. +type Nlist64 struct { + Name uint32 + Type uint8 + Sect uint8 + Desc uint16 + Value uint64 +} + +// Regs386 is the Mach-O 386 register structure. +type Regs386 struct { + AX uint32 + BX uint32 + CX uint32 + DX uint32 + DI uint32 + SI uint32 + BP uint32 + SP uint32 + SS uint32 + FLAGS uint32 + IP uint32 + CS uint32 + DS uint32 + ES uint32 + FS uint32 + GS uint32 +} + +// RegsAMD64 is the Mach-O AMD64 register structure. +type RegsAMD64 struct { + AX uint64 + BX uint64 + CX uint64 + DX uint64 + DI uint64 + SI uint64 + BP uint64 + SP uint64 + R8 uint64 + R9 uint64 + R10 uint64 + R11 uint64 + R12 uint64 + R13 uint64 + R14 uint64 + R15 uint64 + IP uint64 + FLAGS uint64 + CS uint64 + FS uint64 + GS uint64 +} + +type intName struct { + i uint32 + s string +} + +func stringName(i uint32, names []intName, goSyntax bool) string { + for _, n := range names { + if n.i == i { + if goSyntax { + return "macho." + n.s + } + return n.s + } + } + return strconv.FormatUint(uint64(i), 10) +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/macho/reloctype.go b/vendor/github.com/mandiant/GoReSym/debug/macho/reloctype.go new file mode 100644 index 00000000..a61223e6 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/macho/reloctype.go @@ -0,0 +1,74 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package macho + +//go:generate stringer -type=RelocTypeGeneric,RelocTypeX86_64,RelocTypeARM,RelocTypeARM64 -output reloctype_string.go + +type RelocTypeGeneric int + +const ( + GENERIC_RELOC_VANILLA RelocTypeGeneric = 0 + GENERIC_RELOC_PAIR RelocTypeGeneric = 1 + GENERIC_RELOC_SECTDIFF RelocTypeGeneric = 2 + GENERIC_RELOC_PB_LA_PTR RelocTypeGeneric = 3 + GENERIC_RELOC_LOCAL_SECTDIFF RelocTypeGeneric = 4 + GENERIC_RELOC_TLV RelocTypeGeneric = 5 +) + +func (r RelocTypeGeneric) GoString() string { return "macho." + r.String() } + +type RelocTypeX86_64 int + +const ( + X86_64_RELOC_UNSIGNED RelocTypeX86_64 = 0 + X86_64_RELOC_SIGNED RelocTypeX86_64 = 1 + X86_64_RELOC_BRANCH RelocTypeX86_64 = 2 + X86_64_RELOC_GOT_LOAD RelocTypeX86_64 = 3 + X86_64_RELOC_GOT RelocTypeX86_64 = 4 + X86_64_RELOC_SUBTRACTOR RelocTypeX86_64 = 5 + X86_64_RELOC_SIGNED_1 RelocTypeX86_64 = 6 + X86_64_RELOC_SIGNED_2 RelocTypeX86_64 = 7 + X86_64_RELOC_SIGNED_4 RelocTypeX86_64 = 8 + X86_64_RELOC_TLV RelocTypeX86_64 = 9 +) + +func (r RelocTypeX86_64) GoString() string { return "macho." + r.String() } + +type RelocTypeARM int + +const ( + ARM_RELOC_VANILLA RelocTypeARM = 0 + ARM_RELOC_PAIR RelocTypeARM = 1 + ARM_RELOC_SECTDIFF RelocTypeARM = 2 + ARM_RELOC_LOCAL_SECTDIFF RelocTypeARM = 3 + ARM_RELOC_PB_LA_PTR RelocTypeARM = 4 + ARM_RELOC_BR24 RelocTypeARM = 5 + ARM_THUMB_RELOC_BR22 RelocTypeARM = 6 + ARM_THUMB_32BIT_BRANCH RelocTypeARM = 7 + ARM_RELOC_HALF RelocTypeARM = 8 + ARM_RELOC_HALF_SECTDIFF RelocTypeARM = 9 +) + +func (r RelocTypeARM) GoString() string { return "macho." + r.String() } + +type RelocTypeARM64 int + +const ( + ARM64_RELOC_UNSIGNED RelocTypeARM64 = 0 + ARM64_RELOC_SUBTRACTOR RelocTypeARM64 = 1 + ARM64_RELOC_BRANCH26 RelocTypeARM64 = 2 + ARM64_RELOC_PAGE21 RelocTypeARM64 = 3 + ARM64_RELOC_PAGEOFF12 RelocTypeARM64 = 4 + ARM64_RELOC_GOT_LOAD_PAGE21 RelocTypeARM64 = 5 + ARM64_RELOC_GOT_LOAD_PAGEOFF12 RelocTypeARM64 = 6 + ARM64_RELOC_POINTER_TO_GOT RelocTypeARM64 = 7 + ARM64_RELOC_TLVP_LOAD_PAGE21 RelocTypeARM64 = 8 + ARM64_RELOC_TLVP_LOAD_PAGEOFF12 RelocTypeARM64 = 9 + ARM64_RELOC_ADDEND RelocTypeARM64 = 10 +) + +func (r RelocTypeARM64) GoString() string { return "macho." + r.String() } diff --git a/vendor/github.com/mandiant/GoReSym/debug/macho/reloctype_string.go b/vendor/github.com/mandiant/GoReSym/debug/macho/reloctype_string.go new file mode 100644 index 00000000..9c2b1318 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/macho/reloctype_string.go @@ -0,0 +1,49 @@ +// Code generated by "stringer -type=RelocTypeGeneric,RelocTypeX86_64,RelocTypeARM,RelocTypeARM64 -output reloctype_string.go"; DO NOT EDIT. + +package macho + +import "strconv" + +const _RelocTypeGeneric_name = "GENERIC_RELOC_VANILLAGENERIC_RELOC_PAIRGENERIC_RELOC_SECTDIFFGENERIC_RELOC_PB_LA_PTRGENERIC_RELOC_LOCAL_SECTDIFFGENERIC_RELOC_TLV" + +var _RelocTypeGeneric_index = [...]uint8{0, 21, 39, 61, 84, 112, 129} + +func (i RelocTypeGeneric) String() string { + if i < 0 || i >= RelocTypeGeneric(len(_RelocTypeGeneric_index)-1) { + return "RelocTypeGeneric(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _RelocTypeGeneric_name[_RelocTypeGeneric_index[i]:_RelocTypeGeneric_index[i+1]] +} + +const _RelocTypeX86_64_name = "X86_64_RELOC_UNSIGNEDX86_64_RELOC_SIGNEDX86_64_RELOC_BRANCHX86_64_RELOC_GOT_LOADX86_64_RELOC_GOTX86_64_RELOC_SUBTRACTORX86_64_RELOC_SIGNED_1X86_64_RELOC_SIGNED_2X86_64_RELOC_SIGNED_4X86_64_RELOC_TLV" + +var _RelocTypeX86_64_index = [...]uint8{0, 21, 40, 59, 80, 96, 119, 140, 161, 182, 198} + +func (i RelocTypeX86_64) String() string { + if i < 0 || i >= RelocTypeX86_64(len(_RelocTypeX86_64_index)-1) { + return "RelocTypeX86_64(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _RelocTypeX86_64_name[_RelocTypeX86_64_index[i]:_RelocTypeX86_64_index[i+1]] +} + +const _RelocTypeARM_name = "ARM_RELOC_VANILLAARM_RELOC_PAIRARM_RELOC_SECTDIFFARM_RELOC_LOCAL_SECTDIFFARM_RELOC_PB_LA_PTRARM_RELOC_BR24ARM_THUMB_RELOC_BR22ARM_THUMB_32BIT_BRANCHARM_RELOC_HALFARM_RELOC_HALF_SECTDIFF" + +var _RelocTypeARM_index = [...]uint8{0, 17, 31, 49, 73, 92, 106, 126, 148, 162, 185} + +func (i RelocTypeARM) String() string { + if i < 0 || i >= RelocTypeARM(len(_RelocTypeARM_index)-1) { + return "RelocTypeARM(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _RelocTypeARM_name[_RelocTypeARM_index[i]:_RelocTypeARM_index[i+1]] +} + +const _RelocTypeARM64_name = "ARM64_RELOC_UNSIGNEDARM64_RELOC_SUBTRACTORARM64_RELOC_BRANCH26ARM64_RELOC_PAGE21ARM64_RELOC_PAGEOFF12ARM64_RELOC_GOT_LOAD_PAGE21ARM64_RELOC_GOT_LOAD_PAGEOFF12ARM64_RELOC_POINTER_TO_GOTARM64_RELOC_TLVP_LOAD_PAGE21ARM64_RELOC_TLVP_LOAD_PAGEOFF12ARM64_RELOC_ADDEND" + +var _RelocTypeARM64_index = [...]uint16{0, 20, 42, 62, 80, 101, 128, 158, 184, 212, 243, 261} + +func (i RelocTypeARM64) String() string { + if i < 0 || i >= RelocTypeARM64(len(_RelocTypeARM64_index)-1) { + return "RelocTypeARM64(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _RelocTypeARM64_name[_RelocTypeARM64_index[i]:_RelocTypeARM64_index[i+1]] +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/pe/file.go b/vendor/github.com/mandiant/GoReSym/debug/pe/file.go new file mode 100644 index 00000000..5f16fb92 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/pe/file.go @@ -0,0 +1,643 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Package pe implements access to PE (Microsoft Windows Portable Executable) files. +package pe + +import ( + "bytes" + "compress/zlib" + "encoding/binary" + "fmt" + "io" + "os" + "strings" + + "github.com/mandiant/GoReSym/debug/dwarf" +) + +// Avoid use of post-Go 1.4 io features, to make safe for toolchain bootstrap. +const seekStart = 0 + +// A File represents an open PE file. +type File struct { + FileHeader + OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64 + Sections []*Section + Symbols []*Symbol // COFF symbols with auxiliary symbol records removed + COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records) + StringTable StringTable + + closer io.Closer + dataAfterSectionCache map[uint64][]byte // secVA -> dataAfterSection +} + +// Open opens the named file using os.Open and prepares it for use as a PE binary. +func Open(name string) (*File, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + ff, err := NewFile(f) + if err != nil { + f.Close() + return nil, err + } + ff.closer = f + return ff, nil +} + +// Close closes the File. +// If the File was created using NewFile directly instead of Open, +// Close has no effect. +func (f *File) Close() error { + var err error + if f.closer != nil { + err = f.closer.Close() + f.closer = nil + } + return err +} + +// TODO(brainman): add Load function, as a replacement for NewFile, that does not call removeAuxSymbols (for performance) + +// NewFile creates a new File for accessing a PE binary in an underlying reader. +func NewFile(r io.ReaderAt) (*File, error) { + f := new(File) + f.dataAfterSectionCache = make(map[uint64][]byte) + sr := io.NewSectionReader(r, 0, 1<<63-1) + + var dosheader [96]byte + if _, err := r.ReadAt(dosheader[0:], 0); err != nil { + return nil, err + } + var base int64 + if dosheader[0] == 'M' && dosheader[1] == 'Z' { + signoff := int64(binary.LittleEndian.Uint32(dosheader[0x3c:])) + var sign [4]byte + r.ReadAt(sign[:], signoff) + if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) { + return nil, fmt.Errorf("invalid PE file signature: % x", sign) + } + base = signoff + 4 + } else { + base = int64(0) + } + sr.Seek(base, seekStart) + if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil { + return nil, err + } + switch f.FileHeader.Machine { + case IMAGE_FILE_MACHINE_AMD64, + IMAGE_FILE_MACHINE_ARM64, + IMAGE_FILE_MACHINE_ARMNT, + IMAGE_FILE_MACHINE_I386, + IMAGE_FILE_MACHINE_RISCV32, + IMAGE_FILE_MACHINE_RISCV64, + IMAGE_FILE_MACHINE_RISCV128, + IMAGE_FILE_MACHINE_UNKNOWN: + // ok + default: + return nil, fmt.Errorf("unrecognized PE machine: %#x", f.FileHeader.Machine) + } + + var err error + + // Read string table. + f.StringTable, err = readStringTable(&f.FileHeader, sr) + if err != nil { + f.StringTable = nil // this isn't fatal + } + + // Read symbol table. + f.COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr) + if err != nil { + return nil, err + } + f.Symbols, err = removeAuxSymbols(f.COFFSymbols, f.StringTable) + if err != nil { + return nil, err + } + + // Seek past file header. + _, err = sr.Seek(base+int64(binary.Size(f.FileHeader)), seekStart) + if err != nil { + return nil, err + } + + // Read optional header. + f.OptionalHeader, err = readOptionalHeader(sr, f.FileHeader.SizeOfOptionalHeader) + if err != nil { + return nil, err + } + + // Process sections. + f.Sections = make([]*Section, f.FileHeader.NumberOfSections) + for i := 0; i < int(f.FileHeader.NumberOfSections); i++ { + sh := new(SectionHeader32) + if err := binary.Read(sr, binary.LittleEndian, sh); err != nil { + return nil, err + } + name, err := sh.fullName(f.StringTable) + if err != nil { + return nil, err + } + s := new(Section) + s.SectionHeader = SectionHeader{ + Name: name, + VirtualSize: sh.VirtualSize, + VirtualAddress: sh.VirtualAddress, + Size: sh.SizeOfRawData, + Offset: sh.PointerToRawData, + PointerToRelocations: sh.PointerToRelocations, + PointerToLineNumbers: sh.PointerToLineNumbers, + NumberOfRelocations: sh.NumberOfRelocations, + NumberOfLineNumbers: sh.NumberOfLineNumbers, + Characteristics: sh.Characteristics, + } + r2 := r + if sh.PointerToRawData == 0 { // .bss must have all 0s + r2 = zeroReaderAt{} + } + s.sr = io.NewSectionReader(r2, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size)) + s.ReaderAt = s.sr + f.Sections[i] = s + } + for i := range f.Sections { + var err error + f.Sections[i].Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr) + if err != nil { + return nil, err + } + } + return f, nil +} + +// zeroReaderAt is ReaderAt that reads 0s. +type zeroReaderAt struct{} + +// ReadAt writes len(p) 0s into p. +func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) { + for i := range p { + p[i] = 0 + } + return len(p), nil +} + +// getString extracts a string from symbol string table. +func getString(section []byte, start int) (string, bool) { + if start < 0 || start >= len(section) { + return "", false + } + + for end := start; end < len(section); end++ { + if section[end] == 0 { + return string(section[start:end]), true + } + } + return "", false +} + +// Section returns the first section with the given name, or nil if no such +// section exists. +func (f *File) Section(name string) *Section { + for _, s := range f.Sections { + if s.Name == name { + return s + } + } + return nil +} + +func (f *File) DataAfterSection(target *Section) []byte { + if cached, ok := f.dataAfterSectionCache[uint64(target.VirtualAddress)]; ok { + return cached + } + + data := []byte{} + found := false + for _, s := range f.Sections { + if s.VirtualAddress == target.VirtualAddress && s.Name == target.Name { + found = true + } + + if found { + raw, err := s.Data() + if raw != nil { + data = append(data, raw[:]...) + } + + if err != nil { + break + } + } + } + f.dataAfterSectionCache[uint64(target.VirtualAddress)] = data + return data +} + +func (f *File) DWARF() (*dwarf.Data, error) { + dwarfSuffix := func(s *Section) string { + switch { + case strings.HasPrefix(s.Name, ".debug_"): + return s.Name[7:] + case strings.HasPrefix(s.Name, ".zdebug_"): + return s.Name[8:] + default: + return "" + } + + } + + // sectionData gets the data for s and checks its size. + sectionData := func(s *Section) ([]byte, error) { + b, err := s.Data() + if err != nil && uint32(len(b)) < s.Size { + return nil, err + } + + if 0 < s.VirtualSize && s.VirtualSize < s.Size { + b = b[:s.VirtualSize] + } + + if len(b) >= 12 && string(b[:4]) == "ZLIB" { + dlen := binary.BigEndian.Uint64(b[4:12]) + dbuf := make([]byte, dlen) + r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) + if err != nil { + return nil, err + } + if _, err := io.ReadFull(r, dbuf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } + b = dbuf + } + return b, nil + } + + // There are many other DWARF sections, but these + // are the ones the debug/dwarf package uses. + // Don't bother loading others. + var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} + for _, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix == "" { + continue + } + if _, ok := dat[suffix]; !ok { + continue + } + + b, err := sectionData(s) + if err != nil { + return nil, err + } + dat[suffix] = b + } + + d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) + if err != nil { + return nil, err + } + + // Look for DWARF4 .debug_types sections. + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix != "types" { + continue + } + + b, err := sectionData(s) + if err != nil { + return nil, err + } + + err = d.AddTypes(fmt.Sprintf("types-%d", i), b) + if err != nil { + return nil, err + } + } + + return d, nil +} + +// TODO(brainman): document ImportDirectory once we decide what to do with it. + +type ImportDirectory struct { + OriginalFirstThunk uint32 + TimeDateStamp uint32 + ForwarderChain uint32 + Name uint32 + FirstThunk uint32 + + dll string +} + +// ImportedSymbols returns the names of all symbols +// referred to by the binary f that are expected to be +// satisfied by other libraries at dynamic load time. +// It does not return weak symbols. +func (f *File) ImportedSymbols() ([]string, error) { + if f.OptionalHeader == nil { + return nil, nil + } + + _, pe64 := f.OptionalHeader.(*OptionalHeader64) + + // grab the number of data directory entries + var dd_length uint32 + if pe64 { + dd_length = f.OptionalHeader.(*OptionalHeader64).NumberOfRvaAndSizes + } else { + dd_length = f.OptionalHeader.(*OptionalHeader32).NumberOfRvaAndSizes + } + + // check that the length of data directory entries is large + // enough to include the imports directory. + if dd_length < IMAGE_DIRECTORY_ENTRY_IMPORT+1 { + return nil, nil + } + + // grab the import data directory entry + var idd DataDirectory + if pe64 { + idd = f.OptionalHeader.(*OptionalHeader64).DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] + } else { + idd = f.OptionalHeader.(*OptionalHeader32).DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] + } + + // figure out which section contains the import directory table + var ds *Section + ds = nil + for _, s := range f.Sections { + // We are using distance between s.VirtualAddress and idd.VirtualAddress + // to avoid potential overflow of uint32 caused by addition of s.VirtualSize + // to s.VirtualAddress. + if s.VirtualAddress <= idd.VirtualAddress && idd.VirtualAddress-s.VirtualAddress < s.VirtualSize { + ds = s + break + } + } + + // didn't find a section, so no import libraries were found + if ds == nil { + return nil, nil + } + + d, err := ds.Data() + if err != nil { + return nil, err + } + + // seek to the virtual address specified in the import data directory + d = d[idd.VirtualAddress-ds.VirtualAddress:] + + // start decoding the import directory + var ida []ImportDirectory + for len(d) >= 20 { + var dt ImportDirectory + dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4]) + dt.TimeDateStamp = binary.LittleEndian.Uint32(d[4:8]) + dt.ForwarderChain = binary.LittleEndian.Uint32(d[8:12]) + dt.Name = binary.LittleEndian.Uint32(d[12:16]) + dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20]) + d = d[20:] + if dt.OriginalFirstThunk == 0 { + break + } + ida = append(ida, dt) + } + // TODO(brainman): this needs to be rewritten + // ds.Data() returns contents of section containing import table. Why store in variable called "names"? + // Why we are retrieving it second time? We already have it in "d", and it is not modified anywhere. + // getString does not extracts a string from symbol string table (as getString doco says). + // Why ds.Data() called again and again in the loop? + // Needs test before rewrite. + names, _ := ds.Data() + var all []string + for _, dt := range ida { + dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress)) + d, _ = ds.Data() + // seek to OriginalFirstThunk + d = d[dt.OriginalFirstThunk-ds.VirtualAddress:] + for len(d) > 0 { + if pe64 { // 64bit + va := binary.LittleEndian.Uint64(d[0:8]) + d = d[8:] + if va == 0 { + break + } + if va&0x8000000000000000 > 0 { // is Ordinal + // TODO add dynimport ordinal support. + } else { + fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2)) + all = append(all, fn+":"+dt.dll) + } + } else { // 32bit + va := binary.LittleEndian.Uint32(d[0:4]) + d = d[4:] + if va == 0 { + break + } + if va&0x80000000 > 0 { // is Ordinal + // TODO add dynimport ordinal support. + //ord := va&0x0000FFFF + } else { + fn, _ := getString(names, int(va-ds.VirtualAddress+2)) + all = append(all, fn+":"+dt.dll) + } + } + } + } + + return all, nil +} + +// ImportedLibraries returns the names of all libraries +// referred to by the binary f that are expected to be +// linked with the binary at dynamic link time. +func (f *File) ImportedLibraries() ([]string, error) { + // TODO + // cgo -dynimport don't use this for windows PE, so just return. + return nil, nil +} + +// FormatError is unused. +// The type is retained for compatibility. +type FormatError struct { +} + +func (e *FormatError) Error() string { + return "unknown error" +} + +// readOptionalHeader accepts a io.ReadSeeker pointing to optional header in the PE file +// and its size as seen in the file header. +// It parses the given size of bytes and returns optional header. It infers whether the +// bytes being parsed refer to 32 bit or 64 bit version of optional header. +func readOptionalHeader(r io.ReadSeeker, sz uint16) (interface{}, error) { + // If optional header size is 0, return empty optional header. + if sz == 0 { + return nil, nil + } + + var ( + // First couple of bytes in option header state its type. + // We need to read them first to determine the type and + // validity of optional header. + ohMagic uint16 + ohMagicSz = binary.Size(ohMagic) + ) + + // If optional header size is greater than 0 but less than its magic size, return error. + if sz < uint16(ohMagicSz) { + return nil, fmt.Errorf("optional header size is less than optional header magic size") + } + + // read reads from io.ReadSeeke, r, into data. + var err error + read := func(data interface{}) bool { + err = binary.Read(r, binary.LittleEndian, data) + return err == nil + } + + if !read(&ohMagic) { + return nil, fmt.Errorf("failure to read optional header magic: %v", err) + + } + + switch ohMagic { + case 0x10b: // PE32 + var ( + oh32 OptionalHeader32 + // There can be 0 or more data directories. So the minimum size of optional + // header is calculated by subtracting oh32.DataDirectory size from oh32 size. + oh32MinSz = binary.Size(oh32) - binary.Size(oh32.DataDirectory) + ) + + if sz < uint16(oh32MinSz) { + return nil, fmt.Errorf("optional header size(%d) is less minimum size (%d) of PE32 optional header", sz, oh32MinSz) + } + + // Init oh32 fields + oh32.Magic = ohMagic + if !read(&oh32.MajorLinkerVersion) || + !read(&oh32.MinorLinkerVersion) || + !read(&oh32.SizeOfCode) || + !read(&oh32.SizeOfInitializedData) || + !read(&oh32.SizeOfUninitializedData) || + !read(&oh32.AddressOfEntryPoint) || + !read(&oh32.BaseOfCode) || + !read(&oh32.BaseOfData) || + !read(&oh32.ImageBase) || + !read(&oh32.SectionAlignment) || + !read(&oh32.FileAlignment) || + !read(&oh32.MajorOperatingSystemVersion) || + !read(&oh32.MinorOperatingSystemVersion) || + !read(&oh32.MajorImageVersion) || + !read(&oh32.MinorImageVersion) || + !read(&oh32.MajorSubsystemVersion) || + !read(&oh32.MinorSubsystemVersion) || + !read(&oh32.Win32VersionValue) || + !read(&oh32.SizeOfImage) || + !read(&oh32.SizeOfHeaders) || + !read(&oh32.CheckSum) || + !read(&oh32.Subsystem) || + !read(&oh32.DllCharacteristics) || + !read(&oh32.SizeOfStackReserve) || + !read(&oh32.SizeOfStackCommit) || + !read(&oh32.SizeOfHeapReserve) || + !read(&oh32.SizeOfHeapCommit) || + !read(&oh32.LoaderFlags) || + !read(&oh32.NumberOfRvaAndSizes) { + return nil, fmt.Errorf("failure to read PE32 optional header: %v", err) + } + + dd, err := readDataDirectories(r, sz-uint16(oh32MinSz), oh32.NumberOfRvaAndSizes) + if err != nil { + return nil, err + } + + copy(oh32.DataDirectory[:], dd) + + return &oh32, nil + case 0x20b: // PE32+ + var ( + oh64 OptionalHeader64 + // There can be 0 or more data directories. So the minimum size of optional + // header is calculated by subtracting oh64.DataDirectory size from oh64 size. + oh64MinSz = binary.Size(oh64) - binary.Size(oh64.DataDirectory) + ) + + if sz < uint16(oh64MinSz) { + return nil, fmt.Errorf("optional header size(%d) is less minimum size (%d) for PE32+ optional header", sz, oh64MinSz) + } + + // Init oh64 fields + oh64.Magic = ohMagic + if !read(&oh64.MajorLinkerVersion) || + !read(&oh64.MinorLinkerVersion) || + !read(&oh64.SizeOfCode) || + !read(&oh64.SizeOfInitializedData) || + !read(&oh64.SizeOfUninitializedData) || + !read(&oh64.AddressOfEntryPoint) || + !read(&oh64.BaseOfCode) || + !read(&oh64.ImageBase) || + !read(&oh64.SectionAlignment) || + !read(&oh64.FileAlignment) || + !read(&oh64.MajorOperatingSystemVersion) || + !read(&oh64.MinorOperatingSystemVersion) || + !read(&oh64.MajorImageVersion) || + !read(&oh64.MinorImageVersion) || + !read(&oh64.MajorSubsystemVersion) || + !read(&oh64.MinorSubsystemVersion) || + !read(&oh64.Win32VersionValue) || + !read(&oh64.SizeOfImage) || + !read(&oh64.SizeOfHeaders) || + !read(&oh64.CheckSum) || + !read(&oh64.Subsystem) || + !read(&oh64.DllCharacteristics) || + !read(&oh64.SizeOfStackReserve) || + !read(&oh64.SizeOfStackCommit) || + !read(&oh64.SizeOfHeapReserve) || + !read(&oh64.SizeOfHeapCommit) || + !read(&oh64.LoaderFlags) || + !read(&oh64.NumberOfRvaAndSizes) { + return nil, fmt.Errorf("failure to read PE32+ optional header: %v", err) + } + + dd, err := readDataDirectories(r, sz-uint16(oh64MinSz), oh64.NumberOfRvaAndSizes) + if err != nil { + return nil, err + } + + copy(oh64.DataDirectory[:], dd) + + return &oh64, nil + default: + return nil, fmt.Errorf("optional header has unexpected Magic of 0x%x", ohMagic) + } +} + +// readDataDirectories accepts a io.ReadSeeker pointing to data directories in the PE file, +// its size and number of data directories as seen in optional header. +// It parses the given size of bytes and returns given number of data directories. +func readDataDirectories(r io.ReadSeeker, sz uint16, n uint32) ([]DataDirectory, error) { + ddSz := binary.Size(DataDirectory{}) + if uint32(sz) != n*uint32(ddSz) { + return nil, fmt.Errorf("size of data directories(%d) is inconsistent with number of data directories(%d)", sz, n) + } + + dd := make([]DataDirectory, n) + if err := binary.Read(r, binary.LittleEndian, dd); err != nil { + return nil, fmt.Errorf("failure to read data directories: %v", err) + } + + return dd, nil +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/pe/pe.go b/vendor/github.com/mandiant/GoReSym/debug/pe/pe.go new file mode 100644 index 00000000..07550537 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/pe/pe.go @@ -0,0 +1,191 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package pe + +type FileHeader struct { + Machine uint16 + NumberOfSections uint16 + TimeDateStamp uint32 + PointerToSymbolTable uint32 + NumberOfSymbols uint32 + SizeOfOptionalHeader uint16 + Characteristics uint16 +} + +type DataDirectory struct { + VirtualAddress uint32 + Size uint32 +} + +type OptionalHeader32 struct { + Magic uint16 + MajorLinkerVersion uint8 + MinorLinkerVersion uint8 + SizeOfCode uint32 + SizeOfInitializedData uint32 + SizeOfUninitializedData uint32 + AddressOfEntryPoint uint32 + BaseOfCode uint32 + BaseOfData uint32 + ImageBase uint32 + SectionAlignment uint32 + FileAlignment uint32 + MajorOperatingSystemVersion uint16 + MinorOperatingSystemVersion uint16 + MajorImageVersion uint16 + MinorImageVersion uint16 + MajorSubsystemVersion uint16 + MinorSubsystemVersion uint16 + Win32VersionValue uint32 + SizeOfImage uint32 + SizeOfHeaders uint32 + CheckSum uint32 + Subsystem uint16 + DllCharacteristics uint16 + SizeOfStackReserve uint32 + SizeOfStackCommit uint32 + SizeOfHeapReserve uint32 + SizeOfHeapCommit uint32 + LoaderFlags uint32 + NumberOfRvaAndSizes uint32 + DataDirectory [16]DataDirectory +} + +type OptionalHeader64 struct { + Magic uint16 + MajorLinkerVersion uint8 + MinorLinkerVersion uint8 + SizeOfCode uint32 + SizeOfInitializedData uint32 + SizeOfUninitializedData uint32 + AddressOfEntryPoint uint32 + BaseOfCode uint32 + ImageBase uint64 + SectionAlignment uint32 + FileAlignment uint32 + MajorOperatingSystemVersion uint16 + MinorOperatingSystemVersion uint16 + MajorImageVersion uint16 + MinorImageVersion uint16 + MajorSubsystemVersion uint16 + MinorSubsystemVersion uint16 + Win32VersionValue uint32 + SizeOfImage uint32 + SizeOfHeaders uint32 + CheckSum uint32 + Subsystem uint16 + DllCharacteristics uint16 + SizeOfStackReserve uint64 + SizeOfStackCommit uint64 + SizeOfHeapReserve uint64 + SizeOfHeapCommit uint64 + LoaderFlags uint32 + NumberOfRvaAndSizes uint32 + DataDirectory [16]DataDirectory +} + +const ( + IMAGE_FILE_MACHINE_UNKNOWN = 0x0 + IMAGE_FILE_MACHINE_AM33 = 0x1d3 + IMAGE_FILE_MACHINE_AMD64 = 0x8664 + IMAGE_FILE_MACHINE_ARM = 0x1c0 + IMAGE_FILE_MACHINE_ARMNT = 0x1c4 + IMAGE_FILE_MACHINE_ARM64 = 0xaa64 + IMAGE_FILE_MACHINE_EBC = 0xebc + IMAGE_FILE_MACHINE_I386 = 0x14c + IMAGE_FILE_MACHINE_IA64 = 0x200 + IMAGE_FILE_MACHINE_LOONGARCH32 = 0x6232 + IMAGE_FILE_MACHINE_LOONGARCH64 = 0x6264 + IMAGE_FILE_MACHINE_M32R = 0x9041 + IMAGE_FILE_MACHINE_MIPS16 = 0x266 + IMAGE_FILE_MACHINE_MIPSFPU = 0x366 + IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466 + IMAGE_FILE_MACHINE_POWERPC = 0x1f0 + IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1 + IMAGE_FILE_MACHINE_R4000 = 0x166 + IMAGE_FILE_MACHINE_SH3 = 0x1a2 + IMAGE_FILE_MACHINE_SH3DSP = 0x1a3 + IMAGE_FILE_MACHINE_SH4 = 0x1a6 + IMAGE_FILE_MACHINE_SH5 = 0x1a8 + IMAGE_FILE_MACHINE_THUMB = 0x1c2 + IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169 + IMAGE_FILE_MACHINE_RISCV32 = 0x5032 + IMAGE_FILE_MACHINE_RISCV64 = 0x5064 + IMAGE_FILE_MACHINE_RISCV128 = 0x5128 +) + +// IMAGE_DIRECTORY_ENTRY constants +const ( + IMAGE_DIRECTORY_ENTRY_EXPORT = 0 + IMAGE_DIRECTORY_ENTRY_IMPORT = 1 + IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 + IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 + IMAGE_DIRECTORY_ENTRY_SECURITY = 4 + IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 + IMAGE_DIRECTORY_ENTRY_DEBUG = 6 + IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 + IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 + IMAGE_DIRECTORY_ENTRY_TLS = 9 + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 + IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 + IMAGE_DIRECTORY_ENTRY_IAT = 12 + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 + IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 +) + +// Values of IMAGE_FILE_HEADER.Characteristics. These can be combined together. +const ( + IMAGE_FILE_RELOCS_STRIPPED = 0x0001 + IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 + IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004 + IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008 + IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010 + IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 + IMAGE_FILE_BYTES_REVERSED_LO = 0x0080 + IMAGE_FILE_32BIT_MACHINE = 0x0100 + IMAGE_FILE_DEBUG_STRIPPED = 0x0200 + IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400 + IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800 + IMAGE_FILE_SYSTEM = 0x1000 + IMAGE_FILE_DLL = 0x2000 + IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000 + IMAGE_FILE_BYTES_REVERSED_HI = 0x8000 +) + +// OptionalHeader64.Subsystem and OptionalHeader32.Subsystem values. +const ( + IMAGE_SUBSYSTEM_UNKNOWN = 0 + IMAGE_SUBSYSTEM_NATIVE = 1 + IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 + IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 + IMAGE_SUBSYSTEM_OS2_CUI = 5 + IMAGE_SUBSYSTEM_POSIX_CUI = 7 + IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8 + IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9 + IMAGE_SUBSYSTEM_EFI_APPLICATION = 10 + IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11 + IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12 + IMAGE_SUBSYSTEM_EFI_ROM = 13 + IMAGE_SUBSYSTEM_XBOX = 14 + IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16 +) + +// OptionalHeader64.DllCharacteristics and OptionalHeader32.DllCharacteristics +// values. These can be combined together. +const ( + IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020 + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040 + IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x0080 + IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100 + IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200 + IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400 + IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800 + IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 0x1000 + IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000 + IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000 + IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000 +) diff --git a/vendor/github.com/mandiant/GoReSym/debug/pe/section.go b/vendor/github.com/mandiant/GoReSym/debug/pe/section.go new file mode 100644 index 00000000..0ad4bc30 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/pe/section.go @@ -0,0 +1,113 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package pe + +import ( + "encoding/binary" + "fmt" + "io" + "strconv" +) + +// SectionHeader32 represents real PE COFF section header. +type SectionHeader32 struct { + Name [8]uint8 + VirtualSize uint32 + VirtualAddress uint32 + SizeOfRawData uint32 + PointerToRawData uint32 + PointerToRelocations uint32 + PointerToLineNumbers uint32 + NumberOfRelocations uint16 + NumberOfLineNumbers uint16 + Characteristics uint32 +} + +// fullName finds real name of section sh. Normally name is stored +// in sh.Name, but if it is longer then 8 characters, it is stored +// in COFF string table st instead. +func (sh *SectionHeader32) fullName(st StringTable) (string, error) { + if sh.Name[0] != '/' { + return cstring(sh.Name[:]), nil + } + i, err := strconv.Atoi(cstring(sh.Name[1:])) + if err != nil { + return "", err + } + return st.String(uint32(i)) +} + +// TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here + +// Reloc represents a PE COFF relocation. +// Each section contains its own relocation list. +type Reloc struct { + VirtualAddress uint32 + SymbolTableIndex uint32 + Type uint16 +} + +func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) { + if sh.NumberOfRelocations <= 0 { + return nil, nil + } + _, err := r.Seek(int64(sh.PointerToRelocations), seekStart) + if err != nil { + return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err) + } + relocs := make([]Reloc, sh.NumberOfRelocations) + err = binary.Read(r, binary.LittleEndian, relocs) + if err != nil { + return nil, fmt.Errorf("fail to read section relocations: %v", err) + } + return relocs, nil +} + +// SectionHeader is similar to SectionHeader32 with Name +// field replaced by Go string. +type SectionHeader struct { + Name string + VirtualSize uint32 + VirtualAddress uint32 + Size uint32 + Offset uint32 + PointerToRelocations uint32 + PointerToLineNumbers uint32 + NumberOfRelocations uint16 + NumberOfLineNumbers uint16 + Characteristics uint32 +} + +// Section provides access to PE COFF section. +type Section struct { + SectionHeader + Relocs []Reloc + + // Embed ReaderAt for ReadAt method. + // Do not embed SectionReader directly + // to avoid having Read and Seek. + // If a client wants Read and Seek it must use + // Open() to avoid fighting over the seek offset + // with other clients. + io.ReaderAt + sr *io.SectionReader +} + +// Data reads and returns the contents of the PE section s. +func (s *Section) Data() ([]byte, error) { + dat := make([]byte, s.sr.Size()) + n, err := s.sr.ReadAt(dat, 0) + if n == len(dat) { + err = nil + } + return dat[0:n], err +} + +// Open returns a new ReadSeeker reading the PE section s. +func (s *Section) Open() io.ReadSeeker { + return io.NewSectionReader(s.sr, 0, 1<<63-1) +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/pe/string.go b/vendor/github.com/mandiant/GoReSym/debug/pe/string.go new file mode 100644 index 00000000..1dd5447c --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/pe/string.go @@ -0,0 +1,70 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package pe + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" +) + +// cstring converts ASCII byte sequence b to string. +// It stops once it finds 0 or reaches end of b. +func cstring(b []byte) string { + i := bytes.IndexByte(b, 0) + if i == -1 { + i = len(b) + } + return string(b[:i]) +} + +// StringTable is a COFF string table. +type StringTable []byte + +func readStringTable(fh *FileHeader, r io.ReadSeeker) (StringTable, error) { + // COFF string table is located right after COFF symbol table. + if fh.PointerToSymbolTable <= 0 { + return nil, nil + } + offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols + _, err := r.Seek(int64(offset), seekStart) + if err != nil { + return nil, fmt.Errorf("fail to seek to string table: %v", err) + } + var l uint32 + err = binary.Read(r, binary.LittleEndian, &l) + if err != nil { + return nil, fmt.Errorf("fail to read string table length: %v", err) + } + // string table length includes itself + if l <= 4 || l >= 0x40000000 { + return nil, nil + } + l -= 4 + buf := make([]byte, l) + _, err = io.ReadFull(r, buf) + if err != nil { + return nil, fmt.Errorf("fail to read string table: %v", err) + } + return StringTable(buf), nil +} + +// TODO(brainman): decide if start parameter should be int instead of uint32 + +// String extracts string from COFF string table st at offset start. +func (st StringTable) String(start uint32) (string, error) { + // start includes 4 bytes of string table length + if start < 4 { + return "", fmt.Errorf("offset %d is before the start of string table", start) + } + start -= 4 + if int(start) > len(st) { + return "", fmt.Errorf("offset %d is beyond the end of string table", start) + } + return cstring(st[start:]), nil +} diff --git a/vendor/github.com/mandiant/GoReSym/debug/pe/symbol.go b/vendor/github.com/mandiant/GoReSym/debug/pe/symbol.go new file mode 100644 index 00000000..5c901573 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/debug/pe/symbol.go @@ -0,0 +1,100 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package pe + +import ( + "encoding/binary" + "fmt" + "io" +) + +const COFFSymbolSize = 18 + +// COFFSymbol represents single COFF symbol table record. +type COFFSymbol struct { + Name [8]uint8 + Value uint32 + SectionNumber int16 + Type uint16 + StorageClass uint8 + NumberOfAuxSymbols uint8 +} + +func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) { + if fh.PointerToSymbolTable == 0 { + return nil, nil + } + if fh.NumberOfSymbols <= 0 { + return nil, nil + } + _, err := r.Seek(int64(fh.PointerToSymbolTable), seekStart) + if err != nil { + return nil, fmt.Errorf("fail to seek to symbol table: %v", err) + } + syms := make([]COFFSymbol, fh.NumberOfSymbols) + err = binary.Read(r, binary.LittleEndian, syms) + if err != nil { + return nil, fmt.Errorf("fail to read symbol table: %v", err) + } + return syms, nil +} + +// isSymNameOffset checks symbol name if it is encoded as offset into string table. +func isSymNameOffset(name [8]byte) (bool, uint32) { + if name[0] == 0 && name[1] == 0 && name[2] == 0 && name[3] == 0 { + return true, binary.LittleEndian.Uint32(name[4:]) + } + return false, 0 +} + +// FullName finds real name of symbol sym. Normally name is stored +// in sym.Name, but if it is longer then 8 characters, it is stored +// in COFF string table st instead. +func (sym *COFFSymbol) FullName(st StringTable) (string, error) { + if ok, offset := isSymNameOffset(sym.Name); ok { + return st.String(offset) + } + return cstring(sym.Name[:]), nil +} + +func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) { + if len(allsyms) == 0 { + return nil, nil + } + syms := make([]*Symbol, 0) + aux := uint8(0) + for _, sym := range allsyms { + if aux > 0 { + aux-- + continue + } + name, err := sym.FullName(st) + if err != nil { + return nil, err + } + aux = sym.NumberOfAuxSymbols + s := &Symbol{ + Name: name, + Value: sym.Value, + SectionNumber: sym.SectionNumber, + Type: sym.Type, + StorageClass: sym.StorageClass, + } + syms = append(syms, s) + } + return syms, nil +} + +// Symbol is similar to COFFSymbol with Name field replaced +// by Go string. Symbol also does not have NumberOfAuxSymbols. +type Symbol struct { + Name string + Value uint32 + SectionNumber int16 + Type uint16 + StorageClass uint8 +} diff --git a/vendor/github.com/mandiant/GoReSym/goobj/builtin.go b/vendor/github.com/mandiant/GoReSym/goobj/builtin.go new file mode 100644 index 00000000..9edc8d6f --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/goobj/builtin.go @@ -0,0 +1,47 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package goobj + +// Builtin (compiler-generated) function references appear +// frequently. We assign special indices for them, so they +// don't need to be referenced by name. + +// NBuiltin returns the number of listed builtin +// symbols. +func NBuiltin() int { + return len(builtins) +} + +// BuiltinName returns the name and ABI of the i-th +// builtin symbol. +func BuiltinName(i int) (string, int) { + return builtins[i].name, builtins[i].abi +} + +// BuiltinIdx returns the index of the builtin with the +// given name and abi, or -1 if it is not a builtin. +func BuiltinIdx(name string, abi int) int { + i, ok := builtinMap[name] + if !ok { + return -1 + } + if builtins[i].abi != abi { + return -1 + } + return i +} + +//go:generate go run mkbuiltin.go + +var builtinMap map[string]int + +func init() { + builtinMap = make(map[string]int, len(builtins)) + for i, b := range builtins { + builtinMap[b.name] = i + } +} diff --git a/vendor/github.com/mandiant/GoReSym/goobj/builtinlist.go b/vendor/github.com/mandiant/GoReSym/goobj/builtinlist.go new file mode 100644 index 00000000..0cca7523 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/goobj/builtinlist.go @@ -0,0 +1,245 @@ +// Code generated by mkbuiltin.go. DO NOT EDIT. + +package goobj + +var builtins = [...]struct { + name string + abi int +}{ + {"runtime.newobject", 1}, + {"runtime.mallocgc", 1}, + {"runtime.panicdivide", 1}, + {"runtime.panicshift", 1}, + {"runtime.panicmakeslicelen", 1}, + {"runtime.panicmakeslicecap", 1}, + {"runtime.throwinit", 1}, + {"runtime.panicwrap", 1}, + {"runtime.gopanic", 1}, + {"runtime.gorecover", 1}, + {"runtime.goschedguarded", 1}, + {"runtime.goPanicIndex", 1}, + {"runtime.goPanicIndexU", 1}, + {"runtime.goPanicSliceAlen", 1}, + {"runtime.goPanicSliceAlenU", 1}, + {"runtime.goPanicSliceAcap", 1}, + {"runtime.goPanicSliceAcapU", 1}, + {"runtime.goPanicSliceB", 1}, + {"runtime.goPanicSliceBU", 1}, + {"runtime.goPanicSlice3Alen", 1}, + {"runtime.goPanicSlice3AlenU", 1}, + {"runtime.goPanicSlice3Acap", 1}, + {"runtime.goPanicSlice3AcapU", 1}, + {"runtime.goPanicSlice3B", 1}, + {"runtime.goPanicSlice3BU", 1}, + {"runtime.goPanicSlice3C", 1}, + {"runtime.goPanicSlice3CU", 1}, + {"runtime.printbool", 1}, + {"runtime.printfloat", 1}, + {"runtime.printint", 1}, + {"runtime.printhex", 1}, + {"runtime.printuint", 1}, + {"runtime.printcomplex", 1}, + {"runtime.printstring", 1}, + {"runtime.printpointer", 1}, + {"runtime.printiface", 1}, + {"runtime.printeface", 1}, + {"runtime.printslice", 1}, + {"runtime.printnl", 1}, + {"runtime.printsp", 1}, + {"runtime.printlock", 1}, + {"runtime.printunlock", 1}, + {"runtime.concatstring2", 1}, + {"runtime.concatstring3", 1}, + {"runtime.concatstring4", 1}, + {"runtime.concatstring5", 1}, + {"runtime.concatstrings", 1}, + {"runtime.cmpstring", 1}, + {"runtime.intstring", 1}, + {"runtime.slicebytetostring", 1}, + {"runtime.slicebytetostringtmp", 1}, + {"runtime.slicerunetostring", 1}, + {"runtime.stringtoslicebyte", 1}, + {"runtime.stringtoslicerune", 1}, + {"runtime.slicecopy", 1}, + {"runtime.slicestringcopy", 1}, + {"runtime.decoderune", 1}, + {"runtime.countrunes", 1}, + {"runtime.convI2I", 1}, + {"runtime.convT16", 1}, + {"runtime.convT32", 1}, + {"runtime.convT64", 1}, + {"runtime.convTstring", 1}, + {"runtime.convTslice", 1}, + {"runtime.convT2E", 1}, + {"runtime.convT2Enoptr", 1}, + {"runtime.convT2I", 1}, + {"runtime.convT2Inoptr", 1}, + {"runtime.assertE2I", 1}, + {"runtime.assertE2I2", 1}, + {"runtime.assertI2I", 1}, + {"runtime.assertI2I2", 1}, + {"runtime.panicdottypeE", 1}, + {"runtime.panicdottypeI", 1}, + {"runtime.panicnildottype", 1}, + {"runtime.ifaceeq", 1}, + {"runtime.efaceeq", 1}, + {"runtime.fastrand", 1}, + {"runtime.makemap64", 1}, + {"runtime.makemap", 1}, + {"runtime.makemap_small", 1}, + {"runtime.mapaccess1", 1}, + {"runtime.mapaccess1_fast32", 1}, + {"runtime.mapaccess1_fast64", 1}, + {"runtime.mapaccess1_faststr", 1}, + {"runtime.mapaccess1_fat", 1}, + {"runtime.mapaccess2", 1}, + {"runtime.mapaccess2_fast32", 1}, + {"runtime.mapaccess2_fast64", 1}, + {"runtime.mapaccess2_faststr", 1}, + {"runtime.mapaccess2_fat", 1}, + {"runtime.mapassign", 1}, + {"runtime.mapassign_fast32", 1}, + {"runtime.mapassign_fast32ptr", 1}, + {"runtime.mapassign_fast64", 1}, + {"runtime.mapassign_fast64ptr", 1}, + {"runtime.mapassign_faststr", 1}, + {"runtime.mapiterinit", 1}, + {"runtime.mapdelete", 1}, + {"runtime.mapdelete_fast32", 1}, + {"runtime.mapdelete_fast64", 1}, + {"runtime.mapdelete_faststr", 1}, + {"runtime.mapiternext", 1}, + {"runtime.mapclear", 1}, + {"runtime.makechan64", 1}, + {"runtime.makechan", 1}, + {"runtime.chanrecv1", 1}, + {"runtime.chanrecv2", 1}, + {"runtime.chansend1", 1}, + {"runtime.closechan", 1}, + {"runtime.writeBarrier", 0}, + {"runtime.typedmemmove", 1}, + {"runtime.typedmemclr", 1}, + {"runtime.typedslicecopy", 1}, + {"runtime.selectnbsend", 1}, + {"runtime.selectnbrecv", 1}, + {"runtime.selectnbrecv2", 1}, + {"runtime.selectsetpc", 1}, + {"runtime.selectgo", 1}, + {"runtime.block", 1}, + {"runtime.makeslice", 1}, + {"runtime.makeslice64", 1}, + {"runtime.makeslicecopy", 1}, + {"runtime.growslice", 1}, + {"runtime.memmove", 1}, + {"runtime.memclrNoHeapPointers", 1}, + {"runtime.memclrHasPointers", 1}, + {"runtime.memequal", 1}, + {"runtime.memequal0", 1}, + {"runtime.memequal8", 1}, + {"runtime.memequal16", 1}, + {"runtime.memequal32", 1}, + {"runtime.memequal64", 1}, + {"runtime.memequal128", 1}, + {"runtime.f32equal", 1}, + {"runtime.f64equal", 1}, + {"runtime.c64equal", 1}, + {"runtime.c128equal", 1}, + {"runtime.strequal", 1}, + {"runtime.interequal", 1}, + {"runtime.nilinterequal", 1}, + {"runtime.memhash", 1}, + {"runtime.memhash0", 1}, + {"runtime.memhash8", 1}, + {"runtime.memhash16", 1}, + {"runtime.memhash32", 1}, + {"runtime.memhash64", 1}, + {"runtime.memhash128", 1}, + {"runtime.f32hash", 1}, + {"runtime.f64hash", 1}, + {"runtime.c64hash", 1}, + {"runtime.c128hash", 1}, + {"runtime.strhash", 1}, + {"runtime.interhash", 1}, + {"runtime.nilinterhash", 1}, + {"runtime.int64div", 1}, + {"runtime.uint64div", 1}, + {"runtime.int64mod", 1}, + {"runtime.uint64mod", 1}, + {"runtime.float64toint64", 1}, + {"runtime.float64touint64", 1}, + {"runtime.float64touint32", 1}, + {"runtime.int64tofloat64", 1}, + {"runtime.uint64tofloat64", 1}, + {"runtime.uint32tofloat64", 1}, + {"runtime.complex128div", 1}, + {"runtime.racefuncenter", 1}, + {"runtime.racefuncenterfp", 1}, + {"runtime.racefuncexit", 1}, + {"runtime.raceread", 1}, + {"runtime.racewrite", 1}, + {"runtime.racereadrange", 1}, + {"runtime.racewriterange", 1}, + {"runtime.msanread", 1}, + {"runtime.msanwrite", 1}, + {"runtime.checkptrAlignment", 1}, + {"runtime.checkptrArithmetic", 1}, + {"runtime.libfuzzerTraceCmp1", 1}, + {"runtime.libfuzzerTraceCmp2", 1}, + {"runtime.libfuzzerTraceCmp4", 1}, + {"runtime.libfuzzerTraceCmp8", 1}, + {"runtime.libfuzzerTraceConstCmp1", 1}, + {"runtime.libfuzzerTraceConstCmp2", 1}, + {"runtime.libfuzzerTraceConstCmp4", 1}, + {"runtime.libfuzzerTraceConstCmp8", 1}, + {"runtime.x86HasPOPCNT", 0}, + {"runtime.x86HasSSE41", 0}, + {"runtime.x86HasFMA", 0}, + {"runtime.armHasVFPv4", 0}, + {"runtime.arm64HasATOMICS", 0}, + {"runtime.deferproc", 1}, + {"runtime.deferprocStack", 1}, + {"runtime.deferreturn", 1}, + {"runtime.newproc", 1}, + {"runtime.panicoverflow", 1}, + {"runtime.sigpanic", 1}, + {"runtime.gcWriteBarrier", 0}, + {"runtime.morestack", 0}, + {"runtime.morestackc", 0}, + {"runtime.morestack_noctxt", 0}, + {"type.int8", 0}, + {"type.*int8", 0}, + {"type.uint8", 0}, + {"type.*uint8", 0}, + {"type.int16", 0}, + {"type.*int16", 0}, + {"type.uint16", 0}, + {"type.*uint16", 0}, + {"type.int32", 0}, + {"type.*int32", 0}, + {"type.uint32", 0}, + {"type.*uint32", 0}, + {"type.int64", 0}, + {"type.*int64", 0}, + {"type.uint64", 0}, + {"type.*uint64", 0}, + {"type.float32", 0}, + {"type.*float32", 0}, + {"type.float64", 0}, + {"type.*float64", 0}, + {"type.complex64", 0}, + {"type.*complex64", 0}, + {"type.complex128", 0}, + {"type.*complex128", 0}, + {"type.unsafe.Pointer", 0}, + {"type.*unsafe.Pointer", 0}, + {"type.uintptr", 0}, + {"type.*uintptr", 0}, + {"type.bool", 0}, + {"type.*bool", 0}, + {"type.string", 0}, + {"type.*string", 0}, + {"type.error", 0}, + {"type.*error", 0}, + {"type.func(error) string", 0}, + {"type.*func(error) string", 0}, +} diff --git a/vendor/github.com/mandiant/GoReSym/goobj/funcinfo.go b/vendor/github.com/mandiant/GoReSym/goobj/funcinfo.go new file mode 100644 index 00000000..a4b3d167 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/goobj/funcinfo.go @@ -0,0 +1,242 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package goobj + +import ( + "bytes" + "encoding/binary" + + "github.com/mandiant/GoReSym/objabi" +) + +// CUFileIndex is used to index the filenames that are stored in the +// per-package/per-CU FileList. +type CUFileIndex uint32 + +// FuncInfo is serialized as a symbol (aux symbol). The symbol data is +// the binary encoding of the struct below. +// +// TODO: make each pcdata a separate symbol? +type FuncInfo struct { + Args uint32 + Locals uint32 + FuncID objabi.FuncID + + Pcsp SymRef + Pcfile SymRef + Pcline SymRef + Pcinline SymRef + Pcdata []SymRef + Funcdataoff []uint32 + File []CUFileIndex + + InlTree []InlTreeNode +} + +func (a *FuncInfo) Write(w *bytes.Buffer) { + var b [4]byte + writeUint32 := func(x uint32) { + binary.LittleEndian.PutUint32(b[:], x) + w.Write(b[:]) + } + writeSymRef := func(s SymRef) { + writeUint32(s.PkgIdx) + writeUint32(s.SymIdx) + } + + writeUint32(a.Args) + writeUint32(a.Locals) + writeUint32(uint32(a.FuncID)) + + writeSymRef(a.Pcsp) + writeSymRef(a.Pcfile) + writeSymRef(a.Pcline) + writeSymRef(a.Pcinline) + writeUint32(uint32(len(a.Pcdata))) + for _, sym := range a.Pcdata { + writeSymRef(sym) + } + + writeUint32(uint32(len(a.Funcdataoff))) + for _, x := range a.Funcdataoff { + writeUint32(x) + } + writeUint32(uint32(len(a.File))) + for _, f := range a.File { + writeUint32(uint32(f)) + } + writeUint32(uint32(len(a.InlTree))) + for i := range a.InlTree { + a.InlTree[i].Write(w) + } +} + +func (a *FuncInfo) Read(b []byte) { + readUint32 := func() uint32 { + x := binary.LittleEndian.Uint32(b) + b = b[4:] + return x + } + readSymIdx := func() SymRef { + return SymRef{readUint32(), readUint32()} + } + + a.Args = readUint32() + a.Locals = readUint32() + a.FuncID = objabi.FuncID(readUint32()) + + a.Pcsp = readSymIdx() + a.Pcfile = readSymIdx() + a.Pcline = readSymIdx() + a.Pcinline = readSymIdx() + a.Pcdata = make([]SymRef, readUint32()) + for i := range a.Pcdata { + a.Pcdata[i] = readSymIdx() + } + + funcdataofflen := readUint32() + a.Funcdataoff = make([]uint32, funcdataofflen) + for i := range a.Funcdataoff { + a.Funcdataoff[i] = readUint32() + } + filelen := readUint32() + a.File = make([]CUFileIndex, filelen) + for i := range a.File { + a.File[i] = CUFileIndex(readUint32()) + } + inltreelen := readUint32() + a.InlTree = make([]InlTreeNode, inltreelen) + for i := range a.InlTree { + b = a.InlTree[i].Read(b) + } +} + +// FuncInfoLengths is a cache containing a roadmap of offsets and +// lengths for things within a serialized FuncInfo. Each length field +// stores the number of items (e.g. files, inltree nodes, etc), and the +// corresponding "off" field stores the byte offset of the start of +// the items in question. +type FuncInfoLengths struct { + NumPcdata uint32 + PcdataOff uint32 + NumFuncdataoff uint32 + FuncdataoffOff uint32 + NumFile uint32 + FileOff uint32 + NumInlTree uint32 + InlTreeOff uint32 + Initialized bool +} + +func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths { + var result FuncInfoLengths + + // Offset to the number of pcdata values. This value is determined by counting + // the number of bytes until we write pcdata to the file. + const numpcdataOff = 44 + result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:]) + result.PcdataOff = numpcdataOff + 4 + + numfuncdataoffOff := result.PcdataOff + 8*result.NumPcdata + result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:]) + result.FuncdataoffOff = numfuncdataoffOff + 4 + + numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff + result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:]) + result.FileOff = numfileOff + 4 + + numinltreeOff := result.FileOff + 4*result.NumFile + result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:]) + result.InlTreeOff = numinltreeOff + 4 + + result.Initialized = true + + return result +} + +func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } + +func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) } + +func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) } + +func (*FuncInfo) ReadPcsp(b []byte) SymRef { + return SymRef{binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])} +} + +func (*FuncInfo) ReadPcfile(b []byte) SymRef { + return SymRef{binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])} +} + +func (*FuncInfo) ReadPcline(b []byte) SymRef { + return SymRef{binary.LittleEndian.Uint32(b[28:]), binary.LittleEndian.Uint32(b[32:])} +} + +func (*FuncInfo) ReadPcinline(b []byte) SymRef { + return SymRef{binary.LittleEndian.Uint32(b[36:]), binary.LittleEndian.Uint32(b[40:])} +} + +func (*FuncInfo) ReadPcdata(b []byte) []SymRef { + syms := make([]SymRef, binary.LittleEndian.Uint32(b[44:])) + for i := range syms { + syms[i] = SymRef{binary.LittleEndian.Uint32(b[48+i*8:]), binary.LittleEndian.Uint32(b[52+i*8:])} + } + return syms +} + +func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 { + return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:])) +} + +func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex { + return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:])) +} + +func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode { + const inlTreeNodeSize = 4 * 6 + var result InlTreeNode + result.Read(b[inltreeoff+k*inlTreeNodeSize:]) + return result +} + +// InlTreeNode is the serialized form of FileInfo.InlTree. +type InlTreeNode struct { + Parent int32 + File CUFileIndex + Line int32 + Func SymRef + ParentPC int32 +} + +func (inl *InlTreeNode) Write(w *bytes.Buffer) { + var b [4]byte + writeUint32 := func(x uint32) { + binary.LittleEndian.PutUint32(b[:], x) + w.Write(b[:]) + } + writeUint32(uint32(inl.Parent)) + writeUint32(uint32(inl.File)) + writeUint32(uint32(inl.Line)) + writeUint32(inl.Func.PkgIdx) + writeUint32(inl.Func.SymIdx) + writeUint32(uint32(inl.ParentPC)) +} + +// Read an InlTreeNode from b, return the remaining bytes. +func (inl *InlTreeNode) Read(b []byte) []byte { + readUint32 := func() uint32 { + x := binary.LittleEndian.Uint32(b) + b = b[4:] + return x + } + inl.Parent = int32(readUint32()) + inl.File = CUFileIndex(readUint32()) + inl.Line = int32(readUint32()) + inl.Func = SymRef{readUint32(), readUint32()} + inl.ParentPC = int32(readUint32()) + return b +} diff --git a/vendor/github.com/mandiant/GoReSym/goobj/objfile.go b/vendor/github.com/mandiant/GoReSym/goobj/objfile.go new file mode 100644 index 00000000..e1deaf86 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/goobj/objfile.go @@ -0,0 +1,872 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// This package defines the Go object file format, and provide "low-level" functions +// for reading and writing object files. + +// The object file is understood by the compiler, assembler, linker, and tools. They +// have "high level" code that operates on object files, handling application-specific +// logics, and use this package for the actual reading and writing. Specifically, the +// code below: +// +// - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile) +// - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump) +// - cmd/link/internal/loader package (used by cmd/link) +// +// If the object file format changes, they may (or may not) need to change. + +package goobj + +import ( + "bytes" + "crypto/sha1" + "encoding/binary" + "errors" + "fmt" + "io" + "unsafe" + + "github.com/mandiant/GoReSym/bio" + "github.com/mandiant/GoReSym/unsafeheader" +) + +// New object file format. +// +// Header struct { +// Magic [...]byte // "\x00go116ld" +// Fingerprint [8]byte +// Flags uint32 +// Offsets [...]uint32 // byte offset of each block below +// } +// +// Strings [...]struct { +// Data [...]byte +// } +// +// Autolib [...]struct { // imported packages (for file loading) +// Pkg string +// Fingerprint [8]byte +// } +// +// PkgIndex [...]string // referenced packages by index +// +// Files [...]string +// +// SymbolDefs [...]struct { +// Name string +// ABI uint16 +// Type uint8 +// Flag uint8 +// Flag2 uint8 +// Size uint32 +// } +// Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions +// ... // same as SymbolDefs +// } +// HashedDefs [...]struct { // hashed (content-addressable) symbol definitions +// ... // same as SymbolDefs +// } +// NonPkgDefs [...]struct { // non-pkg symbol definitions +// ... // same as SymbolDefs +// } +// NonPkgRefs [...]struct { // non-pkg symbol references +// ... // same as SymbolDefs +// } +// +// RefFlags [...]struct { // referenced symbol flags +// Sym symRef +// Flag uint8 +// Flag2 uint8 +// } +// +// Hash64 [...][8]byte +// Hash [...][N]byte +// +// RelocIndex [...]uint32 // index to Relocs +// AuxIndex [...]uint32 // index to Aux +// DataIndex [...]uint32 // offset to Data +// +// Relocs [...]struct { +// Off int32 +// Size uint8 +// Type uint8 +// Add int64 +// Sym symRef +// } +// +// Aux [...]struct { +// Type uint8 +// Sym symRef +// } +// +// Data [...]byte +// Pcdata [...]byte +// +// // blocks only used by tools (objdump, nm) +// +// RefNames [...]struct { // referenced symbol names +// Sym symRef +// Name string +// // TODO: include ABI version as well? +// } +// +// string is encoded as is a uint32 length followed by a uint32 offset +// that points to the corresponding string bytes. +// +// symRef is struct { PkgIdx, SymIdx uint32 }. +// +// Slice type (e.g. []symRef) is encoded as a length prefix (uint32) +// followed by that number of elements. +// +// The types below correspond to the encoded data structure in the +// object file. + +// Symbol indexing. +// +// Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx }, +// as the symRef struct above. +// +// PkgIdx is either a predeclared index (see PkgIdxNone below) or +// an index of an imported package. For the latter case, PkgIdx is the +// index of the package in the PkgIndex array. 0 is an invalid index. +// +// SymIdx is the index of the symbol in the given package. +// - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the +// SymbolDefs array. +// - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the +// Hashed64Defs array. +// - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the +// HashedDefs array. +// - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the +// NonPkgDefs array (could natually overflow to NonPkgRefs array). +// - Otherwise, SymIdx is the index of the symbol in some other package's +// SymbolDefs array. +// +// {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0. +// +// Hash contains the content hashes of content-addressable symbols, of +// which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array. +// Hash64 is similar, for PkgIdxHashed64 symbols. +// +// RelocIndex, AuxIndex, and DataIndex contains indices/offsets to +// Relocs/Aux/Data blocks, one element per symbol, first for all the +// defined symbols, then all the defined hashed and non-package symbols, +// in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs +// arrays. For N total defined symbols, the array is of length N+1. The +// last element is the total number of relocations (aux symbols, data +// blocks, etc.). +// +// They can be accessed by index. For the i-th symbol, its relocations +// are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive) +// elements in the Relocs array. Aux/Data are likewise. (The index is +// 0-based.) + +// Auxiliary symbols. +// +// Each symbol may (or may not) be associated with a number of auxiliary +// symbols. They are described in the Aux block. See Aux struct below. +// Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols +// are auxiliary symbols. + +const stringRefSize = 8 // two uint32s + +type FingerprintType [8]byte + +func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} } + +// Package Index. +const ( + PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols + PkgIdxHashed64 // Short hashed (content-addressable) symbols + PkgIdxHashed // Hashed (content-addressable) symbols + PkgIdxBuiltin // Predefined runtime symbols (ex: runtime.newobject) + PkgIdxSelf // Symbols defined in the current package + PkgIdxInvalid = 0 + // The index of other referenced packages starts from 1. +) + +// Blocks +const ( + BlkAutolib = iota + BlkPkgIdx + BlkFile + BlkSymdef + BlkHashed64def + BlkHasheddef + BlkNonpkgdef + BlkNonpkgref + BlkRefFlags + BlkHash64 + BlkHash + BlkRelocIdx + BlkAuxIdx + BlkDataIdx + BlkReloc + BlkAux + BlkData + BlkPcdata + BlkRefName + BlkEnd + NBlk +) + +// File header. +// TODO: probably no need to export this. +type Header struct { + Magic string + Fingerprint FingerprintType + Flags uint32 + Offsets [NBlk]uint32 +} + +const Magic = "\x00go116ld" + +func (h *Header) Write(w *Writer) { + w.RawString(h.Magic) + w.Bytes(h.Fingerprint[:]) + w.Uint32(h.Flags) + for _, x := range h.Offsets { + w.Uint32(x) + } +} + +func (h *Header) Read(r *Reader) error { + b := r.BytesAt(0, len(Magic)) + h.Magic = string(b) + if h.Magic != Magic { + return errors.New("wrong magic, not a Go object file") + } + off := uint32(len(h.Magic)) + copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint))) + off += 8 + h.Flags = r.uint32At(off) + off += 4 + for i := range h.Offsets { + h.Offsets[i] = r.uint32At(off) + off += 4 + } + return nil +} + +func (h *Header) Size() int { + return len(h.Magic) + 4 + 4*len(h.Offsets) +} + +// Autolib +type ImportedPkg struct { + Pkg string + Fingerprint FingerprintType +} + +const importedPkgSize = stringRefSize + 8 + +func (p *ImportedPkg) Write(w *Writer) { + w.StringRef(p.Pkg) + w.Bytes(p.Fingerprint[:]) +} + +// Symbol definition. +// +// Serialized format: +// Sym struct { +// Name string +// ABI uint16 +// Type uint8 +// Flag uint8 +// Flag2 uint8 +// Siz uint32 +// Align uint32 +// } +type Sym [SymSize]byte + +const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4 + +const SymABIstatic = ^uint16(0) + +const ( + ObjFlagShared = 1 << iota // this object is built with -shared + ObjFlagNeedNameExpansion // the linker needs to expand `"".` to package path in symbol names + ObjFlagFromAssembly // object is from asm src, not go +) + +// Sym.Flag +const ( + SymFlagDupok = 1 << iota + SymFlagLocal + SymFlagTypelink + SymFlagLeaf + SymFlagNoSplit + SymFlagReflectMethod + SymFlagGoType + SymFlagTopFrame +) + +// Sym.Flag2 +const ( + SymFlagUsedInIface = 1 << iota + SymFlagItab +) + +// Returns the length of the name of the symbol. +func (s *Sym) NameLen(r *Reader) int { + return int(binary.LittleEndian.Uint32(s[:])) +} + +func (s *Sym) Name(r *Reader) string { + len := binary.LittleEndian.Uint32(s[:]) + off := binary.LittleEndian.Uint32(s[4:]) + return r.StringAt(off, len) +} + +func (s *Sym) ABI() uint16 { return binary.LittleEndian.Uint16(s[8:]) } +func (s *Sym) Type() uint8 { return s[10] } +func (s *Sym) Flag() uint8 { return s[11] } +func (s *Sym) Flag2() uint8 { return s[12] } +func (s *Sym) Siz() uint32 { return binary.LittleEndian.Uint32(s[13:]) } +func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) } + +func (s *Sym) Dupok() bool { return s.Flag()&SymFlagDupok != 0 } +func (s *Sym) Local() bool { return s.Flag()&SymFlagLocal != 0 } +func (s *Sym) Typelink() bool { return s.Flag()&SymFlagTypelink != 0 } +func (s *Sym) Leaf() bool { return s.Flag()&SymFlagLeaf != 0 } +func (s *Sym) NoSplit() bool { return s.Flag()&SymFlagNoSplit != 0 } +func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 } +func (s *Sym) IsGoType() bool { return s.Flag()&SymFlagGoType != 0 } +func (s *Sym) TopFrame() bool { return s.Flag()&SymFlagTopFrame != 0 } +func (s *Sym) UsedInIface() bool { return s.Flag2()&SymFlagUsedInIface != 0 } +func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 } + +func (s *Sym) SetName(x string, w *Writer) { + binary.LittleEndian.PutUint32(s[:], uint32(len(x))) + binary.LittleEndian.PutUint32(s[4:], w.stringOff(x)) +} + +func (s *Sym) SetABI(x uint16) { binary.LittleEndian.PutUint16(s[8:], x) } +func (s *Sym) SetType(x uint8) { s[10] = x } +func (s *Sym) SetFlag(x uint8) { s[11] = x } +func (s *Sym) SetFlag2(x uint8) { s[12] = x } +func (s *Sym) SetSiz(x uint32) { binary.LittleEndian.PutUint32(s[13:], x) } +func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) } + +func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) } + +// for testing +func (s *Sym) fromBytes(b []byte) { copy(s[:], b) } + +// Symbol reference. +type SymRef struct { + PkgIdx uint32 + SymIdx uint32 +} + +// Hash64 +type Hash64Type [Hash64Size]byte + +const Hash64Size = 8 + +// Hash +type HashType [HashSize]byte + +const HashSize = sha1.Size + +// Relocation. +// +// Serialized format: +// Reloc struct { +// Off int32 +// Siz uint8 +// Type uint8 +// Add int64 +// Sym SymRef +// } +type Reloc [RelocSize]byte + +const RelocSize = 4 + 1 + 1 + 8 + 8 + +func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) } +func (r *Reloc) Siz() uint8 { return r[4] } +func (r *Reloc) Type() uint8 { return r[5] } +func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[6:])) } +func (r *Reloc) Sym() SymRef { + return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])} +} + +func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) } +func (r *Reloc) SetSiz(x uint8) { r[4] = x } +func (r *Reloc) SetType(x uint8) { r[5] = x } +func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[6:], uint64(x)) } +func (r *Reloc) SetSym(x SymRef) { + binary.LittleEndian.PutUint32(r[14:], x.PkgIdx) + binary.LittleEndian.PutUint32(r[18:], x.SymIdx) +} + +func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) { + r.SetOff(off) + r.SetSiz(size) + r.SetType(typ) + r.SetAdd(add) + r.SetSym(sym) +} + +func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) } + +// for testing +func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) } + +// Aux symbol info. +// +// Serialized format: +// Aux struct { +// Type uint8 +// Sym SymRef +// } +type Aux [AuxSize]byte + +const AuxSize = 1 + 8 + +// Aux Type +const ( + AuxGotype = iota + AuxFuncInfo + AuxFuncdata + AuxDwarfInfo + AuxDwarfLoc + AuxDwarfRanges + AuxDwarfLines + AuxPcsp + AuxPcfile + AuxPcline + AuxPcinline + AuxPcdata +) + +func (a *Aux) Type() uint8 { return a[0] } +func (a *Aux) Sym() SymRef { + return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])} +} + +func (a *Aux) SetType(x uint8) { a[0] = x } +func (a *Aux) SetSym(x SymRef) { + binary.LittleEndian.PutUint32(a[1:], x.PkgIdx) + binary.LittleEndian.PutUint32(a[5:], x.SymIdx) +} + +func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) } + +// for testing +func (a *Aux) fromBytes(b []byte) { copy(a[:], b) } + +// Referenced symbol flags. +// +// Serialized format: +// RefFlags struct { +// Sym symRef +// Flag uint8 +// Flag2 uint8 +// } +type RefFlags [RefFlagsSize]byte + +const RefFlagsSize = 8 + 1 + 1 + +func (r *RefFlags) Sym() SymRef { + return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])} +} +func (r *RefFlags) Flag() uint8 { return r[8] } +func (r *RefFlags) Flag2() uint8 { return r[9] } + +func (r *RefFlags) SetSym(x SymRef) { + binary.LittleEndian.PutUint32(r[:], x.PkgIdx) + binary.LittleEndian.PutUint32(r[4:], x.SymIdx) +} +func (r *RefFlags) SetFlag(x uint8) { r[8] = x } +func (r *RefFlags) SetFlag2(x uint8) { r[9] = x } + +func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) } + +// Referenced symbol name. +// +// Serialized format: +// RefName struct { +// Sym symRef +// Name string +// } +type RefName [RefNameSize]byte + +const RefNameSize = 8 + stringRefSize + +func (n *RefName) Sym() SymRef { + return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])} +} +func (n *RefName) Name(r *Reader) string { + len := binary.LittleEndian.Uint32(n[8:]) + off := binary.LittleEndian.Uint32(n[12:]) + return r.StringAt(off, len) +} + +func (n *RefName) SetSym(x SymRef) { + binary.LittleEndian.PutUint32(n[:], x.PkgIdx) + binary.LittleEndian.PutUint32(n[4:], x.SymIdx) +} +func (n *RefName) SetName(x string, w *Writer) { + binary.LittleEndian.PutUint32(n[8:], uint32(len(x))) + binary.LittleEndian.PutUint32(n[12:], w.stringOff(x)) +} + +func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) } + +type Writer struct { + wr *bio.Writer + stringMap map[string]uint32 + off uint32 // running offset +} + +func NewWriter(wr *bio.Writer) *Writer { + return &Writer{wr: wr, stringMap: make(map[string]uint32)} +} + +func (w *Writer) AddString(s string) { + if _, ok := w.stringMap[s]; ok { + return + } + w.stringMap[s] = w.off + w.RawString(s) +} + +func (w *Writer) stringOff(s string) uint32 { + off, ok := w.stringMap[s] + if !ok { + panic(fmt.Sprintf("writeStringRef: string not added: %q", s)) + } + return off +} + +func (w *Writer) StringRef(s string) { + w.Uint32(uint32(len(s))) + w.Uint32(w.stringOff(s)) +} + +func (w *Writer) RawString(s string) { + w.wr.WriteString(s) + w.off += uint32(len(s)) +} + +func (w *Writer) Bytes(s []byte) { + w.wr.Write(s) + w.off += uint32(len(s)) +} + +func (w *Writer) Uint64(x uint64) { + var b [8]byte + binary.LittleEndian.PutUint64(b[:], x) + w.wr.Write(b[:]) + w.off += 8 +} + +func (w *Writer) Uint32(x uint32) { + var b [4]byte + binary.LittleEndian.PutUint32(b[:], x) + w.wr.Write(b[:]) + w.off += 4 +} + +func (w *Writer) Uint16(x uint16) { + var b [2]byte + binary.LittleEndian.PutUint16(b[:], x) + w.wr.Write(b[:]) + w.off += 2 +} + +func (w *Writer) Uint8(x uint8) { + w.wr.WriteByte(x) + w.off++ +} + +func (w *Writer) Offset() uint32 { + return w.off +} + +type Reader struct { + b []byte // mmapped bytes, if not nil + readonly bool // whether b is backed with read-only memory + + rd io.ReaderAt + start uint32 + h Header // keep block offsets +} + +func NewReaderFromBytes(b []byte, readonly bool) *Reader { + r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0} + err := r.h.Read(r) + if err != nil { + return nil + } + return r +} + +func (r *Reader) BytesAt(off uint32, len int) []byte { + if len == 0 { + return nil + } + end := int(off) + len + return r.b[int(off):end:end] +} + +func (r *Reader) uint64At(off uint32) uint64 { + b := r.BytesAt(off, 8) + return binary.LittleEndian.Uint64(b) +} + +func (r *Reader) int64At(off uint32) int64 { + return int64(r.uint64At(off)) +} + +func (r *Reader) uint32At(off uint32) uint32 { + b := r.BytesAt(off, 4) + return binary.LittleEndian.Uint32(b) +} + +func (r *Reader) int32At(off uint32) int32 { + return int32(r.uint32At(off)) +} + +func (r *Reader) uint16At(off uint32) uint16 { + b := r.BytesAt(off, 2) + return binary.LittleEndian.Uint16(b) +} + +func (r *Reader) uint8At(off uint32) uint8 { + b := r.BytesAt(off, 1) + return b[0] +} + +func (r *Reader) StringAt(off uint32, len uint32) string { + b := r.b[off : off+len] + if r.readonly { + return toString(b) // backed by RO memory, ok to make unsafe string + } + return string(b) +} + +func toString(b []byte) string { + if len(b) == 0 { + return "" + } + + var s string + hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) + hdr.Data = unsafe.Pointer(&b[0]) + hdr.Len = len(b) + + return s +} + +func (r *Reader) StringRef(off uint32) string { + l := r.uint32At(off) + return r.StringAt(r.uint32At(off+4), l) +} + +func (r *Reader) Fingerprint() FingerprintType { + return r.h.Fingerprint +} + +func (r *Reader) Autolib() []ImportedPkg { + n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize + s := make([]ImportedPkg, n) + off := r.h.Offsets[BlkAutolib] + for i := range s { + s[i].Pkg = r.StringRef(off) + copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint))) + off += importedPkgSize + } + return s +} + +func (r *Reader) Pkglist() []string { + n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize + s := make([]string, n) + off := r.h.Offsets[BlkPkgIdx] + for i := range s { + s[i] = r.StringRef(off) + off += stringRefSize + } + return s +} + +func (r *Reader) NPkg() int { + return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize +} + +func (r *Reader) Pkg(i int) string { + off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize + return r.StringRef(off) +} + +func (r *Reader) NFile() int { + return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize +} + +func (r *Reader) File(i int) string { + off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize + return r.StringRef(off) +} + +func (r *Reader) NSym() int { + return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize +} + +func (r *Reader) NHashed64def() int { + return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize +} + +func (r *Reader) NHasheddef() int { + return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize +} + +func (r *Reader) NNonpkgdef() int { + return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize +} + +func (r *Reader) NNonpkgref() int { + return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize +} + +// SymOff returns the offset of the i-th symbol. +func (r *Reader) SymOff(i uint32) uint32 { + return r.h.Offsets[BlkSymdef] + uint32(i*SymSize) +} + +// Sym returns a pointer to the i-th symbol. +func (r *Reader) Sym(i uint32) *Sym { + off := r.SymOff(i) + return (*Sym)(unsafe.Pointer(&r.b[off])) +} + +// NRefFlags returns the number of referenced symbol flags. +func (r *Reader) NRefFlags() int { + return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize +} + +// RefFlags returns a pointer to the i-th referenced symbol flags. +// Note: here i is not a local symbol index, just a counter. +func (r *Reader) RefFlags(i int) *RefFlags { + off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize) + return (*RefFlags)(unsafe.Pointer(&r.b[off])) +} + +// Hash64 returns the i-th short hashed symbol's hash. +// Note: here i is the index of short hashed symbols, not all symbols +// (unlike other accessors). +func (r *Reader) Hash64(i uint32) uint64 { + off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size) + return r.uint64At(off) +} + +// Hash returns a pointer to the i-th hashed symbol's hash. +// Note: here i is the index of hashed symbols, not all symbols +// (unlike other accessors). +func (r *Reader) Hash(i uint32) *HashType { + off := r.h.Offsets[BlkHash] + uint32(i*HashSize) + return (*HashType)(unsafe.Pointer(&r.b[off])) +} + +// NReloc returns the number of relocations of the i-th symbol. +func (r *Reader) NReloc(i uint32) int { + relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) + return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff)) +} + +// RelocOff returns the offset of the j-th relocation of the i-th symbol. +func (r *Reader) RelocOff(i uint32, j int) uint32 { + relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) + relocIdx := r.uint32At(relocIdxOff) + return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize) +} + +// Reloc returns a pointer to the j-th relocation of the i-th symbol. +func (r *Reader) Reloc(i uint32, j int) *Reloc { + off := r.RelocOff(i, j) + return (*Reloc)(unsafe.Pointer(&r.b[off])) +} + +// Relocs returns a pointer to the relocations of the i-th symbol. +func (r *Reader) Relocs(i uint32) []Reloc { + off := r.RelocOff(i, 0) + n := r.NReloc(i) + return (*[1 << 20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n] +} + +// NAux returns the number of aux symbols of the i-th symbol. +func (r *Reader) NAux(i uint32) int { + auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 + return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff)) +} + +// AuxOff returns the offset of the j-th aux symbol of the i-th symbol. +func (r *Reader) AuxOff(i uint32, j int) uint32 { + auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 + auxIdx := r.uint32At(auxIdxOff) + return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize) +} + +// Aux returns a pointer to the j-th aux symbol of the i-th symbol. +func (r *Reader) Aux(i uint32, j int) *Aux { + off := r.AuxOff(i, j) + return (*Aux)(unsafe.Pointer(&r.b[off])) +} + +// Auxs returns the aux symbols of the i-th symbol. +func (r *Reader) Auxs(i uint32) []Aux { + off := r.AuxOff(i, 0) + n := r.NAux(i) + return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n] +} + +// DataOff returns the offset of the i-th symbol's data. +func (r *Reader) DataOff(i uint32) uint32 { + dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 + return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff) +} + +// DataSize returns the size of the i-th symbol's data. +func (r *Reader) DataSize(i uint32) int { + dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 + return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff)) +} + +// Data returns the i-th symbol's data. +func (r *Reader) Data(i uint32) []byte { + dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 + base := r.h.Offsets[BlkData] + off := r.uint32At(dataIdxOff) + end := r.uint32At(dataIdxOff + 4) + return r.BytesAt(base+off, int(end-off)) +} + +// NRefName returns the number of referenced symbol names. +func (r *Reader) NRefName() int { + return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize +} + +// RefName returns a pointer to the i-th referenced symbol name. +// Note: here i is not a local symbol index, just a counter. +func (r *Reader) RefName(i int) *RefName { + off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize) + return (*RefName)(unsafe.Pointer(&r.b[off])) +} + +// ReadOnly returns whether r.BytesAt returns read-only bytes. +func (r *Reader) ReadOnly() bool { + return r.readonly +} + +// Flags returns the flag bits read from the object file header. +func (r *Reader) Flags() uint32 { + return r.h.Flags +} + +func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 } +func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 } +func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 } diff --git a/vendor/github.com/mandiant/GoReSym/objabi/autotype.go b/vendor/github.com/mandiant/GoReSym/objabi/autotype.go new file mode 100644 index 00000000..f9d17a3b --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/autotype.go @@ -0,0 +1,38 @@ +// Derived from Inferno utils/6l/l.h and related files. +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package objabi + +// Auto.name +const ( + A_AUTO = 1 + iota + A_PARAM + A_DELETED_AUTO +) diff --git a/vendor/github.com/mandiant/GoReSym/objabi/funcdata.go b/vendor/github.com/mandiant/GoReSym/objabi/funcdata.go new file mode 100644 index 00000000..faa28633 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/funcdata.go @@ -0,0 +1,47 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +// This file defines the IDs for PCDATA and FUNCDATA instructions +// in Go binaries. +// +// These must agree with ../../../runtime/funcdata.h and +// ../../../runtime/symtab.go. + +const ( + PCDATA_UnsafePoint = 0 + PCDATA_StackMapIndex = 1 + PCDATA_InlTreeIndex = 2 + + FUNCDATA_ArgsPointerMaps = 0 + FUNCDATA_LocalsPointerMaps = 1 + FUNCDATA_StackObjects = 2 + FUNCDATA_InlTree = 3 + FUNCDATA_OpenCodedDeferInfo = 4 + + // ArgsSizeUnknown is set in Func.argsize to mark all functions + // whose argument size is unknown (C vararg functions, and + // assembly code without an explicit specification). + // This value is generated by the compiler, assembler, or linker. + ArgsSizeUnknown = -0x80000000 +) + +// Special PCDATA values. +const ( + // PCDATA_UnsafePoint values. + PCDATA_UnsafePointSafe = -1 // Safe for async preemption + PCDATA_UnsafePointUnsafe = -2 // Unsafe for async preemption + + // PCDATA_Restart1(2) apply on a sequence of instructions, within + // which if an async preemption happens, we should back off the PC + // to the start of the sequence when resuming. + // We need two so we can distinguish the start/end of the sequence + // in case that two sequences are next to each other. + PCDATA_Restart1 = -3 + PCDATA_Restart2 = -4 + + // Like PCDATA_Restart1, but back to function entry if async preempted. + PCDATA_RestartAtEntry = -5 +) diff --git a/vendor/github.com/mandiant/GoReSym/objabi/funcid.go b/vendor/github.com/mandiant/GoReSym/objabi/funcid.go new file mode 100644 index 00000000..1d098ee1 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/funcid.go @@ -0,0 +1,100 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +// A FuncID identifies particular functions that need to be treated +// specially by the runtime. +// Note that in some situations involving plugins, there may be multiple +// copies of a particular special runtime function. +// Note: this list must match the list in runtime/symtab.go. +type FuncID uint8 + +const ( + FuncID_normal FuncID = iota // not a special function + FuncID_runtime_main + FuncID_goexit + FuncID_jmpdefer + FuncID_mcall + FuncID_morestack + FuncID_mstart + FuncID_rt0_go + FuncID_asmcgocall + FuncID_sigpanic + FuncID_runfinq + FuncID_gcBgMarkWorker + FuncID_systemstack_switch + FuncID_systemstack + FuncID_cgocallback + FuncID_gogo + FuncID_externalthreadhandler + FuncID_debugCallV1 + FuncID_gopanic + FuncID_panicwrap + FuncID_handleAsyncEvent + FuncID_asyncPreempt + FuncID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.) +) + +// Get the function ID for the named function in the named file. +// The function should be package-qualified. +func GetFuncID(name string, isWrapper bool) FuncID { + if isWrapper { + return FuncID_wrapper + } + switch name { + case "runtime.main": + return FuncID_runtime_main + case "runtime.goexit": + return FuncID_goexit + case "runtime.jmpdefer": + return FuncID_jmpdefer + case "runtime.mcall": + return FuncID_mcall + case "runtime.morestack": + return FuncID_morestack + case "runtime.mstart": + return FuncID_mstart + case "runtime.rt0_go": + return FuncID_rt0_go + case "runtime.asmcgocall": + return FuncID_asmcgocall + case "runtime.sigpanic": + return FuncID_sigpanic + case "runtime.runfinq": + return FuncID_runfinq + case "runtime.gcBgMarkWorker": + return FuncID_gcBgMarkWorker + case "runtime.systemstack_switch": + return FuncID_systemstack_switch + case "runtime.systemstack": + return FuncID_systemstack + case "runtime.cgocallback": + return FuncID_cgocallback + case "runtime.gogo": + return FuncID_gogo + case "runtime.externalthreadhandler": + return FuncID_externalthreadhandler + case "runtime.debugCallV1": + return FuncID_debugCallV1 + case "runtime.gopanic": + return FuncID_gopanic + case "runtime.panicwrap": + return FuncID_panicwrap + case "runtime.handleAsyncEvent": + return FuncID_handleAsyncEvent + case "runtime.asyncPreempt": + return FuncID_asyncPreempt + case "runtime.deferreturn": + // Don't show in the call stack (used when invoking defer functions) + return FuncID_wrapper + case "runtime.runOpenDeferFrame": + // Don't show in the call stack (used when invoking defer functions) + return FuncID_wrapper + case "runtime.reflectcallSave": + // Don't show in the call stack (used when invoking defer functions) + return FuncID_wrapper + } + return FuncID_normal +} diff --git a/vendor/github.com/mandiant/GoReSym/objabi/head.go b/vendor/github.com/mandiant/GoReSym/objabi/head.go new file mode 100644 index 00000000..48ff2923 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/head.go @@ -0,0 +1,109 @@ +// Derived from Inferno utils/6l/l.h and related files. +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package objabi + +import "fmt" + +// HeadType is the executable header type. +type HeadType uint8 + +const ( + Hunknown HeadType = iota + Hdarwin + Hdragonfly + Hfreebsd + Hjs + Hlinux + Hnetbsd + Hopenbsd + Hplan9 + Hsolaris + Hwindows + Haix +) + +func (h *HeadType) Set(s string) error { + switch s { + case "aix": + *h = Haix + case "darwin", "ios": + *h = Hdarwin + case "dragonfly": + *h = Hdragonfly + case "freebsd": + *h = Hfreebsd + case "js": + *h = Hjs + case "linux", "android": + *h = Hlinux + case "netbsd": + *h = Hnetbsd + case "openbsd": + *h = Hopenbsd + case "plan9": + *h = Hplan9 + case "illumos", "solaris": + *h = Hsolaris + case "windows": + *h = Hwindows + default: + return fmt.Errorf("invalid headtype: %q", s) + } + return nil +} + +func (h *HeadType) String() string { + switch *h { + case Haix: + return "aix" + case Hdarwin: + return "darwin" + case Hdragonfly: + return "dragonfly" + case Hfreebsd: + return "freebsd" + case Hjs: + return "js" + case Hlinux: + return "linux" + case Hnetbsd: + return "netbsd" + case Hopenbsd: + return "openbsd" + case Hplan9: + return "plan9" + case Hsolaris: + return "solaris" + case Hwindows: + return "windows" + } + return fmt.Sprintf("HeadType(%d)", *h) +} diff --git a/vendor/github.com/mandiant/GoReSym/objabi/path.go b/vendor/github.com/mandiant/GoReSym/objabi/path.go new file mode 100644 index 00000000..fd1c9981 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/path.go @@ -0,0 +1,63 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import "strings" + +// PathToPrefix converts raw string to the prefix that will be used in the +// symbol table. All control characters, space, '%' and '"', as well as +// non-7-bit clean bytes turn into %xx. The period needs escaping only in the +// last segment of the path, and it makes for happier users if we escape that as +// little as possible. +func PathToPrefix(s string) string { + slash := strings.LastIndex(s, "/") + // check for chars that need escaping + n := 0 + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + n++ + } + } + + // quick exit + if n == 0 { + return s + } + + // escape + const hex = "0123456789abcdef" + p := make([]byte, 0, len(s)+2*n) + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + p = append(p, '%', hex[c>>4], hex[c&0xF]) + } else { + p = append(p, c) + } + } + + return string(p) +} + +// IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it +// belongs to the collection of "runtime-related" packages, including +// "runtime" itself, "reflect", "syscall", and the +// "runtime/internal/*" packages. The compiler and/or assembler in +// some cases need to be aware of when they are building such a +// package, for example to enable features such as ABI selectors in +// assembly sources. +func IsRuntimePackagePath(pkgpath string) bool { + rval := false + switch pkgpath { + case "runtime": + rval = true + case "reflect": + rval = true + case "syscall": + rval = true + default: + rval = strings.HasPrefix(pkgpath, "runtime/internal") + } + return rval +} diff --git a/vendor/github.com/mandiant/GoReSym/objabi/reloctype.go b/vendor/github.com/mandiant/GoReSym/objabi/reloctype.go new file mode 100644 index 00000000..649f6901 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/reloctype.go @@ -0,0 +1,291 @@ +// Derived from Inferno utils/6l/l.h and related files. +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package objabi + +type RelocType int16 + +//go:generate stringer -type=RelocType +const ( + R_ADDR RelocType = 1 + iota + // R_ADDRPOWER relocates a pair of "D-form" instructions (instructions with 16-bit + // immediates in the low half of the instruction word), usually addis followed by + // another add or a load, inserting the "high adjusted" 16 bits of the address of + // the referenced symbol into the immediate field of the first instruction and the + // low 16 bits into that of the second instruction. + R_ADDRPOWER + // R_ADDRARM64 relocates an adrp, add pair to compute the address of the + // referenced symbol. + R_ADDRARM64 + // R_ADDRMIPS (only used on mips/mips64) resolves to the low 16 bits of an external + // address, by encoding it into the instruction. + R_ADDRMIPS + // R_ADDROFF resolves to a 32-bit offset from the beginning of the section + // holding the data being relocated to the referenced symbol. + R_ADDROFF + // R_WEAKADDROFF resolves just like R_ADDROFF but is a weak relocation. + // A weak relocation does not make the symbol it refers to reachable, + // and is only honored by the linker if the symbol is in some other way + // reachable. + R_WEAKADDROFF + R_SIZE + R_CALL + R_CALLARM + R_CALLARM64 + R_CALLIND + R_CALLPOWER + // R_CALLMIPS (only used on mips64) resolves to non-PC-relative target address + // of a CALL (JAL) instruction, by encoding the address into the instruction. + R_CALLMIPS + // R_CALLRISCV marks RISC-V CALLs for stack checking. + R_CALLRISCV + R_CONST + R_PCREL + // R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the + // thread-local symbol from the thread local base and is used to implement the + // "local exec" model for tls access (r.Sym is not set on intel platforms but is + // set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking). + R_TLS_LE + // R_TLS_IE, used 386, amd64, and ARM resolves to the PC-relative offset to a GOT + // slot containing the offset from the thread-local symbol from the thread local + // base and is used to implemented the "initial exec" model for tls access (r.Sym + // is not set on intel platforms but is set to a TLS symbol -- runtime.tlsg -- in + // the linker when externally linking). + R_TLS_IE + R_GOTOFF + R_PLT0 + R_PLT1 + R_PLT2 + R_USEFIELD + // R_USETYPE resolves to an *rtype, but no relocation is created. The + // linker uses this as a signal that the pointed-to type information + // should be linked into the final binary, even if there are no other + // direct references. (This is used for types reachable by reflection.) + R_USETYPE + // R_USEIFACE marks a type is converted to an interface in the function this + // relocation is applied to. The target is a type descriptor. + // This is a marker relocation (0-sized), for the linker's reachabililty + // analysis. + R_USEIFACE + // R_USEIFACEMETHOD marks an interface method that is used in the function + // this relocation is applied to. The target is an interface type descriptor. + // The addend is the offset of the method in the type descriptor. + // This is a marker relocation (0-sized), for the linker's reachabililty + // analysis. + R_USEIFACEMETHOD + // R_METHODOFF resolves to a 32-bit offset from the beginning of the section + // holding the data being relocated to the referenced symbol. + // It is a variant of R_ADDROFF used when linking from the uncommonType of a + // *rtype, and may be set to zero by the linker if it determines the method + // text is unreachable by the linked program. + R_METHODOFF + R_POWER_TOC + R_GOTPCREL + // R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address + // of a JMP instruction, by encoding the address into the instruction. + // The stack nosplit check ignores this since it is not a function call. + R_JMPMIPS + + // R_DWARFSECREF resolves to the offset of the symbol from its section. + // Target of relocation must be size 4 (in current implementation). + R_DWARFSECREF + + // R_DWARFFILEREF resolves to an index into the DWARF .debug_line + // file table for the specified file symbol. Must be applied to an + // attribute of form DW_FORM_data4. + R_DWARFFILEREF + + // Platform dependent relocations. Architectures with fixed width instructions + // have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be + // stuffed into a 32-bit instruction, so an address needs to be spread across + // several instructions, and in turn this requires a sequence of relocations, each + // updating a part of an instruction. This leads to relocation codes that are + // inherently processor specific. + + // Arm64. + + // Set a MOV[NZ] immediate field to bits [15:0] of the offset from the thread + // local base to the thread local variable defined by the referenced (thread + // local) symbol. Error if the offset does not fit into 16 bits. + R_ARM64_TLS_LE + + // Relocates an ADRP; LD64 instruction sequence to load the offset between + // the thread local base and the thread local variable defined by the + // referenced (thread local) symbol from the GOT. + R_ARM64_TLS_IE + + // R_ARM64_GOTPCREL relocates an adrp, ld64 pair to compute the address of the GOT + // slot of the referenced symbol. + R_ARM64_GOTPCREL + + // R_ARM64_GOT resolves a GOT-relative instruction sequence, usually an adrp + // followed by another ld instruction. + R_ARM64_GOT + + // R_ARM64_PCREL resolves a PC-relative addresses instruction sequence, usually an + // adrp followed by another add instruction. + R_ARM64_PCREL + + // R_ARM64_LDST8 sets a LD/ST immediate value to bits [11:0] of a local address. + R_ARM64_LDST8 + + // R_ARM64_LDST16 sets a LD/ST immediate value to bits [11:1] of a local address. + R_ARM64_LDST16 + + // R_ARM64_LDST32 sets a LD/ST immediate value to bits [11:2] of a local address. + R_ARM64_LDST32 + + // R_ARM64_LDST64 sets a LD/ST immediate value to bits [11:3] of a local address. + R_ARM64_LDST64 + + // R_ARM64_LDST128 sets a LD/ST immediate value to bits [11:4] of a local address. + R_ARM64_LDST128 + + // PPC64. + + // R_POWER_TLS_LE is used to implement the "local exec" model for tls + // access. It resolves to the offset of the thread-local symbol from the + // thread pointer (R13) and inserts this value into the low 16 bits of an + // instruction word. + R_POWER_TLS_LE + + // R_POWER_TLS_IE is used to implement the "initial exec" model for tls access. It + // relocates a D-form, DS-form instruction sequence like R_ADDRPOWER_DS. It + // inserts to the offset of GOT slot for the thread-local symbol from the TOC (the + // GOT slot is filled by the dynamic linker with the offset of the thread-local + // symbol from the thread pointer (R13)). + R_POWER_TLS_IE + + // R_POWER_TLS marks an X-form instruction such as "MOVD 0(R13)(R31*1), g" as + // accessing a particular thread-local symbol. It does not affect code generation + // but is used by the system linker when relaxing "initial exec" model code to + // "local exec" model code. + R_POWER_TLS + + // R_ADDRPOWER_DS is similar to R_ADDRPOWER above, but assumes the second + // instruction is a "DS-form" instruction, which has an immediate field occupying + // bits [15:2] of the instruction word. Bits [15:2] of the address of the + // relocated symbol are inserted into this field; it is an error if the last two + // bits of the address are not 0. + R_ADDRPOWER_DS + + // R_ADDRPOWER_PCREL relocates a D-form, DS-form instruction sequence like + // R_ADDRPOWER_DS but inserts the offset of the GOT slot for the referenced symbol + // from the TOC rather than the symbol's address. + R_ADDRPOWER_GOT + + // R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but + // inserts the displacement from the place being relocated to the address of the + // relocated symbol instead of just its address. + R_ADDRPOWER_PCREL + + // R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but + // inserts the offset from the TOC to the address of the relocated symbol + // rather than the symbol's address. + R_ADDRPOWER_TOCREL + + // R_ADDRPOWER_TOCREL relocates a D-form, DS-form instruction sequence like + // R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the + // relocated symbol rather than the symbol's address. + R_ADDRPOWER_TOCREL_DS + + // RISC-V. + + // R_RISCV_PCREL_ITYPE resolves a 32-bit PC-relative address using an + // AUIPC + I-type instruction pair. + R_RISCV_PCREL_ITYPE + + // R_RISCV_PCREL_STYPE resolves a 32-bit PC-relative address using an + // AUIPC + S-type instruction pair. + R_RISCV_PCREL_STYPE + + // R_RISCV_TLS_IE_ITYPE resolves a 32-bit TLS initial-exec TOC offset + // address using an AUIPC + I-type instruction pair. + R_RISCV_TLS_IE_ITYPE + + // R_RISCV_TLS_IE_STYPE resolves a 32-bit TLS initial-exec TOC offset + // address using an AUIPC + S-type instruction pair. + R_RISCV_TLS_IE_STYPE + + // R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses. + // TODO(mundaym): remove once variants can be serialized - see issue 14218. + R_PCRELDBL + + // R_ADDRMIPSU (only used on mips/mips64) resolves to the sign-adjusted "upper" 16 + // bits (bit 16-31) of an external address, by encoding it into the instruction. + R_ADDRMIPSU + // R_ADDRMIPSTLS (only used on mips64) resolves to the low 16 bits of a TLS + // address (offset from thread pointer), by encoding it into the instruction. + R_ADDRMIPSTLS + + // R_ADDRCUOFF resolves to a pointer-sized offset from the start of the + // symbol's DWARF compile unit. + R_ADDRCUOFF + + // R_WASMIMPORT resolves to the index of the WebAssembly function import. + R_WASMIMPORT + + // R_XCOFFREF (only used on aix/ppc64) prevents garbage collection by ld + // of a symbol. This isn't a real relocation, it can be placed in anywhere + // in a symbol and target any symbols. + R_XCOFFREF +) + +// IsDirectCall reports whether r is a relocation for a direct call. +// A direct call is a CALL instruction that takes the target address +// as an immediate. The address is embedded into the instruction, possibly +// with limited width. An indirect call is a CALL instruction that takes +// the target address in register or memory. +func (r RelocType) IsDirectCall() bool { + switch r { + case R_CALL, R_CALLARM, R_CALLARM64, R_CALLMIPS, R_CALLPOWER, R_CALLRISCV: + return true + } + return false +} + +// IsDirectJump reports whether r is a relocation for a direct jump. +// A direct jump is a JMP instruction that takes the target address +// as an immediate. The address is embedded into the instruction, possibly +// with limited width. An indirect jump is a JMP instruction that takes +// the target address in register or memory. +func (r RelocType) IsDirectJump() bool { + switch r { + case R_JMPMIPS: + return true + } + return false +} + +// IsDirectCallOrJump reports whether r is a relocation for a direct +// call or a direct jump. +func (r RelocType) IsDirectCallOrJump() bool { + return r.IsDirectCall() || r.IsDirectJump() +} diff --git a/vendor/github.com/mandiant/GoReSym/objabi/reloctype_string.go b/vendor/github.com/mandiant/GoReSym/objabi/reloctype_string.go new file mode 100644 index 00000000..658a44f8 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/reloctype_string.go @@ -0,0 +1,83 @@ +// Code generated by "stringer -type=RelocType"; DO NOT EDIT. + +package objabi + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[R_ADDR-1] + _ = x[R_ADDRPOWER-2] + _ = x[R_ADDRARM64-3] + _ = x[R_ADDRMIPS-4] + _ = x[R_ADDROFF-5] + _ = x[R_WEAKADDROFF-6] + _ = x[R_SIZE-7] + _ = x[R_CALL-8] + _ = x[R_CALLARM-9] + _ = x[R_CALLARM64-10] + _ = x[R_CALLIND-11] + _ = x[R_CALLPOWER-12] + _ = x[R_CALLMIPS-13] + _ = x[R_CALLRISCV-14] + _ = x[R_CONST-15] + _ = x[R_PCREL-16] + _ = x[R_TLS_LE-17] + _ = x[R_TLS_IE-18] + _ = x[R_GOTOFF-19] + _ = x[R_PLT0-20] + _ = x[R_PLT1-21] + _ = x[R_PLT2-22] + _ = x[R_USEFIELD-23] + _ = x[R_USETYPE-24] + _ = x[R_USEIFACE-25] + _ = x[R_USEIFACEMETHOD-26] + _ = x[R_METHODOFF-27] + _ = x[R_POWER_TOC-28] + _ = x[R_GOTPCREL-29] + _ = x[R_JMPMIPS-30] + _ = x[R_DWARFSECREF-31] + _ = x[R_DWARFFILEREF-32] + _ = x[R_ARM64_TLS_LE-33] + _ = x[R_ARM64_TLS_IE-34] + _ = x[R_ARM64_GOTPCREL-35] + _ = x[R_ARM64_GOT-36] + _ = x[R_ARM64_PCREL-37] + _ = x[R_ARM64_LDST8-38] + _ = x[R_ARM64_LDST16-39] + _ = x[R_ARM64_LDST32-40] + _ = x[R_ARM64_LDST64-41] + _ = x[R_ARM64_LDST128-42] + _ = x[R_POWER_TLS_LE-43] + _ = x[R_POWER_TLS_IE-44] + _ = x[R_POWER_TLS-45] + _ = x[R_ADDRPOWER_DS-46] + _ = x[R_ADDRPOWER_GOT-47] + _ = x[R_ADDRPOWER_PCREL-48] + _ = x[R_ADDRPOWER_TOCREL-49] + _ = x[R_ADDRPOWER_TOCREL_DS-50] + _ = x[R_RISCV_PCREL_ITYPE-51] + _ = x[R_RISCV_PCREL_STYPE-52] + _ = x[R_RISCV_TLS_IE_ITYPE-53] + _ = x[R_RISCV_TLS_IE_STYPE-54] + _ = x[R_PCRELDBL-55] + _ = x[R_ADDRMIPSU-56] + _ = x[R_ADDRMIPSTLS-57] + _ = x[R_ADDRCUOFF-58] + _ = x[R_WASMIMPORT-59] + _ = x[R_XCOFFREF-60] +} + +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF" + +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 234, 245, 256, 266, 275, 288, 302, 316, 330, 346, 357, 370, 383, 397, 411, 425, 440, 454, 468, 479, 493, 508, 525, 543, 564, 583, 602, 622, 642, 652, 663, 676, 687, 699, 709} + +func (i RelocType) String() string { + i -= 1 + if i < 0 || i >= RelocType(len(_RelocType_index)-1) { + return "RelocType(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _RelocType_name[_RelocType_index[i]:_RelocType_index[i+1]] +} diff --git a/vendor/github.com/mandiant/GoReSym/objabi/symkind.go b/vendor/github.com/mandiant/GoReSym/objabi/symkind.go new file mode 100644 index 00000000..6c991121 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/symkind.go @@ -0,0 +1,79 @@ +// Derived from Inferno utils/6l/l.h and related files. +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package objabi + +// A SymKind describes the kind of memory represented by a symbol. +type SymKind uint8 + +// Defined SymKind values. +// These are used to index into cmd/link/internal/sym/AbiSymKindToSymKind +// +// TODO(rsc): Give idiomatic Go names. +//go:generate stringer -type=SymKind +const ( + // An otherwise invalid zero value for the type + Sxxx SymKind = iota + // Executable instructions + STEXT + // Read only static data + SRODATA + // Static data that does not contain any pointers + SNOPTRDATA + // Static data + SDATA + // Statically data that is initially all 0s + SBSS + // Statically data that is initially all 0s and does not contain pointers + SNOPTRBSS + // Thread-local data that is initially all 0s + STLSBSS + // Debugging data + SDWARFCUINFO + SDWARFCONST + SDWARFFCN + SDWARFABSFCN + SDWARFTYPE + SDWARFVAR + SDWARFRANGE + SDWARFLOC + SDWARFLINES + // ABI alias. An ABI alias symbol is an empty symbol with a + // single relocation with 0 size that references the native + // function implementation symbol. + // + // TODO(austin): Remove this and all uses once the compiler + // generates real ABI wrappers rather than symbol aliases. + SABIALIAS + // Coverage instrumentation counter for libfuzzer. + SLIBFUZZER_EXTRA_COUNTER + // Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values. + +) diff --git a/vendor/github.com/mandiant/GoReSym/objabi/symkind_string.go b/vendor/github.com/mandiant/GoReSym/objabi/symkind_string.go new file mode 100644 index 00000000..1b1c3940 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/symkind_string.go @@ -0,0 +1,41 @@ +// Code generated by "stringer -type=SymKind"; DO NOT EDIT. + +package objabi + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Sxxx-0] + _ = x[STEXT-1] + _ = x[SRODATA-2] + _ = x[SNOPTRDATA-3] + _ = x[SDATA-4] + _ = x[SBSS-5] + _ = x[SNOPTRBSS-6] + _ = x[STLSBSS-7] + _ = x[SDWARFCUINFO-8] + _ = x[SDWARFCONST-9] + _ = x[SDWARFFCN-10] + _ = x[SDWARFABSFCN-11] + _ = x[SDWARFTYPE-12] + _ = x[SDWARFVAR-13] + _ = x[SDWARFRANGE-14] + _ = x[SDWARFLOC-15] + _ = x[SDWARFLINES-16] + _ = x[SABIALIAS-17] + _ = x[SLIBFUZZER_EXTRA_COUNTER-18] +} + +const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSABIALIASSLIBFUZZER_EXTRA_COUNTER" + +var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 63, 74, 83, 95, 105, 114, 125, 134, 145, 154, 178} + +func (i SymKind) String() string { + if i >= SymKind(len(_SymKind_index)-1) { + return "SymKind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]] +} diff --git a/vendor/github.com/mandiant/GoReSym/objabi/typekind.go b/vendor/github.com/mandiant/GoReSym/objabi/typekind.go new file mode 100644 index 00000000..990ff188 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objabi/typekind.go @@ -0,0 +1,40 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +// Must match runtime and reflect. +// Included by cmd/gc. + +const ( + KindBool = 1 + iota + KindInt + KindInt8 + KindInt16 + KindInt32 + KindInt64 + KindUint + KindUint8 + KindUint16 + KindUint32 + KindUint64 + KindUintptr + KindFloat32 + KindFloat64 + KindComplex64 + KindComplex128 + KindArray + KindChan + KindFunc + KindInterface + KindMap + KindPtr + KindSlice + KindString + KindStruct + KindUnsafePointer + KindDirectIface = 1 << 5 + KindGCProg = 1 << 6 + KindMask = (1 << 5) - 1 +) diff --git a/vendor/github.com/mandiant/GoReSym/objfile/disasm.go b/vendor/github.com/mandiant/GoReSym/objfile/disasm.go new file mode 100644 index 00000000..7641ac4c --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/disasm.go @@ -0,0 +1,411 @@ +// Copyright 2014 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +package objfile + +import ( + "bufio" + "bytes" + "container/list" + "encoding/binary" + "fmt" + "io" + "os" + "path/filepath" + "regexp" + "sort" + "strings" + "text/tabwriter" + + "github.com/mandiant/GoReSym/cmd/src" + "github.com/mandiant/GoReSym/debug/gosym" + + "golang.org/x/arch/arm/armasm" + "golang.org/x/arch/arm64/arm64asm" + "golang.org/x/arch/ppc64/ppc64asm" + "golang.org/x/arch/x86/x86asm" +) + +// Disasm is a disassembler for a given File. +type Disasm struct { + syms []Sym //symbols in file, sorted by address + pcln Liner // pcln table + text []byte // bytes of text segment (actual instructions) + textStart uint64 // start PC of text + textEnd uint64 // end PC of text + goarch string // GOARCH string + disasm disasmFunc // disassembler function for goarch + byteOrder binary.ByteOrder // byte order for goarch +} + +// Disasm returns a disassembler for the file f. +func (e *Entry) Disasm() (*Disasm, error) { + syms, err := e.Symbols() + if err != nil { + return nil, err + } + + pclns, err := e.PCLineTable("", 0, 0) + if err != nil { + return nil, err + } + + textStart, textBytes, err := e.Text() + if err != nil { + return nil, err + } + + goarch := e.GOARCH() + disasm := disasms[goarch] + byteOrder := byteOrders[goarch] + if disasm == nil || byteOrder == nil { + return nil, fmt.Errorf("unsupported architecture") + } + + // Filter out section symbols, overwriting syms in place. + keep := syms[:0] + for _, sym := range syms { + switch sym.Name { + case "runtime.text", "text", "_text", "runtime.etext", "etext", "_etext": + // drop + default: + keep = append(keep, sym) + } + } + syms = keep + d := &Disasm{ + syms: syms, + pcln: pclns[0].ParsedPclntab, + text: textBytes, + textStart: textStart, + textEnd: textStart + uint64(len(textBytes)), + goarch: goarch, + disasm: disasm, + byteOrder: byteOrder, + } + + return d, nil +} + +// lookup finds the symbol name containing addr. +func (d *Disasm) lookup(addr uint64) (name string, base uint64) { + i := sort.Search(len(d.syms), func(i int) bool { return addr < d.syms[i].Addr }) + if i > 0 { + s := d.syms[i-1] + if s.Addr != 0 && s.Addr <= addr && addr < s.Addr+uint64(s.Size) { + return s.Name, s.Addr + } + } + return "", 0 +} + +// base returns the final element in the path. +// It works on both Windows and Unix paths, +// regardless of host operating system. +func base(path string) string { + path = path[strings.LastIndex(path, "/")+1:] + path = path[strings.LastIndex(path, `\`)+1:] + return path +} + +// CachedFile contains the content of a file split into lines. +type CachedFile struct { + FileName string + Lines [][]byte +} + +// FileCache is a simple LRU cache of file contents. +type FileCache struct { + files *list.List + maxLen int +} + +// NewFileCache returns a FileCache which can contain up to maxLen cached file contents. +func NewFileCache(maxLen int) *FileCache { + return &FileCache{ + files: list.New(), + maxLen: maxLen, + } +} + +// Line returns the source code line for the given file and line number. +// If the file is not already cached, reads it, inserts it into the cache, +// and removes the least recently used file if necessary. +// If the file is in cache, it is moved to the front of the list. +func (fc *FileCache) Line(filename string, line int) ([]byte, error) { + if filepath.Ext(filename) != ".go" { + return nil, nil + } + + // Clean filenames returned by src.Pos.SymFilename() + // or src.PosBase.SymFilename() removing + // the leading src.FileSymPrefix. + filename = strings.TrimPrefix(filename, src.FileSymPrefix) + + // Expand literal "$GOROOT" rewritten by obj.AbsFile() + filename = filepath.Clean(os.ExpandEnv(filename)) + + var cf *CachedFile + var e *list.Element + + for e = fc.files.Front(); e != nil; e = e.Next() { + cf = e.Value.(*CachedFile) + if cf.FileName == filename { + break + } + } + + if e == nil { + content, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + + cf = &CachedFile{ + FileName: filename, + Lines: bytes.Split(content, []byte{'\n'}), + } + fc.files.PushFront(cf) + + if fc.files.Len() >= fc.maxLen { + fc.files.Remove(fc.files.Back()) + } + } else { + fc.files.MoveToFront(e) + } + + // because //line directives can be out-of-range. (#36683) + if line-1 >= len(cf.Lines) || line-1 < 0 { + return nil, nil + } + + return cf.Lines[line-1], nil +} + +// Print prints a disassembly of the file to w. +// If filter is non-nil, the disassembly only includes functions with names matching filter. +// If printCode is true, the disassembly includs corresponding source lines. +// The disassembly only includes functions that overlap the range [start, end). +func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool, gnuAsm bool) { + if start < d.textStart { + start = d.textStart + } + if end > d.textEnd { + end = d.textEnd + } + printed := false + bw := bufio.NewWriter(w) + + var fc *FileCache + if printCode { + fc = NewFileCache(8) + } + + tw := tabwriter.NewWriter(bw, 18, 8, 1, '\t', tabwriter.StripEscape) + for _, sym := range d.syms { + symStart := sym.Addr + symEnd := sym.Addr + uint64(sym.Size) + relocs := sym.Relocs + if sym.Code != 'T' && sym.Code != 't' || + symStart < d.textStart || + symEnd <= start || end <= symStart || + filter != nil && !filter.MatchString(sym.Name) { + continue + } + if printed { + fmt.Fprintf(bw, "\n") + } + printed = true + + file, _, _ := d.pcln.PCToLine(sym.Addr) + fmt.Fprintf(bw, "TEXT %s(SB) %s\n", sym.Name, file) + + if symEnd > end { + symEnd = end + } + code := d.text[:end-d.textStart] + + var lastFile string + var lastLine int + + d.Decode(symStart, symEnd, relocs, gnuAsm, func(pc, size uint64, file string, line int, text string) { + i := pc - d.textStart + + if printCode { + if file != lastFile || line != lastLine { + if srcLine, err := fc.Line(file, line); err == nil { + fmt.Fprintf(tw, "%s%s%s\n", []byte{tabwriter.Escape}, srcLine, []byte{tabwriter.Escape}) + } + + lastFile, lastLine = file, line + } + + fmt.Fprintf(tw, " %#x\t", pc) + } else { + fmt.Fprintf(tw, " %s:%d\t%#x\t", base(file), line, pc) + } + + if size%4 != 0 || d.goarch == "386" || d.goarch == "amd64" { + // Print instruction as bytes. + fmt.Fprintf(tw, "%x", code[i:i+size]) + } else { + // Print instruction as 32-bit words. + for j := uint64(0); j < size; j += 4 { + if j > 0 { + fmt.Fprintf(tw, " ") + } + fmt.Fprintf(tw, "%08x", d.byteOrder.Uint32(code[i+j:])) + } + } + fmt.Fprintf(tw, "\t%s\t\n", text) + }) + tw.Flush() + } + bw.Flush() +} + +// Decode disassembles the text segment range [start, end), calling f for each instruction. +func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) { + if start < d.textStart { + start = d.textStart + } + if end > d.textEnd { + end = d.textEnd + } + code := d.text[:end-d.textStart] + lookup := d.lookup + for pc := start; pc < end; { + i := pc - d.textStart + text, size := d.disasm(code[i:], pc, lookup, d.byteOrder, gnuAsm) + file, line, _ := d.pcln.PCToLine(pc) + sep := "\t" + for len(relocs) > 0 && relocs[0].Addr < i+uint64(size) { + text += sep + relocs[0].Stringer.String(pc-start) + sep = " " + relocs = relocs[1:] + } + f(pc, uint64(size), file, line, text) + pc += uint64(size) + } +} + +type lookupFunc = func(addr uint64) (sym string, base uint64) +type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder, _ bool) (text string, size int) + +func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { + return disasm_x86(code, pc, lookup, 32, gnuAsm) +} + +func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { + return disasm_x86(code, pc, lookup, 64, gnuAsm) +} + +func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int, gnuAsm bool) (string, int) { + inst, err := x86asm.Decode(code, arch) + var text string + size := inst.Len + if err != nil || size == 0 || inst.Op == 0 { + size = 1 + text = "?" + } else { + if gnuAsm { + text = fmt.Sprintf("%-36s // %s", x86asm.GoSyntax(inst, pc, lookup), x86asm.GNUSyntax(inst, pc, nil)) + } else { + text = x86asm.GoSyntax(inst, pc, lookup) + } + } + return text, size +} + +type textReader struct { + code []byte + pc uint64 +} + +func (r textReader) ReadAt(data []byte, off int64) (n int, err error) { + if off < 0 || uint64(off) < r.pc { + return 0, io.EOF + } + d := uint64(off) - r.pc + if d >= uint64(len(r.code)) { + return 0, io.EOF + } + n = copy(data, r.code[d:]) + if n < len(data) { + err = io.ErrUnexpectedEOF + } + return +} + +func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { + inst, err := armasm.Decode(code, armasm.ModeARM) + var text string + size := inst.Len + if err != nil || size == 0 || inst.Op == 0 { + size = 4 + text = "?" + } else if gnuAsm { + text = fmt.Sprintf("%-36s // %s", armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}), armasm.GNUSyntax(inst)) + } else { + text = armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}) + } + return text, size +} + +func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) { + inst, err := arm64asm.Decode(code) + var text string + if err != nil || inst.Op == 0 { + text = "?" + } else if gnuAsm { + text = fmt.Sprintf("%-36s // %s", arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), arm64asm.GNUSyntax(inst)) + } else { + text = arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}) + } + return text, 4 +} + +func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) { + inst, err := ppc64asm.Decode(code, byteOrder) + var text string + size := inst.Len + if err != nil || size == 0 { + size = 4 + text = "?" + } else { + if gnuAsm { + text = fmt.Sprintf("%-36s // %s", ppc64asm.GoSyntax(inst, pc, lookup), ppc64asm.GNUSyntax(inst, pc)) + } else { + text = ppc64asm.GoSyntax(inst, pc, lookup) + } + } + return text, size +} + +var disasms = map[string]disasmFunc{ + "386": disasm_386, + "amd64": disasm_amd64, + "arm": disasm_arm, + "arm64": disasm_arm64, + "ppc64": disasm_ppc64, + "ppc64le": disasm_ppc64, +} + +var byteOrders = map[string]binary.ByteOrder{ + "386": binary.LittleEndian, + "amd64": binary.LittleEndian, + "arm": binary.LittleEndian, + "arm64": binary.LittleEndian, + "ppc64": binary.BigEndian, + "ppc64le": binary.LittleEndian, + "s390x": binary.BigEndian, +} + +type Liner interface { + // Given a pc, returns the corresponding file, line, and function data. + // If unknown, returns "",0,nil. + PCToLine(uint64) (string, int, *gosym.Func) +} diff --git a/vendor/github.com/mandiant/GoReSym/objfile/elf.go b/vendor/github.com/mandiant/GoReSym/objfile/elf.go new file mode 100644 index 00000000..3777e00d --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/elf.go @@ -0,0 +1,427 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Parsing of ELF executables (Linux, FreeBSD, and so on). + +package objfile + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + + "github.com/mandiant/GoReSym/debug/dwarf" + "github.com/mandiant/GoReSym/debug/elf" +) + +type elfFile struct { + elf *elf.File +} + +func openElf(r io.ReaderAt) (rawFile, error) { + f, err := elf.NewFile(r) + if err != nil { + return nil, err + } + return &elfFile{f}, nil +} + +func (f *elfFile) read_memory(VA uint64, size uint64) (data []byte, err error) { + for _, prog := range f.elf.Progs { + if prog.Vaddr <= VA && VA <= prog.Vaddr+prog.Filesz-1 { + n := prog.Vaddr + prog.Filesz - VA + if n > size { + n = size + } + data := make([]byte, n) + _, err := prog.ReadAt(data, int64(VA-prog.Vaddr)) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("Failed to read memory") +} + +func (f *elfFile) symbols() ([]Sym, error) { + elfSyms, err := f.elf.Symbols() + if err != nil { + return nil, err + } + + var syms []Sym + for _, s := range elfSyms { + sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} + switch s.Section { + case elf.SHN_UNDEF: + sym.Code = 'U' + case elf.SHN_COMMON: + sym.Code = 'B' + default: + i := int(s.Section) + if i < 0 || i >= len(f.elf.Sections) { + break + } + sect := f.elf.Sections[i] + switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { + case elf.SHF_ALLOC | elf.SHF_EXECINSTR: + sym.Code = 'T' + case elf.SHF_ALLOC: + sym.Code = 'R' + case elf.SHF_ALLOC | elf.SHF_WRITE: + sym.Code = 'D' + } + } + if elf.ST_BIND(s.Info) == elf.STB_LOCAL { + sym.Code += 'a' - 'A' + } + syms = append(syms, sym) + } + + return syms, nil +} + +func (f *elfFile) pcln_scan() (candidates []PclntabCandidate, err error) { + // 1) Locate pclntab via symbols (standard way) + foundpcln := false + var pclntab []byte + if sect := f.elf.Section(".gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err == nil { + foundpcln = true + } + } + + pclntab_sigs_le := [][]byte{ + []byte("\xF1\xFF\xFF\xFF\x00\x00"), // little endian + []byte("\xF0\xFF\xFF\xFF\x00\x00"), + []byte("\xFA\xFF\xFF\xFF\x00\x00"), + []byte("\xFB\xFF\xFF\xFF\x00\x00"), + } + + pclntab_sigs_be := [][]byte{ + []byte("\xFF\xFF\xFF\xF1\x00\x00"), // big endian + []byte("\xFF\xFF\xFF\xF0\x00\x00"), + []byte("\xFF\xFF\xFF\xFA\x00\x00"), + []byte("\xFF\xFF\xFF\xFB\x00\x00"), + } + + // 2) if not found, byte scan for it + pclntab_sigs := append(pclntab_sigs_le, pclntab_sigs_be...) + + // candidate array for method 4 of scanning + var stompedmagic_candidates []StompMagicCandidate = make([]StompMagicCandidate, 0) + for _, sec := range f.elf.Sections { + // first section is all zeros, skip + if sec.Type == elf.SHT_NULL { + continue + } + + data := f.elf.DataAfterSection(sec) + if !foundpcln { + // malware can split the pclntab across multiple sections, re-merge + // https://github.com/golang/go/blob/2cb9042dc2d5fdf6013305a077d013dbbfbaac06/src/debug/gosym/pclntab.go#L172 + matches := findAllOccurrences(data, pclntab_sigs) + for _, pclntab_idx := range matches { + if pclntab_idx != -1 && pclntab_idx < int(sec.Size) { + pclntab = data[pclntab_idx:] + + var candidate PclntabCandidate + candidate.Pclntab = pclntab + + candidate.SecStart = uint64(sec.Addr) + candidate.PclntabVA = candidate.SecStart + uint64(pclntab_idx) + + candidates = append(candidates, candidate) + // we must scan all signature for all sections. DO NOT BREAK + } + } + } else { + // 3) if we found it earlier, figure out which section base to return (might be wrong for packed things) + pclntab_idx := bytes.Index(data, pclntab) + if pclntab_idx != -1 && pclntab_idx < int(sec.Size) { + var candidate PclntabCandidate + candidate.Pclntab = pclntab + candidate.SecStart = uint64(sec.Addr) + candidate.PclntabVA = candidate.SecStart + uint64(pclntab_idx) + + candidates = append(candidates, candidate) + } + } + + // TODO this scan needs to occur in both big and little endian mode + // 4) Always try this other way! Sometimes the pclntab magic is stomped as well so our byte OR symbol location fail. Byte scan for the moduledata, use that to find the pclntab instead, fix up magic with all combinations. + // See the obfuscator 'garble' for an example of randomizing the pclntab magic + sigResults := findModuleInitPCHeader(data, sec.Addr) + for _, sigResult := range sigResults { + // example: off_69D0C0 is the moduleData we found via our scan, the first ptr unk_5DF6E0, is the pclntab! + // 0x000000000069D0C0 E0 F6 5D 00 00 00 00 00 off_69D0C0 dq offset unk_5DF6E0 ; DATA XREF: runtime_SetFinalizer+119↑o + // 0x000000000069D0C0 ; runtime_scanstack+40B↑o ... + // 0x000000000069D0C8 40 F7 5D 00 00 00 00 00 dq offset aInternalCpuIni ; "internal/cpu.Initialize" + // 0x000000000069D0D0 F0 db 0F0h + // 0x000000000069D0D1 BB db 0BBh + + // we don't know the endianess or arch, so we submit all combinations as candidates and sort them out later + // example: reads out ptr unk_5DF6E0 + pclntabVARaw64, err := f.read_memory(sigResult.moduleDataVA, 8) // assume 64bit + if err == nil { + stompedMagicCandidateLE := StompMagicCandidate{ + binary.LittleEndian.Uint64(pclntabVARaw64), + sigResult.moduleDataVA, + true, + } + stompedMagicCandidateBE := StompMagicCandidate{ + binary.BigEndian.Uint64(pclntabVARaw64), + sigResult.moduleDataVA, + false, + } + stompedmagic_candidates = append(stompedmagic_candidates, stompedMagicCandidateLE, stompedMagicCandidateBE) + } + + pclntabVARaw32, err := f.read_memory(sigResult.moduleDataVA, 4) // assume 32bit + if err == nil { + stompedMagicCandidateLE := StompMagicCandidate{ + uint64(binary.LittleEndian.Uint32(pclntabVARaw32)), + sigResult.moduleDataVA, + true, + } + stompedMagicCandidateBE := StompMagicCandidate{ + uint64(binary.BigEndian.Uint32(pclntabVARaw32)), + sigResult.moduleDataVA, + false, + } + stompedmagic_candidates = append(stompedmagic_candidates, stompedMagicCandidateLE, stompedMagicCandidateBE) + } + } + } + + // even if we found the pclntab without signature scanning it may have a stomped magic. That would break parsing later! So, let's submit new candidates + // with all the possible magics to get at least one that hopefully parses correctly. + patched_magic_candidates := make([]PclntabCandidate, 0) + for _, candidate := range candidates { + has_some_valid_magic := false + for _, magic := range append(pclntab_sigs_le, pclntab_sigs_be...) { + if bytes.Equal(candidate.Pclntab, magic) { + has_some_valid_magic = true + break + } + } + + if !has_some_valid_magic { + for _, magic := range append(pclntab_sigs_le, pclntab_sigs_be...) { + pclntab_copy := make([]byte, len(candidate.Pclntab)) + copy(pclntab_copy, candidate.Pclntab) + copy(pclntab_copy, magic) + + new_candidate := candidate + new_candidate.Pclntab = pclntab_copy + patched_magic_candidates = append(patched_magic_candidates, new_candidate) + candidate.Pclntab = pclntab_copy + } + } + } + + if len(patched_magic_candidates) > 0 { + candidates = patched_magic_candidates + } + + if len(stompedmagic_candidates) != 0 { + for _, sec := range f.elf.Sections { + data := f.elf.DataAfterSection(sec) + for _, stompedMagicCandidate := range stompedmagic_candidates { + pclntab_va_candidate := stompedMagicCandidate.PclntabVa + + // use data length as some binaries have invalid section length + if pclntab_va_candidate >= sec.Addr && pclntab_va_candidate < (sec.Addr+sec.Size) && pclntab_va_candidate < (sec.Addr+uint64(len(data))) { + sec_offset := pclntab_va_candidate - sec.Addr + pclntab = data[sec_offset:] + + if stompedMagicCandidate.LittleEndian { + for _, magicLE := range pclntab_sigs_le { + pclntab_copy := make([]byte, len(pclntab)) + copy(pclntab_copy, pclntab) + copy(pclntab_copy, magicLE) + + var candidate PclntabCandidate + candidate.StompMagicCandidateMeta = &stompedMagicCandidate + candidate.Pclntab = pclntab_copy + candidate.SecStart = uint64(sec.Addr) + candidate.PclntabVA = pclntab_va_candidate + + candidates = append(candidates, candidate) + } + } else { + for _, magicBE := range pclntab_sigs_be { + pclntab_copy := make([]byte, len(pclntab)) + copy(pclntab_copy, pclntab) + copy(pclntab_copy, magicBE) + + var candidate PclntabCandidate + candidate.StompMagicCandidateMeta = &stompedMagicCandidate + candidate.Pclntab = pclntab_copy + candidate.SecStart = uint64(sec.Addr) + candidate.PclntabVA = pclntab_va_candidate + + candidates = append(candidates, candidate) + } + } + } + } + } + } + + return candidates, nil +} + +func (f *elfFile) pcln() (candidates []PclntabCandidate, err error) { + candidates, err = f.pcln_scan() + if err != nil { + return nil, err + } + + // 4) symtab is completely optional, but try to find it + var symtab []byte + if sect := f.elf.Section(".gosymtab"); sect != nil { + symtab, err = sect.Data() + } + + if err == nil { + for _, c := range candidates { + c.Symtab = symtab + } + } + + return candidates, nil +} + +func (f *elfFile) moduledata_scan(pclntabVA uint64, is64bit bool, littleendian bool, ignorelist []uint64) (candidate *ModuleDataCandidate, err error) { + found := false + + var secStart uint64 + var moduledata []uint8 + var moduledataVA uint64 +scan: + for _, sec := range f.elf.Sections { + // first section is all zeros, skip + if sec.Type == elf.SHT_NULL { + continue + } + + // malware can split the pclntab across multiple sections, re-merge + data := f.elf.DataAfterSection(sec) + + // fall back to scanning for structure using address of pclntab, which is first value in struc + var pclntabVA_bytes []byte + if is64bit { + pclntabVA_bytes = make([]byte, 8) + if littleendian { + binary.LittleEndian.PutUint64(pclntabVA_bytes, pclntabVA) + } else { + binary.BigEndian.PutUint64(pclntabVA_bytes, pclntabVA) + } + } else { + pclntabVA_bytes = make([]byte, 4) + if littleendian { + binary.LittleEndian.PutUint32(pclntabVA_bytes, uint32(pclntabVA)) + } else { + binary.BigEndian.PutUint32(pclntabVA_bytes, uint32(pclntabVA)) + } + } + + moduledata_idx := bytes.Index(data, pclntabVA_bytes) + if moduledata_idx != -1 && moduledata_idx < int(sec.Size) { + moduledata = data[moduledata_idx:] + moduledataVA = sec.Addr + uint64(moduledata_idx) + secStart = sec.Addr + + // optionally consult ignore list, to skip past previous (bad) scan results + for _, ignore := range ignorelist { + if ignore == secStart+uint64(moduledata_idx) { + continue scan + } + } + + found = true + break + } + } + + if !found { + return nil, fmt.Errorf("moduledata containing section could not be located") + } + + return &ModuleDataCandidate{SecStart: secStart, ModuledataVA: moduledataVA, Moduledata: moduledata}, nil +} + +func (f *elfFile) text() (textStart uint64, text []byte, err error) { + sect := f.elf.Section(".text") + if sect == nil { + return 0, nil, fmt.Errorf("text section not found") + } + textStart = sect.Addr + text, err = sect.Data() + return +} + +func (f *elfFile) rdata() (textStart uint64, text []byte, err error) { + sect := f.elf.Section(".rodata") + if sect == nil { + return 0, nil, fmt.Errorf("rdata section not found") + } + textStart = sect.Addr + text, err = sect.Data() + return +} + +func (f *elfFile) rel_rdata() (textStart uint64, text []byte, err error) { + sect := f.elf.Section(".data.rel.ro") + if sect == nil { + return 0, nil, fmt.Errorf(".data.rel.ro section not found") + } + textStart = sect.Addr + text, err = sect.Data() + return +} + +func (f *elfFile) goarch() string { + switch f.elf.Machine { + case elf.EM_386: + return "386" + case elf.EM_X86_64: + return "amd64" + case elf.EM_ARM: + return "arm" + case elf.EM_AARCH64: + return "arm64" + case elf.EM_PPC64: + if f.elf.ByteOrder == binary.LittleEndian { + return "ppc64le" + } + return "ppc64" + case elf.EM_S390: + return "s390x" + } + return "" +} + +func (f *elfFile) loadAddress() (uint64, error) { + for _, p := range f.elf.Progs { + if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 { + // The memory mapping that contains the segment + // starts at an aligned address. Apparently this + // is what pprof expects, as it uses this and the + // start address of the mapping to compute PC + // delta. + return p.Vaddr - p.Vaddr%p.Align, nil + } + } + return 0, fmt.Errorf("unknown load address") +} + +func (f *elfFile) dwarf() (*dwarf.Data, error) { + return f.elf.DWARF() +} diff --git a/vendor/github.com/mandiant/GoReSym/objfile/goobj.go b/vendor/github.com/mandiant/GoReSym/objfile/goobj.go new file mode 100644 index 00000000..4bf55b60 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/goobj.go @@ -0,0 +1,368 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Parsing of Go intermediate object files and archives. + +package objfile + +import ( + "errors" + "fmt" + "io" + "os" + + "github.com/mandiant/GoReSym/archive" + "github.com/mandiant/GoReSym/debug/dwarf" + "github.com/mandiant/GoReSym/debug/gosym" + "github.com/mandiant/GoReSym/goobj" + "github.com/mandiant/GoReSym/objabi" + "github.com/mandiant/GoReSym/sys" +) + +type goobjFile struct { + goobj *archive.GoObj + r *goobj.Reader + f *os.File + arch *sys.Arch +} + +func openGoFile(f *os.File) (*File, error) { + a, err := archive.Parse(f, false) + if err != nil { + return nil, err + } + entries := make([]*Entry, 0, len(a.Entries)) +L: + for _, e := range a.Entries { + switch e.Type { + case archive.EntryPkgDef, archive.EntrySentinelNonObj: + continue + case archive.EntryGoObj: + o := e.Obj + b := make([]byte, o.Size) + _, err := f.ReadAt(b, o.Offset) + if err != nil { + return nil, err + } + r := goobj.NewReaderFromBytes(b, false) + var arch *sys.Arch + for _, a := range sys.Archs { + if a.Name == e.Obj.Arch { + arch = a + break + } + } + entries = append(entries, &Entry{ + name: e.Name, + raw: &goobjFile{e.Obj, r, f, arch}, + }) + continue + case archive.EntryNativeObj: + nr := io.NewSectionReader(f, e.Offset, e.Size) + for _, try := range openers { + if raw, err := try(nr); err == nil { + entries = append(entries, &Entry{ + name: e.Name, + raw: raw, + }) + continue L + } + } + } + return nil, fmt.Errorf("open %s: unrecognized archive member %s", f.Name(), e.Name) + } + return &File{f, entries}, nil +} + +func goobjName(name string, ver int) string { + if ver == 0 { + return name + } + return fmt.Sprintf("%s<%d>", name, ver) +} + +type goobjReloc struct { + Off int32 + Size uint8 + Type objabi.RelocType + Add int64 + Sym string +} + +func (r goobjReloc) String(insnOffset uint64) string { + delta := int64(r.Off) - int64(insnOffset) + s := fmt.Sprintf("[%d:%d]%s", delta, delta+int64(r.Size), r.Type) + if r.Sym != "" { + if r.Add != 0 { + return fmt.Sprintf("%s:%s+%d", s, r.Sym, r.Add) + } + return fmt.Sprintf("%s:%s", s, r.Sym) + } + if r.Add != 0 { + return fmt.Sprintf("%s:%d", s, r.Add) + } + return s +} + +func (f *goobjFile) read_memory(VA uint64, size uint64) (data []byte, err error) { + return nil, errors.New("not implemented for go object file") +} + +func (f *goobjFile) symbols() ([]Sym, error) { + r := f.r + var syms []Sym + + // Name of referenced indexed symbols. + nrefName := r.NRefName() + refNames := make(map[goobj.SymRef]string, nrefName) + for i := 0; i < nrefName; i++ { + rn := r.RefName(i) + refNames[rn.Sym()] = rn.Name(r) + } + + abiToVer := func(abi uint16) int { + var ver int + if abi == goobj.SymABIstatic { + // Static symbol + ver = 1 + } + return ver + } + + resolveSymRef := func(s goobj.SymRef) string { + var i uint32 + switch p := s.PkgIdx; p { + case goobj.PkgIdxInvalid: + if s.SymIdx != 0 { + panic("bad sym ref") + } + return "" + case goobj.PkgIdxHashed64: + i = s.SymIdx + uint32(r.NSym()) + case goobj.PkgIdxHashed: + i = s.SymIdx + uint32(r.NSym()+r.NHashed64def()) + case goobj.PkgIdxNone: + i = s.SymIdx + uint32(r.NSym()+r.NHashed64def()+r.NHasheddef()) + case goobj.PkgIdxBuiltin: + name, abi := goobj.BuiltinName(int(s.SymIdx)) + return goobjName(name, abi) + case goobj.PkgIdxSelf: + i = s.SymIdx + default: + return refNames[s] + } + sym := r.Sym(i) + return goobjName(sym.Name(r), abiToVer(sym.ABI())) + } + + // Defined symbols + ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef()) + for i := uint32(0); i < ndef; i++ { + osym := r.Sym(i) + if osym.Name(r) == "" { + continue // not a real symbol + } + name := osym.Name(r) + ver := osym.ABI() + name = goobjName(name, abiToVer(ver)) + typ := objabi.SymKind(osym.Type()) + var code rune = '?' + switch typ { + case objabi.STEXT: + code = 'T' + case objabi.SRODATA: + code = 'R' + case objabi.SDATA: + code = 'D' + case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS: + code = 'B' + } + if ver >= goobj.SymABIstatic { + code += 'a' - 'A' + } + + sym := Sym{ + Name: name, + Addr: uint64(r.DataOff(i)), + Size: int64(osym.Siz()), + Code: code, + } + + relocs := r.Relocs(i) + sym.Relocs = make([]Reloc, len(relocs)) + for j := range relocs { + rel := &relocs[j] + sym.Relocs[j] = Reloc{ + Addr: uint64(r.DataOff(i)) + uint64(rel.Off()), + Size: uint64(rel.Siz()), + Stringer: goobjReloc{ + Off: rel.Off(), + Size: rel.Siz(), + Type: objabi.RelocType(rel.Type()), + Add: rel.Add(), + Sym: resolveSymRef(rel.Sym()), + }, + } + } + + syms = append(syms, sym) + } + + // Referenced symbols + n := ndef + uint32(r.NNonpkgref()) + for i := ndef; i < n; i++ { + osym := r.Sym(i) + sym := Sym{Name: osym.Name(r), Code: 'U'} + syms = append(syms, sym) + } + for i := 0; i < nrefName; i++ { + rn := r.RefName(i) + sym := Sym{Name: rn.Name(r), Code: 'U'} + syms = append(syms, sym) + } + + return syms, nil +} + +func (f *goobjFile) pcln_scan() (candidates []PclntabCandidate, err error) { + return nil, fmt.Errorf("pcln not available in go object file") +} + +func (f *goobjFile) pcln() (candidates []PclntabCandidate, err error) { + // Should never be called. We implement Liner below, callers + // should use that instead. + return nil, fmt.Errorf("pcln not available in go object file") +} + +func (f *goobjFile) moduledata_scan(pclntabVA uint64, is64bit bool, littleendian bool, ignorelist []uint64) (candidate *ModuleDataCandidate, err error) { + return nil, fmt.Errorf("moduledata not implemented at this time for go object file") +} + +// Find returns the file name, line, and function data for the given pc. +// Returns "",0,nil if unknown. +// This function implements the Liner interface in preference to pcln() above. +func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) { + r := f.r + if f.arch == nil { + return "", 0, nil + } + getSymData := func(s goobj.SymRef) []byte { + if s.PkgIdx != goobj.PkgIdxHashed { + // We don't need the data for non-hashed symbols, yet. + panic("not supported") + } + i := uint32(s.SymIdx + uint32(r.NSym()+r.NHashed64def())) + return r.BytesAt(r.DataOff(i), r.DataSize(i)) + } + + ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef()) + for i := uint32(0); i < ndef; i++ { + osym := r.Sym(i) + addr := uint64(r.DataOff(i)) + if pc < addr || pc >= addr+uint64(osym.Siz()) { + continue + } + isym := ^uint32(0) + auxs := r.Auxs(i) + for j := range auxs { + a := &auxs[j] + if a.Type() != goobj.AuxFuncInfo { + continue + } + if a.Sym().PkgIdx != goobj.PkgIdxSelf { + panic("funcinfo symbol not defined in current package") + } + isym = a.Sym().SymIdx + } + if isym == ^uint32(0) { + continue + } + b := r.BytesAt(r.DataOff(isym), r.DataSize(isym)) + var info *goobj.FuncInfo + pcline := getSymData(info.ReadPcline(b)) + line := int(pcValue(pcline, pc-addr, f.arch)) + pcfile := getSymData(info.ReadPcfile(b)) + fileID := pcValue(pcfile, pc-addr, f.arch) + fileName := r.File(int(fileID)) + // Note: we provide only the name in the Func structure. + // We could provide more if needed. + return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: osym.Name(r)}} + } + return "", 0, nil +} + +// pcValue looks up the given PC in a pc value table. target is the +// offset of the pc from the entry point. +func pcValue(tab []byte, target uint64, arch *sys.Arch) int32 { + val := int32(-1) + var pc uint64 + for step(&tab, &pc, &val, pc == 0, arch) { + if target < pc { + return val + } + } + return -1 +} + +// step advances to the next pc, value pair in the encoded table. +func step(p *[]byte, pc *uint64, val *int32, first bool, arch *sys.Arch) bool { + uvdelta := readvarint(p) + if uvdelta == 0 && !first { + return false + } + if uvdelta&1 != 0 { + uvdelta = ^(uvdelta >> 1) + } else { + uvdelta >>= 1 + } + vdelta := int32(uvdelta) + pcdelta := readvarint(p) * uint32(arch.MinLC) + *pc += uint64(pcdelta) + *val += vdelta + return true +} + +// readvarint reads, removes, and returns a varint from *p. +func readvarint(p *[]byte) uint32 { + var v, shift uint32 + s := *p + for shift = 0; ; shift += 7 { + b := s[0] + s = s[1:] + v |= (uint32(b) & 0x7F) << shift + if b&0x80 == 0 { + break + } + } + *p = s + return v +} + +// We treat the whole object file as the text section. +func (f *goobjFile) text() (textStart uint64, text []byte, err error) { + text = make([]byte, f.goobj.Size) + _, err = f.f.ReadAt(text, int64(f.goobj.Offset)) + return +} + +// We treat the whole object file as the data section. +func (f *goobjFile) rdata() (textStart uint64, text []byte, err error) { + text = make([]byte, f.goobj.Size) + _, err = f.f.ReadAt(text, int64(f.goobj.Offset)) + return +} + +func (f *goobjFile) goarch() string { + return f.goobj.Arch +} + +func (f *goobjFile) loadAddress() (uint64, error) { + return 0, fmt.Errorf("unknown load address") +} + +func (f *goobjFile) dwarf() (*dwarf.Data, error) { + return nil, errors.New("no DWARF data in go object file") +} diff --git a/vendor/github.com/mandiant/GoReSym/objfile/internals.go b/vendor/github.com/mandiant/GoReSym/objfile/internals.go new file mode 100644 index 00000000..a65692fd --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/internals.go @@ -0,0 +1,1366 @@ +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ +package objfile + +import ( + "bytes" + "encoding/binary" +) + +type size_t64 uint64 +type size_t32 uint32 +type pvoid64 uint64 +type pvoid32 uint32 + +// All types following this are the binary representation of internal objects. +// These are 'flat', i.e. one pointer level deep. Access to pointers and such +// require a memory read to retrieve the backing data. +// https://github.com/golang/go/blob/23adc139bf1c0c099dd075da076f5a1f3ac700d4/src/reflect/value.go#L2599 +type GoSlice64 struct { + Data pvoid64 + Len uint64 + Capacity uint64 +} + +func (slice *GoSlice64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, slice) +} + +type GoSlice32 struct { + Data pvoid32 + Len size_t32 + Capacity size_t32 +} + +func (slice *GoSlice32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, slice) +} + +// https://github.com/golang/go/blob/23adc139bf1c0c099dd075da076f5a1f3ac700d4/src/reflect/value.go#L2588 +type GoString64 struct { + Data pvoid64 + Len size_t64 +} + +type GoString32 struct { + Data pvoid32 + Len size_t32 +} + +// https://github.com/golang/go/blob/dbd3cf884986c88f5b3350709c0f51fa02330805/src/runtime/stack.go#L583 +type GoBitVector64 struct { + Bitnum int32 + Bytedata pvoid64 +} + +type GoBitVector32 struct { + Bitnum int32 + Bytedata pvoid32 +} + +// a function table entry in 'ftab' +type FuncTab12_116_64 struct { + Entryoffset pvoid64 // relative to runtime.text, ie. VA + Funcoffset pvoid64 // relative to ftab table start +} + +func (functab *FuncTab12_116_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, functab) +} + +type FuncTab12_116_32 struct { + Entryoffset pvoid32 // relative to runtime.text, ie. VA + Funcoffset pvoid32 // relative to ftab table start +} + +func (functab *FuncTab12_116_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, functab) +} + +type FuncTab118 struct { + Entryoffset uint32 // relative to runtime.text, ie. VA + Funcoffset uint32 // relative to ftab table start +} + +func (functab *FuncTab118) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, functab) +} + +// 1.2, runtime 1.5-1.6, 64bit +type ModuleData12_r15_r16_64 struct { + Pclntable GoSlice64 + Ftab GoSlice64 + Filetab GoSlice64 + Findfunctab pvoid64 + Minpc pvoid64 + Maxpc pvoid64 + + Text pvoid64 + Etext pvoid64 + Noptrdata pvoid64 + Enoptrdata pvoid64 + Data pvoid64 + Edata pvoid64 + Bss pvoid64 + Ebss pvoid64 + Noptrbss pvoid64 + Enoptrbss pvoid64 + End pvoid64 + Gcdata pvoid64 + Gcbss pvoid64 + + Typelinks GoSlice64 + + Modulename GoString64 + Modulehashes GoSlice64 + Gcdatamask GoBitVector64 + Gcbssmask GoBitVector64 + + Next pvoid64 +} + +func (moduledata *ModuleData12_r15_r16_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData12_r15_r16_32 struct { + Pclntable GoSlice32 + Ftab GoSlice32 + Filetab GoSlice32 + Findfunctab pvoid32 + Minpc pvoid32 + Maxpc pvoid32 + + Text pvoid32 + Etext pvoid32 + Noptrdata pvoid32 + Enoptrdata pvoid32 + Data pvoid32 + Edata pvoid32 + Bss pvoid32 + Ebss pvoid32 + Noptrbss pvoid32 + Enoptrbss pvoid32 + End pvoid32 + Gcdata pvoid32 + Gcbss pvoid32 + + Typelinks GoSlice32 + + Modulename GoString32 + Modulehashes GoSlice32 + Gcdatamask GoBitVector32 + Gcbssmask GoBitVector32 + + Next pvoid32 +} + +func (moduledata *ModuleData12_r15_r16_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData12_r17_64 struct { + Pclntable GoSlice64 + Ftab GoSlice64 + Filetab GoSlice64 + Findfunctab pvoid64 + Minpc pvoid64 + Maxpc pvoid64 + + Text pvoid64 + Etext pvoid64 + Noptrdata pvoid64 + Enoptrdata pvoid64 + Data pvoid64 + Edata pvoid64 + Bss pvoid64 + Ebss pvoid64 + Noptrbss pvoid64 + Enoptrbss pvoid64 + End pvoid64 + Gcdata pvoid64 + Gcbss pvoid64 + Types pvoid64 + Etypes pvoid64 + + Typelinks GoSlice64 + Itablinks GoSlice64 + + Modulename GoString64 + Modulehashes GoSlice64 + + Gcdatamask GoBitVector64 + Gcbssmask GoBitVector64 + + Typemap pvoid64 + Next pvoid64 +} + +func (moduledata *ModuleData12_r17_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData12_r17_32 struct { + Pclntable GoSlice32 + Ftab GoSlice32 + Filetab GoSlice32 + Findfunctab pvoid32 + Minpc pvoid32 + Maxpc pvoid32 + + Text pvoid32 + Etext pvoid32 + Noptrdata pvoid32 + Enoptrdata pvoid32 + Data pvoid32 + Edata pvoid32 + Bss pvoid32 + Ebss pvoid32 + Noptrbss pvoid32 + Enoptrbss pvoid32 + End pvoid32 + Gcdata pvoid32 + Gcbss pvoid32 + Types pvoid32 + Etypes pvoid32 + + Typelinks GoSlice32 + Itablinks GoSlice32 + + Modulename GoString32 + Modulehashes GoSlice32 + + Gcdatamask GoBitVector32 + Gcbssmask GoBitVector32 + + Typemap pvoid32 + Next pvoid32 +} + +func (moduledata *ModuleData12_r17_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData12_64 struct { + Pclntable GoSlice64 + Ftab GoSlice64 + FileTab GoSlice64 + Findfunctab pvoid64 + Minpc pvoid64 + Maxpc pvoid64 + Text pvoid64 + Etext pvoid64 + Noptrdata pvoid64 + Enoptrdata pvoid64 + Data pvoid64 + Edata pvoid64 + Bss pvoid64 + Ebss pvoid64 + Noptrbss pvoid64 + Enoptrbss pvoid64 + End pvoid64 + Gcdata pvoid64 + Gcbss pvoid64 + Types pvoid64 + Etypes pvoid64 + Textsectmap GoSlice64 + Typelinks GoSlice64 + Itablinks GoSlice64 + Ptab GoSlice64 + Pluginpath GoString64 + Pkghashes GoSlice64 + Modulename GoString64 + Modulehashes GoSlice64 + Hasmain bool + Gcdatamask GoBitVector64 + Gcbssmask GoBitVector64 + Typemap pvoid64 + Badload bool + Next pvoid64 +} + +func (moduledata *ModuleData12_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData12_32 struct { + Pclntable GoSlice32 + Ftab GoSlice32 + FileTab GoSlice32 + Findfunctab pvoid32 + Minpc pvoid32 + Maxpc pvoid32 + Text pvoid32 + Etext pvoid32 + Noptrdata pvoid32 + Enoptrdata pvoid32 + Data pvoid32 + Edata pvoid32 + Bss pvoid32 + Ebss pvoid32 + Noptrbss pvoid32 + Enoptrbss pvoid32 + End pvoid32 + Gcdata pvoid32 + Gcbss pvoid32 + Types pvoid32 + Etypes pvoid32 + Textsectmap GoSlice32 + Typelinks GoSlice32 + Itablinks GoSlice32 + Ptab GoSlice32 + Pluginpath GoString32 + Pkghashes GoSlice32 + Modulename GoString32 + Modulehashes GoSlice32 + Hasmain bool + Gcdatamask GoBitVector32 + Gcbssmask GoBitVector32 + Typemap pvoid32 + Badload bool + Next pvoid32 +} + +func (moduledata *ModuleData12_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData116_64 struct { + PcHeader pvoid64 + Funcnametab GoSlice64 + Cutab GoSlice64 + Filetab GoSlice64 + Pctab GoSlice64 + Pclntable GoSlice64 + Ftab GoSlice64 + Findfunctab pvoid64 + Minpc pvoid64 + Maxpc pvoid64 + Text pvoid64 + Etext pvoid64 + Noptrdata pvoid64 + Enoptrdata pvoid64 + Data pvoid64 + Edata pvoid64 + Bss pvoid64 + Ebss pvoid64 + Noptrbss pvoid64 + Enoptrbss pvoid64 + End pvoid64 + Gcdata pvoid64 + Gcbss pvoid64 + Types pvoid64 + Etypes pvoid64 + Textsectmap GoSlice64 + Typelinks GoSlice64 + Itablinks GoSlice64 + Ptab GoSlice64 + Pluginpath GoString64 + Pkghashes GoSlice64 + Modulename GoString64 + Modulehashes GoSlice64 + Hasmain bool + Gcdatamask GoBitVector64 + Gcbssmask GoBitVector64 + Typemap pvoid64 + Badload bool + Next pvoid64 +} + +func (moduledata *ModuleData116_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData116_32 struct { + PcHeader pvoid32 + Funcnametab GoSlice32 + Cutab GoSlice32 + Filetab GoSlice32 + Pctab GoSlice32 + Pclntable GoSlice32 + Ftab GoSlice32 + Findfunctab pvoid32 + Minpc pvoid32 + Maxpc pvoid32 + Text pvoid32 + Etext pvoid32 + Noptrdata pvoid32 + Enoptrdata pvoid32 + Data pvoid32 + Edata pvoid32 + Bss pvoid32 + Ebss pvoid32 + Noptrbss pvoid32 + Enoptrbss pvoid32 + End pvoid32 + Gcdata pvoid32 + Gcbss pvoid32 + Types pvoid32 + Etypes pvoid32 + Textsectmap GoSlice32 + Typelinks GoSlice32 + Itablinks GoSlice32 + Ptab GoSlice32 + Pluginpath GoString32 + Pkghashes GoSlice32 + Modulename GoString32 + Modulehashes GoSlice32 + Hasmain bool + Gcdatamask GoBitVector32 + Gcbssmask GoBitVector32 + Typemap pvoid32 + Badload bool + Next pvoid32 +} + +func (moduledata *ModuleData116_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData118_64 struct { + PcHeader pvoid64 + Funcnametab GoSlice64 + Cutab GoSlice64 + Filetab GoSlice64 + Pctab GoSlice64 + Pclntable GoSlice64 + Ftab GoSlice64 + Findfunctab pvoid64 + Minpc pvoid64 + Maxpc pvoid64 + Text pvoid64 + Etext pvoid64 + Noptrdata pvoid64 + Enoptrdata pvoid64 + Data pvoid64 + Edata pvoid64 + Bss pvoid64 + Ebss pvoid64 + Noptrbss pvoid64 + Enoptrbss pvoid64 + End pvoid64 + Gcdata pvoid64 + Gcbss pvoid64 + Types pvoid64 + Etypes pvoid64 + Rodata pvoid64 + Gofunc pvoid64 + Textsectmap GoSlice64 + Typelinks GoSlice64 + Itablinks GoSlice64 + Ptab GoSlice64 + Pluginpath GoString64 + Pkghashes GoSlice64 + Modulename GoString64 + Modulehashes GoSlice64 + Hasmain bool + Gcdatamask GoBitVector64 + Gcbssmask GoBitVector64 + Typemap pvoid64 + Badload bool + Next pvoid64 +} + +func (moduledata *ModuleData118_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData118_32 struct { + PcHeader pvoid32 + Funcnametab GoSlice32 + Cutab GoSlice32 + Filetab GoSlice32 + Pctab GoSlice32 + Pclntable GoSlice32 + Ftab GoSlice32 + Findfunctab pvoid32 + Minpc pvoid32 + Maxpc pvoid32 + Text pvoid32 + Etext pvoid32 + Noptrdata pvoid32 + Enoptrdata pvoid32 + Data pvoid32 + Edata pvoid32 + Bss pvoid32 + Ebss pvoid32 + Noptrbss pvoid32 + Enoptrbss pvoid32 + End pvoid32 + Gcdata pvoid32 + Gcbss pvoid32 + Types pvoid32 + Etypes pvoid32 + Rodata pvoid32 + Gofunc pvoid32 + Textsectmap GoSlice32 + Typelinks GoSlice32 + Itablinks GoSlice32 + Ptab GoSlice32 + Pluginpath GoString32 + Pkghashes GoSlice32 + Modulename GoString32 + Modulehashes GoSlice32 + Hasmain bool + Gcdatamask GoBitVector32 + Gcbssmask GoBitVector32 + Typemap pvoid32 + Badload bool + Next pvoid32 +} + +func (moduledata *ModuleData118_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData120_64 struct { + PcHeader pvoid64 + Funcnametab GoSlice64 + Cutab GoSlice64 + Filetab GoSlice64 + Pctab GoSlice64 + Pclntable GoSlice64 + Ftab GoSlice64 + Findfunctab pvoid64 + Minpc pvoid64 + Maxpc pvoid64 + Text pvoid64 + Etext pvoid64 + Noptrdata pvoid64 + Enoptrdata pvoid64 + Data pvoid64 + Edata pvoid64 + Bss pvoid64 + Ebss pvoid64 + Noptrbss pvoid64 + Enoptrbss pvoid64 + Covctrs pvoid64 + Ecovctrs pvoid64 + End pvoid64 + Gcdata pvoid64 + Gcbss pvoid64 + Types pvoid64 + Etypes pvoid64 + Rodata pvoid64 + Gofunc pvoid64 + Textsectmap GoSlice64 + Typelinks GoSlice64 + Itablinks GoSlice64 + Ptab GoSlice64 + Pluginpath GoString64 + Pkghashes GoSlice64 + Modulename GoString64 + Modulehashes GoSlice64 + Hasmain bool + Gcdatamask GoBitVector64 + Gcbssmask GoBitVector64 + Typemap pvoid64 + Badload bool + Next pvoid64 +} + +func (moduledata *ModuleData120_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData120_32 struct { + PcHeader pvoid32 + Funcnametab GoSlice32 + Cutab GoSlice32 + Filetab GoSlice32 + Pctab GoSlice32 + Pclntable GoSlice32 + Ftab GoSlice32 + Findfunctab pvoid32 + Minpc pvoid32 + Maxpc pvoid32 + Text pvoid32 + Etext pvoid32 + Noptrdata pvoid32 + Enoptrdata pvoid32 + Data pvoid32 + Edata pvoid32 + Bss pvoid32 + Ebss pvoid32 + Noptrbss pvoid32 + Enoptrbss pvoid32 + Covctrs pvoid32 + Ecovctrs pvoid32 + End pvoid32 + Gcdata pvoid32 + Gcbss pvoid32 + Types pvoid32 + Etypes pvoid32 + Rodata pvoid32 + Gofunc pvoid32 + Textsectmap GoSlice32 + Typelinks GoSlice32 + Itablinks GoSlice32 + Ptab GoSlice32 + Pluginpath GoString32 + Pkghashes GoSlice32 + Modulename GoString32 + Modulehashes GoSlice32 + Hasmain bool + Gcdatamask GoBitVector32 + Gcbssmask GoBitVector32 + Typemap pvoid32 + Badload bool + Next pvoid32 +} + +func (moduledata *ModuleData120_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData121_64 struct { + PcHeader pvoid64 + Funcnametab GoSlice64 + Cutab GoSlice64 + Filetab GoSlice64 + Pctab GoSlice64 + Pclntable GoSlice64 + Ftab GoSlice64 + Findfunctab pvoid64 + Minpc pvoid64 + Maxpc pvoid64 + Text pvoid64 + Etext pvoid64 + Noptrdata pvoid64 + Enoptrdata pvoid64 + Data pvoid64 + Edata pvoid64 + Bss pvoid64 + Ebss pvoid64 + Noptrbss pvoid64 + Enoptrbss pvoid64 + Covctrs pvoid64 + Ecovctrs pvoid64 + End pvoid64 + Gcdata pvoid64 + Gcbss pvoid64 + Types pvoid64 + Etypes pvoid64 + Rodata pvoid64 + Gofunc pvoid64 + Textsectmap GoSlice64 + Typelinks GoSlice64 + Itablinks GoSlice64 + Ptab GoSlice64 + Pluginpath GoString64 + Pkghashes GoSlice64 + InitTasks GoSlice64 + Modulename GoString64 + Modulehashes GoSlice64 + Hasmain bool + Gcdatamask GoBitVector64 + Gcbssmask GoBitVector64 + Typemap pvoid64 + Badload bool + Next pvoid64 +} + +func (moduledata *ModuleData121_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type ModuleData121_32 struct { + PcHeader pvoid32 + Funcnametab GoSlice32 + Cutab GoSlice32 + Filetab GoSlice32 + Pctab GoSlice32 + Pclntable GoSlice32 + Ftab GoSlice32 + Findfunctab pvoid32 + Minpc pvoid32 + Maxpc pvoid32 + Text pvoid32 + Etext pvoid32 + Noptrdata pvoid32 + Enoptrdata pvoid32 + Data pvoid32 + Edata pvoid32 + Bss pvoid32 + Ebss pvoid32 + Noptrbss pvoid32 + Enoptrbss pvoid32 + Covctrs pvoid32 + Ecovctrs pvoid32 + End pvoid32 + Gcdata pvoid32 + Gcbss pvoid32 + Types pvoid32 + Etypes pvoid32 + Rodata pvoid32 + Gofunc pvoid32 + Textsectmap GoSlice32 + Typelinks GoSlice32 + Itablinks GoSlice32 + Ptab GoSlice32 + Pluginpath GoString32 + Pkghashes GoSlice32 + InitTasks GoSlice32 + Modulename GoString32 + Modulehashes GoSlice32 + Hasmain bool + Gcdatamask GoBitVector32 + Gcbssmask GoBitVector32 + Typemap pvoid32 + Badload bool + Next pvoid32 +} + +func (moduledata *ModuleData121_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, moduledata) +} + +type Textsect_64 struct { + Vaddr pvoid64 // prelinked section vaddr + End pvoid64 // vaddr + section length + Baseaddr pvoid64 // relocated section address +} + +func (textsect *Textsect_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, textsect) +} + +type Textsect_32 struct { + Vaddr pvoid32 // prelinked section vaddr + End pvoid32 // vaddr + section length + Baseaddr pvoid32 // relocated section address +} + +func (textsect *Textsect_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, textsect) +} + +type IMethod struct { + Name nameOff + Typ typeOff +} + +func (imethod *IMethod) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, imethod) +} + +type Kind uint8 // mask & 0x1f + +const ( + Invalid Kind = iota + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + Array + Chan + Func + Interface + Map + Pointer + Slice + String + Struct + UnsafePointer +) + +func (k Kind) String() string { + switch k { + case Bool: + return "Bool" + case Int: + return "Int" + case Int8: + return "Int8" + case Int16: + return "Int16" + case Int32: + return "Int32" + case Int64: + return "Int64" + case Uint: + return "Uint" + case Uint8: + return "Uint8" + case Uint16: + return "Uint16" + case Uint32: + return "Uint32" + case Uint64: + return "Uint64" + case Uintptr: + return "Uintptr" + case Float32: + return "Float32" + case Complex64: + return "Complex64" + case Complex128: + return "Complex128" + case Array: + return "Array" + case Chan: + return "Chan" + case Func: + return "Func" + case Interface: + return "Interface" + case Map: + return "Map" + case Pointer: + return "Pointer" + case Slice: + return "Slice" + case String: + return "String" + case Struct: + return "Struct" + case UnsafePointer: + return "UnsafePointer" + } + return "Invalid" +} + +type ChanDir uint + +const ( + RecvOnly ChanDir = 1 << iota // <-chan + SendOnly // chan<- + SendRecv = RecvOnly | SendOnly // chan +) + +func (d ChanDir) String() string { + switch d { + case SendRecv: + return "Both" + case SendOnly: + return "Send" + case RecvOnly: + return "Recv" + } + return "Invalid" +} + +type tflag uint8 +type nameOff int32 +type typeOff int32 + +type Rtype15_64 struct { + Size size_t64 + Ptrdata size_t64 // number of bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + Unused uint8 // extra type information flags + Align uint8 // alignment of variable with this type + FieldAlign uint8 // alignment of struct field with this type + Kind Kind // enumeration for C + Alg pvoid64 // algorithm table + Gcdata pvoid64 // garbage collection data + Str pvoid64 // string form + UncommonType pvoid64 + PtrToThis pvoid64 // type for pointer to this type, may be zero + Zero pvoid64 +} + +func (rtype *Rtype15_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, rtype) +} + +type Rtype15_32 struct { + Size size_t32 + Ptrdata size_t32 // number of bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + Unused uint8 // extra type information flags + Align uint8 // alignment of variable with this type + FieldAlign uint8 // alignment of struct field with this type + Kind Kind // enumeration for C + Alg pvoid32 // algorithm table + Gcdata pvoid32 // garbage collection data + Str pvoid32 // string form + UncommonType pvoid32 + PtrToThis pvoid32 // type for pointer to this type, may be zero + Zero pvoid32 +} + +func (rtype *Rtype15_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, rtype) +} + +type Rtype16_64 struct { + Size size_t64 + Ptrdata size_t64 // number of bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + Unused uint8 // extra type information flags + Align uint8 // alignment of variable with this type + FieldAlign uint8 // alignment of struct field with this type + Kind Kind // enumeration for C + Alg pvoid64 // algorithm table + Gcdata pvoid64 // garbage collection data + Str pvoid64 // string form + UncommonType pvoid64 + PtrToThis pvoid64 // type for pointer to this type, may be zero +} + +func (rtype *Rtype16_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, rtype) +} + +type Rtype16_32 struct { + Size size_t32 + Ptrdata size_t32 // number of bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + Unused uint8 // extra type information flags + Align uint8 // alignment of variable with this type + FieldAlign uint8 // alignment of struct field with this type + Kind Kind // enumeration for C + Alg pvoid32 // algorithm table + Gcdata pvoid32 // garbage collection data + Str pvoid32 // string form + UncommonType pvoid32 + PtrToThis pvoid32 // type for pointer to this type, may be zero +} + +func (rtype *Rtype16_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, rtype) +} + +type Rtype17_18_19_110_111_112_113_64 struct { + Size size_t64 + Ptrdata size_t64 // number of bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + Tflag tflag // extra type information flags + Align uint8 // alignment of variable with this type + FieldAlign uint8 // alignment of struct field with this type + Kind Kind // enumeration for C + Alg pvoid64 // algorithm table + Gcdata pvoid64 // garbage collection data + Str nameOff // string form + PtrToThis typeOff // type for pointer to this type, may be zero +} + +func (rtype *Rtype17_18_19_110_111_112_113_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, rtype) +} + +type Rtype17_18_19_110_111_112_113_32 struct { + Size size_t32 + Ptrdata size_t32 // number of bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + Tflag tflag // extra type information flags + Align uint8 // alignment of variable with this type + FieldAlign uint8 // alignment of struct field with this type + Kind Kind // enumeration for C + Alg pvoid32 // algorithm table + Gcdata pvoid32 // garbage collection data + Str nameOff // string form + PtrToThis typeOff // type for pointer to this type, may be zero +} + +func (rtype *Rtype17_18_19_110_111_112_113_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, rtype) +} + +type Rtype114_115_116_117_118_64 struct { + Size size_t64 + Ptrdata size_t64 // number of bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + Tflag tflag // extra type information flags + Align uint8 // alignment of variable with this type + FieldAlign uint8 // alignment of struct field with this type + Kind Kind + Equal pvoid64 + Gcdata pvoid64 // garbage collection data + Str nameOff // string form + PtrToThis typeOff // type for pointer to this type, may be zero +} + +func (rtype *Rtype114_115_116_117_118_64) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, rtype) +} + +type Rtype114_115_116_117_118_32 struct { + Size size_t32 + Ptrdata size_t32 // number of bytes in the type that can contain pointers + Hash uint32 // hash of type; avoids computation in hash tables + Tflag tflag // extra type information flags + Align uint8 // alignment of variable with this type + FieldAlign uint8 // alignment of struct field with this type + Kind Kind + Equal pvoid32 + Gcdata pvoid32 // garbage collection data + Str nameOff // string form + PtrToThis typeOff // type for pointer to this type, may be zero +} + +func (rtype *Rtype114_115_116_117_118_32) parse(rawData []byte, littleEndian bool) error { + srcBytes := bytes.NewBuffer(rawData) + + var byteOrder binary.ByteOrder + if littleEndian { + byteOrder = binary.LittleEndian + } else { + byteOrder = binary.BigEndian + } + + return binary.Read(srcBytes, byteOrder, rtype) +} + +// This is a general structure that just holds the fields I care about +// this lets us return a single type, even though rtypes change between go version +type Type struct { + VA uint64 + Str string + CStr string + Kind string + Reconstructed string `json:",omitempty"` // for Some types we can reconstruct the original definition back to Go code + CReconstructed string `json:",omitempty"` // for Some types we can reconstruct the original definition back to C code + + // rtypes change between runtime versions. Depending on the 'Kind' additional data follows the 'base' rtype. + // We store the size so that this base type can be skipped past, and the additional data read directly in a version independant way. + baseSize uint16 + kindEnum Kind + flags tflag +} + +// This is a general structure that just holds the fields I care about +// this lets us return a single type, even though moduledata changes between go version +type ModuleData struct { + VA uint64 + TextVA uint64 // adjusted (ex: CGO) .text base that pclntab offsets are relative to + Types uint64 // points to type information + ETypes uint64 // points to end of type information + Typelinks GoSlice64 // points to metadata about offsets into types for structures and other types + ITablinks GoSlice64 // points to metadata about offsets into types for interfaces + + // Some versions of go with 1.2 moduledata use a slice instead of the types + offset typelinks list + LegacyTypes GoSlice64 +} + +const ( + // tflagUncommon means that there is a pointer, *uncommonType, + // just beyond the outer type structure. + // + // For example, if t.Kind() == Struct and t.tflag&tflagUncommon != 0, + // then t has uncommonType data and it can be accessed as: + // + // type tUncommon struct { + // structType + // u uncommonType + // } + // u := &(*tUncommon)(unsafe.Pointer(t)).u + tflagUncommon tflag = 1 << 0 + + // tflagExtraStar means the name in the str field has an + // extraneous '*' prefix. This is because for most types T in + // a program, the type *T also exists and reusing the str data + // saves binary size. + tflagExtraStar tflag = 1 << 1 + + // tflagNamed means the type has a name. + tflagNamed tflag = 1 << 2 + + // tflagRegularMemory means that equal and hash functions can treat + // this type as a single region of t.size bytes. + tflagRegularMemory tflag = 1 << 3 +) + +// https://github.com/golang/go/blob/9ecb853cf2252f3cd9ed2e7b3401d17df2d1ab06/src/runtime/symtab.go#L662 +func textAddr64(off32 uint64, text uint64, textsectmap []Textsect_64) uint64 { + off := uint64(off32) + res := uint64(text) + off + if len(textsectmap) > 1 { + for i, sect := range textsectmap { + // For the last section, include the end address (etext), as it is included in the functab. + if off >= uint64(sect.Vaddr) && off < uint64(sect.End) || (i == len(textsectmap)-1 && off == uint64(sect.End)) { + res = uint64(sect.Baseaddr) + off - uint64(sect.Vaddr) + break + } + } + } + return uint64(res) +} + +func textAddr32(off32 uint64, text uint64, textsectmap []Textsect_32) uint64 { + off := uint64(off32) + res := uint64(text) + off + if len(textsectmap) > 1 { + for i, sect := range textsectmap { + // For the last section, include the end address (etext), as it is included in the functab. + if off >= uint64(sect.Vaddr) && off < uint64(sect.End) || (i == len(textsectmap)-1 && off == uint64(sect.End)) { + res = uint64(sect.Baseaddr) + off - uint64(sect.Vaddr) + break + } + } + } + return uint64(res) +} diff --git a/vendor/github.com/mandiant/GoReSym/objfile/macho.go b/vendor/github.com/mandiant/GoReSym/objfile/macho.go new file mode 100644 index 00000000..2f81e0b5 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/macho.go @@ -0,0 +1,425 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Parsing of Mach-O executables (OS X). + +package objfile + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "sort" + + "github.com/mandiant/GoReSym/debug/dwarf" + "github.com/mandiant/GoReSym/debug/macho" +) + +const stabTypeMask = 0xe0 + +type machoFile struct { + macho *macho.File +} + +func openMacho(r io.ReaderAt) (rawFile, error) { + f, err := macho.NewFile(r) + if err != nil { + return nil, err + } + return &machoFile{f}, nil +} + +func (f *machoFile) read_memory(VA uint64, size uint64) (data []byte, err error) { + for _, load := range f.macho.Loads { + seg, ok := load.(*macho.Segment) + if !ok { + continue + } + if seg.Addr <= VA && VA <= seg.Addr+seg.Filesz-1 { + if seg.Name == "__PAGEZERO" { + continue + } + n := seg.Addr + seg.Filesz - VA + if n > size { + n = size + } + data := make([]byte, n) + _, err := seg.ReadAt(data, int64(VA-seg.Addr)) + if err != nil { + return nil, err + } + return data, nil + } + } + return nil, fmt.Errorf("Failed to read memory") +} + +func (f *machoFile) symbols() ([]Sym, error) { + if f.macho.Symtab == nil { + return nil, nil + } + + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + for _, s := range f.macho.Symtab.Syms { + // Skip stab debug info. + if s.Type&stabTypeMask == 0 { + addrs = append(addrs, s.Value) + } + } + sort.Sort(uint64s(addrs)) + + var syms []Sym + for _, s := range f.macho.Symtab.Syms { + if s.Type&stabTypeMask != 0 { + // Skip stab debug info. + continue + } + sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} + i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) + if i < len(addrs) { + sym.Size = int64(addrs[i] - s.Value) + } + if s.Sect == 0 { + sym.Code = 'U' + } else if int(s.Sect) <= len(f.macho.Sections) { + sect := f.macho.Sections[s.Sect-1] + switch sect.Seg { + case "__TEXT", "__DATA_CONST": + sym.Code = 'R' + case "__DATA": + sym.Code = 'D' + } + switch sect.Seg + " " + sect.Name { + case "__TEXT __text": + sym.Code = 'T' + case "__DATA __bss", "__DATA __noptrbss": + sym.Code = 'B' + } + } + syms = append(syms, sym) + } + + return syms, nil +} + +func (f *machoFile) pcln_scan() (candidates []PclntabCandidate, err error) { + // 1) Locate pclntab via symbols (standard way) + foundpcln := false + var pclntab []byte + if sect := f.macho.Section("__gopclntab"); sect != nil { + if pclntab, err = sect.Data(); err == nil { + foundpcln = true + } + } + + pclntab_sigs_le := [][]byte{ + []byte("\xF1\xFF\xFF\xFF\x00\x00"), // little endian + []byte("\xF0\xFF\xFF\xFF\x00\x00"), + []byte("\xFA\xFF\xFF\xFF\x00\x00"), + []byte("\xFB\xFF\xFF\xFF\x00\x00"), + } + + pclntab_sigs_be := [][]byte{ + []byte("\xFF\xFF\xFF\xF1\x00\x00"), // big endian + []byte("\xFF\xFF\xFF\xF0\x00\x00"), + []byte("\xFF\xFF\xFF\xFA\x00\x00"), + []byte("\xFF\xFF\xFF\xFB\x00\x00"), + } + + // 2) if not found, byte scan for it + pclntab_sigs := append(pclntab_sigs_le, pclntab_sigs_be...) + + // candidate array for method 4 of scanning + var stompedmagic_candidates []StompMagicCandidate = make([]StompMagicCandidate, 0) + + // 2) if not found, byte scan for it + for _, sec := range f.macho.Sections { + // malware can split the pclntab across multiple sections, re-merge + data := f.macho.DataAfterSection(sec) + + if !foundpcln { + matches := findAllOccurrences(data, pclntab_sigs) + for _, pclntab_idx := range matches { + if pclntab_idx != -1 && pclntab_idx < int(sec.Size) { + pclntab = data[pclntab_idx:] + + var candidate PclntabCandidate + candidate.Pclntab = pclntab + + candidate.SecStart = uint64(sec.Addr) + candidate.PclntabVA = candidate.SecStart + uint64(pclntab_idx) + + candidates = append(candidates, candidate) + // we must scan all signature for all sections. DO NOT BREAK + } + } + } else { + // 3) if we found it earlier, figure out which section base to return (might be wrong for packed things) + pclntab_idx := bytes.Index(data, pclntab) + if pclntab_idx != -1 { + var candidate PclntabCandidate + candidate.Pclntab = pclntab + + candidate.SecStart = uint64(sec.Addr) + candidate.PclntabVA = candidate.SecStart + uint64(pclntab_idx) + + candidates = append(candidates, candidate) + } + } + + // TODO this scan needs to occur in both big and little endian mode + // 4) Always try this other way! Sometimes the pclntab magic is stomped as well so our byte OR symbol location fail. Byte scan for the moduledata, use that to find the pclntab instead, fix up magic with all combinations. + // See the obfuscator 'garble' for an example of randomizing the pclntab magic + sigResults := findModuleInitPCHeader(data, sec.Addr) + for _, sigResult := range sigResults { + // example: off_69D0C0 is the moduleData we found via our scan, the first ptr unk_5DF6E0, is the pclntab! + // 0x000000000069D0C0 E0 F6 5D 00 00 00 00 00 off_69D0C0 dq offset unk_5DF6E0 ; DATA XREF: runtime_SetFinalizer+119↑o + // 0x000000000069D0C0 ; runtime_scanstack+40B↑o ... + // 0x000000000069D0C8 40 F7 5D 00 00 00 00 00 dq offset aInternalCpuIni ; "internal/cpu.Initialize" + // 0x000000000069D0D0 F0 db 0F0h + // 0x000000000069D0D1 BB db 0BBh + + // we don't know the endianess or arch, so we submit all combinations as candidates and sort them out later + // example: reads out ptr unk_5DF6E0 + pclntabVARaw64, err := f.read_memory(sigResult.moduleDataVA, 8) // assume 64bit + if err == nil { + stompedMagicCandidateLE := StompMagicCandidate{ + binary.LittleEndian.Uint64(pclntabVARaw64), + sigResult.moduleDataVA, + true, + } + stompedMagicCandidateBE := StompMagicCandidate{ + binary.BigEndian.Uint64(pclntabVARaw64), + sigResult.moduleDataVA, + false, + } + stompedmagic_candidates = append(stompedmagic_candidates, stompedMagicCandidateLE, stompedMagicCandidateBE) + } + + pclntabVARaw32, err := f.read_memory(sigResult.moduleDataVA, 4) // assume 32bit + if err == nil { + stompedMagicCandidateLE := StompMagicCandidate{ + uint64(binary.LittleEndian.Uint32(pclntabVARaw32)), + sigResult.moduleDataVA, + true, + } + stompedMagicCandidateBE := StompMagicCandidate{ + uint64(binary.BigEndian.Uint32(pclntabVARaw32)), + sigResult.moduleDataVA, + false, + } + stompedmagic_candidates = append(stompedmagic_candidates, stompedMagicCandidateLE, stompedMagicCandidateBE) + } + } + } + + // even if we found the pclntab without signature scanning it may have a stomped magic. That would break parsing later! So, let's submit new candidates + // with all the possible magics to get at least one that hopefully parses correctly. + patched_magic_candidates := make([]PclntabCandidate, 0) + for _, candidate := range candidates { + has_some_valid_magic := false + for _, magic := range append(pclntab_sigs_le, pclntab_sigs_be...) { + if bytes.Equal(candidate.Pclntab, magic) { + has_some_valid_magic = true + break + } + } + + if !has_some_valid_magic { + for _, magic := range append(pclntab_sigs_le, pclntab_sigs_be...) { + pclntab_copy := make([]byte, len(candidate.Pclntab)) + copy(pclntab_copy, candidate.Pclntab) + copy(pclntab_copy, magic) + + new_candidate := candidate + new_candidate.Pclntab = pclntab_copy + patched_magic_candidates = append(patched_magic_candidates, new_candidate) + candidate.Pclntab = pclntab_copy + } + } + } + + if len(patched_magic_candidates) > 0 { + candidates = patched_magic_candidates + } + + if len(stompedmagic_candidates) != 0 { + for _, sec := range f.macho.Sections { + // malware can split the pclntab across multiple sections, re-merge + data := f.macho.DataAfterSection(sec) + for _, stompedMagicCandidate := range stompedmagic_candidates { + pclntab_va_candidate := stompedMagicCandidate.PclntabVa + + if pclntab_va_candidate >= sec.Addr && pclntab_va_candidate < (sec.Addr+sec.Size) && pclntab_va_candidate < (sec.Addr+uint64(len(data))) { + sec_offset := pclntab_va_candidate - sec.Addr + pclntab = data[sec_offset:] + + if stompedMagicCandidate.LittleEndian { + for _, magicLE := range pclntab_sigs_le { + pclntab_copy := make([]byte, len(pclntab)) + copy(pclntab_copy, pclntab) + copy(pclntab_copy, magicLE) + + var candidate PclntabCandidate + candidate.StompMagicCandidateMeta = &stompedMagicCandidate + candidate.Pclntab = pclntab_copy + candidate.SecStart = uint64(sec.Addr) + candidate.PclntabVA = pclntab_va_candidate + + candidates = append(candidates, candidate) + } + } else { + for _, magicBE := range pclntab_sigs_be { + pclntab_copy := make([]byte, len(pclntab)) + copy(pclntab_copy, pclntab) + copy(pclntab_copy, magicBE) + + var candidate PclntabCandidate + candidate.StompMagicCandidateMeta = &stompedMagicCandidate + candidate.Pclntab = pclntab_copy + candidate.SecStart = uint64(sec.Addr) + candidate.PclntabVA = pclntab_va_candidate + + candidates = append(candidates, candidate) + } + } + } + } + } + } + + return candidates, nil +} + +func (f *machoFile) pcln() (candidates []PclntabCandidate, err error) { + candidates, err = f.pcln_scan() + if err != nil { + return nil, err + } + + // 4) symtab is completely optional, but try to find it + var symtab []byte + if sect := f.macho.Section("__gosymtab"); sect != nil { + symtab, err = sect.Data() + } + + if err == nil { + for _, c := range candidates { + c.Symtab = symtab + } + } + + return candidates, nil +} + +func (f *machoFile) moduledata_scan(pclntabVA uint64, is64bit bool, littleendian bool, ignorelist []uint64) (candidate *ModuleDataCandidate, err error) { + found := false + + var secStart uint64 + var moduledata []uint8 + var moduledataVA uint64 +scan: + for _, sec := range f.macho.Sections { + // malware can split the pclntab across multiple sections, re-merge + data := f.macho.DataAfterSection(sec) + // fall back to scanning for structure using address of pclntab, which is first value in struc + var pclntabVA_bytes []byte + if is64bit { + pclntabVA_bytes = make([]byte, 8) + if littleendian { + binary.LittleEndian.PutUint64(pclntabVA_bytes, pclntabVA) + } else { + binary.BigEndian.PutUint64(pclntabVA_bytes, pclntabVA) + } + } else { + pclntabVA_bytes = make([]byte, 4) + if littleendian { + binary.LittleEndian.PutUint32(pclntabVA_bytes, uint32(pclntabVA)) + } else { + binary.BigEndian.PutUint32(pclntabVA_bytes, uint32(pclntabVA)) + } + } + + moduledata_idx := bytes.Index(data, pclntabVA_bytes) + if moduledata_idx != -1 && moduledata_idx < int(sec.Size) { + moduledata = data[moduledata_idx:] + moduledataVA = sec.Addr + uint64(moduledata_idx) + secStart = sec.Addr + + // optionally consult ignore list, to skip past previous (bad) scan results + for _, ignore := range ignorelist { + if ignore == moduledataVA { + continue scan + } + } + + found = true + break + } + } + + if !found { + return nil, fmt.Errorf("moduledata containing section could not be located") + } + + return &ModuleDataCandidate{SecStart: secStart, ModuledataVA: moduledataVA, Moduledata: moduledata}, nil +} + +func (f *machoFile) text() (textStart uint64, text []byte, err error) { + sect := f.macho.Section("__text") + if sect == nil { + return 0, nil, fmt.Errorf("text section not found") + } + textStart = sect.Addr + text, err = sect.Data() + return +} + +func (f *machoFile) rdata() (textStart uint64, text []byte, err error) { + sect := f.macho.Section("__DATA") + if sect == nil { + return 0, nil, fmt.Errorf("data section not found") + } + textStart = sect.Addr + text, err = sect.Data() + return +} + +func (f *machoFile) goarch() string { + switch f.macho.Cpu { + case macho.Cpu386: + return "386" + case macho.CpuAmd64: + return "amd64" + case macho.CpuArm: + return "arm" + case macho.CpuArm64: + return "arm64" + case macho.CpuPpc64: + return "ppc64" + } + return "" +} + +type uint64s []uint64 + +func (x uint64s) Len() int { return len(x) } +func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x uint64s) Less(i, j int) bool { return x[i] < x[j] } + +func (f *machoFile) loadAddress() (uint64, error) { + if seg := f.macho.Segment("__TEXT"); seg != nil { + return seg.Addr, nil + } + return 0, fmt.Errorf("unknown load address") +} + +func (f *machoFile) dwarf() (*dwarf.Data, error) { + return f.macho.DWARF() +} diff --git a/vendor/github.com/mandiant/GoReSym/objfile/objfile.go b/vendor/github.com/mandiant/GoReSym/objfile/objfile.go new file mode 100644 index 00000000..dfb5ba18 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/objfile.go @@ -0,0 +1,2101 @@ +// Copyright 2014 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Package objfile implements portable access to OS-specific executable files. +package objfile + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "math/rand" + "os" + "sort" + "strconv" + "strings" + "unsafe" + + "github.com/elliotchance/orderedmap" + "github.com/mandiant/GoReSym/debug/dwarf" + "github.com/mandiant/GoReSym/debug/gosym" +) + +type StompMagicCandidate struct { + PclntabVa uint64 + SuspectedModuleDataVa uint64 + LittleEndian bool +} + +type PclntabCandidate struct { + SecStart uint64 + PclntabVA uint64 + StompMagicCandidateMeta *StompMagicCandidate // some search modes might optimistically try to find moduledata or guess endianess, these hints must match the found moduleData VA later to be considered good candidate + Pclntab []byte + Symtab []byte // optional + ParsedPclntab *gosym.Table +} + +type ModuleDataCandidate struct { + SecStart uint64 + ModuledataVA uint64 + Moduledata []byte +} + +type rawFile interface { + symbols() (syms []Sym, err error) + pcln() (candidates []PclntabCandidate, err error) + pcln_scan() (candidates []PclntabCandidate, err error) + moduledata_scan(pclntabVA uint64, is64bit bool, littleendian bool, ignorelist []uint64) (candidate *ModuleDataCandidate, err error) + read_memory(VA uint64, size uint64) (data []byte, err error) + text() (textStart uint64, text []byte, err error) + goarch() string + loadAddress() (uint64, error) + dwarf() (*dwarf.Data, error) +} + +// A File is an opened executable file. +type File struct { + r *os.File + entries []*Entry +} + +type Entry struct { + name string + raw rawFile + pclnCandidates []PclntabCandidate +} + +// A Sym is a symbol defined in an executable file. +type Sym struct { + Name string // symbol name + Addr uint64 // virtual address of symbol + Size int64 // size in bytes + Code rune // nm code (T for text, D for data, and so on) + Type string // XXX? + Relocs []Reloc // in increasing Addr order +} + +type Reloc struct { + Addr uint64 // Address of first byte that reloc applies to. + Size uint64 // Number of bytes + Stringer RelocStringer +} + +type RelocStringer interface { + // insnOffset is the offset of the instruction containing the relocation + // from the start of the symbol containing the relocation. + String(insnOffset uint64) string +} + +var openers = []func(io.ReaderAt) (rawFile, error){ + openElf, + openMacho, + openPE, +} + +// Open opens the named file. +// The caller must call f.Close when the file is no longer needed. +func Open(name string) (*File, error) { + r, err := os.Open(name) + if err != nil { + return nil, err + } + if f, err := openGoFile(r); err == nil { + return f, nil + } + for _, try := range openers { + if raw, err := try(r); err == nil { + return &File{r, []*Entry{{raw: raw}}}, nil + } + } + r.Close() + return nil, fmt.Errorf("open %s: unrecognized object file or bad filepath", name) +} + +func (f *File) Close() error { + return f.r.Close() +} + +func (f *File) Entries() []*Entry { + return f.entries +} + +func (f *File) Symbols() ([]Sym, error) { + return f.entries[0].Symbols() +} + +// previously : func (f *File) PCLineTable() (Liner, error) { +func (f *File) PCLineTable(versionOverride string, knownPclntabVA uint64, knownGoTextBase uint64) ([]PclntabCandidate, error) { + return f.entries[0].PCLineTable(versionOverride, knownPclntabVA, knownGoTextBase) +} + +func (f *File) ModuleDataTable(pclntabVA uint64, runtimeVersion string, version string, is64bit bool, littleendian bool) (secStart uint64, moduleData *ModuleData, err error) { + return f.entries[0].ModuleDataTable(pclntabVA, runtimeVersion, version, is64bit, littleendian) +} + +func (f *File) ParseType(runtimeVersion string, moduleData *ModuleData, typeAddress uint64, is64bit bool, littleendian bool) (types []Type, err error) { + return f.entries[0].ParseType(runtimeVersion, moduleData, typeAddress, is64bit, littleendian) +} + +func (f *File) ParseTypeLinks(runtimeVersion string, moduleData *ModuleData, is64bit bool, littleendian bool) (types []Type, err error) { + return f.entries[0].ParseTypeLinks(runtimeVersion, moduleData, is64bit, littleendian) +} + +func (f *File) ParseITabLinks(runtimeVersion string, moduleData *ModuleData, is64bit bool, littleendian bool) (types []Type, err error) { + return f.entries[0].ParseITabLinks(runtimeVersion, moduleData, is64bit, littleendian) +} + +func (f *File) Text() (uint64, []byte, error) { + return f.entries[0].Text() +} + +func (f *File) GOARCH() string { + return f.entries[0].GOARCH() +} + +func (f *File) LoadAddress() (uint64, error) { + return f.entries[0].LoadAddress() +} + +func (f *File) DWARF() (*dwarf.Data, error) { + return f.entries[0].DWARF() +} + +func (f *File) Disasm() (*Disasm, error) { + return f.entries[0].Disasm() +} + +func (e *Entry) Name() string { + return e.name +} + +func (e *Entry) Symbols() ([]Sym, error) { + syms, err := e.raw.symbols() + if err != nil { + return nil, err + } + sort.Sort(byAddr(syms)) + return syms, nil +} + +type byAddr []Sym + +func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } +func (x byAddr) Len() int { return len(x) } +func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func findAllOccurrences(data []byte, searches [][]byte) []int { + var results []int + + for _, search := range searches { + var offset = 0 + + for { + var index = bytes.Index(data[offset:], search) + if index == -1 { + break + } + + offset += index + results = append(results, offset) + + offset += 1 + } + } + + return results +} + +// previously: func (e *Entry) PCLineTable() (Liner, error) +func (e *Entry) PCLineTable(versionOverride string, knownPclntabVA uint64, knownGoTextBase uint64) ([]PclntabCandidate, error) { + // If the raw file implements Liner directly, use that. + // Currently, only Go intermediate objects and archives (goobj) use this path. + + // DISABLED, We want to gopclntab table 95% of the time + // if pcln, ok := e.raw.(Liner); ok { + // return pcln, nil + // } + + // Otherwise, read the pcln tables and build a Liner out of that. + // https://github.com/golang/go/blob/89f687d6dbc11613f715d1644b4983905293dd33/src/debug/gosym/pclntab.go#L169 + // https://github.com/golang/go/issues/42954 + if e.pclnCandidates == nil { + candidates, err := e.raw.pcln() + if err != nil { + return nil, err + } + e.pclnCandidates = candidates + } + candidates := e.pclnCandidates + + var finalCandidates []PclntabCandidate + var atLeastOneGood bool = false + for _, candidate := range candidates { + /* See https://github.com/mandiant/GoReSym/pull/11 + Locating the .text base is not safe by name due to packers which mangle names. We also have to consider CGO + which appears to update the base with an 'adjusted' one to add some shim code. So, PCLineTable + get called first with the candidate.SecStart just to find symbols, just so we can find the moduledata. + Then, we invoke it again with a 'known' text base, which is found by reading data held in the moduledata. + That is, we do all this parsing twice, on purpose, to be resiliant, we have better info on round 2. + */ + if knownGoTextBase != 0 { + candidate.SecStart = knownGoTextBase + } + + // using this VA a moduledata was successfully found, this time around we can avoid re-parsing known bad pclntab candidates + if knownPclntabVA != 0 && candidate.PclntabVA != knownPclntabVA { + continue + } + + parsedTable, err := gosym.NewTable(candidate.Symtab, gosym.NewLineTable(candidate.Pclntab, candidate.SecStart), versionOverride) + if err != nil || parsedTable.Go12line == nil { + continue + } + + // the first good one happens to be correct more often than the last + candidate.ParsedPclntab = parsedTable + finalCandidates = append(finalCandidates, candidate) + atLeastOneGood = true + } + + if atLeastOneGood { + return finalCandidates, nil + } + + return finalCandidates, fmt.Errorf("failed to locate pclntab") +} + +func (e *Entry) ModuleDataTable(pclntabVA uint64, runtimeVersion string, version string, is64bit bool, littleendian bool) (secStart uint64, moduleData *ModuleData, err error) { + moduleData = &ModuleData{} + // Major version only, 1.15.5 -> 1.15 + parts := strings.Split(runtimeVersion, ".") + if len(parts) >= 2 { + runtimeVersion = parts[0] + "." + parts[1] + } + + var moduleDataCandidate *ModuleDataCandidate = nil + + const maxattempts = 5 + var ignorelist []uint64 + for i := 0; i < maxattempts; i++ { + // we're trying again, ignore the previous candidate + if moduleDataCandidate != nil { + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + } + + moduleDataCandidate, err = e.raw.moduledata_scan(pclntabVA, is64bit, littleendian, ignorelist) + if err != nil { + continue + } + + // there's really only 3 main versions for these internal runtime changes 1.2 (<= 1.15), 1.16 (<= 1.17), 1.18 (>= 1.18) + // this routine needs the pclntab version, NOT the go runtime version (ex: go 1.15 generates 1.2 style tables) + switch version { + case "1.22": + fallthrough + case "1.21": + if is64bit { + var module ModuleData121_64 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab118 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // prevent loop on invalid modules with bogus length + if module.Textsectmap.Len > 0x100 { + continue + } + + var textsectmap []Textsect_64 + for i := 0; i < int(module.Textsectmap.Len); i++ { + var textsect Textsect_64 + var sectSize = uint64(unsafe.Sizeof(textsect)) + textsec_raw, err := e.raw.read_memory(uint64(module.Textsectmap.Data)+uint64(i)*sectSize, sectSize) + if err != nil { + continue + } + + err = textsect.parse(textsec_raw, littleendian) + if err != nil { + continue + } + textsectmap = append(textsectmap, textsect) + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + // https://github.com/golang/go/blob/9ecb853cf2252f3cd9ed2e7b3401d17df2d1ab06/src/runtime/symtab.go#L630-L632 + if textAddr64(uint64(firstFunc.Entryoffset), uint64(module.Text), textsectmap) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks = module.Typelinks + moduleData.ITablinks = module.Itablinks + return secStart, moduleData, err + } else { + var module ModuleData121_32 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab118 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // prevent loop on invalid modules with bogus length + if module.Textsectmap.Len > 0x100 { + continue + } + + var textsectmap []Textsect_32 + for i := 0; i < int(module.Textsectmap.Len); i++ { + var textsect Textsect_32 + var sectSize = uint64(unsafe.Sizeof(textsect)) + textsec_raw, err := e.raw.read_memory(uint64(module.Textsectmap.Data)+uint64(i)*sectSize, sectSize) + if err != nil { + continue + } + + err = textsect.parse(textsec_raw, littleendian) + if err != nil { + continue + } + textsectmap = append(textsectmap, textsect) + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + // https://github.com/golang/go/blob/9ecb853cf2252f3cd9ed2e7b3401d17df2d1ab06/src/runtime/symtab.go#L630-L632 + if textAddr32(uint64(firstFunc.Entryoffset), uint64(module.Text), textsectmap) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks.Data = pvoid64(module.Typelinks.Data) + moduleData.Typelinks.Len = uint64(module.Typelinks.Len) + moduleData.Typelinks.Capacity = uint64(module.Typelinks.Capacity) + + moduleData.ITablinks.Data = pvoid64(module.Itablinks.Data) + moduleData.ITablinks.Len = uint64(module.Itablinks.Len) + moduleData.ITablinks.Capacity = uint64(module.Itablinks.Capacity) + return secStart, moduleData, err + } + case "1.20": + if is64bit { + var module ModuleData120_64 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab118 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // prevent loop on invalid modules with bogus length + if module.Textsectmap.Len > 0x100 { + continue + } + + var textsectmap []Textsect_64 + for i := 0; i < int(module.Textsectmap.Len); i++ { + var textsect Textsect_64 + var sectSize = uint64(unsafe.Sizeof(textsect)) + textsec_raw, err := e.raw.read_memory(uint64(module.Textsectmap.Data)+uint64(i)*sectSize, sectSize) + if err != nil { + continue + } + + err = textsect.parse(textsec_raw, littleendian) + if err != nil { + continue + } + textsectmap = append(textsectmap, textsect) + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + // https://github.com/golang/go/blob/9ecb853cf2252f3cd9ed2e7b3401d17df2d1ab06/src/runtime/symtab.go#L630-L632 + if textAddr64(uint64(firstFunc.Entryoffset), uint64(module.Text), textsectmap) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks = module.Typelinks + moduleData.ITablinks = module.Itablinks + return secStart, moduleData, err + } else { + var module ModuleData120_32 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab118 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // prevent loop on invalid modules with bogus length + if module.Textsectmap.Len > 0x100 { + continue + } + + var textsectmap []Textsect_32 + for i := 0; i < int(module.Textsectmap.Len); i++ { + var textsect Textsect_32 + var sectSize = uint64(unsafe.Sizeof(textsect)) + textsec_raw, err := e.raw.read_memory(uint64(module.Textsectmap.Data)+uint64(i)*sectSize, sectSize) + if err != nil { + continue + } + + err = textsect.parse(textsec_raw, littleendian) + if err != nil { + continue + } + textsectmap = append(textsectmap, textsect) + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + // https://github.com/golang/go/blob/9ecb853cf2252f3cd9ed2e7b3401d17df2d1ab06/src/runtime/symtab.go#L630-L632 + if textAddr32(uint64(firstFunc.Entryoffset), uint64(module.Text), textsectmap) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks.Data = pvoid64(module.Typelinks.Data) + moduleData.Typelinks.Len = uint64(module.Typelinks.Len) + moduleData.Typelinks.Capacity = uint64(module.Typelinks.Capacity) + + moduleData.ITablinks.Data = pvoid64(module.Itablinks.Data) + moduleData.ITablinks.Len = uint64(module.Itablinks.Len) + moduleData.ITablinks.Capacity = uint64(module.Itablinks.Capacity) + return secStart, moduleData, err + } + case "1.18": + if is64bit { + var module ModuleData118_64 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab118 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // prevent loop on invalid modules with bogus length + if module.Textsectmap.Len > 0x100 { + continue + } + + var textsectmap []Textsect_64 + for i := 0; i < int(module.Textsectmap.Len); i++ { + var textsect Textsect_64 + var sectSize = uint64(unsafe.Sizeof(textsect)) + textsec_raw, err := e.raw.read_memory(uint64(module.Textsectmap.Data)+uint64(i)*sectSize, sectSize) + if err != nil { + continue + } + + err = textsect.parse(textsec_raw, littleendian) + if err != nil { + continue + } + textsectmap = append(textsectmap, textsect) + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + // https://github.com/golang/go/blob/9ecb853cf2252f3cd9ed2e7b3401d17df2d1ab06/src/runtime/symtab.go#L630-L632 + if textAddr64(uint64(firstFunc.Entryoffset), uint64(module.Text), textsectmap) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks = module.Typelinks + moduleData.ITablinks = module.Itablinks + return secStart, moduleData, err + } else { + var module ModuleData118_32 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab118 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // prevent loop on invalid modules with bogus length + if module.Textsectmap.Len > 0x100 { + continue + } + + var textsectmap []Textsect_32 + for i := 0; i < int(module.Textsectmap.Len); i++ { + var textsect Textsect_32 + var sectSize = uint64(unsafe.Sizeof(textsect)) + textsec_raw, err := e.raw.read_memory(uint64(module.Textsectmap.Data)+uint64(i)*sectSize, sectSize) + if err != nil { + continue + } + + err = textsect.parse(textsec_raw, littleendian) + if err != nil { + continue + } + textsectmap = append(textsectmap, textsect) + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + // https://github.com/golang/go/blob/9ecb853cf2252f3cd9ed2e7b3401d17df2d1ab06/src/runtime/symtab.go#L630-L632 + if textAddr32(uint64(firstFunc.Entryoffset), uint64(module.Text), textsectmap) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks.Data = pvoid64(module.Typelinks.Data) + moduleData.Typelinks.Len = uint64(module.Typelinks.Len) + moduleData.Typelinks.Capacity = uint64(module.Typelinks.Capacity) + + moduleData.ITablinks.Data = pvoid64(module.Itablinks.Data) + moduleData.ITablinks.Len = uint64(module.Itablinks.Len) + moduleData.ITablinks.Capacity = uint64(module.Itablinks.Capacity) + return secStart, moduleData, err + } + case "1.16": + if is64bit { + var module ModuleData116_64 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab12_116_64 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + if uint64(firstFunc.Entryoffset) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks = module.Typelinks + moduleData.ITablinks = module.Itablinks + return secStart, moduleData, err + } else { + var module ModuleData116_32 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab12_116_32 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + if uint64(firstFunc.Entryoffset) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks.Data = pvoid64(module.Typelinks.Data) + moduleData.Typelinks.Len = uint64(module.Typelinks.Len) + moduleData.Typelinks.Capacity = uint64(module.Typelinks.Capacity) + + moduleData.ITablinks.Data = pvoid64(module.Itablinks.Data) + moduleData.ITablinks.Len = uint64(module.Itablinks.Len) + moduleData.ITablinks.Capacity = uint64(module.Itablinks.Capacity) + return secStart, moduleData, err + } + + case "1.2": + // this layout changes <= 1.5 even though the tab version stays constant + switch runtimeVersion { + case "1.5": + fallthrough + case "1.6": + if is64bit { + var module ModuleData12_r15_r16_64 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab12_116_64 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + if uint64(firstFunc.Entryoffset) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + // Fake the same Types + Typelinks offsets that later moduledata's use. + // The base would be the normal typelinks pointer, and then we + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.LegacyTypes = module.Typelinks + return secStart, moduleData, err + } else { + var module ModuleData12_r15_r16_32 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab12_116_32 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + if uint64(firstFunc.Entryoffset) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.LegacyTypes.Data = pvoid64(module.Typelinks.Data) + moduleData.LegacyTypes.Len = uint64(module.Typelinks.Len) + moduleData.LegacyTypes.Capacity = uint64(module.Typelinks.Capacity) + return secStart, moduleData, err + } + case "1.7": + if is64bit { + var module ModuleData12_r17_64 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab12_116_64 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + if uint64(firstFunc.Entryoffset) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + // Fake the same Types + Typelinks offsets that later moduledata's use. + // The base would be the normal typelinks pointer, and then we + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks = module.Typelinks + moduleData.ITablinks = module.Itablinks + return secStart, moduleData, err + } else { + var module ModuleData12_r17_32 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab12_116_32 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + if uint64(firstFunc.Entryoffset) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks.Data = pvoid64(module.Typelinks.Data) + moduleData.Typelinks.Len = uint64(module.Typelinks.Len) + moduleData.Typelinks.Capacity = uint64(module.Typelinks.Capacity) + + moduleData.ITablinks.Data = pvoid64(module.Itablinks.Data) + moduleData.ITablinks.Len = uint64(module.Itablinks.Len) + moduleData.ITablinks.Capacity = uint64(module.Itablinks.Capacity) + return secStart, moduleData, err + } + case "1.8": + fallthrough + case "1.9": + fallthrough + case "1.10": + fallthrough + case "1.11": + fallthrough + case "1.12": + fallthrough + case "1.13": + fallthrough + case "1.14": + fallthrough + case "1.15": + if is64bit { + var module ModuleData12_64 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab12_116_64 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + if uint64(firstFunc.Entryoffset) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks = module.Typelinks + moduleData.ITablinks = module.Itablinks + return secStart, moduleData, err + } else { + var module ModuleData12_32 + err := module.parse(moduleDataCandidate.Moduledata, littleendian) + if err != nil { + continue + } + + var firstFunc FuncTab12_116_32 + ftab_raw, err := e.raw.read_memory(uint64(module.Ftab.Data), uint64(unsafe.Sizeof(firstFunc))) + if err != nil { + continue + } + + err = firstFunc.parse(ftab_raw, littleendian) + if err != nil { + continue + } + + // functab's first function should equal the minpc value of moduledata. If not, parse failed, or we found wrong moduledata + if uint64(firstFunc.Entryoffset) != uint64(module.Minpc) { + // wrong moduledata, try next + ignorelist = append(ignorelist, moduleDataCandidate.ModuledataVA) + continue + } + + moduleData.VA = moduleDataCandidate.ModuledataVA + moduleData.TextVA = uint64(module.Text) + moduleData.Types = uint64(module.Types) + moduleData.ETypes = uint64(module.Etypes) + moduleData.Typelinks.Data = pvoid64(module.Typelinks.Data) + moduleData.Typelinks.Len = uint64(module.Typelinks.Len) + moduleData.Typelinks.Capacity = uint64(module.Typelinks.Capacity) + + moduleData.ITablinks.Data = pvoid64(module.Itablinks.Data) + moduleData.ITablinks.Len = uint64(module.Itablinks.Len) + moduleData.ITablinks.Capacity = uint64(module.Itablinks.Capacity) + return secStart, moduleData, err + } + } + } + } + + // should only happen if all scan attempts and validation fail + return 0, nil, fmt.Errorf("moduledata not found") +} + +func (e *Entry) readVarint(address uint64) (int, int, error) { + v := 0 + for i := 0; ; i++ { + data, err := e.raw.read_memory(address+uint64(i), 1) + if err != nil { + return 0, 0, fmt.Errorf("Failed to read varint") + } + x := data[0] + v += int(x&0x7f) << (7 * i) + if x&0x80 == 0 { + return i + 1, v, nil + } + } +} + +func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr uint64, is64bit bool, littleendian bool) (name string, err error) { + // name str (for <= 1.16 encodes length like this, beyond it uses a varint encoding) + // The first byte is a bit field containing: + // + // 1<<0 the name is exported + // 1<<1 tag data follows the name + // 1<<2 pkgPath nameOff follows the name and tag + // + // The next two bytes are the data length OR varint encoding if newer version OR pointer to gostring if really old + // + // l := uint16(data[1])<<8 | uint16(data[2]) + // + // Bytes [3:3+l] are the string data. + + // Starting in >= 1.8 An rtype's string often has an extra *, the go runtime says: + // func (t *rtype) String() string { + // if t.tflag&tflagExtraStar then strip leading * + // tflagExtraStar means the name in the str field has an + // extraneous '*' prefix. This is because for most types T in + // a program, the type *T also exists and reusing the str data + // saves binary size. + + var ptrSize uint64 = 0 + if is64bit { + ptrSize = 8 + } else { + ptrSize = 4 + } + + switch runtimeVersion { + case "1.5": + fallthrough + case "1.6": + // pointer to GoString + nameLen, err := e.ReadPointerSizeMem(namePtr+ptrSize, is64bit, littleendian) + if err != nil { + return "", fmt.Errorf("Failed to read name") + } + + deref, err := e.ReadPointerSizeMem(namePtr, is64bit, littleendian) + if err != nil { + return "", fmt.Errorf("Failed to read name") + } + + name_raw, err := e.raw.read_memory(deref, nameLen) + if err != nil { + return "", fmt.Errorf("Failed to read name") + } + + return string(name_raw), nil + case "1.7": // types flags exists >= 1.7 + fallthrough + case "1.8": // type flag tflagExtraStart exists >= 1.8 + fallthrough + case "1.9": + fallthrough + case "1.10": + fallthrough + case "1.11": + fallthrough + case "1.12": + fallthrough + case "1.13": + fallthrough + case "1.14": + fallthrough + case "1.15": + fallthrough + case "1.16": + name_len_raw, err := e.raw.read_memory(namePtr, 3) + if err != nil { + return "", fmt.Errorf("Failed to read name") + } + + name_len := uint16(uint16(name_len_raw[1])<<8 | uint16(name_len_raw[2])) + name_raw, err := e.raw.read_memory(namePtr+3, uint64(name_len)) + if err != nil { + return "", fmt.Errorf("Failed to read name") + } + + name := string(name_raw) + if typeFlags&tflagExtraStar != 0 { + return name[1:], nil + } else { + return name, nil + } + case "1.17": + fallthrough + case "1.18": + fallthrough + case "1.19": + fallthrough + case "1.20": + fallthrough + case "1.21": + fallthrough + case "1.22": + varint_len, namelen, err := e.readVarint(namePtr + 1) + if err != nil { + return "", fmt.Errorf("Failed to read name") + } + + name_raw, err := e.raw.read_memory(namePtr+1+uint64(varint_len), uint64(namelen)) + if err != nil { + return "", fmt.Errorf("Failed to read name") + } + + name := string(name_raw) + if typeFlags&tflagExtraStar != 0 { + return name[1:], nil + } else { + return name, nil + } + } + return "", fmt.Errorf("Failed to read name") +} + +func decodePtrSizeBytes(data []byte, is64bit bool, littleendian bool) (result uint64) { + if is64bit { + if littleendian { + return binary.LittleEndian.Uint64(data) + } else { + return binary.BigEndian.Uint64(data) + } + } else { + if littleendian { + return uint64(binary.LittleEndian.Uint32(data)) + } else { + return uint64(binary.BigEndian.Uint32(data)) + } + } +} + +func (e *Entry) ReadPointerSizeMem(addr uint64, is64bit bool, littleendian bool) (result uint64, err error) { + var ptrSize uint64 = 0 + if is64bit { + ptrSize = 8 + } else { + ptrSize = 4 + } + + deref, err := e.raw.read_memory(addr, ptrSize) + if err != nil { + return 0, fmt.Errorf("Failed to dereference pointer memory") + } + + return decodePtrSizeBytes(deref, is64bit, littleendian), nil +} + +func typename_to_c(typename string) string { + result := strings.ReplaceAll(typename, "*", "_ptr_") + result = strings.ReplaceAll(result, "[]", "_slice_") + result = strings.ReplaceAll(result, "<-", "_chan_left_") + result = strings.ReplaceAll(result, ".", "_") + result = strings.ReplaceAll(result, "[", "_") + result = strings.ReplaceAll(result, "]", "_") + result = strings.ReplaceAll(result, " ", "_") + + // this one may be incorrect + result = strings.ReplaceAll(result, "{}", "") + return result +} + +// not exhaustive, just the likely ones to be in Go +func replace_cpp_keywords(fieldname string) string { + switch fieldname { + case "private": + fallthrough + case "public": + fallthrough + case "protected": + fallthrough + case "friend": + fallthrough + case "register": + fallthrough + case "typename": + fallthrough + case "template": + fallthrough + case "typeid": + fallthrough + case "typedef": + fallthrough + case "default": + fallthrough + case "continue": + fallthrough + case "signed": + fallthrough + case "unsigned": + fallthrough + case "class": + return "_" + fieldname + case "_": + return "_anon" + fmt.Sprint(rand.Intn(1000)) + } + return fieldname +} + +func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, typeAddress uint64, is64bit bool, littleendian bool, parsedTypesIn *orderedmap.OrderedMap) (*orderedmap.OrderedMap, error) { + // all return paths must return the original map, even if there's an error. An empty map rather than a nil simplifies recursion and allows tail calls. + // exit condition: type address seen before + if _, exists := parsedTypesIn.Get(typeAddress); exists { + return parsedTypesIn, nil + } + + var _type *Type = nil + + switch runtimeVersion { + case "1.5": + if is64bit { + var rtype Rtype15_64 + rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type address") + } + + err = rtype.parse(rtype_raw, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse type") + } + + name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type name") + } + + _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} + } else { + var rtype Rtype15_32 + rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type address") + } + + err = rtype.parse(rtype_raw, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse type") + } + + name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type name") + } + _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} + } + case "1.6": + if is64bit { + var rtype Rtype16_64 + rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type address") + } + + err = rtype.parse(rtype_raw, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse type") + } + + name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type name") + } + _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} + } else { + var rtype Rtype16_32 + rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type address") + } + + err = rtype.parse(rtype_raw, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse type") + } + + name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type name") + } + _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} + } + case "1.7": + fallthrough + case "1.8": + fallthrough + case "1.9": + fallthrough + case "1.10": + fallthrough + case "1.11": + fallthrough + case "1.12": + fallthrough + case "1.13": + if is64bit { + var rtype Rtype17_18_19_110_111_112_113_64 + rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type address") + } + err = rtype.parse(rtype_raw, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse type") + } + name_ptr := moduleData.Types + uint64(rtype.Str) + name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type name") + } + _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} + } else { + var rtype Rtype17_18_19_110_111_112_113_32 + rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type address") + } + err = rtype.parse(rtype_raw, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse type") + } + name_ptr := moduleData.Types + uint64(rtype.Str) + name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type name") + } + _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} + } + case "1.14": + fallthrough + case "1.15": + fallthrough + case "1.16": + fallthrough + case "1.17": + fallthrough + case "1.18": + fallthrough + case "1.19": + fallthrough + case "1.20": + fallthrough + case "1.21": + fallthrough + case "1.22": + if is64bit { + var rtype Rtype114_115_116_117_118_64 + rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type address") + } + err = rtype.parse(rtype_raw, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse type") + } + name_ptr := moduleData.Types + uint64(rtype.Str) + name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type name") + } + _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} + } else { + var rtype Rtype114_115_116_117_118_32 + rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type address") + } + err = rtype.parse(rtype_raw, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse type") + } + name_ptr := moduleData.Types + uint64(rtype.Str) + name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read type name") + } + _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} + } + default: + return parsedTypesIn, fmt.Errorf("Unknown runtime version") + } + + // insert into seen list + parsedTypesIn.Set(typeAddress, *_type) + + var UintType string = "" + var IntType string = "" + var ptrSize uint64 = 0 + if is64bit { + ptrSize = 8 + IntType = "int64" + UintType = "uint64" + } else { + ptrSize = 4 + IntType = "int32" + UintType = "uint32" + } + + // we must parse each type to cover other types it points to + // this list only contains root type, we optionally recurse to parse those + // and then we may update the map to insert pretty reconstructed string forms of the types + // src/runtume/type.go + switch _type.kindEnum { + case Func: + //type FuncType struct { + // Type + // InCount uint16 + // OutCount uint16 // top bit is set if last input parameter is ... + //} + //inCountAddr := typeAddress + uint64(_type.baseSize) + //outCountAddr := typeAddress + uint64(_type.baseSize) + uint64(unsafe.Sizeof(Uint16)) + // TODO: parse this nicer to get C style args and return + (*_type).CStr = "void*" + parsedTypesIn.Set(typeAddress, *_type) + case Array: + // type arraytype struct { + // typ _type + // elem *_type + // slice *_type + // len uintptr + // } + elemTypeAddress, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Array's elem") + } + + sliceTypeAddress, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize)+ptrSize, is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Array's slice") + } + + arrayLen, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize)+ptrSize+ptrSize, is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Array's len") + } + + parsed, _ := e.ParseType_impl(runtimeVersion, moduleData, elemTypeAddress, is64bit, littleendian, parsedTypesIn) + elemType, found := parsedTypesIn.Get(elemTypeAddress) + if found { + (*_type).Reconstructed = (*_type).Str // ends up being the same for an array + (*_type).CReconstructed = "typedef " + elemType.(Type).CStr + " " + (*_type).CStr + "[" + strconv.Itoa(int(arrayLen)) + "];" + parsed.Set(typeAddress, *_type) + } + return e.ParseType_impl(runtimeVersion, moduleData, sliceTypeAddress, is64bit, littleendian, parsed) + case Chan: + // type chantype struct { + // typ _type + // elem *_type + // dir uintptr + // } + elemTypeAddress, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Chan's elem") + } + + // append channel direction to Str of type + // channelDir, err := e.raw.read_memory(typeAddress+uint64(_type.baseSize)+ptrSize, ptrSize) + // if err == nil { + // var dir string = "" + // if is64bit { + // if littleendian { + // dir = (ChanDir)(binary.LittleEndian.Uint64(channelDir)).String() + // } else { + // dir = (ChanDir)(binary.BigEndian.Uint64(channelDir)).String() + // } + // } else { + // if littleendian { + // dir = (ChanDir)(binary.LittleEndian.Uint32(channelDir)).String() + // } else { + // dir = (ChanDir)(binary.BigEndian.Uint32(channelDir)).String() + // } + // } + // + // _type.Str += " Direction: (" + dir + ")" + // } + + parsedTypesIn, err = e.ParseType_impl(runtimeVersion, moduleData, elemTypeAddress, is64bit, littleendian, parsedTypesIn) + if err != nil { + return parsedTypesIn, err + } + + elemType, found := parsedTypesIn.Get(elemTypeAddress) + if found { + (*_type).Str = "chan(" + elemType.(Type).Str + ")" + (*_type).CStr = "chan_" + elemType.(Type).CStr + (*_type).Reconstructed = "chan(" + elemType.(Type).Str + ")" + (*_type).CReconstructed = "typedef void* chan_" + elemType.(Type).CStr + ";" + parsedTypesIn.Set(typeAddress, *_type) + } + case Slice: + // type slicetype struct { + // typ _type + // elem *_type + // } + elemTypeAddress, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Slice's elem") + } + + parsedTypesIn, err = e.ParseType_impl(runtimeVersion, moduleData, elemTypeAddress, is64bit, littleendian, parsedTypesIn) + if err != nil { + return parsedTypesIn, err + } + + elemType, found := parsedTypesIn.Get(elemTypeAddress) + if found { + (*_type).Reconstructed = "struct " + (*_type).Str + "{ ptr *" + elemType.(Type).Str + "\nlen int\ncap int }" + (*_type).CReconstructed = "struct " + (*_type).CStr + "{ " + elemType.(Type).CStr + "* ptr;" + "size_t len; size_t cap; }" + parsedTypesIn.Set(typeAddress, *_type) + } + case Pointer: + // type ptrtype struct { + // typ _type + // elem *_type + // } + elemTypeAddress, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Pointer's elem") + } + + parsedTypesIn, err = e.ParseType_impl(runtimeVersion, moduleData, elemTypeAddress, is64bit, littleendian, parsedTypesIn) + if err != nil { + return parsedTypesIn, err + } + + elemType, found := parsedTypesIn.Get(elemTypeAddress) + if found { + (*_type).Reconstructed = "type " + (*_type).Str + " = " + elemType.(Type).CStr + (*_type).CReconstructed = "typedef " + elemType.(Type).CStr + "* " + (*_type).CStr + ";" + parsedTypesIn.Set(typeAddress, *_type) + } + case UnsafePointer: + // IDA doesn't reconstruct unsafe pointers, just sets them to void*, we are fine with that too + (*_type).CReconstructed = fmt.Sprintf("typedef void* %s", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Map: + // type mapType struct { + // rtype + // key *rtype // map key type + // elem *rtype // map element (value) type + // bucket *rtype // internal bucket structure + // // function for hashing keys (ptr to key, seed) -> hash + // hasher func(unsafe.Pointer, uintptr) uintptr + // keysize uint8 // size of key slot + // valuesize uint8 // size of value slot + // bucketsize uint16 // size of bucket + // flags uint32 + // } + keyTypeAddress, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize), is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Map's elem") + } + + elemTypeAddress, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize)+ptrSize, is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Array's slice") + } + + bucketTypeAddress, err := e.ReadPointerSizeMem(typeAddress+uint64(_type.baseSize)+ptrSize+ptrSize, is64bit, littleendian) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to read Kind Array's slice") + } + + // IDA doesn't reconstruct maps, just sets them to void*, we are fine with that too + // TODO: reconstruct this as a real map struct + (*_type).CReconstructed = fmt.Sprintf("typedef void* %s", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + + parsed, _ := e.ParseType_impl(runtimeVersion, moduleData, keyTypeAddress, is64bit, littleendian, parsedTypesIn) + parsed2, _ := e.ParseType_impl(runtimeVersion, moduleData, elemTypeAddress, is64bit, littleendian, parsed) + return e.ParseType_impl(runtimeVersion, moduleData, bucketTypeAddress, is64bit, littleendian, parsed2) + case Interface: + // type interfaceType struct { + // rtype + // pkgPath name // import path (pointer) + // methods []imethod // sorted by hash + // } + + switch runtimeVersion { + case "1.5": + fallthrough + case "1.6": + // + // type interfaceType struct { + // rtype `reflect:"interface"` + // methods []imethod // sorted by hash + // } + var methodsStartAddr uint64 = typeAddress + uint64(_type.baseSize) + var methods GoSlice64 = GoSlice64{} + if is64bit { + data, err := e.raw.read_memory(methodsStartAddr, uint64(unsafe.Sizeof(GoSlice64{}))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse Kind Interface's method slice") + } + methods.parse(data, littleendian) + } else { + data, err := e.raw.read_memory(methodsStartAddr, uint64(unsafe.Sizeof(GoSlice32{}))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse Kind Interface's method slice") + } + + var tmp GoSlice32 = GoSlice32{} + tmp.parse(data, littleendian) + + methods.Data = pvoid64(tmp.Data) + methods.Len = uint64(tmp.Len) + methods.Capacity = uint64(tmp.Capacity) + } + + interfaceDef := fmt.Sprintf("type %s interface {", _type.Str) + cinterfaceDef := fmt.Sprintf("struct %s {\n", _type.CStr) + + // type imethod struct { + // name *string // name of method + // pkgPath *string // nil for exported Names; otherwise import path + // typ *rtype // .(*FuncType) underneath + // } + // size = 3 * ptrsize + for i := 0; i < int(methods.Len); i++ { + imethoddata, err := e.raw.read_memory(uint64(methods.Data)+(uint64(i)*3*ptrSize), 3*ptrSize) + if err != nil { + continue + } + + typeAddr := decodePtrSizeBytes(imethoddata[ptrSize*2:ptrSize*3], is64bit, littleendian) + parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn) + + name_ptr := decodePtrSizeBytes(imethoddata[0:ptrSize], is64bit, littleendian) + name, err := e.readRTypeName(runtimeVersion, 0, name_ptr, is64bit, littleendian) + if err != nil { + continue + } + + methodfunc, found := parsedTypesIn.Get(typeAddr) + if found { + interfaceDef += strings.Replace(methodfunc.(Type).Str, "func", name, 1) + "\n" + cinterfaceDef += methodfunc.(Type).CStr + " " + name + ";\n" + } + } + interfaceDef += "\n}" + cinterfaceDef += "}" + (*_type).Reconstructed = interfaceDef + (*_type).CReconstructed = cinterfaceDef + parsedTypesIn.Set(typeAddress, *_type) + return parsedTypesIn, nil + case "1.7": + fallthrough + case "1.8": + fallthrough + case "1.9": + fallthrough + case "1.10": + fallthrough + case "1.11": + fallthrough + case "1.12": + fallthrough + case "1.13": + fallthrough + case "1.14": + fallthrough + case "1.15": + fallthrough + case "1.16": + fallthrough + case "1.17": + fallthrough + case "1.18": + fallthrough + case "1.19": + fallthrough + case "1.20": + fallthrough + case "1.21": + fallthrough + case "1.22": + var methodsStartAddr uint64 = typeAddress + uint64(_type.baseSize) + ptrSize + var methods GoSlice64 = GoSlice64{} + if is64bit { + data, err := e.raw.read_memory(methodsStartAddr, uint64(unsafe.Sizeof(GoSlice64{}))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse Kind Interface's method slice") + } + methods.parse(data, littleendian) + } else { + data, err := e.raw.read_memory(methodsStartAddr, uint64(unsafe.Sizeof(GoSlice32{}))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse Kind Interface's method slice") + } + + var tmp GoSlice32 = GoSlice32{} + tmp.parse(data, littleendian) + + methods.Data = pvoid64(tmp.Data) + methods.Len = uint64(tmp.Len) + methods.Capacity = uint64(tmp.Capacity) + } + + interfaceDef := "type interface {" + cinterfaceDef := "struct interface {\n" + if _type.flags&tflagNamed != 0 { + interfaceDef = fmt.Sprintf("type %s interface {", _type.Str) + cinterfaceDef = fmt.Sprintf("struct %s {\n", _type.CStr) + } + + // type imethod struct { + // name nameOff // name of method + // typ typeOff // .(*FuncType) underneath + // } + entrySize := uint64(unsafe.Sizeof(IMethod{})) + for i := 0; i < int(methods.Len); i++ { + imethoddata, err := e.raw.read_memory(uint64(methods.Data)+entrySize*uint64(i), entrySize) + if err != nil { + continue + } + + var method IMethod + err = method.parse(imethoddata, littleendian) + if err != nil { + continue + } + + typeAddr := moduleData.Types + uint64(method.Typ) + parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn) + + name_ptr := moduleData.Types + uint64(method.Name) + name, err := e.readRTypeName(runtimeVersion, 0, name_ptr, is64bit, littleendian) + if err != nil { + continue + } + + methodfunc, found := parsedTypesIn.Get(typeAddr) + if found { + interfaceDef += strings.Replace(methodfunc.(Type).Str, "func", name, 1) + "\n" + cinterfaceDef += methodfunc.(Type).CStr + " " + name + ";\n" + } + } + interfaceDef += "\n}" + cinterfaceDef += "}" + (*_type).Reconstructed = interfaceDef + (*_type).CReconstructed = cinterfaceDef + parsedTypesIn.Set(typeAddress, *_type) + return parsedTypesIn, nil + } + case Struct: + switch runtimeVersion { + case "1.5": + fallthrough + case "1.6": + // type structType struct { + // rtype `reflect:"struct"` + // fields []structField // sorted by offset + // } + var fieldsStartAddr uint64 = typeAddress + uint64(_type.baseSize) + var fields GoSlice64 = GoSlice64{} + if is64bit { + data, err := e.raw.read_memory(fieldsStartAddr, uint64(unsafe.Sizeof(GoSlice64{}))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse Kind Interface's method slice") + } + fields.parse(data, littleendian) + } else { + data, err := e.raw.read_memory(fieldsStartAddr, uint64(unsafe.Sizeof(GoSlice32{}))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse Kind Interface's method slice") + } + + var tmp GoSlice32 = GoSlice32{} + tmp.parse(data, littleendian) + + fields.Data = pvoid64(tmp.Data) + fields.Len = uint64(tmp.Len) + fields.Capacity = uint64(tmp.Capacity) + } + + structDef := fmt.Sprintf("type %s struct {", _type.Str) + cstructDef := fmt.Sprintf("struct %s {\n", _type.CStr) + + // type structField struct { + // name *string // nil for embedded fields + // pkgPath *string // nil for exported Names; otherwise import path + // typ *rtype // type of field + // tag *string // nil if no tag + // offset uintptr // byte offset of field within struct + // } + // size = 5 * ptrsize + for i := 0; i < int(fields.Len); i++ { + data, err := e.raw.read_memory(uint64(fields.Data)+(uint64(i)*(ptrSize*5)), ptrSize*5) + if err != nil { + continue + } + + typeAddr := decodePtrSizeBytes(data[ptrSize*2:ptrSize*3], is64bit, littleendian) + parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn) + field, found := parsedTypesIn.Get(typeAddr) + if found { + typeNameAddr := decodePtrSizeBytes(data[0:ptrSize], is64bit, littleendian) + typeName, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian) + if err == nil { + structDef += fmt.Sprintf("\n %-10s %s", typeName, field.(Type).Str) + cstructDef += fmt.Sprintf(" %-10s %s;\n", field.(Type).CStr, replace_cpp_keywords(typeName)) + } + } + } + structDef += "\n}" + cstructDef += "}" + (*_type).Reconstructed = structDef + (*_type).CReconstructed = cstructDef + parsedTypesIn.Set(typeAddress, *_type) + return parsedTypesIn, nil + case "1.7": + fallthrough + case "1.8": + fallthrough + case "1.9": + fallthrough + case "1.10": + fallthrough + case "1.11": + fallthrough + case "1.12": + fallthrough + case "1.13": + fallthrough + case "1.14": + fallthrough + case "1.15": + fallthrough + case "1.16": + fallthrough + case "1.17": + fallthrough + case "1.18": + fallthrough + case "1.19": + fallthrough + case "1.20": + fallthrough + case "1.21": + fallthrough + case "1.22": + // type structType struct { + // rtype + // pkgPath name // pointer + // fields []structField // sorted by offset + // } + var fieldsStartAddr uint64 = typeAddress + uint64(_type.baseSize) + ptrSize + var fields GoSlice64 = GoSlice64{} + if is64bit { + data, err := e.raw.read_memory(fieldsStartAddr, uint64(unsafe.Sizeof(GoSlice64{}))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse Kind Interface's method slice") + } + fields.parse(data, littleendian) + } else { + data, err := e.raw.read_memory(fieldsStartAddr, uint64(unsafe.Sizeof(GoSlice32{}))) + if err != nil { + return parsedTypesIn, fmt.Errorf("Failed to parse Kind Interface's method slice") + } + + var tmp GoSlice32 = GoSlice32{} + tmp.parse(data, littleendian) + + fields.Data = pvoid64(tmp.Data) + fields.Len = uint64(tmp.Len) + fields.Capacity = uint64(tmp.Capacity) + } + + structDef := "type struct {" + cstructDef := "struct {\n" + if _type.flags&tflagNamed != 0 { + structDef = fmt.Sprintf("type %s struct {", _type.Str) + cstructDef = fmt.Sprintf("struct %s {\n", _type.CStr) + } + + // type structField struct { + // name name // name is empty for embedded fields (ptr) + // typ *rtype // type of field + // offset uintptr // byte offset of field within struct + // } + // + // size = ptrsize * 3 + for i := 0; i < int(fields.Len); i++ { + data, err := e.raw.read_memory(uint64(fields.Data)+(uint64(i)*(ptrSize*3)), ptrSize*3) + if err != nil { + continue + } + + typeAddr := decodePtrSizeBytes(data[ptrSize:ptrSize*2], is64bit, littleendian) + parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn) + + field, found := parsedTypesIn.Get(typeAddr) + if found { + typeNameAddr := decodePtrSizeBytes(data[0:ptrSize], is64bit, littleendian) + typeName, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian) + if err == nil { + structDef += fmt.Sprintf("\n %-10s %s", typeName, field.(Type).Str) + cstructDef += fmt.Sprintf(" %-10s %s;\n", field.(Type).CStr, replace_cpp_keywords(typeName)) + } + } + } + structDef += "\n}" + cstructDef += "}" + (*_type).Reconstructed = structDef + (*_type).CReconstructed = cstructDef + parsedTypesIn.Set(typeAddress, *_type) + return parsedTypesIn, nil + } + case Int: + (*_type).CReconstructed = fmt.Sprintf("typedef %s %s;", IntType, _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s int;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Uint: + (*_type).CReconstructed = fmt.Sprintf("typedef %s %s;", UintType, _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s uint;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Int8: + (*_type).CReconstructed = fmt.Sprintf("typedef int8 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s int8;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Uint8: + (*_type).CReconstructed = fmt.Sprintf("typedef uint8 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s uint8;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Int16: + (*_type).CReconstructed = fmt.Sprintf("typedef int16 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s int16;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Uint16: + (*_type).CReconstructed = fmt.Sprintf("typedef uint16 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s uint16;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Int32: + (*_type).CReconstructed = fmt.Sprintf("typedef int32 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s int32;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Uint32: + (*_type).CReconstructed = fmt.Sprintf("typedef uint32 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s uint32;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Int64: + (*_type).CReconstructed = fmt.Sprintf("typedef int64 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s int64;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Uint64: + (*_type).CReconstructed = fmt.Sprintf("typedef uint64 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s uint64;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Uintptr: + (*_type).CReconstructed = fmt.Sprintf("typedef uintptr %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s uintptr;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Float32: + (*_type).CReconstructed = fmt.Sprintf("typedef float32 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s float32;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Float64: + (*_type).CReconstructed = fmt.Sprintf("typedef float64 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s float64;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Complex64: + (*_type).CReconstructed = fmt.Sprintf("typedef complex64 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s complex64;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Complex128: + (*_type).CReconstructed = fmt.Sprintf("typedef complex128 %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s complex128;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + case Bool: + (*_type).CReconstructed = fmt.Sprintf("typedef bool %s;", _type.CStr) + (*_type).Reconstructed = fmt.Sprintf("type %s bool;", _type.CStr) + parsedTypesIn.Set(typeAddress, *_type) + default: + // this is not an error, we just may not support recursion on this 'Kind' + } + return parsedTypesIn, nil +} + +func (e *Entry) ParseType(runtimeVersion string, moduleData *ModuleData, typeAddress uint64, is64bit bool, littleendian bool) (_type []Type, err error) { + // Major version only, 1.15.5 -> 1.15 + parts := strings.Split(runtimeVersion, ".") + if len(parts) >= 2 { + runtimeVersion = parts[0] + "." + parts[1] + } + + m := orderedmap.NewOrderedMap() + + parsedTypes, err := e.ParseType_impl(runtimeVersion, moduleData, typeAddress, is64bit, littleendian, m) + if err != nil { + return nil, err + } + + // map values to array + values := make([]Type, 0, parsedTypes.Len()) + + for el := m.Front(); el != nil; el = el.Next() { + values = append(values, (el.Value).(Type)) + } + + return values, nil +} + +func (e *Entry) ParseTypeLinks(runtimeVersion string, moduleData *ModuleData, is64bit bool, littleendian bool) (types []Type, err error) { + // Major version only, 1.15.5 -> 1.15 + parts := strings.Split(runtimeVersion, ".") + if len(parts) >= 2 { + runtimeVersion = parts[0] + "." + parts[1] + } + + var ptrSize uint64 = 0 + if is64bit { + ptrSize = 8 + } else { + ptrSize = 4 + } + + // Handle legacy layout first (1.5, 1.6). The typelinks is a pointer array + if moduleData.LegacyTypes.Data != 0 && moduleData.LegacyTypes.Len != 0 { + for i := 0; i < int(moduleData.LegacyTypes.Len); i++ { + typeAddress, err := e.ReadPointerSizeMem(uint64(moduleData.LegacyTypes.Data)+ptrSize*uint64(i), is64bit, littleendian) + if err != nil { + continue + } + + parsed, err := e.ParseType(runtimeVersion, moduleData, typeAddress, is64bit, littleendian) + if err == nil { + types = append(types, parsed...) + } + } + return types, nil + } + + // Modern layout, the typelinks is an array of offsets + for i := 0; i < int(moduleData.Typelinks.Len); i++ { + // array of int32 offsets into moduleData.Types + offset, err := e.raw.read_memory(uint64(moduleData.Typelinks.Data)+uint64(i)*4, 4) + if err != nil { + continue + } + + var typeAddress uint64 = 0 + if littleendian { + offset_signed := int32(binary.LittleEndian.Uint32(offset)) + typeAddress = uint64(int64(moduleData.Types) + int64(offset_signed)) + } else { + offset_signed := int32(binary.BigEndian.Uint32(offset)) + typeAddress = uint64(int64(moduleData.Types) + int64(offset_signed)) + } + + parsed, err := e.ParseType(runtimeVersion, moduleData, typeAddress, is64bit, littleendian) + if err == nil { + types = append(types, parsed...) + } + } + return types, nil +} + +func (e *Entry) ParseITabLinks(runtimeVersion string, moduleData *ModuleData, is64bit bool, littleendian bool) (types []Type, err error) { + // Major version only, 1.15.5 -> 1.15 + parts := strings.Split(runtimeVersion, ".") + if len(parts) >= 2 { + runtimeVersion = parts[0] + "." + parts[1] + } + + var ptrSize uint64 = 0 + if is64bit { + ptrSize = 8 + } else { + ptrSize = 4 + } + + for i := 0; i < int(moduleData.ITablinks.Len); i++ { + itabAddr, err := e.ReadPointerSizeMem(uint64(moduleData.ITablinks.Data)+ptrSize*uint64(i), is64bit, littleendian) + if err != nil { + continue + } + + interfaceAddr, err := e.ReadPointerSizeMem(itabAddr, is64bit, littleendian) + if err != nil { + continue + } + + typeAddr, err := e.ReadPointerSizeMem(itabAddr+ptrSize, is64bit, littleendian) + if err != nil { + continue + } + + // type itab struct { + // inter *interfacetype + // _type *_type + // hash uint32 // copy of _type.hash. Used for type switches. + // _ [4]byte + // fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter. + // } + parsed, err := e.ParseType(runtimeVersion, moduleData, interfaceAddr, is64bit, littleendian) + if err == nil { + types = append(types, parsed...) + } + + parsed2, err2 := e.ParseType(runtimeVersion, moduleData, typeAddr, is64bit, littleendian) + if err2 == nil { + types = append(types, parsed2...) + } + + // the interface itself, we need to insert as a type. We'll name it after its interface + its implementing type, the 0th of each parsed array + if err == nil && err2 == nil && len(parsed) > 0 && len(parsed2) > 0 { + interfaceName := parsed[0].Str + implementerName := parsed2[0].Str + types = append(types, Type{VA: itabAddr, Str: fmt.Sprintf("interface_%s_impl_%s", interfaceName, implementerName), Kind: Interface.String()}) + } + } + return types, nil +} + +func (e *Entry) Text() (uint64, []byte, error) { + return e.raw.text() +} + +func (e *Entry) GOARCH() string { + return e.raw.goarch() +} + +// LoadAddress returns the expected load address of the file. +// This differs from the actual load address for a position-independent +// executable. +func (e *Entry) LoadAddress() (uint64, error) { + return e.raw.loadAddress() +} + +// DWARF returns DWARF debug data for the file, if any. +// This is for cmd/pprof to locate cgo functions. +func (e *Entry) DWARF() (*dwarf.Data, error) { + return e.raw.dwarf() +} diff --git a/vendor/github.com/mandiant/GoReSym/objfile/patterns.go b/vendor/github.com/mandiant/GoReSym/objfile/patterns.go new file mode 100644 index 00000000..f5ec6525 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/patterns.go @@ -0,0 +1,298 @@ +package objfile + +import ( + "errors" + "strconv" + "strings" + + "golang.org/x/exp/slices" + "rsc.io/binaryregexp" +) + +func contains(s []rune, c rune) bool { + for _, v := range s { + if v == c { + return true + } + } + + return false +} + +func isHexRune(c rune) bool { + return contains([]rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}, c) +} + +func isHex(s string) bool { + for _, c := range s { + if !isHexRune(c) { + return false + } + } + return true +} + +// translate from a yara-style pattern, like: +// +// { 48 8D 0? ?? ?? ?? ?? EB ?? 48 8? 8? ?? 02 00 00 66 0F 1F 44 00 00 } +// +// to a regular expression string compatible with the binaryregexp module, like: +// +// \x48\x8D[\x00-\x0F]....\xEB.\x48[\x80-\x8F][\x80-\x8F].\x02\x00\x00\x66\x0F\x1F\x44\x00\x00 +// +// although this requires more code, we provide this functionality +// because these patterns are *much* more readable than raw regular expressions, +// we strongly value people being able to understand GoReSym's algorithm. +func RegexpPatternFromYaraPattern(pattern string) (*RegexAndNeedle, error) { + + if !strings.HasPrefix(pattern, "{") { + return nil, errors.New("missing prefix") + } + + if !strings.HasSuffix(pattern, "}") { + return nil, errors.New("missing suffix") + } + + pattern = strings.Trim(pattern, "{}") + + pattern = strings.ReplaceAll(pattern, " ", "") + + pattern = strings.ToLower(pattern) + + patLen := 0 + sequenceLen := 0 + needleOffset := 0 + needle := make([]byte, 0) + tmpNeedle := make([]byte, 0) + + resetNeedle := func() { + patLen += sequenceLen + sequenceLen = 0 + if len(tmpNeedle) > len(needle) { + needle = slices.Clone(tmpNeedle) + needleOffset = patLen - len(tmpNeedle) + } + tmpNeedle = make([]byte, 0) + } + + var regex_pattern string + for i := 0; i < len(pattern); { + // at the start of this loop, + // i will be aligned to the start of a nibble (or [] range), + // so both i and i+1 will be valid. + + c := pattern[i : i+1] + d := pattern[i+1 : i+2] + + // input: ?? + // output: . + if c == "?" { + if d != "?" { + return nil, errors.New("cannot mask the first nibble") + } + + regex_pattern += "." + + i += 2 + resetNeedle() + sequenceLen = 1 + continue + } + + // input: [x-y] + // output: .{x,y} + if c == "[" { + end := strings.Index(pattern[i:], "]") + if end == -1 { + return nil, errors.New("unbalanced [") + } + + chunk := pattern[i+1 : i+end] + low, high, found := strings.Cut(chunk, "-") + if !found { + return nil, errors.New("[] didn't contain a dash") + } + + _, err := strconv.Atoi(low) + if err != nil { + return nil, errors.New("invalid number") + } + + highInt, err := strconv.Atoi(high) + if err != nil { + return nil, errors.New("invalid number") + } + + regex_pattern += "." + regex_pattern += "{" + regex_pattern += low + regex_pattern += "," + regex_pattern += high + regex_pattern += "}" + + // YARA evaluates lazily, make sure we match that: + // AA BB BB + // { AA [0-1] BB } + // must produce: + // AA BB + regex_pattern += "?" + + i += end + 1 + resetNeedle() + sequenceLen = highInt // pessimistic length + continue + } + + // input: (AA|BB|CC) + // output: (\xAA|\xBB|\xCC) + if c == "(" { + end := strings.Index(pattern[i:], ")") + if end == -1 { + return nil, errors.New("unbalanced (") + } + + chunk := pattern[i+1 : i+end] + choices := strings.Split(chunk, "|") + + regex_pattern += "(" + for j, choice := range choices { + if !isHex(choice) { + return nil, errors.New("choice not hex") + } + + if j != 0 { + regex_pattern += "|" + } + + regex_pattern += `\x` + strings.ToUpper(choice) + } + regex_pattern += ")" + + i += end + 1 + resetNeedle() + sequenceLen = 1 + continue + } + + // input: 0? + // output: [\x00-\x0F] + if d == "?" { + if !isHex(c) { + return nil, errors.New("not hex digit") + } + + regex_pattern += "[" + regex_pattern += `\x` + strings.ToUpper(c) + "0" + regex_pattern += "-" + regex_pattern += `\x` + strings.ToUpper(c) + "F" + regex_pattern += "]" + + i += 2 + resetNeedle() + sequenceLen = 1 + continue + } + + // input: AB + // output: \xAB + if isHex(c) && isHex(d) { + regex_pattern += `\x` + strings.ToUpper(c+d) + byt, err := strconv.ParseInt(c+d, 16, 64) + if err != nil { + return nil, errors.New("not hex digit") + } + tmpNeedle = append(tmpNeedle, byte(byt)) + i += 2 + sequenceLen += 1 + continue + } + + // input: ~AB + // output: [^\xAB] + if c == "~" { + if len(pattern) < i+3 { + return nil, errors.New("incomplete negated byte") + } + e := pattern[i+2 : i+3] + + regex_pattern += "[^" + regex_pattern += `\x` + strings.ToUpper(d+e) + regex_pattern += "]" + + i += 3 + resetNeedle() + sequenceLen = 1 + continue + } + + return nil, errors.New("unexpected value") + } + + resetNeedle() + + // use "single line" flag to match "\n" as regular character + r, err := binaryregexp.Compile("(?s)" + regex_pattern) + if err != nil { + return nil, errors.New("failed to compile regex") + } + return &RegexAndNeedle{patLen, regex_pattern, r, needleOffset, needle}, nil +} + +func FindRegex(data []byte, regexInfo *RegexAndNeedle) []int { + data_len := len(data) + matches := make([]int, 0) + + // use an optimized memscan to find some candidates chunks from the much larger haystack + needleMatches := findAllOccurrences(data, [][]byte{regexInfo.needle}) + for _, needleMatch := range needleMatches { + // adjust the window to the pattern start and end + data_start := needleMatch - regexInfo.needleOffset + data_end := data_start + regexInfo.len + if data_start >= data_len { + continue + } + if data_start < 0 { + data_start = 0 + } + if data_end > data_len { + data_end = data_len + } + + // do the full regex scan on a very small chunk + for _, reMatch := range regexInfo.re.FindAllIndex(data[data_start:data_end], -1) { + // the match offset is the start index of the chunk + reMatch index + start := reMatch[0] + data_start + + //end := reMatch[1] + data_start + matches = append(matches, start) + + // special case to handle sub-matches, which are skipped by regex but matched by YARA: + // AA AA BB CC + // { AA [0-1] BB CC } + // must produce: + // AA AA BB CC + // AA BB CC + subStart := start + 1 + for { + subMatches := regexInfo.re.FindAllIndex(data[subStart:data_end], -1) + if len(subMatches) == 0 { + break + } + + for _, match := range subMatches { + matches = append(matches, match[0]+subStart) + } + subStart += subMatches[0][0] + 1 + } + } + } + return matches +} + +type RegexAndNeedle struct { + len int + rawre string + re *binaryregexp.Regexp + needleOffset int // offset within the pattern + needle []byte // longest fixed sub-sequence of regex +} diff --git a/vendor/github.com/mandiant/GoReSym/objfile/pe.go b/vendor/github.com/mandiant/GoReSym/objfile/pe.go new file mode 100644 index 00000000..6b4b1441 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/pe.go @@ -0,0 +1,528 @@ +// 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. + +/*Copyright (C) 2022 Mandiant, Inc. All Rights Reserved.*/ + +// Parsing of PE executables (Microsoft Windows). + +package objfile + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "sort" + + "github.com/mandiant/GoReSym/debug/dwarf" + "github.com/mandiant/GoReSym/debug/pe" +) + +type peFile struct { + pe *pe.File +} + +func openPE(r io.ReaderAt) (rawFile, error) { + f, err := pe.NewFile(r) + if err != nil { + return nil, err + } + return &peFile{f}, nil +} + +func (f *peFile) read_memory(VA uint64, size uint64) (data []byte, err error) { + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + } + + VA -= imageBase + for _, sect := range f.pe.Sections { + if uint64(sect.VirtualAddress) <= VA && VA <= uint64(sect.VirtualAddress+sect.Size-1) { + n := uint64(sect.VirtualAddress+sect.Size) - VA + if n > size { + n = size + } + data := make([]byte, n) + _, err := sect.ReadAt(data, int64(VA-uint64(sect.VirtualAddress))) + if err != nil { + return nil, fmt.Errorf("Reading section data failed") + } + return data, nil + } + } + return nil, fmt.Errorf("Failed to read memory") +} + +func (f *peFile) symbols() ([]Sym, error) { + // Build sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + } + + var syms []Sym + for _, s := range f.pe.Symbols { + const ( + N_UNDEF = 0 // An undefined (extern) symbol + N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) + N_DEBUG = -2 // A debugging symbol + ) + sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} + switch s.SectionNumber { + case N_UNDEF: + sym.Code = 'U' + case N_ABS: + sym.Code = 'C' + case N_DEBUG: + sym.Code = '?' + default: + if s.SectionNumber < 0 || len(f.pe.Sections) < int(s.SectionNumber) { + return nil, fmt.Errorf("invalid section number in symbol table") + } + sect := f.pe.Sections[s.SectionNumber-1] + const ( + text = 0x20 + data = 0x40 + bss = 0x80 + permW = 0x80000000 + ) + ch := sect.Characteristics + switch { + case ch&text != 0: + sym.Code = 'T' + case ch&data != 0: + if ch&permW == 0 { + sym.Code = 'R' + } else { + sym.Code = 'D' + } + case ch&bss != 0: + sym.Code = 'B' + } + sym.Addr += imageBase + uint64(sect.VirtualAddress) + } + syms = append(syms, sym) + addrs = append(addrs, sym.Addr) + } + + sort.Sort(uint64s(addrs)) + for i := range syms { + j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) + if j < len(addrs) { + syms[i].Size = int64(addrs[j] - syms[i].Addr) + } + } + + return syms, nil +} + +func (f *peFile) pcln_scan() (candidates []PclntabCandidate, err error) { + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + return nil, fmt.Errorf("pe file format not recognized") + } + + // 1) Locate pclntab via symbols (standard way) + foundpcln := false + var pclntab []byte + + if pclntab, err = loadPETable(f.pe, "runtime.pclntab", "runtime.epclntab"); err == nil { + foundpcln = true + } else { + // We didn't find the symbols, so look for the names used in 1.3 and earlier. + // TODO: Remove code looking for the old symbols when we no longer care about 1.3. + var err2 error + if pclntab, err2 = loadPETable(f.pe, "pclntab", "epclntab"); err2 == nil { + foundpcln = true + } + } + + pclntab_sigs_le := [][]byte{ + []byte("\xF1\xFF\xFF\xFF\x00\x00"), // little endian + []byte("\xF0\xFF\xFF\xFF\x00\x00"), + []byte("\xFA\xFF\xFF\xFF\x00\x00"), + []byte("\xFB\xFF\xFF\xFF\x00\x00"), + } + + pclntab_sigs_be := [][]byte{ + []byte("\xFF\xFF\xFF\xF1\x00\x00"), // big endian + []byte("\xFF\xFF\xFF\xF0\x00\x00"), + []byte("\xFF\xFF\xFF\xFA\x00\x00"), + []byte("\xFF\xFF\xFF\xFB\x00\x00"), + } + + // 2) if not found, byte scan for it + pclntab_sigs := append(pclntab_sigs_le, pclntab_sigs_be...) + + // candidate array for method 4 of scanning + var stompedmagic_candidates []StompMagicCandidate = make([]StompMagicCandidate, 0) + + // 2) if not found, byte scan for it + for _, sec := range f.pe.Sections { + // malware can split the pclntab across multiple sections, re-merge + data := f.pe.DataAfterSection(sec) + + if !foundpcln { + matches := findAllOccurrences(data, pclntab_sigs) + for _, pclntab_idx := range matches { + if pclntab_idx != -1 { + pclntab = data[pclntab_idx:] + + var candidate PclntabCandidate + candidate.Pclntab = pclntab + + candidate.SecStart = imageBase + uint64(sec.VirtualAddress) + candidate.PclntabVA = candidate.SecStart + uint64(pclntab_idx) + + candidates = append(candidates, candidate) + // we must scan all signature for all sections. DO NOT BREAK + } + } + } else { + // 3) if we found it earlier, figure out which section base to return (might be wrong for packed things) + pclntab_idx := bytes.Index(data, pclntab) + if pclntab_idx != -1 { + var candidate PclntabCandidate + candidate.Pclntab = pclntab + + candidate.SecStart = imageBase + uint64(sec.VirtualAddress) + candidate.PclntabVA = candidate.SecStart + uint64(pclntab_idx) + + candidates = append(candidates, candidate) + } + } + + // TODO this scan needs to occur in both big and little endian mode + // 4) Always try this other way! Sometimes the pclntab magic is stomped as well so our byte OR symbol location fail. Byte scan for the moduledata, use that to find the pclntab instead, fix up magic with all combinations. + // See the obfuscator 'garble' for an example of randomizing the pclntab magic + sigResults := findModuleInitPCHeader(data, uint64(sec.VirtualAddress)+imageBase) + for _, sigResult := range sigResults { + // example: off_69D0C0 is the moduleData we found via our scan, the first ptr unk_5DF6E0, is the pclntab! + // 0x000000000069D0C0 E0 F6 5D 00 00 00 00 00 off_69D0C0 dq offset unk_5DF6E0 ; DATA XREF: runtime_SetFinalizer+119↑o + // 0x000000000069D0C0 ; runtime_scanstack+40B↑o ... + // 0x000000000069D0C8 40 F7 5D 00 00 00 00 00 dq offset aInternalCpuIni ; "internal/cpu.Initialize" + // 0x000000000069D0D0 F0 db 0F0h + // 0x000000000069D0D1 BB db 0BBh + + // we don't know the endianess or arch, so we submit all combinations as candidates and sort them out later + // example: reads out ptr unk_5DF6E0 + pclntabVARaw64, err := f.read_memory(sigResult.moduleDataVA, 8) // assume 64bit + if err == nil { + stompedMagicCandidateLE := StompMagicCandidate{ + binary.LittleEndian.Uint64(pclntabVARaw64), + sigResult.moduleDataVA, + true, + } + stompedMagicCandidateBE := StompMagicCandidate{ + binary.BigEndian.Uint64(pclntabVARaw64), + sigResult.moduleDataVA, + false, + } + stompedmagic_candidates = append(stompedmagic_candidates, stompedMagicCandidateLE, stompedMagicCandidateBE) + } + + pclntabVARaw32, err := f.read_memory(sigResult.moduleDataVA, 4) // assume 32bit + if err == nil { + stompedMagicCandidateLE := StompMagicCandidate{ + uint64(binary.LittleEndian.Uint32(pclntabVARaw32)), + sigResult.moduleDataVA, + true, + } + stompedMagicCandidateBE := StompMagicCandidate{ + uint64(binary.BigEndian.Uint32(pclntabVARaw32)), + sigResult.moduleDataVA, + false, + } + stompedmagic_candidates = append(stompedmagic_candidates, stompedMagicCandidateLE, stompedMagicCandidateBE) + } + } + } + + // even if we found the pclntab without signature scanning it may have a stomped magic. That would break parsing later! So, let's submit new candidates + // with all the possible magics to get at least one that hopefully parses correctly. + patched_magic_candidates := make([]PclntabCandidate, 0) + for _, candidate := range candidates { + has_some_valid_magic := false + for _, magic := range append(pclntab_sigs_le, pclntab_sigs_be...) { + if bytes.Equal(candidate.Pclntab, magic) { + has_some_valid_magic = true + break + } + } + + if !has_some_valid_magic { + for _, magic := range append(pclntab_sigs_le, pclntab_sigs_be...) { + pclntab_copy := make([]byte, len(candidate.Pclntab)) + copy(pclntab_copy, candidate.Pclntab) + copy(pclntab_copy, magic) + + new_candidate := candidate + new_candidate.Pclntab = pclntab_copy + patched_magic_candidates = append(patched_magic_candidates, new_candidate) + candidate.Pclntab = pclntab_copy + } + } + } + + if len(patched_magic_candidates) > 0 { + candidates = patched_magic_candidates + } + + // 4.1) Take the pclntab stomped candidates, and read the pclntab data at each location. Usually the BIG/LITTLE endian pointers that are invalid are filtered out here + if len(stompedmagic_candidates) != 0 { + for _, sec := range f.pe.Sections { + // malware can split the pclntab across multiple sections, re-merge + data := f.pe.DataAfterSection(sec) + for _, stompedMagicCandidate := range stompedmagic_candidates { + pclntab_va_candidate := stompedMagicCandidate.PclntabVa + + // We must ensure our pointer starts within the first section of the data returned by DataAfterSection so that we use the right base address + if pclntab_va_candidate >= (imageBase+uint64(sec.VirtualAddress)) && pclntab_va_candidate < (imageBase+uint64(sec.VirtualAddress)+uint64(sec.Size)) && pclntab_va_candidate < (imageBase+uint64(sec.VirtualAddress)+uint64(len(data))) { + sec_offset := pclntab_va_candidate - (imageBase + uint64(sec.VirtualAddress)) + pclntab = data[sec_offset:] + + if stompedMagicCandidate.LittleEndian { + for _, magicLE := range pclntab_sigs_le { + // Make a copy of the pclntab with each magic possible. For when the magic is intentionally corrupted + // Parsing will fail at some later point for the magics that don't match the version, filtering out that candidate + pclntab_copy := make([]byte, len(pclntab)) + copy(pclntab_copy, pclntab) + copy(pclntab_copy, magicLE) + + var candidate PclntabCandidate + candidate.StompMagicCandidateMeta = &stompedMagicCandidate + candidate.Pclntab = pclntab_copy + candidate.SecStart = imageBase + uint64(sec.VirtualAddress) + candidate.PclntabVA = pclntab_va_candidate + + candidates = append(candidates, candidate) + } + } else { + for _, magicBE := range pclntab_sigs_be { + // Make a copy of the pclntab with each magic possible. For when the magic is intentionally corrupted + // Parsing will fail at some later point for the magics that don't match the version, filtering out that candidate + pclntab_copy := make([]byte, len(pclntab)) + copy(pclntab_copy, pclntab) + copy(pclntab_copy, magicBE) + + var candidate PclntabCandidate + candidate.StompMagicCandidateMeta = &stompedMagicCandidate + candidate.Pclntab = pclntab_copy + candidate.SecStart = imageBase + uint64(sec.VirtualAddress) + candidate.PclntabVA = pclntab_va_candidate + + candidates = append(candidates, candidate) + } + } + } + } + } + } + + return candidates, nil +} + +func (f *peFile) pcln() (candidates []PclntabCandidate, err error) { + candidates, err = f.pcln_scan() + if err != nil { + return nil, err + } + + // 4) symtab is completely optional, but try to find it + var symtab []byte + if symtab, err = loadPETable(f.pe, "runtime.symtab", "runtime.esymtab"); err != nil { + symtab, err = loadPETable(f.pe, "symtab", "esymtab") + } + + if err == nil { + for _, c := range candidates { + c.Symtab = symtab + } + } + + return candidates, nil +} + +func (f *peFile) moduledata_scan(pclntabVA uint64, is64bit bool, littleendian bool, ignorelist []uint64) (candidate *ModuleDataCandidate, err error) { + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + return nil, fmt.Errorf("pe file format not recognized") + } + found := false + + var moduledata []uint8 + var secStart uint64 + var moduledata_idx = 0 +scan: + for _, sec := range f.pe.Sections { + // malware can split the pclntab across multiple sections, re-merge + data := f.pe.DataAfterSection(sec) + // fall back to scanning for structure using address of pclntab, which is first value in struc + var pclntabVA_bytes []byte + if is64bit { + pclntabVA_bytes = make([]byte, 8) + if littleendian { + binary.LittleEndian.PutUint64(pclntabVA_bytes, pclntabVA) + } else { + binary.BigEndian.PutUint64(pclntabVA_bytes, pclntabVA) + } + } else { + pclntabVA_bytes = make([]byte, 4) + if littleendian { + binary.LittleEndian.PutUint32(pclntabVA_bytes, uint32(pclntabVA)) + } else { + binary.BigEndian.PutUint32(pclntabVA_bytes, uint32(pclntabVA)) + } + } + + moduledata_idx = bytes.Index(data, pclntabVA_bytes) + if moduledata_idx != -1 && moduledata_idx < int(sec.Size) { + moduledata = data[moduledata_idx:] + secStart = imageBase + uint64(sec.VirtualAddress) + + // optionally consult ignore list, to skip past previous (bad) scan results + if ignorelist != nil { + for _, ignore := range ignorelist { + if ignore == secStart+uint64(moduledata_idx) { + continue scan + } + } + } + + found = true + break + } + } + + if !found { + return nil, fmt.Errorf("moduledata containing section could not be located") + } + + return &ModuleDataCandidate{SecStart: secStart, ModuledataVA: secStart + uint64(moduledata_idx), Moduledata: moduledata}, nil +} + +func (f *peFile) text() (textStart uint64, text []byte, err error) { + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + return 0, nil, fmt.Errorf("pe file format not recognized") + } + sect := f.pe.Section(".text") + if sect == nil { + return 0, nil, fmt.Errorf("text section not found") + } + textStart = imageBase + uint64(sect.VirtualAddress) + text, err = sect.Data() + return +} + +func (f *peFile) rdata() (textStart uint64, text []byte, err error) { + var imageBase uint64 + switch oh := f.pe.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(oh.ImageBase) + case *pe.OptionalHeader64: + imageBase = oh.ImageBase + default: + return 0, nil, fmt.Errorf("pe file format not recognized") + } + sect := f.pe.Section(".rdata") + if sect == nil { + return 0, nil, fmt.Errorf("rdata section not found") + } + textStart = imageBase + uint64(sect.VirtualAddress) + text, err = sect.Data() + return +} + +func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { + for _, s := range f.Symbols { + if s.Name != name { + continue + } + if s.SectionNumber <= 0 { + return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) + } + if len(f.Sections) < int(s.SectionNumber) { + return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) + } + return s, nil + } + return nil, fmt.Errorf("no %s symbol found", name) +} + +func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { + ssym, err := findPESymbol(f, sname) + if err != nil { + return nil, err + } + esym, err := findPESymbol(f, ename) + if err != nil { + return nil, err + } + if ssym.SectionNumber != esym.SectionNumber { + return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) + } + + if uint32(ssym.SectionNumber) > uint32(len(f.Sections)) { + return nil, fmt.Errorf("pclntab symbol section index out of range") + } + + sect := f.Sections[ssym.SectionNumber-1] + data, err := sect.Data() + if err != nil { + return nil, err + } + + if ssym.Value > esym.Value || esym.Value > uint32(len(data)) { + return nil, fmt.Errorf("pclntab symbols are malformed") + } + + return data[ssym.Value:esym.Value], nil +} + +func (f *peFile) goarch() string { + switch f.pe.Machine { + case pe.IMAGE_FILE_MACHINE_I386: + return "386" + case pe.IMAGE_FILE_MACHINE_AMD64: + return "amd64" + case pe.IMAGE_FILE_MACHINE_ARMNT: + return "arm" + default: + return "" + } +} + +func (f *peFile) loadAddress() (uint64, error) { + return 0, fmt.Errorf("unknown load address") +} + +func (f *peFile) dwarf() (*dwarf.Data, error) { + return f.pe.DWARF() +} diff --git a/vendor/github.com/mandiant/GoReSym/objfile/scanner.go b/vendor/github.com/mandiant/GoReSym/objfile/scanner.go new file mode 100644 index 00000000..a4b33da9 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/objfile/scanner.go @@ -0,0 +1,204 @@ +package objfile + +import "encoding/binary" + +type signatureModuleDataInitx64 struct { + moduleDataPtrLoc uint64 // offset in signature to the location of the pointer to the PCHeader + moduleDataPtrOffsetLoc uint64 // Ptr is a relative ptr, we need to include the instruction length + next instruction IP to resolve final VA + signature string + compiledRegex *RegexAndNeedle +} + +type signatureModuleDataInitx86 struct { + moduleDataPtrLoc uint64 // offset in signature to the location of the pointer to the PCHeader (ptr is absolute addr) + signature string + compiledRegex *RegexAndNeedle +} + +type signatureModuleDataInitPPC struct { + moduleDataPtrHi uint64 + moduleDataPtrLo uint64 + signature string + compiledRegex *RegexAndNeedle +} + +type signatureModuleDataInitARM64 struct { + moduleDataPtrADRP uint64 // offset to ADRP instruction holding PAGE address + moduleDataPtrADD uint64 // offset to ADD instruction holding PAGE offset + signature string + compiledRegex *RegexAndNeedle +} + +type signatureModuleDataInitARM32 struct { + moduleDataPtrLDR uint64 // offset to LDR instruction holding pc relative imm offset to PCHeader + signature string + compiledRegex *RegexAndNeedle +} + +type SignatureMatch struct { + moduleDataVA uint64 +} + +// 0x000000000044D80A: 48 8D 0D 8F DA 26 00 lea rcx, runtime_firstmoduledata +// 0x000000000044D811: EB 0D jmp short loc_44D820 +// 0x000000000044D813: 48 8B 89 30 02 00 00 mov rcx, [rcx+230h] +var x64sig = signatureModuleDataInitx64{3, 7, `{ 48 8D 0? ?? ?? ?? ?? E? ?? 48 8? 8? ?? 02 00 00 }`, nil} + +// 0x00438A94: 8D 05 60 49 6A 00 lea eax, off_6A4960 +// 0x00438A9A: EB 1A jmp short loc_438AB6 +// ...gap... +// 0x00438AAC: 8B 80 18 01 00 00 mov eax, [eax+118h] +// 0x00438AB2: 8B 54 24 20 mov edx, [esp+2Ch+var_C] +// 0x00438AB6: +// 0x00438AB6: loc_438AB6: ; CODE XREF: sub_438A60+3A↑j +// 0x00438AB6: 85 C0 test eax, eax +// 0x00438AB8: 75 E2 jnz short loc_438A9C +var x86sig = signatureModuleDataInitx86{2, `{ 8D ?? ?? ?? ?? ?? EB ?? [0-50] 8B ?? ?? 01 00 00 8B ?? ?? ?? 85 ?? 75 ?? }`, nil} + +// 0x0000000000061a74: 3C 80 00 2C lis r4, 0x2c // moduledata +// 0x0000000000061a78: 38 84 80 00 addi r4, r4, 0x8000 // moduledata ((0x2c << 16) - 0x8000) +// 0x0000000000061a7c: 48 00 00 08 b 0x61a84 +// 0x0000000000061a80: E8 84 02 30 ld r4, 0x230(r4) +// 0x0000000000061a84: 7C 24 00 00 cmpd r4, r0 +// 0x0000000000061a88: 41 82 01 A8 beq 0x61c30 +var PPC_BE_sig = signatureModuleDataInitPPC{2, 6, `{ 3? 80 00 ?? 3? ?? ?? ?? 48 ?? ?? ?? E? ?? 02 ?? 7C ?? ?? ?? 41 82 ?? ?? }`, nil} + +// 0x000000000005C1E8 41 14 00 F0 ADRP X1, #unk_2E7000 // 0xF0001441 -> 0b1 11 10000 0000000000010100010 00001 -> op=1, immlo=0b11, immhi=0b0000000000010100010 +// ........................................................................ // X1 = ((0b0000000000010100010 11 << 12) + 0x5C1E8) = 0b1011100111000111101000 = 0b1011100111000111101000 & 0xFFFFFFFFFFFFF000 = 0x2E7000 +// 0x000000000005C1EC 21 80 3D 91 ADD X1, X1, #firstmoduleData@PAGEOFF // 0x913d8021 -> 0b100 100010 0 111101100000 00001 00001 -> sh = 0, imm12 = 0b111101100000, Rn = 00001, Rb = 00001 +// ....................................................................... // X1 = 0x2E7000 + 0b111101100000 (0xF60) = 0x2E7F60 +// 0x000000000005C1F0 02 00 00 14 B loc_5C1F8 0x14 00 00 02 +// 0x000000000005C1F4 21 18 41 F9 LDR X1, [X1,#0x230] +// 0x000000000005C1F8 21 0D 00 B4 CBZ X1, loc_5C39C 0xb4000d21 +// THIS SIG ENCODES the 0x230 struct field offset - might need to mask that more if we see misses - TODO +var ARM64_sig = signatureModuleDataInitARM64{0, 4, `{ ?? ?? ?? (90 | b0 | f0 | d0) ?? ?? ?? 91 ?? ?? ?? (14 | 17) ?? ?? 41 F9 ?? ?? ?? B4 }`, nil} + +// 0x0006AA00 80 12 9F E5 LDR R1, =firstmoduleData // 0xE59F1280 -> 0b11 100101100111110001001010000000 -> size = 11, +// 0x0006AA04 00 00 00 EA B loc_6AA0C +// 0x0006AA08 18 11 91 E5 LDR R1, [R1,#0x118] +// 0x0006AA0C 00 00 51 E3 CMP R1, #0 +// 0x0006AA10 69 00 00 0A BEQ loc_6ABBC +var ARM32_sig = signatureModuleDataInitARM32{0, `{ ?? ?? 9F E5 ?? ?? ?? EA ?? ?? ?? E5 ?? ?? ?? E3 ?? ?? ?? 0A }`, nil} + +func findModuleInitPCHeader(data []byte, sectionBase uint64) []SignatureMatch { + var matches []SignatureMatch = make([]SignatureMatch, 0) + + var x64reg = x64sig.compiledRegex + if x64reg == nil { + var err error + x64reg, err = RegexpPatternFromYaraPattern(x64sig.signature) + if err != nil { + panic(err) + } + x64sig.compiledRegex = x64reg + } + + for _, match := range FindRegex(data, x64reg) { + sigPtr := uint64(match) // from int + + // this is the pointer offset stored in the instruction + // 0x44E06A: 48 8D 0D 4F F0 24 00 lea rcx, off_69D0C0 (result: 0x24f04f) + moduleDataPtrOffset := uint64(binary.LittleEndian.Uint32(data[sigPtr+x64sig.moduleDataPtrLoc:][:4])) + + // the ptr we get is position dependant, add the sigPtr + sectionBase to get current IP, then offset to next instruction + // as relative ptrs are encoded by the NEXT instruction va, not the current one + moduleDataIpOffset := sigPtr + sectionBase + x64sig.moduleDataPtrOffsetLoc + matches = append(matches, SignatureMatch{ + moduleDataPtrOffset + moduleDataIpOffset, + }) + } + + var x86reg = x86sig.compiledRegex + if x86reg == nil { + var err error + x86reg, err = RegexpPatternFromYaraPattern(x86sig.signature) + if err != nil { + panic(err) + } + x86sig.compiledRegex = x86reg + } + + for _, match := range FindRegex(data, x86reg) { + sigPtr := uint64(match) // from int + + moduleDataPtr := uint64(binary.LittleEndian.Uint32(data[sigPtr+x86sig.moduleDataPtrLoc:][:4])) + matches = append(matches, SignatureMatch{ + moduleDataPtr, + }) + } + + var arm64reg = ARM64_sig.compiledRegex + if arm64reg == nil { + var err error + arm64reg, err = RegexpPatternFromYaraPattern(ARM64_sig.signature) + if err != nil { + panic(err) + } + ARM64_sig.compiledRegex = arm64reg + } + + for _, match := range FindRegex(data, arm64reg) { + sigPtr := uint64(match) // from int + + adrp := binary.LittleEndian.Uint32(data[sigPtr+ARM64_sig.moduleDataPtrADRP:][:4]) + add := binary.LittleEndian.Uint32(data[sigPtr+ARM64_sig.moduleDataPtrADD:][:4]) + moduleDataIpOffset := sigPtr + sectionBase + + adrp_immhi := uint64((adrp & 0xFFFFF0) >> 5) + adrp_immlo := uint64((adrp & 0x60000000) >> 29) + adrp_imm := adrp_immhi<<2 | adrp_immlo // combine hi:lo + page := ((adrp_imm << 12) + moduleDataIpOffset) & 0xFFFFFFFFFFFFF000 // PAGE imm is aligned to page, left shift 12 and zero lower 12 to align + + // the page offset fills in lower 12 + page_off := uint64((add & 0x3FFC00) >> 10) + + final := page + page_off + matches = append(matches, SignatureMatch{ + final, + }) + } + + var arm32reg = ARM32_sig.compiledRegex + if arm32reg == nil { + var err error + arm32reg, err = RegexpPatternFromYaraPattern(ARM32_sig.signature) + if err != nil { + panic(err) + } + ARM32_sig.compiledRegex = arm32reg + } + + for _, match := range FindRegex(data, arm32reg) { + sigPtr := uint64(match) // from int + ldr := binary.LittleEndian.Uint32(data[sigPtr+ARM32_sig.moduleDataPtrLDR:][:4]) + // ARM PC relative is always +8 due to legacy nonsense + ldr_pointer_stub := uint64((ldr & 0x00000FFF) + 8) + final := uint64(binary.LittleEndian.Uint32(data[sigPtr+ARM32_sig.moduleDataPtrLDR+ldr_pointer_stub:][:4])) + matches = append(matches, SignatureMatch{ + final, + }) + } + + var ppcBEreg = PPC_BE_sig.compiledRegex + if ppcBEreg == nil { + var err error + ppcBEreg, err = RegexpPatternFromYaraPattern(PPC_BE_sig.signature) + if err != nil { + panic(err) + } + PPC_BE_sig.compiledRegex = ppcBEreg + } + + for _, match := range FindRegex(data, ppcBEreg) { + sigPtr := uint64(match) // from int + moduleDataPtrHi := int64(binary.BigEndian.Uint16(data[sigPtr+PPC_BE_sig.moduleDataPtrHi:][:2])) + // addi takes a signed immediate + moduleDataPtrLo := int64(int16(binary.BigEndian.Uint16(data[sigPtr+PPC_BE_sig.moduleDataPtrLo:][:2]))) + moduleDataIpOffset := uint64((moduleDataPtrHi << 16) + moduleDataPtrLo) + matches = append(matches, SignatureMatch{ + moduleDataIpOffset, + }) + } + + return matches +} diff --git a/vendor/github.com/mandiant/GoReSym/saferio/io.go b/vendor/github.com/mandiant/GoReSym/saferio/io.go new file mode 100644 index 00000000..66cc044c --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/saferio/io.go @@ -0,0 +1,135 @@ +// Copyright 2022 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 saferio provides I/O functions that avoid allocating large +// amounts of memory unnecessarily. This is intended for packages that +// read data from an [io.Reader] where the size is part of the input +// data but the input may be corrupt, or may be provided by an +// untrustworthy attacker. +package saferio + +import ( + "io" + "reflect" +) + +// chunk is an arbitrary limit on how much memory we are willing +// to allocate without concern. +const chunk = 10 << 20 // 10M + +// ReadData reads n bytes from the input stream, but avoids allocating +// all n bytes if n is large. This avoids crashing the program by +// allocating all n bytes in cases where n is incorrect. +// +// The error is io.EOF only if no bytes were read. +// If an io.EOF happens after reading some but not all the bytes, +// ReadData returns io.ErrUnexpectedEOF. +func ReadData(r io.Reader, n uint64) ([]byte, error) { + if int64(n) < 0 || n != uint64(int(n)) { + // n is too large to fit in int, so we can't allocate + // a buffer large enough. Treat this as a read failure. + return nil, io.ErrUnexpectedEOF + } + + if n < chunk { + buf := make([]byte, n) + _, err := io.ReadFull(r, buf) + if err != nil { + return nil, err + } + return buf, nil + } + + var buf []byte + buf1 := make([]byte, chunk) + for n > 0 { + next := n + if next > chunk { + next = chunk + } + _, err := io.ReadFull(r, buf1[:next]) + if err != nil { + if len(buf) > 0 && err == io.EOF { + err = io.ErrUnexpectedEOF + } + return nil, err + } + buf = append(buf, buf1[:next]...) + n -= next + } + return buf, nil +} + +// ReadDataAt reads n bytes from the input stream at off, but avoids +// allocating all n bytes if n is large. This avoids crashing the program +// by allocating all n bytes in cases where n is incorrect. +func ReadDataAt(r io.ReaderAt, n uint64, off int64) ([]byte, error) { + if int64(n) < 0 || n != uint64(int(n)) { + // n is too large to fit in int, so we can't allocate + // a buffer large enough. Treat this as a read failure. + return nil, io.ErrUnexpectedEOF + } + + if n < chunk { + buf := make([]byte, n) + _, err := r.ReadAt(buf, off) + if err != nil { + // io.SectionReader can return EOF for n == 0, + // but for our purposes that is a success. + if err != io.EOF || n > 0 { + return nil, err + } + } + return buf, nil + } + + var buf []byte + buf1 := make([]byte, chunk) + for n > 0 { + next := n + if next > chunk { + next = chunk + } + _, err := r.ReadAt(buf1[:next], off) + if err != nil { + return nil, err + } + buf = append(buf, buf1[:next]...) + n -= next + off += int64(next) + } + return buf, nil +} + +// SliceCap returns the capacity to use when allocating a slice. +// After the slice is allocated with the capacity, it should be +// built using append. This will avoid allocating too much memory +// if the capacity is large and incorrect. +// +// A negative result means that the value is always too big. +// +// The element type is described by passing a pointer to a value of that type. +// This would ideally use generics, but this code is built with +// the bootstrap compiler which need not support generics. +// We use a pointer so that we can handle slices of interface type. +func SliceCap(v any, c uint64) int { + if int64(c) < 0 || c != uint64(int(c)) { + return -1 + } + typ := reflect.TypeOf(v) + if typ.Kind() != reflect.Ptr { + panic("SliceCap called with non-pointer type") + } + size := uint64(typ.Elem().Size()) + if size > 0 && c > (1<<64-1)/size { + return -1 + } + if c*size > chunk { + c = uint64(chunk / size) + if c == 0 { + c = 1 + } + } + return int(c) +} diff --git a/vendor/github.com/mandiant/GoReSym/sys/arch.go b/vendor/github.com/mandiant/GoReSym/sys/arch.go new file mode 100644 index 00000000..e8687363 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/sys/arch.go @@ -0,0 +1,187 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sys + +import "encoding/binary" + +// ArchFamily represents a family of one or more related architectures. +// For example, ppc64 and ppc64le are both members of the PPC64 family. +type ArchFamily byte + +const ( + NoArch ArchFamily = iota + AMD64 + ARM + ARM64 + I386 + MIPS + MIPS64 + PPC64 + RISCV64 + S390X + Wasm +) + +// Arch represents an individual architecture. +type Arch struct { + Name string + Family ArchFamily + + ByteOrder binary.ByteOrder + + // PtrSize is the size in bytes of pointers and the + // predeclared "int", "uint", and "uintptr" types. + PtrSize int + + // RegSize is the size in bytes of general purpose registers. + RegSize int + + // MinLC is the minimum length of an instruction code. + MinLC int +} + +// InFamily reports whether a is a member of any of the specified +// architecture families. +func (a *Arch) InFamily(xs ...ArchFamily) bool { + for _, x := range xs { + if a.Family == x { + return true + } + } + return false +} + +var Arch386 = &Arch{ + Name: "386", + Family: I386, + ByteOrder: binary.LittleEndian, + PtrSize: 4, + RegSize: 4, + MinLC: 1, +} + +var ArchAMD64 = &Arch{ + Name: "amd64", + Family: AMD64, + ByteOrder: binary.LittleEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 1, +} + +var ArchARM = &Arch{ + Name: "arm", + Family: ARM, + ByteOrder: binary.LittleEndian, + PtrSize: 4, + RegSize: 4, + MinLC: 4, +} + +var ArchARM64 = &Arch{ + Name: "arm64", + Family: ARM64, + ByteOrder: binary.LittleEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 4, +} + +var ArchMIPS = &Arch{ + Name: "mips", + Family: MIPS, + ByteOrder: binary.BigEndian, + PtrSize: 4, + RegSize: 4, + MinLC: 4, +} + +var ArchMIPSLE = &Arch{ + Name: "mipsle", + Family: MIPS, + ByteOrder: binary.LittleEndian, + PtrSize: 4, + RegSize: 4, + MinLC: 4, +} + +var ArchMIPS64 = &Arch{ + Name: "mips64", + Family: MIPS64, + ByteOrder: binary.BigEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 4, +} + +var ArchMIPS64LE = &Arch{ + Name: "mips64le", + Family: MIPS64, + ByteOrder: binary.LittleEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 4, +} + +var ArchPPC64 = &Arch{ + Name: "ppc64", + Family: PPC64, + ByteOrder: binary.BigEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 4, +} + +var ArchPPC64LE = &Arch{ + Name: "ppc64le", + Family: PPC64, + ByteOrder: binary.LittleEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 4, +} + +var ArchRISCV64 = &Arch{ + Name: "riscv64", + Family: RISCV64, + ByteOrder: binary.LittleEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 4, +} + +var ArchS390X = &Arch{ + Name: "s390x", + Family: S390X, + ByteOrder: binary.BigEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 2, +} + +var ArchWasm = &Arch{ + Name: "wasm", + Family: Wasm, + ByteOrder: binary.LittleEndian, + PtrSize: 8, + RegSize: 8, + MinLC: 1, +} + +var Archs = [...]*Arch{ + Arch386, + ArchAMD64, + ArchARM, + ArchARM64, + ArchMIPS, + ArchMIPSLE, + ArchMIPS64, + ArchMIPS64LE, + ArchPPC64, + ArchPPC64LE, + ArchRISCV64, + ArchS390X, + ArchWasm, +} diff --git a/vendor/github.com/mandiant/GoReSym/sys/supported.go b/vendor/github.com/mandiant/GoReSym/sys/supported.go new file mode 100644 index 00000000..ef7c017b --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/sys/supported.go @@ -0,0 +1,131 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sys + +// RaceDetectorSupported reports whether goos/goarch supports the race +// detector. There is a copy of this function in cmd/dist/test.go. +// Race detector only supports 48-bit VMA on arm64. But it will always +// return true for arm64, because we don't have VMA size information during +// the compile time. +func RaceDetectorSupported(goos, goarch string) bool { + switch goos { + case "linux": + return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" + case "darwin": + return goarch == "amd64" || goarch == "arm64" + case "freebsd", "netbsd", "windows": + return goarch == "amd64" + default: + return false + } +} + +// MSanSupported reports whether goos/goarch supports the memory +// sanitizer option. There is a copy of this function in cmd/dist/test.go. +func MSanSupported(goos, goarch string) bool { + switch goos { + case "linux": + return goarch == "amd64" || goarch == "arm64" + default: + return false + } +} + +// MustLinkExternal reports whether goos/goarch requires external linking. +// (This is the opposite of internal/testenv.CanInternalLink. Keep them in sync.) +func MustLinkExternal(goos, goarch string) bool { + switch goos { + case "android": + if goarch != "arm64" { + return true + } + case "ios": + if goarch == "arm64" { + return true + } + } + return false +} + +// BuildModeSupported reports whether goos/goarch supports the given build mode +// using the given compiler. +func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { + if compiler == "gccgo" { + return true + } + + platform := goos + "/" + goarch + + switch buildmode { + case "archive": + return true + + case "c-archive": + // TODO(bcmills): This seems dubious. + // Do we really support c-archive mode on js/wasm‽ + return platform != "linux/ppc64" + + case "c-shared": + switch platform { + case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x", + "android/amd64", "android/arm", "android/arm64", "android/386", + "freebsd/amd64", + "darwin/amd64", "darwin/arm64", + "windows/amd64", "windows/386": + return true + } + return false + + case "default": + return true + + case "exe": + return true + + case "pie": + switch platform { + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x", + "android/amd64", "android/arm", "android/arm64", "android/386", + "freebsd/amd64", + "darwin/amd64", "darwin/arm64", + "ios/amd64", "ios/arm64", + "aix/ppc64", + "windows/386", "windows/amd64", "windows/arm": + return true + } + return false + + case "shared": + switch platform { + case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x": + return true + } + return false + + case "plugin": + switch platform { + case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le", + "android/amd64", "android/arm", "android/arm64", "android/386", + "darwin/amd64", "darwin/arm64", + "freebsd/amd64": + return true + } + return false + + default: + return false + } +} + +func InternalLinkPIESupported(goos, goarch string) bool { + switch goos + "/" + goarch { + case "darwin/amd64", "darwin/arm64", + "linux/amd64", "linux/arm64", + "android/arm64", + "windows-amd64", "windows-386", "windows-arm": + return true + } + return false +} diff --git a/vendor/github.com/mandiant/GoReSym/unsafeheader/unsafeheader.go b/vendor/github.com/mandiant/GoReSym/unsafeheader/unsafeheader.go new file mode 100644 index 00000000..6d092c62 --- /dev/null +++ b/vendor/github.com/mandiant/GoReSym/unsafeheader/unsafeheader.go @@ -0,0 +1,37 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package unsafeheader contains header declarations for the Go runtime's slice +// and string implementations. +// +// This package allows packages that cannot import "reflect" to use types that +// are tested to be equivalent to reflect.SliceHeader and reflect.StringHeader. +package unsafeheader + +import ( + "unsafe" +) + +// Slice is the runtime representation of a slice. +// It cannot be used safely or portably and its representation may +// change in a later release. +// +// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the +// data it references will not be garbage collected. +type Slice struct { + Data unsafe.Pointer + Len int + Cap int +} + +// String is the runtime representation of a string. +// It cannot be used safely or portably and its representation may +// change in a later release. +// +// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the +// data it references will not be garbage collected. +type String struct { + Data unsafe.Pointer + Len int +} diff --git a/vendor/golang.org/x/arch/arm/armasm/Makefile b/vendor/golang.org/x/arch/arm/armasm/Makefile new file mode 100644 index 00000000..a3f57001 --- /dev/null +++ b/vendor/golang.org/x/arch/arm/armasm/Makefile @@ -0,0 +1,2 @@ +tables.go: ../armmap/map.go ../arm.csv + go run ../armmap/map.go -fmt=decoder ../arm.csv >_tables.go && gofmt _tables.go >tables.go && rm _tables.go diff --git a/vendor/golang.org/x/arch/arm/armasm/decode.go b/vendor/golang.org/x/arch/arm/armasm/decode.go new file mode 100644 index 00000000..f61ac124 --- /dev/null +++ b/vendor/golang.org/x/arch/arm/armasm/decode.go @@ -0,0 +1,569 @@ +// Copyright 2014 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 armasm + +import ( + "encoding/binary" + "fmt" +) + +// An instFormat describes the format of an instruction encoding. +// An instruction with 32-bit value x matches the format if x&mask == value +// and the condition matches. +// The condition matches if x>>28 == 0xF && value>>28==0xF +// or if x>>28 != 0xF and value>>28 == 0. +// If x matches the format, then the rest of the fields describe how to interpret x. +// The opBits describe bits that should be extracted from x and added to the opcode. +// For example opBits = 0x1234 means that the value +// +// (2 bits at offset 1) followed by (4 bits at offset 3) +// +// should be added to op. +// Finally the args describe how to decode the instruction arguments. +// args is stored as a fixed-size array; if there are fewer than len(args) arguments, +// args[i] == 0 marks the end of the argument list. +type instFormat struct { + mask uint32 + value uint32 + priority int8 + op Op + opBits uint64 + args instArgs +} + +type instArgs [4]instArg + +var ( + errMode = fmt.Errorf("unsupported execution mode") + errShort = fmt.Errorf("truncated instruction") + errUnknown = fmt.Errorf("unknown instruction") +) + +var decoderCover []bool + +// Decode decodes the leading bytes in src as a single instruction. +func Decode(src []byte, mode Mode) (inst Inst, err error) { + if mode != ModeARM { + return Inst{}, errMode + } + if len(src) < 4 { + return Inst{}, errShort + } + + if decoderCover == nil { + decoderCover = make([]bool, len(instFormats)) + } + + x := binary.LittleEndian.Uint32(src) + + // The instFormat table contains both conditional and unconditional instructions. + // Considering only the top 4 bits, the conditional instructions use mask=0, value=0, + // while the unconditional instructions use mask=f, value=f. + // Prepare a version of x with the condition cleared to 0 in conditional instructions + // and then assume mask=f during matching. + const condMask = 0xf0000000 + xNoCond := x + if x&condMask != condMask { + xNoCond &^= condMask + } + var priority int8 +Search: + for i := range instFormats { + f := &instFormats[i] + if xNoCond&(f.mask|condMask) != f.value || f.priority <= priority { + continue + } + delta := uint32(0) + deltaShift := uint(0) + for opBits := f.opBits; opBits != 0; opBits >>= 16 { + n := uint(opBits & 0xFF) + off := uint((opBits >> 8) & 0xFF) + delta |= (x >> off) & (1<> 8) & (1<<4 - 1)) + case arg_R_12: + return Reg((x >> 12) & (1<<4 - 1)) + case arg_R_16: + return Reg((x >> 16) & (1<<4 - 1)) + + case arg_R_12_nzcv: + r := Reg((x >> 12) & (1<<4 - 1)) + if r == R15 { + return APSR_nzcv + } + return r + + case arg_R_16_WB: + mode := AddrLDM + if (x>>21)&1 != 0 { + mode = AddrLDM_WB + } + return Mem{Base: Reg((x >> 16) & (1<<4 - 1)), Mode: mode} + + case arg_R_rotate: + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + // ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1. + if typ == RotateRightExt { + return Rm + } + return RegShift{Rm, typ, count} + + case arg_R_shift_R: + Rm := Reg(x & (1<<4 - 1)) + Rs := Reg((x >> 8) & (1<<4 - 1)) + typ := Shift((x >> 5) & (1<<2 - 1)) + return RegShiftReg{Rm, typ, Rs} + + case arg_R_shift_imm: + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + if typ == ShiftLeft && count == 0 { + return Reg(Rm) + } + return RegShift{Rm, typ, count} + + case arg_R1_0: + return Reg((x & (1<<4 - 1))) + case arg_R1_12: + return Reg(((x >> 12) & (1<<4 - 1))) + case arg_R2_0: + return Reg((x & (1<<4 - 1)) | 1) + case arg_R2_12: + return Reg(((x >> 12) & (1<<4 - 1)) | 1) + + case arg_SP: + return SP + + case arg_Sd_Dd: + v := (x >> 12) & (1<<4 - 1) + vx := (x >> 22) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Dd_Sd: + return decodeArg(arg_Sd_Dd, x^(1<<8)) + + case arg_Sd: + v := (x >> 12) & (1<<4 - 1) + vx := (x >> 22) & 1 + return S0 + Reg(v<<1+vx) + + case arg_Sm_Dm: + v := (x >> 0) & (1<<4 - 1) + vx := (x >> 5) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Sm: + v := (x >> 0) & (1<<4 - 1) + vx := (x >> 5) & 1 + return S0 + Reg(v<<1+vx) + + case arg_Dn_half: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + return RegX{D0 + Reg(vx<<4+v), int((x >> 21) & 1)} + + case arg_Sn_Dn: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Sn: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + return S0 + Reg(v<<1+vx) + + case arg_const: + v := x & (1<<8 - 1) + rot := (x >> 8) & (1<<4 - 1) * 2 + if rot > 0 && v&3 == 0 { + // could rotate less + return ImmAlt{uint8(v), uint8(rot)} + } + if rot >= 24 && ((v<<(32-rot))&0xFF)>>(32-rot) == v { + // could wrap around to rot==0. + return ImmAlt{uint8(v), uint8(rot)} + } + return Imm(v>>rot | v<<(32-rot)) + + case arg_endian: + return Endian((x >> 9) & 1) + + case arg_fbits: + return Imm((16 << ((x >> 7) & 1)) - ((x&(1<<4-1))<<1 | (x>>5)&1)) + + case arg_fp_0: + return Imm(0) + + case arg_imm24: + return Imm(x & (1<<24 - 1)) + + case arg_imm5: + return Imm((x >> 7) & (1<<5 - 1)) + + case arg_imm5_32: + x = (x >> 7) & (1<<5 - 1) + if x == 0 { + x = 32 + } + return Imm(x) + + case arg_imm5_nz: + x = (x >> 7) & (1<<5 - 1) + if x == 0 { + return nil + } + return Imm(x) + + case arg_imm_4at16_12at0: + return Imm((x>>16)&(1<<4-1)<<12 | x&(1<<12-1)) + + case arg_imm_12at8_4at0: + return Imm((x>>8)&(1<<12-1)<<4 | x&(1<<4-1)) + + case arg_imm_vfp: + x = (x>>16)&(1<<4-1)<<4 | x&(1<<4-1) + return Imm(x) + + case arg_label24: + imm := (x & (1<<24 - 1)) << 2 + return PCRel(int32(imm<<6) >> 6) + + case arg_label24H: + h := (x >> 24) & 1 + imm := (x&(1<<24-1))<<2 | h<<1 + return PCRel(int32(imm<<6) >> 6) + + case arg_label_m_12: + d := int32(x & (1<<12 - 1)) + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(-d)} + + case arg_label_p_12: + d := int32(x & (1<<12 - 1)) + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)} + + case arg_label_pm_12: + d := int32(x & (1<<12 - 1)) + u := (x >> 23) & 1 + if u == 0 { + d = -d + } + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)} + + case arg_label_pm_4_4: + d := int32((x>>8)&(1<<4-1)<<4 | x&(1<<4-1)) + u := (x >> 23) & 1 + if u == 0 { + d = -d + } + return PCRel(d) + + case arg_lsb_width: + lsb := (x >> 7) & (1<<5 - 1) + msb := (x >> 16) & (1<<5 - 1) + if msb < lsb || msb >= 32 { + return nil + } + return Imm(msb + 1 - lsb) + + case arg_mem_R: + Rn := Reg((x >> 16) & (1<<4 - 1)) + return Mem{Base: Rn, Mode: AddrOffset} + + case arg_mem_R_pm_R_postindex: + // Treat [],+/- like [,+/-{,}]{!} + // by forcing shift bits to <<0 and P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5|1<<24|1<<21)) + + case arg_mem_R_pm_R_W: + // Treat [,+/-]{!} like [,+/-{,}]{!} + // by forcing shift bits to <<0. + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5)) + + case arg_mem_R_pm_R_shift_imm_offset: + // Treat [],+/-{,} like [,+/-{,}]{!} + // by forcing P=1, W=0 (index=false, wback=false). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<21)|1<<24) + + case arg_mem_R_pm_R_shift_imm_postindex: + // Treat [],+/-{,} like [,+/-{,}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_R_shift_imm_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Sign: sign, Index: Rm, Shift: typ, Count: count} + + case arg_mem_R_pm_imm12_offset: + // Treat [,#+/-] like [{,#+/-}]{!} + // by forcing P=1, W=0 (index=false, wback=false). + return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<21)|1<<24) + + case arg_mem_R_pm_imm12_postindex: + // Treat [],#+/- like [{,#+/-}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_imm12_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16(x & (1<<12 - 1)) + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm} + + case arg_mem_R_pm_imm8_postindex: + // Treat [],#+/- like [{,#+/-}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_imm8_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_imm8_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16((x>>8)&(1<<4-1)<<4 | x&(1<<4-1)) + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm} + + case arg_mem_R_pm_imm8at0_offset: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16(x&(1<<8-1)) << 2 + return Mem{Base: Rn, Mode: AddrOffset, Offset: int16(sign) * imm} + + case arg_option: + return Imm(x & (1<<4 - 1)) + + case arg_registers: + return RegList(x & (1<<16 - 1)) + + case arg_registers2: + x &= 1<<16 - 1 + n := 0 + for i := 0; i < 16; i++ { + if x>>uint(i)&1 != 0 { + n++ + } + } + if n < 2 { + return nil + } + return RegList(x) + + case arg_registers1: + Rt := (x >> 12) & (1<<4 - 1) + return RegList(1 << Rt) + + case arg_satimm4: + return Imm((x >> 16) & (1<<4 - 1)) + + case arg_satimm5: + return Imm((x >> 16) & (1<<5 - 1)) + + case arg_satimm4m1: + return Imm((x>>16)&(1<<4-1) + 1) + + case arg_satimm5m1: + return Imm((x>>16)&(1<<5-1) + 1) + + case arg_widthm1: + return Imm((x>>16)&(1<<5-1) + 1) + + } +} + +// decodeShift decodes the shift-by-immediate encoded in x. +func decodeShift(x uint32) (Shift, uint8) { + count := (x >> 7) & (1<<5 - 1) + typ := Shift((x >> 5) & (1<<2 - 1)) + switch typ { + case ShiftRight, ShiftRightSigned: + if count == 0 { + count = 32 + } + case RotateRight: + if count == 0 { + typ = RotateRightExt + count = 1 + } + } + return typ, uint8(count) +} diff --git a/vendor/golang.org/x/arch/arm/armasm/gnu.go b/vendor/golang.org/x/arch/arm/armasm/gnu.go new file mode 100644 index 00000000..1a97a5a8 --- /dev/null +++ b/vendor/golang.org/x/arch/arm/armasm/gnu.go @@ -0,0 +1,164 @@ +// Copyright 2014 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 armasm + +import ( + "bytes" + "fmt" + "strings" +) + +var saveDot = strings.NewReplacer( + ".F16", "_dot_F16", + ".F32", "_dot_F32", + ".F64", "_dot_F64", + ".S32", "_dot_S32", + ".U32", "_dot_U32", + ".FXS", "_dot_S", + ".FXU", "_dot_U", + ".32", "_dot_32", +) + +// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. +// This form typically matches the syntax defined in the ARM Reference Manual. +func GNUSyntax(inst Inst) string { + var buf bytes.Buffer + op := inst.Op.String() + op = saveDot.Replace(op) + op = strings.Replace(op, ".", "", -1) + op = strings.Replace(op, "_dot_", ".", -1) + op = strings.ToLower(op) + buf.WriteString(op) + sep := " " + for i, arg := range inst.Args { + if arg == nil { + break + } + text := gnuArg(&inst, i, arg) + if text == "" { + continue + } + buf.WriteString(sep) + sep = ", " + buf.WriteString(text) + } + return buf.String() +} + +func gnuArg(inst *Inst, argIndex int, arg Arg) string { + switch inst.Op &^ 15 { + case LDRD_EQ, LDREXD_EQ, STRD_EQ: + if argIndex == 1 { + // second argument in consecutive pair not printed + return "" + } + case STREXD_EQ: + if argIndex == 2 { + // second argument in consecutive pair not printed + return "" + } + } + + switch arg := arg.(type) { + case Imm: + switch inst.Op &^ 15 { + case BKPT_EQ: + return fmt.Sprintf("%#04x", uint32(arg)) + case SVC_EQ: + return fmt.Sprintf("%#08x", uint32(arg)) + } + return fmt.Sprintf("#%d", int32(arg)) + + case ImmAlt: + return fmt.Sprintf("#%d, %d", arg.Val, arg.Rot) + + case Mem: + R := gnuArg(inst, -1, arg.Base) + X := "" + if arg.Sign != 0 { + X = "" + if arg.Sign < 0 { + X = "-" + } + X += gnuArg(inst, -1, arg.Index) + if arg.Shift == ShiftLeft && arg.Count == 0 { + // nothing + } else if arg.Shift == RotateRightExt { + X += ", rrx" + } else { + X += fmt.Sprintf(", %s #%d", strings.ToLower(arg.Shift.String()), arg.Count) + } + } else { + X = fmt.Sprintf("#%d", arg.Offset) + } + + switch arg.Mode { + case AddrOffset: + if X == "#0" { + return fmt.Sprintf("[%s]", R) + } + return fmt.Sprintf("[%s, %s]", R, X) + case AddrPreIndex: + return fmt.Sprintf("[%s, %s]!", R, X) + case AddrPostIndex: + return fmt.Sprintf("[%s], %s", R, X) + case AddrLDM: + if X == "#0" { + return R + } + case AddrLDM_WB: + if X == "#0" { + return R + "!" + } + } + return fmt.Sprintf("[%s Mode(%d) %s]", R, int(arg.Mode), X) + + case PCRel: + return fmt.Sprintf(".%+#x", int32(arg)+4) + + case Reg: + switch inst.Op &^ 15 { + case LDREX_EQ: + if argIndex == 0 { + return fmt.Sprintf("r%d", int32(arg)) + } + } + switch arg { + case R10: + return "sl" + case R11: + return "fp" + case R12: + return "ip" + } + + case RegList: + var buf bytes.Buffer + fmt.Fprintf(&buf, "{") + sep := "" + for i := 0; i < 16; i++ { + if arg&(1<= Op(len(opstr)) || opstr[op] == "" { + return fmt.Sprintf("Op(%d)", int(op)) + } + return opstr[op] +} + +// An Inst is a single instruction. +type Inst struct { + Op Op // Opcode mnemonic + Enc uint32 // Raw encoding bits. + Len int // Length of encoding in bytes. + Args Args // Instruction arguments, in ARM manual order. +} + +func (i Inst) String() string { + var buf bytes.Buffer + buf.WriteString(i.Op.String()) + for j, arg := range i.Args { + if arg == nil { + break + } + if j == 0 { + buf.WriteString(" ") + } else { + buf.WriteString(", ") + } + buf.WriteString(arg.String()) + } + return buf.String() +} + +// An Args holds the instruction arguments. +// If an instruction has fewer than 4 arguments, +// the final elements in the array are nil. +type Args [4]Arg + +// An Arg is a single instruction argument, one of these types: +// Endian, Imm, Mem, PCRel, Reg, RegList, RegShift, RegShiftReg. +type Arg interface { + IsArg() + String() string +} + +type Float32Imm float32 + +func (Float32Imm) IsArg() {} + +func (f Float32Imm) String() string { + return fmt.Sprintf("#%v", float32(f)) +} + +type Float64Imm float32 + +func (Float64Imm) IsArg() {} + +func (f Float64Imm) String() string { + return fmt.Sprintf("#%v", float64(f)) +} + +// An Imm is an integer constant. +type Imm uint32 + +func (Imm) IsArg() {} + +func (i Imm) String() string { + return fmt.Sprintf("#%#x", uint32(i)) +} + +// An ImmAlt is an alternate encoding of an integer constant. +type ImmAlt struct { + Val uint8 + Rot uint8 +} + +func (ImmAlt) IsArg() {} + +func (i ImmAlt) Imm() Imm { + v := uint32(i.Val) + r := uint(i.Rot) + return Imm(v>>r | v<<(32-r)) +} + +func (i ImmAlt) String() string { + return fmt.Sprintf("#%#x, %d", i.Val, i.Rot) +} + +// A Label is a text (code) address. +type Label uint32 + +func (Label) IsArg() {} + +func (i Label) String() string { + return fmt.Sprintf("%#x", uint32(i)) +} + +// A Reg is a single register. +// The zero value denotes R0, not the absence of a register. +type Reg uint8 + +const ( + R0 Reg = iota + R1 + R2 + R3 + R4 + R5 + R6 + R7 + R8 + R9 + R10 + R11 + R12 + R13 + R14 + R15 + + S0 + S1 + S2 + S3 + S4 + S5 + S6 + S7 + S8 + S9 + S10 + S11 + S12 + S13 + S14 + S15 + S16 + S17 + S18 + S19 + S20 + S21 + S22 + S23 + S24 + S25 + S26 + S27 + S28 + S29 + S30 + S31 + + D0 + D1 + D2 + D3 + D4 + D5 + D6 + D7 + D8 + D9 + D10 + D11 + D12 + D13 + D14 + D15 + D16 + D17 + D18 + D19 + D20 + D21 + D22 + D23 + D24 + D25 + D26 + D27 + D28 + D29 + D30 + D31 + + APSR + APSR_nzcv + FPSCR + + SP = R13 + LR = R14 + PC = R15 +) + +func (Reg) IsArg() {} + +func (r Reg) String() string { + switch r { + case APSR: + return "APSR" + case APSR_nzcv: + return "APSR_nzcv" + case FPSCR: + return "FPSCR" + case SP: + return "SP" + case PC: + return "PC" + case LR: + return "LR" + } + if R0 <= r && r <= R15 { + return fmt.Sprintf("R%d", int(r-R0)) + } + if S0 <= r && r <= S31 { + return fmt.Sprintf("S%d", int(r-S0)) + } + if D0 <= r && r <= D31 { + return fmt.Sprintf("D%d", int(r-D0)) + } + return fmt.Sprintf("Reg(%d)", int(r)) +} + +// A RegX represents a fraction of a multi-value register. +// The Index field specifies the index number, +// but the size of the fraction is not specified. +// It must be inferred from the instruction and the register type. +// For example, in a VMOV instruction, RegX{D5, 1} represents +// the top 32 bits of the 64-bit D5 register. +type RegX struct { + Reg Reg + Index int +} + +func (RegX) IsArg() {} + +func (r RegX) String() string { + return fmt.Sprintf("%s[%d]", r.Reg, r.Index) +} + +// A RegList is a register list. +// Bits at indexes x = 0 through 15 indicate whether the corresponding Rx register is in the list. +type RegList uint16 + +func (RegList) IsArg() {} + +func (r RegList) String() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "{") + sep := "" + for i := 0; i < 16; i++ { + if r&(1< MOV like + switch inst.Op &^ 15 { + case MOV_EQ: + op = "MOVW" + op[3:] + case LDR_EQ, MSR_EQ, MRS_EQ: + op = "MOVW" + op[3:] + suffix + case VMRS_EQ, VMSR_EQ: + op = "MOVW" + op[4:] + suffix + case LDRB_EQ, UXTB_EQ: + op = "MOVBU" + op[4:] + suffix + case LDRSB_EQ: + op = "MOVBS" + op[5:] + suffix + case SXTB_EQ: + op = "MOVBS" + op[4:] + suffix + case LDRH_EQ, UXTH_EQ: + op = "MOVHU" + op[4:] + suffix + case LDRSH_EQ: + op = "MOVHS" + op[5:] + suffix + case SXTH_EQ: + op = "MOVHS" + op[4:] + suffix + case STR_EQ: + op = "MOVW" + op[3:] + suffix + args[0], args[1] = args[1], args[0] + case STRB_EQ: + op = "MOVB" + op[4:] + suffix + args[0], args[1] = args[1], args[0] + case STRH_EQ: + op = "MOVH" + op[4:] + suffix + args[0], args[1] = args[1], args[0] + case VSTR_EQ: + args[0], args[1] = args[1], args[0] + default: + op = op + suffix + } + + if args != nil { + op += " " + strings.Join(args, ", ") + } + + return op +} + +// assembler syntax for the various shifts. +// @x> is a lie; the assembler uses @> 0 +// instead of @x> 1, but i wanted to be clear that it +// was a different operation (rotate right extended, not rotate right). +var plan9Shift = []string{"<<", ">>", "->", "@>", "@x>"} + +func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { + switch a := arg.(type) { + case Endian: + + case Imm: + return fmt.Sprintf("$%d", uint32(a)) + + case Mem: + + case PCRel: + addr := uint32(pc) + 8 + uint32(a) + if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base { + return fmt.Sprintf("%s(SB)", s) + } + return fmt.Sprintf("%#x", addr) + + case Reg: + if a < 16 { + return fmt.Sprintf("R%d", int(a)) + } + + case RegList: + var buf bytes.Buffer + start := -2 + end := -2 + fmt.Fprintf(&buf, "[") + flush := func() { + if start >= 0 { + if buf.Len() > 1 { + fmt.Fprintf(&buf, ",") + } + if start == end { + fmt.Fprintf(&buf, "R%d", start) + } else { + fmt.Fprintf(&buf, "R%d-R%d", start, end) + } + start = -2 + end = -2 + } + } + for i := 0; i < 16; i++ { + if a&(1< (R5) +// [r6, #4080] -> 0xff0(R6) +// [r2, r0, ror #1] -> (R2)(R0@>1) +// inst [r2, -r0, ror #1] -> INST.U (R2)(R0@>1) +// input: +// +// a memory operand +// +// return values: +// +// corresponding memory operand in Plan 9 syntax +// .W/.P/.U suffix +func memOpTrans(mem Mem) (string, string) { + suffix := "" + switch mem.Mode { + case AddrOffset, AddrLDM: + // no suffix + case AddrPreIndex, AddrLDM_WB: + suffix = ".W" + case AddrPostIndex: + suffix = ".P" + } + off := "" + if mem.Offset != 0 { + off = fmt.Sprintf("%#x", mem.Offset) + } + base := fmt.Sprintf("(R%d)", int(mem.Base)) + index := "" + if mem.Sign != 0 { + sign := "" + if mem.Sign < 0 { + suffix += ".U" + } + shift := "" + if mem.Count != 0 { + shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count) + } + index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift) + } + return off + base + index, suffix +} + +type goFPInfo struct { + op Op + transArgs []int // indexes of arguments which need transformation + gnuName string // instruction name in GNU syntax + goName string // instruction name in Plan 9 syntax +} + +var fpInst []goFPInfo = []goFPInfo{ + {VADD_EQ_F32, []int{2, 1, 0}, "VADD", "ADDF"}, + {VADD_EQ_F64, []int{2, 1, 0}, "VADD", "ADDD"}, + {VSUB_EQ_F32, []int{2, 1, 0}, "VSUB", "SUBF"}, + {VSUB_EQ_F64, []int{2, 1, 0}, "VSUB", "SUBD"}, + {VMUL_EQ_F32, []int{2, 1, 0}, "VMUL", "MULF"}, + {VMUL_EQ_F64, []int{2, 1, 0}, "VMUL", "MULD"}, + {VNMUL_EQ_F32, []int{2, 1, 0}, "VNMUL", "NMULF"}, + {VNMUL_EQ_F64, []int{2, 1, 0}, "VNMUL", "NMULD"}, + {VMLA_EQ_F32, []int{2, 1, 0}, "VMLA", "MULAF"}, + {VMLA_EQ_F64, []int{2, 1, 0}, "VMLA", "MULAD"}, + {VMLS_EQ_F32, []int{2, 1, 0}, "VMLS", "MULSF"}, + {VMLS_EQ_F64, []int{2, 1, 0}, "VMLS", "MULSD"}, + {VNMLA_EQ_F32, []int{2, 1, 0}, "VNMLA", "NMULAF"}, + {VNMLA_EQ_F64, []int{2, 1, 0}, "VNMLA", "NMULAD"}, + {VNMLS_EQ_F32, []int{2, 1, 0}, "VNMLS", "NMULSF"}, + {VNMLS_EQ_F64, []int{2, 1, 0}, "VNMLS", "NMULSD"}, + {VDIV_EQ_F32, []int{2, 1, 0}, "VDIV", "DIVF"}, + {VDIV_EQ_F64, []int{2, 1, 0}, "VDIV", "DIVD"}, + {VNEG_EQ_F32, []int{1, 0}, "VNEG", "NEGF"}, + {VNEG_EQ_F64, []int{1, 0}, "VNEG", "NEGD"}, + {VABS_EQ_F32, []int{1, 0}, "VABS", "ABSF"}, + {VABS_EQ_F64, []int{1, 0}, "VABS", "ABSD"}, + {VSQRT_EQ_F32, []int{1, 0}, "VSQRT", "SQRTF"}, + {VSQRT_EQ_F64, []int{1, 0}, "VSQRT", "SQRTD"}, + {VCMP_EQ_F32, []int{1, 0}, "VCMP", "CMPF"}, + {VCMP_EQ_F64, []int{1, 0}, "VCMP", "CMPD"}, + {VCMP_E_EQ_F32, []int{1, 0}, "VCMP.E", "CMPF"}, + {VCMP_E_EQ_F64, []int{1, 0}, "VCMP.E", "CMPD"}, + {VLDR_EQ, []int{1}, "VLDR", "MOV"}, + {VSTR_EQ, []int{1}, "VSTR", "MOV"}, + {VMOV_EQ_F32, []int{1, 0}, "VMOV", "MOVF"}, + {VMOV_EQ_F64, []int{1, 0}, "VMOV", "MOVD"}, + {VMOV_EQ_32, []int{1, 0}, "VMOV", "MOVW"}, + {VMOV_EQ, []int{1, 0}, "VMOV", "MOVW"}, + {VCVT_EQ_F64_F32, []int{1, 0}, "VCVT", "MOVFD"}, + {VCVT_EQ_F32_F64, []int{1, 0}, "VCVT", "MOVDF"}, + {VCVT_EQ_F32_U32, []int{1, 0}, "VCVT", "MOVWF.U"}, + {VCVT_EQ_F32_S32, []int{1, 0}, "VCVT", "MOVWF"}, + {VCVT_EQ_S32_F32, []int{1, 0}, "VCVT", "MOVFW"}, + {VCVT_EQ_U32_F32, []int{1, 0}, "VCVT", "MOVFW.U"}, + {VCVT_EQ_F64_U32, []int{1, 0}, "VCVT", "MOVWD.U"}, + {VCVT_EQ_F64_S32, []int{1, 0}, "VCVT", "MOVWD"}, + {VCVT_EQ_S32_F64, []int{1, 0}, "VCVT", "MOVDW"}, + {VCVT_EQ_U32_F64, []int{1, 0}, "VCVT", "MOVDW.U"}, +} + +// convert FP instructions from GNU syntax to Plan 9 syntax, for example, +// vadd.f32 s0, s3, s4 -> ADDF F0, S3, F2 +// vsub.f64 d0, d2, d4 -> SUBD F0, F2, F4 +// vldr s2, [r11] -> MOVF (R11), F1 +// inputs: instruction name and arguments in GNU syntax +// return values: corresponding instruction name and arguments in Plan 9 syntax +func fpTrans(inst *Inst, op string, args []string) (string, []string) { + for _, fp := range fpInst { + if inst.Op&^15 == fp.op { + // remove gnu syntax suffixes + op = strings.Replace(op, ".F32", "", -1) + op = strings.Replace(op, ".F64", "", -1) + op = strings.Replace(op, ".S32", "", -1) + op = strings.Replace(op, ".U32", "", -1) + op = strings.Replace(op, ".32", "", -1) + // compose op name + if fp.op == VLDR_EQ || fp.op == VSTR_EQ { + switch { + case strings.HasPrefix(args[fp.transArgs[0]], "D"): + op = "MOVD" + op[len(fp.gnuName):] + case strings.HasPrefix(args[fp.transArgs[0]], "S"): + op = "MOVF" + op[len(fp.gnuName):] + default: + panic(fmt.Sprintf("wrong FP register: %v", inst)) + } + } else { + op = fp.goName + op[len(fp.gnuName):] + } + // transform registers + for ix, ri := range fp.transArgs { + switch { + case strings.HasSuffix(args[ri], "[1]"): // MOVW Rx, Dy[1] + break + case strings.HasSuffix(args[ri], "[0]"): // Dx[0] -> Fx + args[ri] = strings.Replace(args[ri], "[0]", "", -1) + fallthrough + case strings.HasPrefix(args[ri], "D"): // Dx -> Fx + args[ri] = "F" + args[ri][1:] + case strings.HasPrefix(args[ri], "S"): + if inst.Args[ix].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even + args[ri] = fmt.Sprintf("F%d", (inst.Args[ix].(Reg)-S0)/2) + } + case strings.HasPrefix(args[ri], "$"): // CMPF/CMPD $0, Fx + break + case strings.HasPrefix(args[ri], "R"): // MOVW Rx, Dy[1] + break + default: + panic(fmt.Sprintf("wrong FP register: %v", inst)) + } + } + break + } + } + return op, args +} diff --git a/vendor/golang.org/x/arch/arm/armasm/tables.go b/vendor/golang.org/x/arch/arm/armasm/tables.go new file mode 100644 index 00000000..3ad489e0 --- /dev/null +++ b/vendor/golang.org/x/arch/arm/armasm/tables.go @@ -0,0 +1,9552 @@ +package armasm + +const ( + _ Op = iota + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + ADC_EQ + ADC_NE + ADC_CS + ADC_CC + ADC_MI + ADC_PL + ADC_VS + ADC_VC + ADC_HI + ADC_LS + ADC_GE + ADC_LT + ADC_GT + ADC_LE + ADC + ADC_ZZ + ADC_S_EQ + ADC_S_NE + ADC_S_CS + ADC_S_CC + ADC_S_MI + ADC_S_PL + ADC_S_VS + ADC_S_VC + ADC_S_HI + ADC_S_LS + ADC_S_GE + ADC_S_LT + ADC_S_GT + ADC_S_LE + ADC_S + ADC_S_ZZ + ADD_EQ + ADD_NE + ADD_CS + ADD_CC + ADD_MI + ADD_PL + ADD_VS + ADD_VC + ADD_HI + ADD_LS + ADD_GE + ADD_LT + ADD_GT + ADD_LE + ADD + ADD_ZZ + ADD_S_EQ + ADD_S_NE + ADD_S_CS + ADD_S_CC + ADD_S_MI + ADD_S_PL + ADD_S_VS + ADD_S_VC + ADD_S_HI + ADD_S_LS + ADD_S_GE + ADD_S_LT + ADD_S_GT + ADD_S_LE + ADD_S + ADD_S_ZZ + AND_EQ + AND_NE + AND_CS + AND_CC + AND_MI + AND_PL + AND_VS + AND_VC + AND_HI + AND_LS + AND_GE + AND_LT + AND_GT + AND_LE + AND + AND_ZZ + AND_S_EQ + AND_S_NE + AND_S_CS + AND_S_CC + AND_S_MI + AND_S_PL + AND_S_VS + AND_S_VC + AND_S_HI + AND_S_LS + AND_S_GE + AND_S_LT + AND_S_GT + AND_S_LE + AND_S + AND_S_ZZ + ASR_EQ + ASR_NE + ASR_CS + ASR_CC + ASR_MI + ASR_PL + ASR_VS + ASR_VC + ASR_HI + ASR_LS + ASR_GE + ASR_LT + ASR_GT + ASR_LE + ASR + ASR_ZZ + ASR_S_EQ + ASR_S_NE + ASR_S_CS + ASR_S_CC + ASR_S_MI + ASR_S_PL + ASR_S_VS + ASR_S_VC + ASR_S_HI + ASR_S_LS + ASR_S_GE + ASR_S_LT + ASR_S_GT + ASR_S_LE + ASR_S + ASR_S_ZZ + B_EQ + B_NE + B_CS + B_CC + B_MI + B_PL + B_VS + B_VC + B_HI + B_LS + B_GE + B_LT + B_GT + B_LE + B + B_ZZ + BFC_EQ + BFC_NE + BFC_CS + BFC_CC + BFC_MI + BFC_PL + BFC_VS + BFC_VC + BFC_HI + BFC_LS + BFC_GE + BFC_LT + BFC_GT + BFC_LE + BFC + BFC_ZZ + BFI_EQ + BFI_NE + BFI_CS + BFI_CC + BFI_MI + BFI_PL + BFI_VS + BFI_VC + BFI_HI + BFI_LS + BFI_GE + BFI_LT + BFI_GT + BFI_LE + BFI + BFI_ZZ + BIC_EQ + BIC_NE + BIC_CS + BIC_CC + BIC_MI + BIC_PL + BIC_VS + BIC_VC + BIC_HI + BIC_LS + BIC_GE + BIC_LT + BIC_GT + BIC_LE + BIC + BIC_ZZ + BIC_S_EQ + BIC_S_NE + BIC_S_CS + BIC_S_CC + BIC_S_MI + BIC_S_PL + BIC_S_VS + BIC_S_VC + BIC_S_HI + BIC_S_LS + BIC_S_GE + BIC_S_LT + BIC_S_GT + BIC_S_LE + BIC_S + BIC_S_ZZ + BKPT_EQ + BKPT_NE + BKPT_CS + BKPT_CC + BKPT_MI + BKPT_PL + BKPT_VS + BKPT_VC + BKPT_HI + BKPT_LS + BKPT_GE + BKPT_LT + BKPT_GT + BKPT_LE + BKPT + BKPT_ZZ + BL_EQ + BL_NE + BL_CS + BL_CC + BL_MI + BL_PL + BL_VS + BL_VC + BL_HI + BL_LS + BL_GE + BL_LT + BL_GT + BL_LE + BL + BL_ZZ + BLX_EQ + BLX_NE + BLX_CS + BLX_CC + BLX_MI + BLX_PL + BLX_VS + BLX_VC + BLX_HI + BLX_LS + BLX_GE + BLX_LT + BLX_GT + BLX_LE + BLX + BLX_ZZ + BX_EQ + BX_NE + BX_CS + BX_CC + BX_MI + BX_PL + BX_VS + BX_VC + BX_HI + BX_LS + BX_GE + BX_LT + BX_GT + BX_LE + BX + BX_ZZ + BXJ_EQ + BXJ_NE + BXJ_CS + BXJ_CC + BXJ_MI + BXJ_PL + BXJ_VS + BXJ_VC + BXJ_HI + BXJ_LS + BXJ_GE + BXJ_LT + BXJ_GT + BXJ_LE + BXJ + BXJ_ZZ + CLREX + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + CLZ_EQ + CLZ_NE + CLZ_CS + CLZ_CC + CLZ_MI + CLZ_PL + CLZ_VS + CLZ_VC + CLZ_HI + CLZ_LS + CLZ_GE + CLZ_LT + CLZ_GT + CLZ_LE + CLZ + CLZ_ZZ + CMN_EQ + CMN_NE + CMN_CS + CMN_CC + CMN_MI + CMN_PL + CMN_VS + CMN_VC + CMN_HI + CMN_LS + CMN_GE + CMN_LT + CMN_GT + CMN_LE + CMN + CMN_ZZ + CMP_EQ + CMP_NE + CMP_CS + CMP_CC + CMP_MI + CMP_PL + CMP_VS + CMP_VC + CMP_HI + CMP_LS + CMP_GE + CMP_LT + CMP_GT + CMP_LE + CMP + CMP_ZZ + DBG_EQ + DBG_NE + DBG_CS + DBG_CC + DBG_MI + DBG_PL + DBG_VS + DBG_VC + DBG_HI + DBG_LS + DBG_GE + DBG_LT + DBG_GT + DBG_LE + DBG + DBG_ZZ + DMB + DSB + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + EOR_EQ + EOR_NE + EOR_CS + EOR_CC + EOR_MI + EOR_PL + EOR_VS + EOR_VC + EOR_HI + EOR_LS + EOR_GE + EOR_LT + EOR_GT + EOR_LE + EOR + EOR_ZZ + EOR_S_EQ + EOR_S_NE + EOR_S_CS + EOR_S_CC + EOR_S_MI + EOR_S_PL + EOR_S_VS + EOR_S_VC + EOR_S_HI + EOR_S_LS + EOR_S_GE + EOR_S_LT + EOR_S_GT + EOR_S_LE + EOR_S + EOR_S_ZZ + ISB + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + LDM_EQ + LDM_NE + LDM_CS + LDM_CC + LDM_MI + LDM_PL + LDM_VS + LDM_VC + LDM_HI + LDM_LS + LDM_GE + LDM_LT + LDM_GT + LDM_LE + LDM + LDM_ZZ + LDMDA_EQ + LDMDA_NE + LDMDA_CS + LDMDA_CC + LDMDA_MI + LDMDA_PL + LDMDA_VS + LDMDA_VC + LDMDA_HI + LDMDA_LS + LDMDA_GE + LDMDA_LT + LDMDA_GT + LDMDA_LE + LDMDA + LDMDA_ZZ + LDMDB_EQ + LDMDB_NE + LDMDB_CS + LDMDB_CC + LDMDB_MI + LDMDB_PL + LDMDB_VS + LDMDB_VC + LDMDB_HI + LDMDB_LS + LDMDB_GE + LDMDB_LT + LDMDB_GT + LDMDB_LE + LDMDB + LDMDB_ZZ + LDMIB_EQ + LDMIB_NE + LDMIB_CS + LDMIB_CC + LDMIB_MI + LDMIB_PL + LDMIB_VS + LDMIB_VC + LDMIB_HI + LDMIB_LS + LDMIB_GE + LDMIB_LT + LDMIB_GT + LDMIB_LE + LDMIB + LDMIB_ZZ + LDR_EQ + LDR_NE + LDR_CS + LDR_CC + LDR_MI + LDR_PL + LDR_VS + LDR_VC + LDR_HI + LDR_LS + LDR_GE + LDR_LT + LDR_GT + LDR_LE + LDR + LDR_ZZ + LDRB_EQ + LDRB_NE + LDRB_CS + LDRB_CC + LDRB_MI + LDRB_PL + LDRB_VS + LDRB_VC + LDRB_HI + LDRB_LS + LDRB_GE + LDRB_LT + LDRB_GT + LDRB_LE + LDRB + LDRB_ZZ + LDRBT_EQ + LDRBT_NE + LDRBT_CS + LDRBT_CC + LDRBT_MI + LDRBT_PL + LDRBT_VS + LDRBT_VC + LDRBT_HI + LDRBT_LS + LDRBT_GE + LDRBT_LT + LDRBT_GT + LDRBT_LE + LDRBT + LDRBT_ZZ + LDRD_EQ + LDRD_NE + LDRD_CS + LDRD_CC + LDRD_MI + LDRD_PL + LDRD_VS + LDRD_VC + LDRD_HI + LDRD_LS + LDRD_GE + LDRD_LT + LDRD_GT + LDRD_LE + LDRD + LDRD_ZZ + LDREX_EQ + LDREX_NE + LDREX_CS + LDREX_CC + LDREX_MI + LDREX_PL + LDREX_VS + LDREX_VC + LDREX_HI + LDREX_LS + LDREX_GE + LDREX_LT + LDREX_GT + LDREX_LE + LDREX + LDREX_ZZ + LDREXB_EQ + LDREXB_NE + LDREXB_CS + LDREXB_CC + LDREXB_MI + LDREXB_PL + LDREXB_VS + LDREXB_VC + LDREXB_HI + LDREXB_LS + LDREXB_GE + LDREXB_LT + LDREXB_GT + LDREXB_LE + LDREXB + LDREXB_ZZ + LDREXD_EQ + LDREXD_NE + LDREXD_CS + LDREXD_CC + LDREXD_MI + LDREXD_PL + LDREXD_VS + LDREXD_VC + LDREXD_HI + LDREXD_LS + LDREXD_GE + LDREXD_LT + LDREXD_GT + LDREXD_LE + LDREXD + LDREXD_ZZ + LDREXH_EQ + LDREXH_NE + LDREXH_CS + LDREXH_CC + LDREXH_MI + LDREXH_PL + LDREXH_VS + LDREXH_VC + LDREXH_HI + LDREXH_LS + LDREXH_GE + LDREXH_LT + LDREXH_GT + LDREXH_LE + LDREXH + LDREXH_ZZ + LDRH_EQ + LDRH_NE + LDRH_CS + LDRH_CC + LDRH_MI + LDRH_PL + LDRH_VS + LDRH_VC + LDRH_HI + LDRH_LS + LDRH_GE + LDRH_LT + LDRH_GT + LDRH_LE + LDRH + LDRH_ZZ + LDRHT_EQ + LDRHT_NE + LDRHT_CS + LDRHT_CC + LDRHT_MI + LDRHT_PL + LDRHT_VS + LDRHT_VC + LDRHT_HI + LDRHT_LS + LDRHT_GE + LDRHT_LT + LDRHT_GT + LDRHT_LE + LDRHT + LDRHT_ZZ + LDRSB_EQ + LDRSB_NE + LDRSB_CS + LDRSB_CC + LDRSB_MI + LDRSB_PL + LDRSB_VS + LDRSB_VC + LDRSB_HI + LDRSB_LS + LDRSB_GE + LDRSB_LT + LDRSB_GT + LDRSB_LE + LDRSB + LDRSB_ZZ + LDRSBT_EQ + LDRSBT_NE + LDRSBT_CS + LDRSBT_CC + LDRSBT_MI + LDRSBT_PL + LDRSBT_VS + LDRSBT_VC + LDRSBT_HI + LDRSBT_LS + LDRSBT_GE + LDRSBT_LT + LDRSBT_GT + LDRSBT_LE + LDRSBT + LDRSBT_ZZ + LDRSH_EQ + LDRSH_NE + LDRSH_CS + LDRSH_CC + LDRSH_MI + LDRSH_PL + LDRSH_VS + LDRSH_VC + LDRSH_HI + LDRSH_LS + LDRSH_GE + LDRSH_LT + LDRSH_GT + LDRSH_LE + LDRSH + LDRSH_ZZ + LDRSHT_EQ + LDRSHT_NE + LDRSHT_CS + LDRSHT_CC + LDRSHT_MI + LDRSHT_PL + LDRSHT_VS + LDRSHT_VC + LDRSHT_HI + LDRSHT_LS + LDRSHT_GE + LDRSHT_LT + LDRSHT_GT + LDRSHT_LE + LDRSHT + LDRSHT_ZZ + LDRT_EQ + LDRT_NE + LDRT_CS + LDRT_CC + LDRT_MI + LDRT_PL + LDRT_VS + LDRT_VC + LDRT_HI + LDRT_LS + LDRT_GE + LDRT_LT + LDRT_GT + LDRT_LE + LDRT + LDRT_ZZ + LSL_EQ + LSL_NE + LSL_CS + LSL_CC + LSL_MI + LSL_PL + LSL_VS + LSL_VC + LSL_HI + LSL_LS + LSL_GE + LSL_LT + LSL_GT + LSL_LE + LSL + LSL_ZZ + LSL_S_EQ + LSL_S_NE + LSL_S_CS + LSL_S_CC + LSL_S_MI + LSL_S_PL + LSL_S_VS + LSL_S_VC + LSL_S_HI + LSL_S_LS + LSL_S_GE + LSL_S_LT + LSL_S_GT + LSL_S_LE + LSL_S + LSL_S_ZZ + LSR_EQ + LSR_NE + LSR_CS + LSR_CC + LSR_MI + LSR_PL + LSR_VS + LSR_VC + LSR_HI + LSR_LS + LSR_GE + LSR_LT + LSR_GT + LSR_LE + LSR + LSR_ZZ + LSR_S_EQ + LSR_S_NE + LSR_S_CS + LSR_S_CC + LSR_S_MI + LSR_S_PL + LSR_S_VS + LSR_S_VC + LSR_S_HI + LSR_S_LS + LSR_S_GE + LSR_S_LT + LSR_S_GT + LSR_S_LE + LSR_S + LSR_S_ZZ + MLA_EQ + MLA_NE + MLA_CS + MLA_CC + MLA_MI + MLA_PL + MLA_VS + MLA_VC + MLA_HI + MLA_LS + MLA_GE + MLA_LT + MLA_GT + MLA_LE + MLA + MLA_ZZ + MLA_S_EQ + MLA_S_NE + MLA_S_CS + MLA_S_CC + MLA_S_MI + MLA_S_PL + MLA_S_VS + MLA_S_VC + MLA_S_HI + MLA_S_LS + MLA_S_GE + MLA_S_LT + MLA_S_GT + MLA_S_LE + MLA_S + MLA_S_ZZ + MLS_EQ + MLS_NE + MLS_CS + MLS_CC + MLS_MI + MLS_PL + MLS_VS + MLS_VC + MLS_HI + MLS_LS + MLS_GE + MLS_LT + MLS_GT + MLS_LE + MLS + MLS_ZZ + MOV_EQ + MOV_NE + MOV_CS + MOV_CC + MOV_MI + MOV_PL + MOV_VS + MOV_VC + MOV_HI + MOV_LS + MOV_GE + MOV_LT + MOV_GT + MOV_LE + MOV + MOV_ZZ + MOV_S_EQ + MOV_S_NE + MOV_S_CS + MOV_S_CC + MOV_S_MI + MOV_S_PL + MOV_S_VS + MOV_S_VC + MOV_S_HI + MOV_S_LS + MOV_S_GE + MOV_S_LT + MOV_S_GT + MOV_S_LE + MOV_S + MOV_S_ZZ + MOVT_EQ + MOVT_NE + MOVT_CS + MOVT_CC + MOVT_MI + MOVT_PL + MOVT_VS + MOVT_VC + MOVT_HI + MOVT_LS + MOVT_GE + MOVT_LT + MOVT_GT + MOVT_LE + MOVT + MOVT_ZZ + MOVW_EQ + MOVW_NE + MOVW_CS + MOVW_CC + MOVW_MI + MOVW_PL + MOVW_VS + MOVW_VC + MOVW_HI + MOVW_LS + MOVW_GE + MOVW_LT + MOVW_GT + MOVW_LE + MOVW + MOVW_ZZ + MRS_EQ + MRS_NE + MRS_CS + MRS_CC + MRS_MI + MRS_PL + MRS_VS + MRS_VC + MRS_HI + MRS_LS + MRS_GE + MRS_LT + MRS_GT + MRS_LE + MRS + MRS_ZZ + MSR_EQ + MSR_NE + MSR_CS + MSR_CC + MSR_MI + MSR_PL + MSR_VS + MSR_VC + MSR_HI + MSR_LS + MSR_GE + MSR_LT + MSR_GT + MSR_LE + MSR + MSR_ZZ + MUL_EQ + MUL_NE + MUL_CS + MUL_CC + MUL_MI + MUL_PL + MUL_VS + MUL_VC + MUL_HI + MUL_LS + MUL_GE + MUL_LT + MUL_GT + MUL_LE + MUL + MUL_ZZ + MUL_S_EQ + MUL_S_NE + MUL_S_CS + MUL_S_CC + MUL_S_MI + MUL_S_PL + MUL_S_VS + MUL_S_VC + MUL_S_HI + MUL_S_LS + MUL_S_GE + MUL_S_LT + MUL_S_GT + MUL_S_LE + MUL_S + MUL_S_ZZ + MVN_EQ + MVN_NE + MVN_CS + MVN_CC + MVN_MI + MVN_PL + MVN_VS + MVN_VC + MVN_HI + MVN_LS + MVN_GE + MVN_LT + MVN_GT + MVN_LE + MVN + MVN_ZZ + MVN_S_EQ + MVN_S_NE + MVN_S_CS + MVN_S_CC + MVN_S_MI + MVN_S_PL + MVN_S_VS + MVN_S_VC + MVN_S_HI + MVN_S_LS + MVN_S_GE + MVN_S_LT + MVN_S_GT + MVN_S_LE + MVN_S + MVN_S_ZZ + NOP_EQ + NOP_NE + NOP_CS + NOP_CC + NOP_MI + NOP_PL + NOP_VS + NOP_VC + NOP_HI + NOP_LS + NOP_GE + NOP_LT + NOP_GT + NOP_LE + NOP + NOP_ZZ + ORR_EQ + ORR_NE + ORR_CS + ORR_CC + ORR_MI + ORR_PL + ORR_VS + ORR_VC + ORR_HI + ORR_LS + ORR_GE + ORR_LT + ORR_GT + ORR_LE + ORR + ORR_ZZ + ORR_S_EQ + ORR_S_NE + ORR_S_CS + ORR_S_CC + ORR_S_MI + ORR_S_PL + ORR_S_VS + ORR_S_VC + ORR_S_HI + ORR_S_LS + ORR_S_GE + ORR_S_LT + ORR_S_GT + ORR_S_LE + ORR_S + ORR_S_ZZ + PKHBT_EQ + PKHBT_NE + PKHBT_CS + PKHBT_CC + PKHBT_MI + PKHBT_PL + PKHBT_VS + PKHBT_VC + PKHBT_HI + PKHBT_LS + PKHBT_GE + PKHBT_LT + PKHBT_GT + PKHBT_LE + PKHBT + PKHBT_ZZ + PKHTB_EQ + PKHTB_NE + PKHTB_CS + PKHTB_CC + PKHTB_MI + PKHTB_PL + PKHTB_VS + PKHTB_VC + PKHTB_HI + PKHTB_LS + PKHTB_GE + PKHTB_LT + PKHTB_GT + PKHTB_LE + PKHTB + PKHTB_ZZ + PLD_W + PLD + PLI + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + POP_EQ + POP_NE + POP_CS + POP_CC + POP_MI + POP_PL + POP_VS + POP_VC + POP_HI + POP_LS + POP_GE + POP_LT + POP_GT + POP_LE + POP + POP_ZZ + PUSH_EQ + PUSH_NE + PUSH_CS + PUSH_CC + PUSH_MI + PUSH_PL + PUSH_VS + PUSH_VC + PUSH_HI + PUSH_LS + PUSH_GE + PUSH_LT + PUSH_GT + PUSH_LE + PUSH + PUSH_ZZ + QADD_EQ + QADD_NE + QADD_CS + QADD_CC + QADD_MI + QADD_PL + QADD_VS + QADD_VC + QADD_HI + QADD_LS + QADD_GE + QADD_LT + QADD_GT + QADD_LE + QADD + QADD_ZZ + QADD16_EQ + QADD16_NE + QADD16_CS + QADD16_CC + QADD16_MI + QADD16_PL + QADD16_VS + QADD16_VC + QADD16_HI + QADD16_LS + QADD16_GE + QADD16_LT + QADD16_GT + QADD16_LE + QADD16 + QADD16_ZZ + QADD8_EQ + QADD8_NE + QADD8_CS + QADD8_CC + QADD8_MI + QADD8_PL + QADD8_VS + QADD8_VC + QADD8_HI + QADD8_LS + QADD8_GE + QADD8_LT + QADD8_GT + QADD8_LE + QADD8 + QADD8_ZZ + QASX_EQ + QASX_NE + QASX_CS + QASX_CC + QASX_MI + QASX_PL + QASX_VS + QASX_VC + QASX_HI + QASX_LS + QASX_GE + QASX_LT + QASX_GT + QASX_LE + QASX + QASX_ZZ + QDADD_EQ + QDADD_NE + QDADD_CS + QDADD_CC + QDADD_MI + QDADD_PL + QDADD_VS + QDADD_VC + QDADD_HI + QDADD_LS + QDADD_GE + QDADD_LT + QDADD_GT + QDADD_LE + QDADD + QDADD_ZZ + QDSUB_EQ + QDSUB_NE + QDSUB_CS + QDSUB_CC + QDSUB_MI + QDSUB_PL + QDSUB_VS + QDSUB_VC + QDSUB_HI + QDSUB_LS + QDSUB_GE + QDSUB_LT + QDSUB_GT + QDSUB_LE + QDSUB + QDSUB_ZZ + QSAX_EQ + QSAX_NE + QSAX_CS + QSAX_CC + QSAX_MI + QSAX_PL + QSAX_VS + QSAX_VC + QSAX_HI + QSAX_LS + QSAX_GE + QSAX_LT + QSAX_GT + QSAX_LE + QSAX + QSAX_ZZ + QSUB_EQ + QSUB_NE + QSUB_CS + QSUB_CC + QSUB_MI + QSUB_PL + QSUB_VS + QSUB_VC + QSUB_HI + QSUB_LS + QSUB_GE + QSUB_LT + QSUB_GT + QSUB_LE + QSUB + QSUB_ZZ + QSUB16_EQ + QSUB16_NE + QSUB16_CS + QSUB16_CC + QSUB16_MI + QSUB16_PL + QSUB16_VS + QSUB16_VC + QSUB16_HI + QSUB16_LS + QSUB16_GE + QSUB16_LT + QSUB16_GT + QSUB16_LE + QSUB16 + QSUB16_ZZ + QSUB8_EQ + QSUB8_NE + QSUB8_CS + QSUB8_CC + QSUB8_MI + QSUB8_PL + QSUB8_VS + QSUB8_VC + QSUB8_HI + QSUB8_LS + QSUB8_GE + QSUB8_LT + QSUB8_GT + QSUB8_LE + QSUB8 + QSUB8_ZZ + RBIT_EQ + RBIT_NE + RBIT_CS + RBIT_CC + RBIT_MI + RBIT_PL + RBIT_VS + RBIT_VC + RBIT_HI + RBIT_LS + RBIT_GE + RBIT_LT + RBIT_GT + RBIT_LE + RBIT + RBIT_ZZ + REV_EQ + REV_NE + REV_CS + REV_CC + REV_MI + REV_PL + REV_VS + REV_VC + REV_HI + REV_LS + REV_GE + REV_LT + REV_GT + REV_LE + REV + REV_ZZ + REV16_EQ + REV16_NE + REV16_CS + REV16_CC + REV16_MI + REV16_PL + REV16_VS + REV16_VC + REV16_HI + REV16_LS + REV16_GE + REV16_LT + REV16_GT + REV16_LE + REV16 + REV16_ZZ + REVSH_EQ + REVSH_NE + REVSH_CS + REVSH_CC + REVSH_MI + REVSH_PL + REVSH_VS + REVSH_VC + REVSH_HI + REVSH_LS + REVSH_GE + REVSH_LT + REVSH_GT + REVSH_LE + REVSH + REVSH_ZZ + ROR_EQ + ROR_NE + ROR_CS + ROR_CC + ROR_MI + ROR_PL + ROR_VS + ROR_VC + ROR_HI + ROR_LS + ROR_GE + ROR_LT + ROR_GT + ROR_LE + ROR + ROR_ZZ + ROR_S_EQ + ROR_S_NE + ROR_S_CS + ROR_S_CC + ROR_S_MI + ROR_S_PL + ROR_S_VS + ROR_S_VC + ROR_S_HI + ROR_S_LS + ROR_S_GE + ROR_S_LT + ROR_S_GT + ROR_S_LE + ROR_S + ROR_S_ZZ + RRX_EQ + RRX_NE + RRX_CS + RRX_CC + RRX_MI + RRX_PL + RRX_VS + RRX_VC + RRX_HI + RRX_LS + RRX_GE + RRX_LT + RRX_GT + RRX_LE + RRX + RRX_ZZ + RRX_S_EQ + RRX_S_NE + RRX_S_CS + RRX_S_CC + RRX_S_MI + RRX_S_PL + RRX_S_VS + RRX_S_VC + RRX_S_HI + RRX_S_LS + RRX_S_GE + RRX_S_LT + RRX_S_GT + RRX_S_LE + RRX_S + RRX_S_ZZ + RSB_EQ + RSB_NE + RSB_CS + RSB_CC + RSB_MI + RSB_PL + RSB_VS + RSB_VC + RSB_HI + RSB_LS + RSB_GE + RSB_LT + RSB_GT + RSB_LE + RSB + RSB_ZZ + RSB_S_EQ + RSB_S_NE + RSB_S_CS + RSB_S_CC + RSB_S_MI + RSB_S_PL + RSB_S_VS + RSB_S_VC + RSB_S_HI + RSB_S_LS + RSB_S_GE + RSB_S_LT + RSB_S_GT + RSB_S_LE + RSB_S + RSB_S_ZZ + RSC_EQ + RSC_NE + RSC_CS + RSC_CC + RSC_MI + RSC_PL + RSC_VS + RSC_VC + RSC_HI + RSC_LS + RSC_GE + RSC_LT + RSC_GT + RSC_LE + RSC + RSC_ZZ + RSC_S_EQ + RSC_S_NE + RSC_S_CS + RSC_S_CC + RSC_S_MI + RSC_S_PL + RSC_S_VS + RSC_S_VC + RSC_S_HI + RSC_S_LS + RSC_S_GE + RSC_S_LT + RSC_S_GT + RSC_S_LE + RSC_S + RSC_S_ZZ + SADD16_EQ + SADD16_NE + SADD16_CS + SADD16_CC + SADD16_MI + SADD16_PL + SADD16_VS + SADD16_VC + SADD16_HI + SADD16_LS + SADD16_GE + SADD16_LT + SADD16_GT + SADD16_LE + SADD16 + SADD16_ZZ + SADD8_EQ + SADD8_NE + SADD8_CS + SADD8_CC + SADD8_MI + SADD8_PL + SADD8_VS + SADD8_VC + SADD8_HI + SADD8_LS + SADD8_GE + SADD8_LT + SADD8_GT + SADD8_LE + SADD8 + SADD8_ZZ + SASX_EQ + SASX_NE + SASX_CS + SASX_CC + SASX_MI + SASX_PL + SASX_VS + SASX_VC + SASX_HI + SASX_LS + SASX_GE + SASX_LT + SASX_GT + SASX_LE + SASX + SASX_ZZ + SBC_EQ + SBC_NE + SBC_CS + SBC_CC + SBC_MI + SBC_PL + SBC_VS + SBC_VC + SBC_HI + SBC_LS + SBC_GE + SBC_LT + SBC_GT + SBC_LE + SBC + SBC_ZZ + SBC_S_EQ + SBC_S_NE + SBC_S_CS + SBC_S_CC + SBC_S_MI + SBC_S_PL + SBC_S_VS + SBC_S_VC + SBC_S_HI + SBC_S_LS + SBC_S_GE + SBC_S_LT + SBC_S_GT + SBC_S_LE + SBC_S + SBC_S_ZZ + SBFX_EQ + SBFX_NE + SBFX_CS + SBFX_CC + SBFX_MI + SBFX_PL + SBFX_VS + SBFX_VC + SBFX_HI + SBFX_LS + SBFX_GE + SBFX_LT + SBFX_GT + SBFX_LE + SBFX + SBFX_ZZ + SDIV_EQ + SDIV_NE + SDIV_CS + SDIV_CC + SDIV_MI + SDIV_PL + SDIV_VS + SDIV_VC + SDIV_HI + SDIV_LS + SDIV_GE + SDIV_LT + SDIV_GT + SDIV_LE + SDIV + SDIV_ZZ + SEL_EQ + SEL_NE + SEL_CS + SEL_CC + SEL_MI + SEL_PL + SEL_VS + SEL_VC + SEL_HI + SEL_LS + SEL_GE + SEL_LT + SEL_GT + SEL_LE + SEL + SEL_ZZ + SETEND + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + SEV_EQ + SEV_NE + SEV_CS + SEV_CC + SEV_MI + SEV_PL + SEV_VS + SEV_VC + SEV_HI + SEV_LS + SEV_GE + SEV_LT + SEV_GT + SEV_LE + SEV + SEV_ZZ + SHADD16_EQ + SHADD16_NE + SHADD16_CS + SHADD16_CC + SHADD16_MI + SHADD16_PL + SHADD16_VS + SHADD16_VC + SHADD16_HI + SHADD16_LS + SHADD16_GE + SHADD16_LT + SHADD16_GT + SHADD16_LE + SHADD16 + SHADD16_ZZ + SHADD8_EQ + SHADD8_NE + SHADD8_CS + SHADD8_CC + SHADD8_MI + SHADD8_PL + SHADD8_VS + SHADD8_VC + SHADD8_HI + SHADD8_LS + SHADD8_GE + SHADD8_LT + SHADD8_GT + SHADD8_LE + SHADD8 + SHADD8_ZZ + SHASX_EQ + SHASX_NE + SHASX_CS + SHASX_CC + SHASX_MI + SHASX_PL + SHASX_VS + SHASX_VC + SHASX_HI + SHASX_LS + SHASX_GE + SHASX_LT + SHASX_GT + SHASX_LE + SHASX + SHASX_ZZ + SHSAX_EQ + SHSAX_NE + SHSAX_CS + SHSAX_CC + SHSAX_MI + SHSAX_PL + SHSAX_VS + SHSAX_VC + SHSAX_HI + SHSAX_LS + SHSAX_GE + SHSAX_LT + SHSAX_GT + SHSAX_LE + SHSAX + SHSAX_ZZ + SHSUB16_EQ + SHSUB16_NE + SHSUB16_CS + SHSUB16_CC + SHSUB16_MI + SHSUB16_PL + SHSUB16_VS + SHSUB16_VC + SHSUB16_HI + SHSUB16_LS + SHSUB16_GE + SHSUB16_LT + SHSUB16_GT + SHSUB16_LE + SHSUB16 + SHSUB16_ZZ + SHSUB8_EQ + SHSUB8_NE + SHSUB8_CS + SHSUB8_CC + SHSUB8_MI + SHSUB8_PL + SHSUB8_VS + SHSUB8_VC + SHSUB8_HI + SHSUB8_LS + SHSUB8_GE + SHSUB8_LT + SHSUB8_GT + SHSUB8_LE + SHSUB8 + SHSUB8_ZZ + SMLABB_EQ + SMLABB_NE + SMLABB_CS + SMLABB_CC + SMLABB_MI + SMLABB_PL + SMLABB_VS + SMLABB_VC + SMLABB_HI + SMLABB_LS + SMLABB_GE + SMLABB_LT + SMLABB_GT + SMLABB_LE + SMLABB + SMLABB_ZZ + SMLABT_EQ + SMLABT_NE + SMLABT_CS + SMLABT_CC + SMLABT_MI + SMLABT_PL + SMLABT_VS + SMLABT_VC + SMLABT_HI + SMLABT_LS + SMLABT_GE + SMLABT_LT + SMLABT_GT + SMLABT_LE + SMLABT + SMLABT_ZZ + SMLATB_EQ + SMLATB_NE + SMLATB_CS + SMLATB_CC + SMLATB_MI + SMLATB_PL + SMLATB_VS + SMLATB_VC + SMLATB_HI + SMLATB_LS + SMLATB_GE + SMLATB_LT + SMLATB_GT + SMLATB_LE + SMLATB + SMLATB_ZZ + SMLATT_EQ + SMLATT_NE + SMLATT_CS + SMLATT_CC + SMLATT_MI + SMLATT_PL + SMLATT_VS + SMLATT_VC + SMLATT_HI + SMLATT_LS + SMLATT_GE + SMLATT_LT + SMLATT_GT + SMLATT_LE + SMLATT + SMLATT_ZZ + SMLAD_EQ + SMLAD_NE + SMLAD_CS + SMLAD_CC + SMLAD_MI + SMLAD_PL + SMLAD_VS + SMLAD_VC + SMLAD_HI + SMLAD_LS + SMLAD_GE + SMLAD_LT + SMLAD_GT + SMLAD_LE + SMLAD + SMLAD_ZZ + SMLAD_X_EQ + SMLAD_X_NE + SMLAD_X_CS + SMLAD_X_CC + SMLAD_X_MI + SMLAD_X_PL + SMLAD_X_VS + SMLAD_X_VC + SMLAD_X_HI + SMLAD_X_LS + SMLAD_X_GE + SMLAD_X_LT + SMLAD_X_GT + SMLAD_X_LE + SMLAD_X + SMLAD_X_ZZ + SMLAL_EQ + SMLAL_NE + SMLAL_CS + SMLAL_CC + SMLAL_MI + SMLAL_PL + SMLAL_VS + SMLAL_VC + SMLAL_HI + SMLAL_LS + SMLAL_GE + SMLAL_LT + SMLAL_GT + SMLAL_LE + SMLAL + SMLAL_ZZ + SMLAL_S_EQ + SMLAL_S_NE + SMLAL_S_CS + SMLAL_S_CC + SMLAL_S_MI + SMLAL_S_PL + SMLAL_S_VS + SMLAL_S_VC + SMLAL_S_HI + SMLAL_S_LS + SMLAL_S_GE + SMLAL_S_LT + SMLAL_S_GT + SMLAL_S_LE + SMLAL_S + SMLAL_S_ZZ + SMLALBB_EQ + SMLALBB_NE + SMLALBB_CS + SMLALBB_CC + SMLALBB_MI + SMLALBB_PL + SMLALBB_VS + SMLALBB_VC + SMLALBB_HI + SMLALBB_LS + SMLALBB_GE + SMLALBB_LT + SMLALBB_GT + SMLALBB_LE + SMLALBB + SMLALBB_ZZ + SMLALBT_EQ + SMLALBT_NE + SMLALBT_CS + SMLALBT_CC + SMLALBT_MI + SMLALBT_PL + SMLALBT_VS + SMLALBT_VC + SMLALBT_HI + SMLALBT_LS + SMLALBT_GE + SMLALBT_LT + SMLALBT_GT + SMLALBT_LE + SMLALBT + SMLALBT_ZZ + SMLALTB_EQ + SMLALTB_NE + SMLALTB_CS + SMLALTB_CC + SMLALTB_MI + SMLALTB_PL + SMLALTB_VS + SMLALTB_VC + SMLALTB_HI + SMLALTB_LS + SMLALTB_GE + SMLALTB_LT + SMLALTB_GT + SMLALTB_LE + SMLALTB + SMLALTB_ZZ + SMLALTT_EQ + SMLALTT_NE + SMLALTT_CS + SMLALTT_CC + SMLALTT_MI + SMLALTT_PL + SMLALTT_VS + SMLALTT_VC + SMLALTT_HI + SMLALTT_LS + SMLALTT_GE + SMLALTT_LT + SMLALTT_GT + SMLALTT_LE + SMLALTT + SMLALTT_ZZ + SMLALD_EQ + SMLALD_NE + SMLALD_CS + SMLALD_CC + SMLALD_MI + SMLALD_PL + SMLALD_VS + SMLALD_VC + SMLALD_HI + SMLALD_LS + SMLALD_GE + SMLALD_LT + SMLALD_GT + SMLALD_LE + SMLALD + SMLALD_ZZ + SMLALD_X_EQ + SMLALD_X_NE + SMLALD_X_CS + SMLALD_X_CC + SMLALD_X_MI + SMLALD_X_PL + SMLALD_X_VS + SMLALD_X_VC + SMLALD_X_HI + SMLALD_X_LS + SMLALD_X_GE + SMLALD_X_LT + SMLALD_X_GT + SMLALD_X_LE + SMLALD_X + SMLALD_X_ZZ + SMLAWB_EQ + SMLAWB_NE + SMLAWB_CS + SMLAWB_CC + SMLAWB_MI + SMLAWB_PL + SMLAWB_VS + SMLAWB_VC + SMLAWB_HI + SMLAWB_LS + SMLAWB_GE + SMLAWB_LT + SMLAWB_GT + SMLAWB_LE + SMLAWB + SMLAWB_ZZ + SMLAWT_EQ + SMLAWT_NE + SMLAWT_CS + SMLAWT_CC + SMLAWT_MI + SMLAWT_PL + SMLAWT_VS + SMLAWT_VC + SMLAWT_HI + SMLAWT_LS + SMLAWT_GE + SMLAWT_LT + SMLAWT_GT + SMLAWT_LE + SMLAWT + SMLAWT_ZZ + SMLSD_EQ + SMLSD_NE + SMLSD_CS + SMLSD_CC + SMLSD_MI + SMLSD_PL + SMLSD_VS + SMLSD_VC + SMLSD_HI + SMLSD_LS + SMLSD_GE + SMLSD_LT + SMLSD_GT + SMLSD_LE + SMLSD + SMLSD_ZZ + SMLSD_X_EQ + SMLSD_X_NE + SMLSD_X_CS + SMLSD_X_CC + SMLSD_X_MI + SMLSD_X_PL + SMLSD_X_VS + SMLSD_X_VC + SMLSD_X_HI + SMLSD_X_LS + SMLSD_X_GE + SMLSD_X_LT + SMLSD_X_GT + SMLSD_X_LE + SMLSD_X + SMLSD_X_ZZ + SMLSLD_EQ + SMLSLD_NE + SMLSLD_CS + SMLSLD_CC + SMLSLD_MI + SMLSLD_PL + SMLSLD_VS + SMLSLD_VC + SMLSLD_HI + SMLSLD_LS + SMLSLD_GE + SMLSLD_LT + SMLSLD_GT + SMLSLD_LE + SMLSLD + SMLSLD_ZZ + SMLSLD_X_EQ + SMLSLD_X_NE + SMLSLD_X_CS + SMLSLD_X_CC + SMLSLD_X_MI + SMLSLD_X_PL + SMLSLD_X_VS + SMLSLD_X_VC + SMLSLD_X_HI + SMLSLD_X_LS + SMLSLD_X_GE + SMLSLD_X_LT + SMLSLD_X_GT + SMLSLD_X_LE + SMLSLD_X + SMLSLD_X_ZZ + SMMLA_EQ + SMMLA_NE + SMMLA_CS + SMMLA_CC + SMMLA_MI + SMMLA_PL + SMMLA_VS + SMMLA_VC + SMMLA_HI + SMMLA_LS + SMMLA_GE + SMMLA_LT + SMMLA_GT + SMMLA_LE + SMMLA + SMMLA_ZZ + SMMLA_R_EQ + SMMLA_R_NE + SMMLA_R_CS + SMMLA_R_CC + SMMLA_R_MI + SMMLA_R_PL + SMMLA_R_VS + SMMLA_R_VC + SMMLA_R_HI + SMMLA_R_LS + SMMLA_R_GE + SMMLA_R_LT + SMMLA_R_GT + SMMLA_R_LE + SMMLA_R + SMMLA_R_ZZ + SMMLS_EQ + SMMLS_NE + SMMLS_CS + SMMLS_CC + SMMLS_MI + SMMLS_PL + SMMLS_VS + SMMLS_VC + SMMLS_HI + SMMLS_LS + SMMLS_GE + SMMLS_LT + SMMLS_GT + SMMLS_LE + SMMLS + SMMLS_ZZ + SMMLS_R_EQ + SMMLS_R_NE + SMMLS_R_CS + SMMLS_R_CC + SMMLS_R_MI + SMMLS_R_PL + SMMLS_R_VS + SMMLS_R_VC + SMMLS_R_HI + SMMLS_R_LS + SMMLS_R_GE + SMMLS_R_LT + SMMLS_R_GT + SMMLS_R_LE + SMMLS_R + SMMLS_R_ZZ + SMMUL_EQ + SMMUL_NE + SMMUL_CS + SMMUL_CC + SMMUL_MI + SMMUL_PL + SMMUL_VS + SMMUL_VC + SMMUL_HI + SMMUL_LS + SMMUL_GE + SMMUL_LT + SMMUL_GT + SMMUL_LE + SMMUL + SMMUL_ZZ + SMMUL_R_EQ + SMMUL_R_NE + SMMUL_R_CS + SMMUL_R_CC + SMMUL_R_MI + SMMUL_R_PL + SMMUL_R_VS + SMMUL_R_VC + SMMUL_R_HI + SMMUL_R_LS + SMMUL_R_GE + SMMUL_R_LT + SMMUL_R_GT + SMMUL_R_LE + SMMUL_R + SMMUL_R_ZZ + SMUAD_EQ + SMUAD_NE + SMUAD_CS + SMUAD_CC + SMUAD_MI + SMUAD_PL + SMUAD_VS + SMUAD_VC + SMUAD_HI + SMUAD_LS + SMUAD_GE + SMUAD_LT + SMUAD_GT + SMUAD_LE + SMUAD + SMUAD_ZZ + SMUAD_X_EQ + SMUAD_X_NE + SMUAD_X_CS + SMUAD_X_CC + SMUAD_X_MI + SMUAD_X_PL + SMUAD_X_VS + SMUAD_X_VC + SMUAD_X_HI + SMUAD_X_LS + SMUAD_X_GE + SMUAD_X_LT + SMUAD_X_GT + SMUAD_X_LE + SMUAD_X + SMUAD_X_ZZ + SMULBB_EQ + SMULBB_NE + SMULBB_CS + SMULBB_CC + SMULBB_MI + SMULBB_PL + SMULBB_VS + SMULBB_VC + SMULBB_HI + SMULBB_LS + SMULBB_GE + SMULBB_LT + SMULBB_GT + SMULBB_LE + SMULBB + SMULBB_ZZ + SMULBT_EQ + SMULBT_NE + SMULBT_CS + SMULBT_CC + SMULBT_MI + SMULBT_PL + SMULBT_VS + SMULBT_VC + SMULBT_HI + SMULBT_LS + SMULBT_GE + SMULBT_LT + SMULBT_GT + SMULBT_LE + SMULBT + SMULBT_ZZ + SMULTB_EQ + SMULTB_NE + SMULTB_CS + SMULTB_CC + SMULTB_MI + SMULTB_PL + SMULTB_VS + SMULTB_VC + SMULTB_HI + SMULTB_LS + SMULTB_GE + SMULTB_LT + SMULTB_GT + SMULTB_LE + SMULTB + SMULTB_ZZ + SMULTT_EQ + SMULTT_NE + SMULTT_CS + SMULTT_CC + SMULTT_MI + SMULTT_PL + SMULTT_VS + SMULTT_VC + SMULTT_HI + SMULTT_LS + SMULTT_GE + SMULTT_LT + SMULTT_GT + SMULTT_LE + SMULTT + SMULTT_ZZ + SMULL_EQ + SMULL_NE + SMULL_CS + SMULL_CC + SMULL_MI + SMULL_PL + SMULL_VS + SMULL_VC + SMULL_HI + SMULL_LS + SMULL_GE + SMULL_LT + SMULL_GT + SMULL_LE + SMULL + SMULL_ZZ + SMULL_S_EQ + SMULL_S_NE + SMULL_S_CS + SMULL_S_CC + SMULL_S_MI + SMULL_S_PL + SMULL_S_VS + SMULL_S_VC + SMULL_S_HI + SMULL_S_LS + SMULL_S_GE + SMULL_S_LT + SMULL_S_GT + SMULL_S_LE + SMULL_S + SMULL_S_ZZ + SMULWB_EQ + SMULWB_NE + SMULWB_CS + SMULWB_CC + SMULWB_MI + SMULWB_PL + SMULWB_VS + SMULWB_VC + SMULWB_HI + SMULWB_LS + SMULWB_GE + SMULWB_LT + SMULWB_GT + SMULWB_LE + SMULWB + SMULWB_ZZ + SMULWT_EQ + SMULWT_NE + SMULWT_CS + SMULWT_CC + SMULWT_MI + SMULWT_PL + SMULWT_VS + SMULWT_VC + SMULWT_HI + SMULWT_LS + SMULWT_GE + SMULWT_LT + SMULWT_GT + SMULWT_LE + SMULWT + SMULWT_ZZ + SMUSD_EQ + SMUSD_NE + SMUSD_CS + SMUSD_CC + SMUSD_MI + SMUSD_PL + SMUSD_VS + SMUSD_VC + SMUSD_HI + SMUSD_LS + SMUSD_GE + SMUSD_LT + SMUSD_GT + SMUSD_LE + SMUSD + SMUSD_ZZ + SMUSD_X_EQ + SMUSD_X_NE + SMUSD_X_CS + SMUSD_X_CC + SMUSD_X_MI + SMUSD_X_PL + SMUSD_X_VS + SMUSD_X_VC + SMUSD_X_HI + SMUSD_X_LS + SMUSD_X_GE + SMUSD_X_LT + SMUSD_X_GT + SMUSD_X_LE + SMUSD_X + SMUSD_X_ZZ + SSAT_EQ + SSAT_NE + SSAT_CS + SSAT_CC + SSAT_MI + SSAT_PL + SSAT_VS + SSAT_VC + SSAT_HI + SSAT_LS + SSAT_GE + SSAT_LT + SSAT_GT + SSAT_LE + SSAT + SSAT_ZZ + SSAT16_EQ + SSAT16_NE + SSAT16_CS + SSAT16_CC + SSAT16_MI + SSAT16_PL + SSAT16_VS + SSAT16_VC + SSAT16_HI + SSAT16_LS + SSAT16_GE + SSAT16_LT + SSAT16_GT + SSAT16_LE + SSAT16 + SSAT16_ZZ + SSAX_EQ + SSAX_NE + SSAX_CS + SSAX_CC + SSAX_MI + SSAX_PL + SSAX_VS + SSAX_VC + SSAX_HI + SSAX_LS + SSAX_GE + SSAX_LT + SSAX_GT + SSAX_LE + SSAX + SSAX_ZZ + SSUB16_EQ + SSUB16_NE + SSUB16_CS + SSUB16_CC + SSUB16_MI + SSUB16_PL + SSUB16_VS + SSUB16_VC + SSUB16_HI + SSUB16_LS + SSUB16_GE + SSUB16_LT + SSUB16_GT + SSUB16_LE + SSUB16 + SSUB16_ZZ + SSUB8_EQ + SSUB8_NE + SSUB8_CS + SSUB8_CC + SSUB8_MI + SSUB8_PL + SSUB8_VS + SSUB8_VC + SSUB8_HI + SSUB8_LS + SSUB8_GE + SSUB8_LT + SSUB8_GT + SSUB8_LE + SSUB8 + SSUB8_ZZ + STM_EQ + STM_NE + STM_CS + STM_CC + STM_MI + STM_PL + STM_VS + STM_VC + STM_HI + STM_LS + STM_GE + STM_LT + STM_GT + STM_LE + STM + STM_ZZ + STMDA_EQ + STMDA_NE + STMDA_CS + STMDA_CC + STMDA_MI + STMDA_PL + STMDA_VS + STMDA_VC + STMDA_HI + STMDA_LS + STMDA_GE + STMDA_LT + STMDA_GT + STMDA_LE + STMDA + STMDA_ZZ + STMDB_EQ + STMDB_NE + STMDB_CS + STMDB_CC + STMDB_MI + STMDB_PL + STMDB_VS + STMDB_VC + STMDB_HI + STMDB_LS + STMDB_GE + STMDB_LT + STMDB_GT + STMDB_LE + STMDB + STMDB_ZZ + STMIB_EQ + STMIB_NE + STMIB_CS + STMIB_CC + STMIB_MI + STMIB_PL + STMIB_VS + STMIB_VC + STMIB_HI + STMIB_LS + STMIB_GE + STMIB_LT + STMIB_GT + STMIB_LE + STMIB + STMIB_ZZ + STR_EQ + STR_NE + STR_CS + STR_CC + STR_MI + STR_PL + STR_VS + STR_VC + STR_HI + STR_LS + STR_GE + STR_LT + STR_GT + STR_LE + STR + STR_ZZ + STRB_EQ + STRB_NE + STRB_CS + STRB_CC + STRB_MI + STRB_PL + STRB_VS + STRB_VC + STRB_HI + STRB_LS + STRB_GE + STRB_LT + STRB_GT + STRB_LE + STRB + STRB_ZZ + STRBT_EQ + STRBT_NE + STRBT_CS + STRBT_CC + STRBT_MI + STRBT_PL + STRBT_VS + STRBT_VC + STRBT_HI + STRBT_LS + STRBT_GE + STRBT_LT + STRBT_GT + STRBT_LE + STRBT + STRBT_ZZ + STRD_EQ + STRD_NE + STRD_CS + STRD_CC + STRD_MI + STRD_PL + STRD_VS + STRD_VC + STRD_HI + STRD_LS + STRD_GE + STRD_LT + STRD_GT + STRD_LE + STRD + STRD_ZZ + STREX_EQ + STREX_NE + STREX_CS + STREX_CC + STREX_MI + STREX_PL + STREX_VS + STREX_VC + STREX_HI + STREX_LS + STREX_GE + STREX_LT + STREX_GT + STREX_LE + STREX + STREX_ZZ + STREXB_EQ + STREXB_NE + STREXB_CS + STREXB_CC + STREXB_MI + STREXB_PL + STREXB_VS + STREXB_VC + STREXB_HI + STREXB_LS + STREXB_GE + STREXB_LT + STREXB_GT + STREXB_LE + STREXB + STREXB_ZZ + STREXD_EQ + STREXD_NE + STREXD_CS + STREXD_CC + STREXD_MI + STREXD_PL + STREXD_VS + STREXD_VC + STREXD_HI + STREXD_LS + STREXD_GE + STREXD_LT + STREXD_GT + STREXD_LE + STREXD + STREXD_ZZ + STREXH_EQ + STREXH_NE + STREXH_CS + STREXH_CC + STREXH_MI + STREXH_PL + STREXH_VS + STREXH_VC + STREXH_HI + STREXH_LS + STREXH_GE + STREXH_LT + STREXH_GT + STREXH_LE + STREXH + STREXH_ZZ + STRH_EQ + STRH_NE + STRH_CS + STRH_CC + STRH_MI + STRH_PL + STRH_VS + STRH_VC + STRH_HI + STRH_LS + STRH_GE + STRH_LT + STRH_GT + STRH_LE + STRH + STRH_ZZ + STRHT_EQ + STRHT_NE + STRHT_CS + STRHT_CC + STRHT_MI + STRHT_PL + STRHT_VS + STRHT_VC + STRHT_HI + STRHT_LS + STRHT_GE + STRHT_LT + STRHT_GT + STRHT_LE + STRHT + STRHT_ZZ + STRT_EQ + STRT_NE + STRT_CS + STRT_CC + STRT_MI + STRT_PL + STRT_VS + STRT_VC + STRT_HI + STRT_LS + STRT_GE + STRT_LT + STRT_GT + STRT_LE + STRT + STRT_ZZ + SUB_EQ + SUB_NE + SUB_CS + SUB_CC + SUB_MI + SUB_PL + SUB_VS + SUB_VC + SUB_HI + SUB_LS + SUB_GE + SUB_LT + SUB_GT + SUB_LE + SUB + SUB_ZZ + SUB_S_EQ + SUB_S_NE + SUB_S_CS + SUB_S_CC + SUB_S_MI + SUB_S_PL + SUB_S_VS + SUB_S_VC + SUB_S_HI + SUB_S_LS + SUB_S_GE + SUB_S_LT + SUB_S_GT + SUB_S_LE + SUB_S + SUB_S_ZZ + SVC_EQ + SVC_NE + SVC_CS + SVC_CC + SVC_MI + SVC_PL + SVC_VS + SVC_VC + SVC_HI + SVC_LS + SVC_GE + SVC_LT + SVC_GT + SVC_LE + SVC + SVC_ZZ + SWP_EQ + SWP_NE + SWP_CS + SWP_CC + SWP_MI + SWP_PL + SWP_VS + SWP_VC + SWP_HI + SWP_LS + SWP_GE + SWP_LT + SWP_GT + SWP_LE + SWP + SWP_ZZ + SWP_B_EQ + SWP_B_NE + SWP_B_CS + SWP_B_CC + SWP_B_MI + SWP_B_PL + SWP_B_VS + SWP_B_VC + SWP_B_HI + SWP_B_LS + SWP_B_GE + SWP_B_LT + SWP_B_GT + SWP_B_LE + SWP_B + SWP_B_ZZ + SXTAB_EQ + SXTAB_NE + SXTAB_CS + SXTAB_CC + SXTAB_MI + SXTAB_PL + SXTAB_VS + SXTAB_VC + SXTAB_HI + SXTAB_LS + SXTAB_GE + SXTAB_LT + SXTAB_GT + SXTAB_LE + SXTAB + SXTAB_ZZ + SXTAB16_EQ + SXTAB16_NE + SXTAB16_CS + SXTAB16_CC + SXTAB16_MI + SXTAB16_PL + SXTAB16_VS + SXTAB16_VC + SXTAB16_HI + SXTAB16_LS + SXTAB16_GE + SXTAB16_LT + SXTAB16_GT + SXTAB16_LE + SXTAB16 + SXTAB16_ZZ + SXTAH_EQ + SXTAH_NE + SXTAH_CS + SXTAH_CC + SXTAH_MI + SXTAH_PL + SXTAH_VS + SXTAH_VC + SXTAH_HI + SXTAH_LS + SXTAH_GE + SXTAH_LT + SXTAH_GT + SXTAH_LE + SXTAH + SXTAH_ZZ + SXTB_EQ + SXTB_NE + SXTB_CS + SXTB_CC + SXTB_MI + SXTB_PL + SXTB_VS + SXTB_VC + SXTB_HI + SXTB_LS + SXTB_GE + SXTB_LT + SXTB_GT + SXTB_LE + SXTB + SXTB_ZZ + SXTB16_EQ + SXTB16_NE + SXTB16_CS + SXTB16_CC + SXTB16_MI + SXTB16_PL + SXTB16_VS + SXTB16_VC + SXTB16_HI + SXTB16_LS + SXTB16_GE + SXTB16_LT + SXTB16_GT + SXTB16_LE + SXTB16 + SXTB16_ZZ + SXTH_EQ + SXTH_NE + SXTH_CS + SXTH_CC + SXTH_MI + SXTH_PL + SXTH_VS + SXTH_VC + SXTH_HI + SXTH_LS + SXTH_GE + SXTH_LT + SXTH_GT + SXTH_LE + SXTH + SXTH_ZZ + TEQ_EQ + TEQ_NE + TEQ_CS + TEQ_CC + TEQ_MI + TEQ_PL + TEQ_VS + TEQ_VC + TEQ_HI + TEQ_LS + TEQ_GE + TEQ_LT + TEQ_GT + TEQ_LE + TEQ + TEQ_ZZ + TST_EQ + TST_NE + TST_CS + TST_CC + TST_MI + TST_PL + TST_VS + TST_VC + TST_HI + TST_LS + TST_GE + TST_LT + TST_GT + TST_LE + TST + TST_ZZ + UADD16_EQ + UADD16_NE + UADD16_CS + UADD16_CC + UADD16_MI + UADD16_PL + UADD16_VS + UADD16_VC + UADD16_HI + UADD16_LS + UADD16_GE + UADD16_LT + UADD16_GT + UADD16_LE + UADD16 + UADD16_ZZ + UADD8_EQ + UADD8_NE + UADD8_CS + UADD8_CC + UADD8_MI + UADD8_PL + UADD8_VS + UADD8_VC + UADD8_HI + UADD8_LS + UADD8_GE + UADD8_LT + UADD8_GT + UADD8_LE + UADD8 + UADD8_ZZ + UASX_EQ + UASX_NE + UASX_CS + UASX_CC + UASX_MI + UASX_PL + UASX_VS + UASX_VC + UASX_HI + UASX_LS + UASX_GE + UASX_LT + UASX_GT + UASX_LE + UASX + UASX_ZZ + UBFX_EQ + UBFX_NE + UBFX_CS + UBFX_CC + UBFX_MI + UBFX_PL + UBFX_VS + UBFX_VC + UBFX_HI + UBFX_LS + UBFX_GE + UBFX_LT + UBFX_GT + UBFX_LE + UBFX + UBFX_ZZ + UDIV_EQ + UDIV_NE + UDIV_CS + UDIV_CC + UDIV_MI + UDIV_PL + UDIV_VS + UDIV_VC + UDIV_HI + UDIV_LS + UDIV_GE + UDIV_LT + UDIV_GT + UDIV_LE + UDIV + UDIV_ZZ + UHADD16_EQ + UHADD16_NE + UHADD16_CS + UHADD16_CC + UHADD16_MI + UHADD16_PL + UHADD16_VS + UHADD16_VC + UHADD16_HI + UHADD16_LS + UHADD16_GE + UHADD16_LT + UHADD16_GT + UHADD16_LE + UHADD16 + UHADD16_ZZ + UHADD8_EQ + UHADD8_NE + UHADD8_CS + UHADD8_CC + UHADD8_MI + UHADD8_PL + UHADD8_VS + UHADD8_VC + UHADD8_HI + UHADD8_LS + UHADD8_GE + UHADD8_LT + UHADD8_GT + UHADD8_LE + UHADD8 + UHADD8_ZZ + UHASX_EQ + UHASX_NE + UHASX_CS + UHASX_CC + UHASX_MI + UHASX_PL + UHASX_VS + UHASX_VC + UHASX_HI + UHASX_LS + UHASX_GE + UHASX_LT + UHASX_GT + UHASX_LE + UHASX + UHASX_ZZ + UHSAX_EQ + UHSAX_NE + UHSAX_CS + UHSAX_CC + UHSAX_MI + UHSAX_PL + UHSAX_VS + UHSAX_VC + UHSAX_HI + UHSAX_LS + UHSAX_GE + UHSAX_LT + UHSAX_GT + UHSAX_LE + UHSAX + UHSAX_ZZ + UHSUB16_EQ + UHSUB16_NE + UHSUB16_CS + UHSUB16_CC + UHSUB16_MI + UHSUB16_PL + UHSUB16_VS + UHSUB16_VC + UHSUB16_HI + UHSUB16_LS + UHSUB16_GE + UHSUB16_LT + UHSUB16_GT + UHSUB16_LE + UHSUB16 + UHSUB16_ZZ + UHSUB8_EQ + UHSUB8_NE + UHSUB8_CS + UHSUB8_CC + UHSUB8_MI + UHSUB8_PL + UHSUB8_VS + UHSUB8_VC + UHSUB8_HI + UHSUB8_LS + UHSUB8_GE + UHSUB8_LT + UHSUB8_GT + UHSUB8_LE + UHSUB8 + UHSUB8_ZZ + UMAAL_EQ + UMAAL_NE + UMAAL_CS + UMAAL_CC + UMAAL_MI + UMAAL_PL + UMAAL_VS + UMAAL_VC + UMAAL_HI + UMAAL_LS + UMAAL_GE + UMAAL_LT + UMAAL_GT + UMAAL_LE + UMAAL + UMAAL_ZZ + UMLAL_EQ + UMLAL_NE + UMLAL_CS + UMLAL_CC + UMLAL_MI + UMLAL_PL + UMLAL_VS + UMLAL_VC + UMLAL_HI + UMLAL_LS + UMLAL_GE + UMLAL_LT + UMLAL_GT + UMLAL_LE + UMLAL + UMLAL_ZZ + UMLAL_S_EQ + UMLAL_S_NE + UMLAL_S_CS + UMLAL_S_CC + UMLAL_S_MI + UMLAL_S_PL + UMLAL_S_VS + UMLAL_S_VC + UMLAL_S_HI + UMLAL_S_LS + UMLAL_S_GE + UMLAL_S_LT + UMLAL_S_GT + UMLAL_S_LE + UMLAL_S + UMLAL_S_ZZ + UMULL_EQ + UMULL_NE + UMULL_CS + UMULL_CC + UMULL_MI + UMULL_PL + UMULL_VS + UMULL_VC + UMULL_HI + UMULL_LS + UMULL_GE + UMULL_LT + UMULL_GT + UMULL_LE + UMULL + UMULL_ZZ + UMULL_S_EQ + UMULL_S_NE + UMULL_S_CS + UMULL_S_CC + UMULL_S_MI + UMULL_S_PL + UMULL_S_VS + UMULL_S_VC + UMULL_S_HI + UMULL_S_LS + UMULL_S_GE + UMULL_S_LT + UMULL_S_GT + UMULL_S_LE + UMULL_S + UMULL_S_ZZ + UNDEF + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + UQADD16_EQ + UQADD16_NE + UQADD16_CS + UQADD16_CC + UQADD16_MI + UQADD16_PL + UQADD16_VS + UQADD16_VC + UQADD16_HI + UQADD16_LS + UQADD16_GE + UQADD16_LT + UQADD16_GT + UQADD16_LE + UQADD16 + UQADD16_ZZ + UQADD8_EQ + UQADD8_NE + UQADD8_CS + UQADD8_CC + UQADD8_MI + UQADD8_PL + UQADD8_VS + UQADD8_VC + UQADD8_HI + UQADD8_LS + UQADD8_GE + UQADD8_LT + UQADD8_GT + UQADD8_LE + UQADD8 + UQADD8_ZZ + UQASX_EQ + UQASX_NE + UQASX_CS + UQASX_CC + UQASX_MI + UQASX_PL + UQASX_VS + UQASX_VC + UQASX_HI + UQASX_LS + UQASX_GE + UQASX_LT + UQASX_GT + UQASX_LE + UQASX + UQASX_ZZ + UQSAX_EQ + UQSAX_NE + UQSAX_CS + UQSAX_CC + UQSAX_MI + UQSAX_PL + UQSAX_VS + UQSAX_VC + UQSAX_HI + UQSAX_LS + UQSAX_GE + UQSAX_LT + UQSAX_GT + UQSAX_LE + UQSAX + UQSAX_ZZ + UQSUB16_EQ + UQSUB16_NE + UQSUB16_CS + UQSUB16_CC + UQSUB16_MI + UQSUB16_PL + UQSUB16_VS + UQSUB16_VC + UQSUB16_HI + UQSUB16_LS + UQSUB16_GE + UQSUB16_LT + UQSUB16_GT + UQSUB16_LE + UQSUB16 + UQSUB16_ZZ + UQSUB8_EQ + UQSUB8_NE + UQSUB8_CS + UQSUB8_CC + UQSUB8_MI + UQSUB8_PL + UQSUB8_VS + UQSUB8_VC + UQSUB8_HI + UQSUB8_LS + UQSUB8_GE + UQSUB8_LT + UQSUB8_GT + UQSUB8_LE + UQSUB8 + UQSUB8_ZZ + USAD8_EQ + USAD8_NE + USAD8_CS + USAD8_CC + USAD8_MI + USAD8_PL + USAD8_VS + USAD8_VC + USAD8_HI + USAD8_LS + USAD8_GE + USAD8_LT + USAD8_GT + USAD8_LE + USAD8 + USAD8_ZZ + USADA8_EQ + USADA8_NE + USADA8_CS + USADA8_CC + USADA8_MI + USADA8_PL + USADA8_VS + USADA8_VC + USADA8_HI + USADA8_LS + USADA8_GE + USADA8_LT + USADA8_GT + USADA8_LE + USADA8 + USADA8_ZZ + USAT_EQ + USAT_NE + USAT_CS + USAT_CC + USAT_MI + USAT_PL + USAT_VS + USAT_VC + USAT_HI + USAT_LS + USAT_GE + USAT_LT + USAT_GT + USAT_LE + USAT + USAT_ZZ + USAT16_EQ + USAT16_NE + USAT16_CS + USAT16_CC + USAT16_MI + USAT16_PL + USAT16_VS + USAT16_VC + USAT16_HI + USAT16_LS + USAT16_GE + USAT16_LT + USAT16_GT + USAT16_LE + USAT16 + USAT16_ZZ + USAX_EQ + USAX_NE + USAX_CS + USAX_CC + USAX_MI + USAX_PL + USAX_VS + USAX_VC + USAX_HI + USAX_LS + USAX_GE + USAX_LT + USAX_GT + USAX_LE + USAX + USAX_ZZ + USUB16_EQ + USUB16_NE + USUB16_CS + USUB16_CC + USUB16_MI + USUB16_PL + USUB16_VS + USUB16_VC + USUB16_HI + USUB16_LS + USUB16_GE + USUB16_LT + USUB16_GT + USUB16_LE + USUB16 + USUB16_ZZ + USUB8_EQ + USUB8_NE + USUB8_CS + USUB8_CC + USUB8_MI + USUB8_PL + USUB8_VS + USUB8_VC + USUB8_HI + USUB8_LS + USUB8_GE + USUB8_LT + USUB8_GT + USUB8_LE + USUB8 + USUB8_ZZ + UXTAB_EQ + UXTAB_NE + UXTAB_CS + UXTAB_CC + UXTAB_MI + UXTAB_PL + UXTAB_VS + UXTAB_VC + UXTAB_HI + UXTAB_LS + UXTAB_GE + UXTAB_LT + UXTAB_GT + UXTAB_LE + UXTAB + UXTAB_ZZ + UXTAB16_EQ + UXTAB16_NE + UXTAB16_CS + UXTAB16_CC + UXTAB16_MI + UXTAB16_PL + UXTAB16_VS + UXTAB16_VC + UXTAB16_HI + UXTAB16_LS + UXTAB16_GE + UXTAB16_LT + UXTAB16_GT + UXTAB16_LE + UXTAB16 + UXTAB16_ZZ + UXTAH_EQ + UXTAH_NE + UXTAH_CS + UXTAH_CC + UXTAH_MI + UXTAH_PL + UXTAH_VS + UXTAH_VC + UXTAH_HI + UXTAH_LS + UXTAH_GE + UXTAH_LT + UXTAH_GT + UXTAH_LE + UXTAH + UXTAH_ZZ + UXTB_EQ + UXTB_NE + UXTB_CS + UXTB_CC + UXTB_MI + UXTB_PL + UXTB_VS + UXTB_VC + UXTB_HI + UXTB_LS + UXTB_GE + UXTB_LT + UXTB_GT + UXTB_LE + UXTB + UXTB_ZZ + UXTB16_EQ + UXTB16_NE + UXTB16_CS + UXTB16_CC + UXTB16_MI + UXTB16_PL + UXTB16_VS + UXTB16_VC + UXTB16_HI + UXTB16_LS + UXTB16_GE + UXTB16_LT + UXTB16_GT + UXTB16_LE + UXTB16 + UXTB16_ZZ + UXTH_EQ + UXTH_NE + UXTH_CS + UXTH_CC + UXTH_MI + UXTH_PL + UXTH_VS + UXTH_VC + UXTH_HI + UXTH_LS + UXTH_GE + UXTH_LT + UXTH_GT + UXTH_LE + UXTH + UXTH_ZZ + VABS_EQ_F32 + VABS_NE_F32 + VABS_CS_F32 + VABS_CC_F32 + VABS_MI_F32 + VABS_PL_F32 + VABS_VS_F32 + VABS_VC_F32 + VABS_HI_F32 + VABS_LS_F32 + VABS_GE_F32 + VABS_LT_F32 + VABS_GT_F32 + VABS_LE_F32 + VABS_F32 + VABS_ZZ_F32 + VABS_EQ_F64 + VABS_NE_F64 + VABS_CS_F64 + VABS_CC_F64 + VABS_MI_F64 + VABS_PL_F64 + VABS_VS_F64 + VABS_VC_F64 + VABS_HI_F64 + VABS_LS_F64 + VABS_GE_F64 + VABS_LT_F64 + VABS_GT_F64 + VABS_LE_F64 + VABS_F64 + VABS_ZZ_F64 + VADD_EQ_F32 + VADD_NE_F32 + VADD_CS_F32 + VADD_CC_F32 + VADD_MI_F32 + VADD_PL_F32 + VADD_VS_F32 + VADD_VC_F32 + VADD_HI_F32 + VADD_LS_F32 + VADD_GE_F32 + VADD_LT_F32 + VADD_GT_F32 + VADD_LE_F32 + VADD_F32 + VADD_ZZ_F32 + VADD_EQ_F64 + VADD_NE_F64 + VADD_CS_F64 + VADD_CC_F64 + VADD_MI_F64 + VADD_PL_F64 + VADD_VS_F64 + VADD_VC_F64 + VADD_HI_F64 + VADD_LS_F64 + VADD_GE_F64 + VADD_LT_F64 + VADD_GT_F64 + VADD_LE_F64 + VADD_F64 + VADD_ZZ_F64 + VCMP_EQ_F32 + VCMP_NE_F32 + VCMP_CS_F32 + VCMP_CC_F32 + VCMP_MI_F32 + VCMP_PL_F32 + VCMP_VS_F32 + VCMP_VC_F32 + VCMP_HI_F32 + VCMP_LS_F32 + VCMP_GE_F32 + VCMP_LT_F32 + VCMP_GT_F32 + VCMP_LE_F32 + VCMP_F32 + VCMP_ZZ_F32 + VCMP_EQ_F64 + VCMP_NE_F64 + VCMP_CS_F64 + VCMP_CC_F64 + VCMP_MI_F64 + VCMP_PL_F64 + VCMP_VS_F64 + VCMP_VC_F64 + VCMP_HI_F64 + VCMP_LS_F64 + VCMP_GE_F64 + VCMP_LT_F64 + VCMP_GT_F64 + VCMP_LE_F64 + VCMP_F64 + VCMP_ZZ_F64 + VCMP_E_EQ_F32 + VCMP_E_NE_F32 + VCMP_E_CS_F32 + VCMP_E_CC_F32 + VCMP_E_MI_F32 + VCMP_E_PL_F32 + VCMP_E_VS_F32 + VCMP_E_VC_F32 + VCMP_E_HI_F32 + VCMP_E_LS_F32 + VCMP_E_GE_F32 + VCMP_E_LT_F32 + VCMP_E_GT_F32 + VCMP_E_LE_F32 + VCMP_E_F32 + VCMP_E_ZZ_F32 + VCMP_E_EQ_F64 + VCMP_E_NE_F64 + VCMP_E_CS_F64 + VCMP_E_CC_F64 + VCMP_E_MI_F64 + VCMP_E_PL_F64 + VCMP_E_VS_F64 + VCMP_E_VC_F64 + VCMP_E_HI_F64 + VCMP_E_LS_F64 + VCMP_E_GE_F64 + VCMP_E_LT_F64 + VCMP_E_GT_F64 + VCMP_E_LE_F64 + VCMP_E_F64 + VCMP_E_ZZ_F64 + VCVT_EQ_F32_FXS16 + VCVT_NE_F32_FXS16 + VCVT_CS_F32_FXS16 + VCVT_CC_F32_FXS16 + VCVT_MI_F32_FXS16 + VCVT_PL_F32_FXS16 + VCVT_VS_F32_FXS16 + VCVT_VC_F32_FXS16 + VCVT_HI_F32_FXS16 + VCVT_LS_F32_FXS16 + VCVT_GE_F32_FXS16 + VCVT_LT_F32_FXS16 + VCVT_GT_F32_FXS16 + VCVT_LE_F32_FXS16 + VCVT_F32_FXS16 + VCVT_ZZ_F32_FXS16 + VCVT_EQ_F32_FXS32 + VCVT_NE_F32_FXS32 + VCVT_CS_F32_FXS32 + VCVT_CC_F32_FXS32 + VCVT_MI_F32_FXS32 + VCVT_PL_F32_FXS32 + VCVT_VS_F32_FXS32 + VCVT_VC_F32_FXS32 + VCVT_HI_F32_FXS32 + VCVT_LS_F32_FXS32 + VCVT_GE_F32_FXS32 + VCVT_LT_F32_FXS32 + VCVT_GT_F32_FXS32 + VCVT_LE_F32_FXS32 + VCVT_F32_FXS32 + VCVT_ZZ_F32_FXS32 + VCVT_EQ_F32_FXU16 + VCVT_NE_F32_FXU16 + VCVT_CS_F32_FXU16 + VCVT_CC_F32_FXU16 + VCVT_MI_F32_FXU16 + VCVT_PL_F32_FXU16 + VCVT_VS_F32_FXU16 + VCVT_VC_F32_FXU16 + VCVT_HI_F32_FXU16 + VCVT_LS_F32_FXU16 + VCVT_GE_F32_FXU16 + VCVT_LT_F32_FXU16 + VCVT_GT_F32_FXU16 + VCVT_LE_F32_FXU16 + VCVT_F32_FXU16 + VCVT_ZZ_F32_FXU16 + VCVT_EQ_F32_FXU32 + VCVT_NE_F32_FXU32 + VCVT_CS_F32_FXU32 + VCVT_CC_F32_FXU32 + VCVT_MI_F32_FXU32 + VCVT_PL_F32_FXU32 + VCVT_VS_F32_FXU32 + VCVT_VC_F32_FXU32 + VCVT_HI_F32_FXU32 + VCVT_LS_F32_FXU32 + VCVT_GE_F32_FXU32 + VCVT_LT_F32_FXU32 + VCVT_GT_F32_FXU32 + VCVT_LE_F32_FXU32 + VCVT_F32_FXU32 + VCVT_ZZ_F32_FXU32 + VCVT_EQ_F64_FXS16 + VCVT_NE_F64_FXS16 + VCVT_CS_F64_FXS16 + VCVT_CC_F64_FXS16 + VCVT_MI_F64_FXS16 + VCVT_PL_F64_FXS16 + VCVT_VS_F64_FXS16 + VCVT_VC_F64_FXS16 + VCVT_HI_F64_FXS16 + VCVT_LS_F64_FXS16 + VCVT_GE_F64_FXS16 + VCVT_LT_F64_FXS16 + VCVT_GT_F64_FXS16 + VCVT_LE_F64_FXS16 + VCVT_F64_FXS16 + VCVT_ZZ_F64_FXS16 + VCVT_EQ_F64_FXS32 + VCVT_NE_F64_FXS32 + VCVT_CS_F64_FXS32 + VCVT_CC_F64_FXS32 + VCVT_MI_F64_FXS32 + VCVT_PL_F64_FXS32 + VCVT_VS_F64_FXS32 + VCVT_VC_F64_FXS32 + VCVT_HI_F64_FXS32 + VCVT_LS_F64_FXS32 + VCVT_GE_F64_FXS32 + VCVT_LT_F64_FXS32 + VCVT_GT_F64_FXS32 + VCVT_LE_F64_FXS32 + VCVT_F64_FXS32 + VCVT_ZZ_F64_FXS32 + VCVT_EQ_F64_FXU16 + VCVT_NE_F64_FXU16 + VCVT_CS_F64_FXU16 + VCVT_CC_F64_FXU16 + VCVT_MI_F64_FXU16 + VCVT_PL_F64_FXU16 + VCVT_VS_F64_FXU16 + VCVT_VC_F64_FXU16 + VCVT_HI_F64_FXU16 + VCVT_LS_F64_FXU16 + VCVT_GE_F64_FXU16 + VCVT_LT_F64_FXU16 + VCVT_GT_F64_FXU16 + VCVT_LE_F64_FXU16 + VCVT_F64_FXU16 + VCVT_ZZ_F64_FXU16 + VCVT_EQ_F64_FXU32 + VCVT_NE_F64_FXU32 + VCVT_CS_F64_FXU32 + VCVT_CC_F64_FXU32 + VCVT_MI_F64_FXU32 + VCVT_PL_F64_FXU32 + VCVT_VS_F64_FXU32 + VCVT_VC_F64_FXU32 + VCVT_HI_F64_FXU32 + VCVT_LS_F64_FXU32 + VCVT_GE_F64_FXU32 + VCVT_LT_F64_FXU32 + VCVT_GT_F64_FXU32 + VCVT_LE_F64_FXU32 + VCVT_F64_FXU32 + VCVT_ZZ_F64_FXU32 + VCVT_EQ_F32_U32 + VCVT_NE_F32_U32 + VCVT_CS_F32_U32 + VCVT_CC_F32_U32 + VCVT_MI_F32_U32 + VCVT_PL_F32_U32 + VCVT_VS_F32_U32 + VCVT_VC_F32_U32 + VCVT_HI_F32_U32 + VCVT_LS_F32_U32 + VCVT_GE_F32_U32 + VCVT_LT_F32_U32 + VCVT_GT_F32_U32 + VCVT_LE_F32_U32 + VCVT_F32_U32 + VCVT_ZZ_F32_U32 + VCVT_EQ_F32_S32 + VCVT_NE_F32_S32 + VCVT_CS_F32_S32 + VCVT_CC_F32_S32 + VCVT_MI_F32_S32 + VCVT_PL_F32_S32 + VCVT_VS_F32_S32 + VCVT_VC_F32_S32 + VCVT_HI_F32_S32 + VCVT_LS_F32_S32 + VCVT_GE_F32_S32 + VCVT_LT_F32_S32 + VCVT_GT_F32_S32 + VCVT_LE_F32_S32 + VCVT_F32_S32 + VCVT_ZZ_F32_S32 + VCVT_EQ_F64_U32 + VCVT_NE_F64_U32 + VCVT_CS_F64_U32 + VCVT_CC_F64_U32 + VCVT_MI_F64_U32 + VCVT_PL_F64_U32 + VCVT_VS_F64_U32 + VCVT_VC_F64_U32 + VCVT_HI_F64_U32 + VCVT_LS_F64_U32 + VCVT_GE_F64_U32 + VCVT_LT_F64_U32 + VCVT_GT_F64_U32 + VCVT_LE_F64_U32 + VCVT_F64_U32 + VCVT_ZZ_F64_U32 + VCVT_EQ_F64_S32 + VCVT_NE_F64_S32 + VCVT_CS_F64_S32 + VCVT_CC_F64_S32 + VCVT_MI_F64_S32 + VCVT_PL_F64_S32 + VCVT_VS_F64_S32 + VCVT_VC_F64_S32 + VCVT_HI_F64_S32 + VCVT_LS_F64_S32 + VCVT_GE_F64_S32 + VCVT_LT_F64_S32 + VCVT_GT_F64_S32 + VCVT_LE_F64_S32 + VCVT_F64_S32 + VCVT_ZZ_F64_S32 + VCVT_EQ_F64_F32 + VCVT_NE_F64_F32 + VCVT_CS_F64_F32 + VCVT_CC_F64_F32 + VCVT_MI_F64_F32 + VCVT_PL_F64_F32 + VCVT_VS_F64_F32 + VCVT_VC_F64_F32 + VCVT_HI_F64_F32 + VCVT_LS_F64_F32 + VCVT_GE_F64_F32 + VCVT_LT_F64_F32 + VCVT_GT_F64_F32 + VCVT_LE_F64_F32 + VCVT_F64_F32 + VCVT_ZZ_F64_F32 + VCVT_EQ_F32_F64 + VCVT_NE_F32_F64 + VCVT_CS_F32_F64 + VCVT_CC_F32_F64 + VCVT_MI_F32_F64 + VCVT_PL_F32_F64 + VCVT_VS_F32_F64 + VCVT_VC_F32_F64 + VCVT_HI_F32_F64 + VCVT_LS_F32_F64 + VCVT_GE_F32_F64 + VCVT_LT_F32_F64 + VCVT_GT_F32_F64 + VCVT_LE_F32_F64 + VCVT_F32_F64 + VCVT_ZZ_F32_F64 + VCVT_EQ_FXS16_F32 + VCVT_NE_FXS16_F32 + VCVT_CS_FXS16_F32 + VCVT_CC_FXS16_F32 + VCVT_MI_FXS16_F32 + VCVT_PL_FXS16_F32 + VCVT_VS_FXS16_F32 + VCVT_VC_FXS16_F32 + VCVT_HI_FXS16_F32 + VCVT_LS_FXS16_F32 + VCVT_GE_FXS16_F32 + VCVT_LT_FXS16_F32 + VCVT_GT_FXS16_F32 + VCVT_LE_FXS16_F32 + VCVT_FXS16_F32 + VCVT_ZZ_FXS16_F32 + VCVT_EQ_FXS16_F64 + VCVT_NE_FXS16_F64 + VCVT_CS_FXS16_F64 + VCVT_CC_FXS16_F64 + VCVT_MI_FXS16_F64 + VCVT_PL_FXS16_F64 + VCVT_VS_FXS16_F64 + VCVT_VC_FXS16_F64 + VCVT_HI_FXS16_F64 + VCVT_LS_FXS16_F64 + VCVT_GE_FXS16_F64 + VCVT_LT_FXS16_F64 + VCVT_GT_FXS16_F64 + VCVT_LE_FXS16_F64 + VCVT_FXS16_F64 + VCVT_ZZ_FXS16_F64 + VCVT_EQ_FXS32_F32 + VCVT_NE_FXS32_F32 + VCVT_CS_FXS32_F32 + VCVT_CC_FXS32_F32 + VCVT_MI_FXS32_F32 + VCVT_PL_FXS32_F32 + VCVT_VS_FXS32_F32 + VCVT_VC_FXS32_F32 + VCVT_HI_FXS32_F32 + VCVT_LS_FXS32_F32 + VCVT_GE_FXS32_F32 + VCVT_LT_FXS32_F32 + VCVT_GT_FXS32_F32 + VCVT_LE_FXS32_F32 + VCVT_FXS32_F32 + VCVT_ZZ_FXS32_F32 + VCVT_EQ_FXS32_F64 + VCVT_NE_FXS32_F64 + VCVT_CS_FXS32_F64 + VCVT_CC_FXS32_F64 + VCVT_MI_FXS32_F64 + VCVT_PL_FXS32_F64 + VCVT_VS_FXS32_F64 + VCVT_VC_FXS32_F64 + VCVT_HI_FXS32_F64 + VCVT_LS_FXS32_F64 + VCVT_GE_FXS32_F64 + VCVT_LT_FXS32_F64 + VCVT_GT_FXS32_F64 + VCVT_LE_FXS32_F64 + VCVT_FXS32_F64 + VCVT_ZZ_FXS32_F64 + VCVT_EQ_FXU16_F32 + VCVT_NE_FXU16_F32 + VCVT_CS_FXU16_F32 + VCVT_CC_FXU16_F32 + VCVT_MI_FXU16_F32 + VCVT_PL_FXU16_F32 + VCVT_VS_FXU16_F32 + VCVT_VC_FXU16_F32 + VCVT_HI_FXU16_F32 + VCVT_LS_FXU16_F32 + VCVT_GE_FXU16_F32 + VCVT_LT_FXU16_F32 + VCVT_GT_FXU16_F32 + VCVT_LE_FXU16_F32 + VCVT_FXU16_F32 + VCVT_ZZ_FXU16_F32 + VCVT_EQ_FXU16_F64 + VCVT_NE_FXU16_F64 + VCVT_CS_FXU16_F64 + VCVT_CC_FXU16_F64 + VCVT_MI_FXU16_F64 + VCVT_PL_FXU16_F64 + VCVT_VS_FXU16_F64 + VCVT_VC_FXU16_F64 + VCVT_HI_FXU16_F64 + VCVT_LS_FXU16_F64 + VCVT_GE_FXU16_F64 + VCVT_LT_FXU16_F64 + VCVT_GT_FXU16_F64 + VCVT_LE_FXU16_F64 + VCVT_FXU16_F64 + VCVT_ZZ_FXU16_F64 + VCVT_EQ_FXU32_F32 + VCVT_NE_FXU32_F32 + VCVT_CS_FXU32_F32 + VCVT_CC_FXU32_F32 + VCVT_MI_FXU32_F32 + VCVT_PL_FXU32_F32 + VCVT_VS_FXU32_F32 + VCVT_VC_FXU32_F32 + VCVT_HI_FXU32_F32 + VCVT_LS_FXU32_F32 + VCVT_GE_FXU32_F32 + VCVT_LT_FXU32_F32 + VCVT_GT_FXU32_F32 + VCVT_LE_FXU32_F32 + VCVT_FXU32_F32 + VCVT_ZZ_FXU32_F32 + VCVT_EQ_FXU32_F64 + VCVT_NE_FXU32_F64 + VCVT_CS_FXU32_F64 + VCVT_CC_FXU32_F64 + VCVT_MI_FXU32_F64 + VCVT_PL_FXU32_F64 + VCVT_VS_FXU32_F64 + VCVT_VC_FXU32_F64 + VCVT_HI_FXU32_F64 + VCVT_LS_FXU32_F64 + VCVT_GE_FXU32_F64 + VCVT_LT_FXU32_F64 + VCVT_GT_FXU32_F64 + VCVT_LE_FXU32_F64 + VCVT_FXU32_F64 + VCVT_ZZ_FXU32_F64 + VCVTB_EQ_F32_F16 + VCVTB_NE_F32_F16 + VCVTB_CS_F32_F16 + VCVTB_CC_F32_F16 + VCVTB_MI_F32_F16 + VCVTB_PL_F32_F16 + VCVTB_VS_F32_F16 + VCVTB_VC_F32_F16 + VCVTB_HI_F32_F16 + VCVTB_LS_F32_F16 + VCVTB_GE_F32_F16 + VCVTB_LT_F32_F16 + VCVTB_GT_F32_F16 + VCVTB_LE_F32_F16 + VCVTB_F32_F16 + VCVTB_ZZ_F32_F16 + VCVTB_EQ_F16_F32 + VCVTB_NE_F16_F32 + VCVTB_CS_F16_F32 + VCVTB_CC_F16_F32 + VCVTB_MI_F16_F32 + VCVTB_PL_F16_F32 + VCVTB_VS_F16_F32 + VCVTB_VC_F16_F32 + VCVTB_HI_F16_F32 + VCVTB_LS_F16_F32 + VCVTB_GE_F16_F32 + VCVTB_LT_F16_F32 + VCVTB_GT_F16_F32 + VCVTB_LE_F16_F32 + VCVTB_F16_F32 + VCVTB_ZZ_F16_F32 + VCVTT_EQ_F32_F16 + VCVTT_NE_F32_F16 + VCVTT_CS_F32_F16 + VCVTT_CC_F32_F16 + VCVTT_MI_F32_F16 + VCVTT_PL_F32_F16 + VCVTT_VS_F32_F16 + VCVTT_VC_F32_F16 + VCVTT_HI_F32_F16 + VCVTT_LS_F32_F16 + VCVTT_GE_F32_F16 + VCVTT_LT_F32_F16 + VCVTT_GT_F32_F16 + VCVTT_LE_F32_F16 + VCVTT_F32_F16 + VCVTT_ZZ_F32_F16 + VCVTT_EQ_F16_F32 + VCVTT_NE_F16_F32 + VCVTT_CS_F16_F32 + VCVTT_CC_F16_F32 + VCVTT_MI_F16_F32 + VCVTT_PL_F16_F32 + VCVTT_VS_F16_F32 + VCVTT_VC_F16_F32 + VCVTT_HI_F16_F32 + VCVTT_LS_F16_F32 + VCVTT_GE_F16_F32 + VCVTT_LT_F16_F32 + VCVTT_GT_F16_F32 + VCVTT_LE_F16_F32 + VCVTT_F16_F32 + VCVTT_ZZ_F16_F32 + VCVTR_EQ_U32_F32 + VCVTR_NE_U32_F32 + VCVTR_CS_U32_F32 + VCVTR_CC_U32_F32 + VCVTR_MI_U32_F32 + VCVTR_PL_U32_F32 + VCVTR_VS_U32_F32 + VCVTR_VC_U32_F32 + VCVTR_HI_U32_F32 + VCVTR_LS_U32_F32 + VCVTR_GE_U32_F32 + VCVTR_LT_U32_F32 + VCVTR_GT_U32_F32 + VCVTR_LE_U32_F32 + VCVTR_U32_F32 + VCVTR_ZZ_U32_F32 + VCVTR_EQ_U32_F64 + VCVTR_NE_U32_F64 + VCVTR_CS_U32_F64 + VCVTR_CC_U32_F64 + VCVTR_MI_U32_F64 + VCVTR_PL_U32_F64 + VCVTR_VS_U32_F64 + VCVTR_VC_U32_F64 + VCVTR_HI_U32_F64 + VCVTR_LS_U32_F64 + VCVTR_GE_U32_F64 + VCVTR_LT_U32_F64 + VCVTR_GT_U32_F64 + VCVTR_LE_U32_F64 + VCVTR_U32_F64 + VCVTR_ZZ_U32_F64 + VCVTR_EQ_S32_F32 + VCVTR_NE_S32_F32 + VCVTR_CS_S32_F32 + VCVTR_CC_S32_F32 + VCVTR_MI_S32_F32 + VCVTR_PL_S32_F32 + VCVTR_VS_S32_F32 + VCVTR_VC_S32_F32 + VCVTR_HI_S32_F32 + VCVTR_LS_S32_F32 + VCVTR_GE_S32_F32 + VCVTR_LT_S32_F32 + VCVTR_GT_S32_F32 + VCVTR_LE_S32_F32 + VCVTR_S32_F32 + VCVTR_ZZ_S32_F32 + VCVTR_EQ_S32_F64 + VCVTR_NE_S32_F64 + VCVTR_CS_S32_F64 + VCVTR_CC_S32_F64 + VCVTR_MI_S32_F64 + VCVTR_PL_S32_F64 + VCVTR_VS_S32_F64 + VCVTR_VC_S32_F64 + VCVTR_HI_S32_F64 + VCVTR_LS_S32_F64 + VCVTR_GE_S32_F64 + VCVTR_LT_S32_F64 + VCVTR_GT_S32_F64 + VCVTR_LE_S32_F64 + VCVTR_S32_F64 + VCVTR_ZZ_S32_F64 + VCVT_EQ_U32_F32 + VCVT_NE_U32_F32 + VCVT_CS_U32_F32 + VCVT_CC_U32_F32 + VCVT_MI_U32_F32 + VCVT_PL_U32_F32 + VCVT_VS_U32_F32 + VCVT_VC_U32_F32 + VCVT_HI_U32_F32 + VCVT_LS_U32_F32 + VCVT_GE_U32_F32 + VCVT_LT_U32_F32 + VCVT_GT_U32_F32 + VCVT_LE_U32_F32 + VCVT_U32_F32 + VCVT_ZZ_U32_F32 + VCVT_EQ_U32_F64 + VCVT_NE_U32_F64 + VCVT_CS_U32_F64 + VCVT_CC_U32_F64 + VCVT_MI_U32_F64 + VCVT_PL_U32_F64 + VCVT_VS_U32_F64 + VCVT_VC_U32_F64 + VCVT_HI_U32_F64 + VCVT_LS_U32_F64 + VCVT_GE_U32_F64 + VCVT_LT_U32_F64 + VCVT_GT_U32_F64 + VCVT_LE_U32_F64 + VCVT_U32_F64 + VCVT_ZZ_U32_F64 + VCVT_EQ_S32_F32 + VCVT_NE_S32_F32 + VCVT_CS_S32_F32 + VCVT_CC_S32_F32 + VCVT_MI_S32_F32 + VCVT_PL_S32_F32 + VCVT_VS_S32_F32 + VCVT_VC_S32_F32 + VCVT_HI_S32_F32 + VCVT_LS_S32_F32 + VCVT_GE_S32_F32 + VCVT_LT_S32_F32 + VCVT_GT_S32_F32 + VCVT_LE_S32_F32 + VCVT_S32_F32 + VCVT_ZZ_S32_F32 + VCVT_EQ_S32_F64 + VCVT_NE_S32_F64 + VCVT_CS_S32_F64 + VCVT_CC_S32_F64 + VCVT_MI_S32_F64 + VCVT_PL_S32_F64 + VCVT_VS_S32_F64 + VCVT_VC_S32_F64 + VCVT_HI_S32_F64 + VCVT_LS_S32_F64 + VCVT_GE_S32_F64 + VCVT_LT_S32_F64 + VCVT_GT_S32_F64 + VCVT_LE_S32_F64 + VCVT_S32_F64 + VCVT_ZZ_S32_F64 + VDIV_EQ_F32 + VDIV_NE_F32 + VDIV_CS_F32 + VDIV_CC_F32 + VDIV_MI_F32 + VDIV_PL_F32 + VDIV_VS_F32 + VDIV_VC_F32 + VDIV_HI_F32 + VDIV_LS_F32 + VDIV_GE_F32 + VDIV_LT_F32 + VDIV_GT_F32 + VDIV_LE_F32 + VDIV_F32 + VDIV_ZZ_F32 + VDIV_EQ_F64 + VDIV_NE_F64 + VDIV_CS_F64 + VDIV_CC_F64 + VDIV_MI_F64 + VDIV_PL_F64 + VDIV_VS_F64 + VDIV_VC_F64 + VDIV_HI_F64 + VDIV_LS_F64 + VDIV_GE_F64 + VDIV_LT_F64 + VDIV_GT_F64 + VDIV_LE_F64 + VDIV_F64 + VDIV_ZZ_F64 + VLDR_EQ + VLDR_NE + VLDR_CS + VLDR_CC + VLDR_MI + VLDR_PL + VLDR_VS + VLDR_VC + VLDR_HI + VLDR_LS + VLDR_GE + VLDR_LT + VLDR_GT + VLDR_LE + VLDR + VLDR_ZZ + VMLA_EQ_F32 + VMLA_NE_F32 + VMLA_CS_F32 + VMLA_CC_F32 + VMLA_MI_F32 + VMLA_PL_F32 + VMLA_VS_F32 + VMLA_VC_F32 + VMLA_HI_F32 + VMLA_LS_F32 + VMLA_GE_F32 + VMLA_LT_F32 + VMLA_GT_F32 + VMLA_LE_F32 + VMLA_F32 + VMLA_ZZ_F32 + VMLA_EQ_F64 + VMLA_NE_F64 + VMLA_CS_F64 + VMLA_CC_F64 + VMLA_MI_F64 + VMLA_PL_F64 + VMLA_VS_F64 + VMLA_VC_F64 + VMLA_HI_F64 + VMLA_LS_F64 + VMLA_GE_F64 + VMLA_LT_F64 + VMLA_GT_F64 + VMLA_LE_F64 + VMLA_F64 + VMLA_ZZ_F64 + VMLS_EQ_F32 + VMLS_NE_F32 + VMLS_CS_F32 + VMLS_CC_F32 + VMLS_MI_F32 + VMLS_PL_F32 + VMLS_VS_F32 + VMLS_VC_F32 + VMLS_HI_F32 + VMLS_LS_F32 + VMLS_GE_F32 + VMLS_LT_F32 + VMLS_GT_F32 + VMLS_LE_F32 + VMLS_F32 + VMLS_ZZ_F32 + VMLS_EQ_F64 + VMLS_NE_F64 + VMLS_CS_F64 + VMLS_CC_F64 + VMLS_MI_F64 + VMLS_PL_F64 + VMLS_VS_F64 + VMLS_VC_F64 + VMLS_HI_F64 + VMLS_LS_F64 + VMLS_GE_F64 + VMLS_LT_F64 + VMLS_GT_F64 + VMLS_LE_F64 + VMLS_F64 + VMLS_ZZ_F64 + VMOV_EQ + VMOV_NE + VMOV_CS + VMOV_CC + VMOV_MI + VMOV_PL + VMOV_VS + VMOV_VC + VMOV_HI + VMOV_LS + VMOV_GE + VMOV_LT + VMOV_GT + VMOV_LE + VMOV + VMOV_ZZ + VMOV_EQ_32 + VMOV_NE_32 + VMOV_CS_32 + VMOV_CC_32 + VMOV_MI_32 + VMOV_PL_32 + VMOV_VS_32 + VMOV_VC_32 + VMOV_HI_32 + VMOV_LS_32 + VMOV_GE_32 + VMOV_LT_32 + VMOV_GT_32 + VMOV_LE_32 + VMOV_32 + VMOV_ZZ_32 + VMOV_EQ_F32 + VMOV_NE_F32 + VMOV_CS_F32 + VMOV_CC_F32 + VMOV_MI_F32 + VMOV_PL_F32 + VMOV_VS_F32 + VMOV_VC_F32 + VMOV_HI_F32 + VMOV_LS_F32 + VMOV_GE_F32 + VMOV_LT_F32 + VMOV_GT_F32 + VMOV_LE_F32 + VMOV_F32 + VMOV_ZZ_F32 + VMOV_EQ_F64 + VMOV_NE_F64 + VMOV_CS_F64 + VMOV_CC_F64 + VMOV_MI_F64 + VMOV_PL_F64 + VMOV_VS_F64 + VMOV_VC_F64 + VMOV_HI_F64 + VMOV_LS_F64 + VMOV_GE_F64 + VMOV_LT_F64 + VMOV_GT_F64 + VMOV_LE_F64 + VMOV_F64 + VMOV_ZZ_F64 + VMRS_EQ + VMRS_NE + VMRS_CS + VMRS_CC + VMRS_MI + VMRS_PL + VMRS_VS + VMRS_VC + VMRS_HI + VMRS_LS + VMRS_GE + VMRS_LT + VMRS_GT + VMRS_LE + VMRS + VMRS_ZZ + VMSR_EQ + VMSR_NE + VMSR_CS + VMSR_CC + VMSR_MI + VMSR_PL + VMSR_VS + VMSR_VC + VMSR_HI + VMSR_LS + VMSR_GE + VMSR_LT + VMSR_GT + VMSR_LE + VMSR + VMSR_ZZ + VMUL_EQ_F32 + VMUL_NE_F32 + VMUL_CS_F32 + VMUL_CC_F32 + VMUL_MI_F32 + VMUL_PL_F32 + VMUL_VS_F32 + VMUL_VC_F32 + VMUL_HI_F32 + VMUL_LS_F32 + VMUL_GE_F32 + VMUL_LT_F32 + VMUL_GT_F32 + VMUL_LE_F32 + VMUL_F32 + VMUL_ZZ_F32 + VMUL_EQ_F64 + VMUL_NE_F64 + VMUL_CS_F64 + VMUL_CC_F64 + VMUL_MI_F64 + VMUL_PL_F64 + VMUL_VS_F64 + VMUL_VC_F64 + VMUL_HI_F64 + VMUL_LS_F64 + VMUL_GE_F64 + VMUL_LT_F64 + VMUL_GT_F64 + VMUL_LE_F64 + VMUL_F64 + VMUL_ZZ_F64 + VNEG_EQ_F32 + VNEG_NE_F32 + VNEG_CS_F32 + VNEG_CC_F32 + VNEG_MI_F32 + VNEG_PL_F32 + VNEG_VS_F32 + VNEG_VC_F32 + VNEG_HI_F32 + VNEG_LS_F32 + VNEG_GE_F32 + VNEG_LT_F32 + VNEG_GT_F32 + VNEG_LE_F32 + VNEG_F32 + VNEG_ZZ_F32 + VNEG_EQ_F64 + VNEG_NE_F64 + VNEG_CS_F64 + VNEG_CC_F64 + VNEG_MI_F64 + VNEG_PL_F64 + VNEG_VS_F64 + VNEG_VC_F64 + VNEG_HI_F64 + VNEG_LS_F64 + VNEG_GE_F64 + VNEG_LT_F64 + VNEG_GT_F64 + VNEG_LE_F64 + VNEG_F64 + VNEG_ZZ_F64 + VNMLS_EQ_F32 + VNMLS_NE_F32 + VNMLS_CS_F32 + VNMLS_CC_F32 + VNMLS_MI_F32 + VNMLS_PL_F32 + VNMLS_VS_F32 + VNMLS_VC_F32 + VNMLS_HI_F32 + VNMLS_LS_F32 + VNMLS_GE_F32 + VNMLS_LT_F32 + VNMLS_GT_F32 + VNMLS_LE_F32 + VNMLS_F32 + VNMLS_ZZ_F32 + VNMLS_EQ_F64 + VNMLS_NE_F64 + VNMLS_CS_F64 + VNMLS_CC_F64 + VNMLS_MI_F64 + VNMLS_PL_F64 + VNMLS_VS_F64 + VNMLS_VC_F64 + VNMLS_HI_F64 + VNMLS_LS_F64 + VNMLS_GE_F64 + VNMLS_LT_F64 + VNMLS_GT_F64 + VNMLS_LE_F64 + VNMLS_F64 + VNMLS_ZZ_F64 + VNMLA_EQ_F32 + VNMLA_NE_F32 + VNMLA_CS_F32 + VNMLA_CC_F32 + VNMLA_MI_F32 + VNMLA_PL_F32 + VNMLA_VS_F32 + VNMLA_VC_F32 + VNMLA_HI_F32 + VNMLA_LS_F32 + VNMLA_GE_F32 + VNMLA_LT_F32 + VNMLA_GT_F32 + VNMLA_LE_F32 + VNMLA_F32 + VNMLA_ZZ_F32 + VNMLA_EQ_F64 + VNMLA_NE_F64 + VNMLA_CS_F64 + VNMLA_CC_F64 + VNMLA_MI_F64 + VNMLA_PL_F64 + VNMLA_VS_F64 + VNMLA_VC_F64 + VNMLA_HI_F64 + VNMLA_LS_F64 + VNMLA_GE_F64 + VNMLA_LT_F64 + VNMLA_GT_F64 + VNMLA_LE_F64 + VNMLA_F64 + VNMLA_ZZ_F64 + VNMUL_EQ_F32 + VNMUL_NE_F32 + VNMUL_CS_F32 + VNMUL_CC_F32 + VNMUL_MI_F32 + VNMUL_PL_F32 + VNMUL_VS_F32 + VNMUL_VC_F32 + VNMUL_HI_F32 + VNMUL_LS_F32 + VNMUL_GE_F32 + VNMUL_LT_F32 + VNMUL_GT_F32 + VNMUL_LE_F32 + VNMUL_F32 + VNMUL_ZZ_F32 + VNMUL_EQ_F64 + VNMUL_NE_F64 + VNMUL_CS_F64 + VNMUL_CC_F64 + VNMUL_MI_F64 + VNMUL_PL_F64 + VNMUL_VS_F64 + VNMUL_VC_F64 + VNMUL_HI_F64 + VNMUL_LS_F64 + VNMUL_GE_F64 + VNMUL_LT_F64 + VNMUL_GT_F64 + VNMUL_LE_F64 + VNMUL_F64 + VNMUL_ZZ_F64 + VSQRT_EQ_F32 + VSQRT_NE_F32 + VSQRT_CS_F32 + VSQRT_CC_F32 + VSQRT_MI_F32 + VSQRT_PL_F32 + VSQRT_VS_F32 + VSQRT_VC_F32 + VSQRT_HI_F32 + VSQRT_LS_F32 + VSQRT_GE_F32 + VSQRT_LT_F32 + VSQRT_GT_F32 + VSQRT_LE_F32 + VSQRT_F32 + VSQRT_ZZ_F32 + VSQRT_EQ_F64 + VSQRT_NE_F64 + VSQRT_CS_F64 + VSQRT_CC_F64 + VSQRT_MI_F64 + VSQRT_PL_F64 + VSQRT_VS_F64 + VSQRT_VC_F64 + VSQRT_HI_F64 + VSQRT_LS_F64 + VSQRT_GE_F64 + VSQRT_LT_F64 + VSQRT_GT_F64 + VSQRT_LE_F64 + VSQRT_F64 + VSQRT_ZZ_F64 + VSTR_EQ + VSTR_NE + VSTR_CS + VSTR_CC + VSTR_MI + VSTR_PL + VSTR_VS + VSTR_VC + VSTR_HI + VSTR_LS + VSTR_GE + VSTR_LT + VSTR_GT + VSTR_LE + VSTR + VSTR_ZZ + VSUB_EQ_F32 + VSUB_NE_F32 + VSUB_CS_F32 + VSUB_CC_F32 + VSUB_MI_F32 + VSUB_PL_F32 + VSUB_VS_F32 + VSUB_VC_F32 + VSUB_HI_F32 + VSUB_LS_F32 + VSUB_GE_F32 + VSUB_LT_F32 + VSUB_GT_F32 + VSUB_LE_F32 + VSUB_F32 + VSUB_ZZ_F32 + VSUB_EQ_F64 + VSUB_NE_F64 + VSUB_CS_F64 + VSUB_CC_F64 + VSUB_MI_F64 + VSUB_PL_F64 + VSUB_VS_F64 + VSUB_VC_F64 + VSUB_HI_F64 + VSUB_LS_F64 + VSUB_GE_F64 + VSUB_LT_F64 + VSUB_GT_F64 + VSUB_LE_F64 + VSUB_F64 + VSUB_ZZ_F64 + WFE_EQ + WFE_NE + WFE_CS + WFE_CC + WFE_MI + WFE_PL + WFE_VS + WFE_VC + WFE_HI + WFE_LS + WFE_GE + WFE_LT + WFE_GT + WFE_LE + WFE + WFE_ZZ + WFI_EQ + WFI_NE + WFI_CS + WFI_CC + WFI_MI + WFI_PL + WFI_VS + WFI_VC + WFI_HI + WFI_LS + WFI_GE + WFI_LT + WFI_GT + WFI_LE + WFI + WFI_ZZ + YIELD_EQ + YIELD_NE + YIELD_CS + YIELD_CC + YIELD_MI + YIELD_PL + YIELD_VS + YIELD_VC + YIELD_HI + YIELD_LS + YIELD_GE + YIELD_LT + YIELD_GT + YIELD_LE + YIELD + YIELD_ZZ +) + +var opstr = [...]string{ + ADC_EQ: "ADC.EQ", + ADC_NE: "ADC.NE", + ADC_CS: "ADC.CS", + ADC_CC: "ADC.CC", + ADC_MI: "ADC.MI", + ADC_PL: "ADC.PL", + ADC_VS: "ADC.VS", + ADC_VC: "ADC.VC", + ADC_HI: "ADC.HI", + ADC_LS: "ADC.LS", + ADC_GE: "ADC.GE", + ADC_LT: "ADC.LT", + ADC_GT: "ADC.GT", + ADC_LE: "ADC.LE", + ADC: "ADC", + ADC_ZZ: "ADC.ZZ", + ADC_S_EQ: "ADC.S.EQ", + ADC_S_NE: "ADC.S.NE", + ADC_S_CS: "ADC.S.CS", + ADC_S_CC: "ADC.S.CC", + ADC_S_MI: "ADC.S.MI", + ADC_S_PL: "ADC.S.PL", + ADC_S_VS: "ADC.S.VS", + ADC_S_VC: "ADC.S.VC", + ADC_S_HI: "ADC.S.HI", + ADC_S_LS: "ADC.S.LS", + ADC_S_GE: "ADC.S.GE", + ADC_S_LT: "ADC.S.LT", + ADC_S_GT: "ADC.S.GT", + ADC_S_LE: "ADC.S.LE", + ADC_S: "ADC.S", + ADC_S_ZZ: "ADC.S.ZZ", + ADD_EQ: "ADD.EQ", + ADD_NE: "ADD.NE", + ADD_CS: "ADD.CS", + ADD_CC: "ADD.CC", + ADD_MI: "ADD.MI", + ADD_PL: "ADD.PL", + ADD_VS: "ADD.VS", + ADD_VC: "ADD.VC", + ADD_HI: "ADD.HI", + ADD_LS: "ADD.LS", + ADD_GE: "ADD.GE", + ADD_LT: "ADD.LT", + ADD_GT: "ADD.GT", + ADD_LE: "ADD.LE", + ADD: "ADD", + ADD_ZZ: "ADD.ZZ", + ADD_S_EQ: "ADD.S.EQ", + ADD_S_NE: "ADD.S.NE", + ADD_S_CS: "ADD.S.CS", + ADD_S_CC: "ADD.S.CC", + ADD_S_MI: "ADD.S.MI", + ADD_S_PL: "ADD.S.PL", + ADD_S_VS: "ADD.S.VS", + ADD_S_VC: "ADD.S.VC", + ADD_S_HI: "ADD.S.HI", + ADD_S_LS: "ADD.S.LS", + ADD_S_GE: "ADD.S.GE", + ADD_S_LT: "ADD.S.LT", + ADD_S_GT: "ADD.S.GT", + ADD_S_LE: "ADD.S.LE", + ADD_S: "ADD.S", + ADD_S_ZZ: "ADD.S.ZZ", + AND_EQ: "AND.EQ", + AND_NE: "AND.NE", + AND_CS: "AND.CS", + AND_CC: "AND.CC", + AND_MI: "AND.MI", + AND_PL: "AND.PL", + AND_VS: "AND.VS", + AND_VC: "AND.VC", + AND_HI: "AND.HI", + AND_LS: "AND.LS", + AND_GE: "AND.GE", + AND_LT: "AND.LT", + AND_GT: "AND.GT", + AND_LE: "AND.LE", + AND: "AND", + AND_ZZ: "AND.ZZ", + AND_S_EQ: "AND.S.EQ", + AND_S_NE: "AND.S.NE", + AND_S_CS: "AND.S.CS", + AND_S_CC: "AND.S.CC", + AND_S_MI: "AND.S.MI", + AND_S_PL: "AND.S.PL", + AND_S_VS: "AND.S.VS", + AND_S_VC: "AND.S.VC", + AND_S_HI: "AND.S.HI", + AND_S_LS: "AND.S.LS", + AND_S_GE: "AND.S.GE", + AND_S_LT: "AND.S.LT", + AND_S_GT: "AND.S.GT", + AND_S_LE: "AND.S.LE", + AND_S: "AND.S", + AND_S_ZZ: "AND.S.ZZ", + ASR_EQ: "ASR.EQ", + ASR_NE: "ASR.NE", + ASR_CS: "ASR.CS", + ASR_CC: "ASR.CC", + ASR_MI: "ASR.MI", + ASR_PL: "ASR.PL", + ASR_VS: "ASR.VS", + ASR_VC: "ASR.VC", + ASR_HI: "ASR.HI", + ASR_LS: "ASR.LS", + ASR_GE: "ASR.GE", + ASR_LT: "ASR.LT", + ASR_GT: "ASR.GT", + ASR_LE: "ASR.LE", + ASR: "ASR", + ASR_ZZ: "ASR.ZZ", + ASR_S_EQ: "ASR.S.EQ", + ASR_S_NE: "ASR.S.NE", + ASR_S_CS: "ASR.S.CS", + ASR_S_CC: "ASR.S.CC", + ASR_S_MI: "ASR.S.MI", + ASR_S_PL: "ASR.S.PL", + ASR_S_VS: "ASR.S.VS", + ASR_S_VC: "ASR.S.VC", + ASR_S_HI: "ASR.S.HI", + ASR_S_LS: "ASR.S.LS", + ASR_S_GE: "ASR.S.GE", + ASR_S_LT: "ASR.S.LT", + ASR_S_GT: "ASR.S.GT", + ASR_S_LE: "ASR.S.LE", + ASR_S: "ASR.S", + ASR_S_ZZ: "ASR.S.ZZ", + B_EQ: "B.EQ", + B_NE: "B.NE", + B_CS: "B.CS", + B_CC: "B.CC", + B_MI: "B.MI", + B_PL: "B.PL", + B_VS: "B.VS", + B_VC: "B.VC", + B_HI: "B.HI", + B_LS: "B.LS", + B_GE: "B.GE", + B_LT: "B.LT", + B_GT: "B.GT", + B_LE: "B.LE", + B: "B", + B_ZZ: "B.ZZ", + BFC_EQ: "BFC.EQ", + BFC_NE: "BFC.NE", + BFC_CS: "BFC.CS", + BFC_CC: "BFC.CC", + BFC_MI: "BFC.MI", + BFC_PL: "BFC.PL", + BFC_VS: "BFC.VS", + BFC_VC: "BFC.VC", + BFC_HI: "BFC.HI", + BFC_LS: "BFC.LS", + BFC_GE: "BFC.GE", + BFC_LT: "BFC.LT", + BFC_GT: "BFC.GT", + BFC_LE: "BFC.LE", + BFC: "BFC", + BFC_ZZ: "BFC.ZZ", + BFI_EQ: "BFI.EQ", + BFI_NE: "BFI.NE", + BFI_CS: "BFI.CS", + BFI_CC: "BFI.CC", + BFI_MI: "BFI.MI", + BFI_PL: "BFI.PL", + BFI_VS: "BFI.VS", + BFI_VC: "BFI.VC", + BFI_HI: "BFI.HI", + BFI_LS: "BFI.LS", + BFI_GE: "BFI.GE", + BFI_LT: "BFI.LT", + BFI_GT: "BFI.GT", + BFI_LE: "BFI.LE", + BFI: "BFI", + BFI_ZZ: "BFI.ZZ", + BIC_EQ: "BIC.EQ", + BIC_NE: "BIC.NE", + BIC_CS: "BIC.CS", + BIC_CC: "BIC.CC", + BIC_MI: "BIC.MI", + BIC_PL: "BIC.PL", + BIC_VS: "BIC.VS", + BIC_VC: "BIC.VC", + BIC_HI: "BIC.HI", + BIC_LS: "BIC.LS", + BIC_GE: "BIC.GE", + BIC_LT: "BIC.LT", + BIC_GT: "BIC.GT", + BIC_LE: "BIC.LE", + BIC: "BIC", + BIC_ZZ: "BIC.ZZ", + BIC_S_EQ: "BIC.S.EQ", + BIC_S_NE: "BIC.S.NE", + BIC_S_CS: "BIC.S.CS", + BIC_S_CC: "BIC.S.CC", + BIC_S_MI: "BIC.S.MI", + BIC_S_PL: "BIC.S.PL", + BIC_S_VS: "BIC.S.VS", + BIC_S_VC: "BIC.S.VC", + BIC_S_HI: "BIC.S.HI", + BIC_S_LS: "BIC.S.LS", + BIC_S_GE: "BIC.S.GE", + BIC_S_LT: "BIC.S.LT", + BIC_S_GT: "BIC.S.GT", + BIC_S_LE: "BIC.S.LE", + BIC_S: "BIC.S", + BIC_S_ZZ: "BIC.S.ZZ", + BKPT_EQ: "BKPT.EQ", + BKPT_NE: "BKPT.NE", + BKPT_CS: "BKPT.CS", + BKPT_CC: "BKPT.CC", + BKPT_MI: "BKPT.MI", + BKPT_PL: "BKPT.PL", + BKPT_VS: "BKPT.VS", + BKPT_VC: "BKPT.VC", + BKPT_HI: "BKPT.HI", + BKPT_LS: "BKPT.LS", + BKPT_GE: "BKPT.GE", + BKPT_LT: "BKPT.LT", + BKPT_GT: "BKPT.GT", + BKPT_LE: "BKPT.LE", + BKPT: "BKPT", + BKPT_ZZ: "BKPT.ZZ", + BL_EQ: "BL.EQ", + BL_NE: "BL.NE", + BL_CS: "BL.CS", + BL_CC: "BL.CC", + BL_MI: "BL.MI", + BL_PL: "BL.PL", + BL_VS: "BL.VS", + BL_VC: "BL.VC", + BL_HI: "BL.HI", + BL_LS: "BL.LS", + BL_GE: "BL.GE", + BL_LT: "BL.LT", + BL_GT: "BL.GT", + BL_LE: "BL.LE", + BL: "BL", + BL_ZZ: "BL.ZZ", + BLX_EQ: "BLX.EQ", + BLX_NE: "BLX.NE", + BLX_CS: "BLX.CS", + BLX_CC: "BLX.CC", + BLX_MI: "BLX.MI", + BLX_PL: "BLX.PL", + BLX_VS: "BLX.VS", + BLX_VC: "BLX.VC", + BLX_HI: "BLX.HI", + BLX_LS: "BLX.LS", + BLX_GE: "BLX.GE", + BLX_LT: "BLX.LT", + BLX_GT: "BLX.GT", + BLX_LE: "BLX.LE", + BLX: "BLX", + BLX_ZZ: "BLX.ZZ", + BX_EQ: "BX.EQ", + BX_NE: "BX.NE", + BX_CS: "BX.CS", + BX_CC: "BX.CC", + BX_MI: "BX.MI", + BX_PL: "BX.PL", + BX_VS: "BX.VS", + BX_VC: "BX.VC", + BX_HI: "BX.HI", + BX_LS: "BX.LS", + BX_GE: "BX.GE", + BX_LT: "BX.LT", + BX_GT: "BX.GT", + BX_LE: "BX.LE", + BX: "BX", + BX_ZZ: "BX.ZZ", + BXJ_EQ: "BXJ.EQ", + BXJ_NE: "BXJ.NE", + BXJ_CS: "BXJ.CS", + BXJ_CC: "BXJ.CC", + BXJ_MI: "BXJ.MI", + BXJ_PL: "BXJ.PL", + BXJ_VS: "BXJ.VS", + BXJ_VC: "BXJ.VC", + BXJ_HI: "BXJ.HI", + BXJ_LS: "BXJ.LS", + BXJ_GE: "BXJ.GE", + BXJ_LT: "BXJ.LT", + BXJ_GT: "BXJ.GT", + BXJ_LE: "BXJ.LE", + BXJ: "BXJ", + BXJ_ZZ: "BXJ.ZZ", + CLREX: "CLREX", + CLZ_EQ: "CLZ.EQ", + CLZ_NE: "CLZ.NE", + CLZ_CS: "CLZ.CS", + CLZ_CC: "CLZ.CC", + CLZ_MI: "CLZ.MI", + CLZ_PL: "CLZ.PL", + CLZ_VS: "CLZ.VS", + CLZ_VC: "CLZ.VC", + CLZ_HI: "CLZ.HI", + CLZ_LS: "CLZ.LS", + CLZ_GE: "CLZ.GE", + CLZ_LT: "CLZ.LT", + CLZ_GT: "CLZ.GT", + CLZ_LE: "CLZ.LE", + CLZ: "CLZ", + CLZ_ZZ: "CLZ.ZZ", + CMN_EQ: "CMN.EQ", + CMN_NE: "CMN.NE", + CMN_CS: "CMN.CS", + CMN_CC: "CMN.CC", + CMN_MI: "CMN.MI", + CMN_PL: "CMN.PL", + CMN_VS: "CMN.VS", + CMN_VC: "CMN.VC", + CMN_HI: "CMN.HI", + CMN_LS: "CMN.LS", + CMN_GE: "CMN.GE", + CMN_LT: "CMN.LT", + CMN_GT: "CMN.GT", + CMN_LE: "CMN.LE", + CMN: "CMN", + CMN_ZZ: "CMN.ZZ", + CMP_EQ: "CMP.EQ", + CMP_NE: "CMP.NE", + CMP_CS: "CMP.CS", + CMP_CC: "CMP.CC", + CMP_MI: "CMP.MI", + CMP_PL: "CMP.PL", + CMP_VS: "CMP.VS", + CMP_VC: "CMP.VC", + CMP_HI: "CMP.HI", + CMP_LS: "CMP.LS", + CMP_GE: "CMP.GE", + CMP_LT: "CMP.LT", + CMP_GT: "CMP.GT", + CMP_LE: "CMP.LE", + CMP: "CMP", + CMP_ZZ: "CMP.ZZ", + DBG_EQ: "DBG.EQ", + DBG_NE: "DBG.NE", + DBG_CS: "DBG.CS", + DBG_CC: "DBG.CC", + DBG_MI: "DBG.MI", + DBG_PL: "DBG.PL", + DBG_VS: "DBG.VS", + DBG_VC: "DBG.VC", + DBG_HI: "DBG.HI", + DBG_LS: "DBG.LS", + DBG_GE: "DBG.GE", + DBG_LT: "DBG.LT", + DBG_GT: "DBG.GT", + DBG_LE: "DBG.LE", + DBG: "DBG", + DBG_ZZ: "DBG.ZZ", + DMB: "DMB", + DSB: "DSB", + EOR_EQ: "EOR.EQ", + EOR_NE: "EOR.NE", + EOR_CS: "EOR.CS", + EOR_CC: "EOR.CC", + EOR_MI: "EOR.MI", + EOR_PL: "EOR.PL", + EOR_VS: "EOR.VS", + EOR_VC: "EOR.VC", + EOR_HI: "EOR.HI", + EOR_LS: "EOR.LS", + EOR_GE: "EOR.GE", + EOR_LT: "EOR.LT", + EOR_GT: "EOR.GT", + EOR_LE: "EOR.LE", + EOR: "EOR", + EOR_ZZ: "EOR.ZZ", + EOR_S_EQ: "EOR.S.EQ", + EOR_S_NE: "EOR.S.NE", + EOR_S_CS: "EOR.S.CS", + EOR_S_CC: "EOR.S.CC", + EOR_S_MI: "EOR.S.MI", + EOR_S_PL: "EOR.S.PL", + EOR_S_VS: "EOR.S.VS", + EOR_S_VC: "EOR.S.VC", + EOR_S_HI: "EOR.S.HI", + EOR_S_LS: "EOR.S.LS", + EOR_S_GE: "EOR.S.GE", + EOR_S_LT: "EOR.S.LT", + EOR_S_GT: "EOR.S.GT", + EOR_S_LE: "EOR.S.LE", + EOR_S: "EOR.S", + EOR_S_ZZ: "EOR.S.ZZ", + ISB: "ISB", + LDM_EQ: "LDM.EQ", + LDM_NE: "LDM.NE", + LDM_CS: "LDM.CS", + LDM_CC: "LDM.CC", + LDM_MI: "LDM.MI", + LDM_PL: "LDM.PL", + LDM_VS: "LDM.VS", + LDM_VC: "LDM.VC", + LDM_HI: "LDM.HI", + LDM_LS: "LDM.LS", + LDM_GE: "LDM.GE", + LDM_LT: "LDM.LT", + LDM_GT: "LDM.GT", + LDM_LE: "LDM.LE", + LDM: "LDM", + LDM_ZZ: "LDM.ZZ", + LDMDA_EQ: "LDMDA.EQ", + LDMDA_NE: "LDMDA.NE", + LDMDA_CS: "LDMDA.CS", + LDMDA_CC: "LDMDA.CC", + LDMDA_MI: "LDMDA.MI", + LDMDA_PL: "LDMDA.PL", + LDMDA_VS: "LDMDA.VS", + LDMDA_VC: "LDMDA.VC", + LDMDA_HI: "LDMDA.HI", + LDMDA_LS: "LDMDA.LS", + LDMDA_GE: "LDMDA.GE", + LDMDA_LT: "LDMDA.LT", + LDMDA_GT: "LDMDA.GT", + LDMDA_LE: "LDMDA.LE", + LDMDA: "LDMDA", + LDMDA_ZZ: "LDMDA.ZZ", + LDMDB_EQ: "LDMDB.EQ", + LDMDB_NE: "LDMDB.NE", + LDMDB_CS: "LDMDB.CS", + LDMDB_CC: "LDMDB.CC", + LDMDB_MI: "LDMDB.MI", + LDMDB_PL: "LDMDB.PL", + LDMDB_VS: "LDMDB.VS", + LDMDB_VC: "LDMDB.VC", + LDMDB_HI: "LDMDB.HI", + LDMDB_LS: "LDMDB.LS", + LDMDB_GE: "LDMDB.GE", + LDMDB_LT: "LDMDB.LT", + LDMDB_GT: "LDMDB.GT", + LDMDB_LE: "LDMDB.LE", + LDMDB: "LDMDB", + LDMDB_ZZ: "LDMDB.ZZ", + LDMIB_EQ: "LDMIB.EQ", + LDMIB_NE: "LDMIB.NE", + LDMIB_CS: "LDMIB.CS", + LDMIB_CC: "LDMIB.CC", + LDMIB_MI: "LDMIB.MI", + LDMIB_PL: "LDMIB.PL", + LDMIB_VS: "LDMIB.VS", + LDMIB_VC: "LDMIB.VC", + LDMIB_HI: "LDMIB.HI", + LDMIB_LS: "LDMIB.LS", + LDMIB_GE: "LDMIB.GE", + LDMIB_LT: "LDMIB.LT", + LDMIB_GT: "LDMIB.GT", + LDMIB_LE: "LDMIB.LE", + LDMIB: "LDMIB", + LDMIB_ZZ: "LDMIB.ZZ", + LDR_EQ: "LDR.EQ", + LDR_NE: "LDR.NE", + LDR_CS: "LDR.CS", + LDR_CC: "LDR.CC", + LDR_MI: "LDR.MI", + LDR_PL: "LDR.PL", + LDR_VS: "LDR.VS", + LDR_VC: "LDR.VC", + LDR_HI: "LDR.HI", + LDR_LS: "LDR.LS", + LDR_GE: "LDR.GE", + LDR_LT: "LDR.LT", + LDR_GT: "LDR.GT", + LDR_LE: "LDR.LE", + LDR: "LDR", + LDR_ZZ: "LDR.ZZ", + LDRB_EQ: "LDRB.EQ", + LDRB_NE: "LDRB.NE", + LDRB_CS: "LDRB.CS", + LDRB_CC: "LDRB.CC", + LDRB_MI: "LDRB.MI", + LDRB_PL: "LDRB.PL", + LDRB_VS: "LDRB.VS", + LDRB_VC: "LDRB.VC", + LDRB_HI: "LDRB.HI", + LDRB_LS: "LDRB.LS", + LDRB_GE: "LDRB.GE", + LDRB_LT: "LDRB.LT", + LDRB_GT: "LDRB.GT", + LDRB_LE: "LDRB.LE", + LDRB: "LDRB", + LDRB_ZZ: "LDRB.ZZ", + LDRBT_EQ: "LDRBT.EQ", + LDRBT_NE: "LDRBT.NE", + LDRBT_CS: "LDRBT.CS", + LDRBT_CC: "LDRBT.CC", + LDRBT_MI: "LDRBT.MI", + LDRBT_PL: "LDRBT.PL", + LDRBT_VS: "LDRBT.VS", + LDRBT_VC: "LDRBT.VC", + LDRBT_HI: "LDRBT.HI", + LDRBT_LS: "LDRBT.LS", + LDRBT_GE: "LDRBT.GE", + LDRBT_LT: "LDRBT.LT", + LDRBT_GT: "LDRBT.GT", + LDRBT_LE: "LDRBT.LE", + LDRBT: "LDRBT", + LDRBT_ZZ: "LDRBT.ZZ", + LDRD_EQ: "LDRD.EQ", + LDRD_NE: "LDRD.NE", + LDRD_CS: "LDRD.CS", + LDRD_CC: "LDRD.CC", + LDRD_MI: "LDRD.MI", + LDRD_PL: "LDRD.PL", + LDRD_VS: "LDRD.VS", + LDRD_VC: "LDRD.VC", + LDRD_HI: "LDRD.HI", + LDRD_LS: "LDRD.LS", + LDRD_GE: "LDRD.GE", + LDRD_LT: "LDRD.LT", + LDRD_GT: "LDRD.GT", + LDRD_LE: "LDRD.LE", + LDRD: "LDRD", + LDRD_ZZ: "LDRD.ZZ", + LDREX_EQ: "LDREX.EQ", + LDREX_NE: "LDREX.NE", + LDREX_CS: "LDREX.CS", + LDREX_CC: "LDREX.CC", + LDREX_MI: "LDREX.MI", + LDREX_PL: "LDREX.PL", + LDREX_VS: "LDREX.VS", + LDREX_VC: "LDREX.VC", + LDREX_HI: "LDREX.HI", + LDREX_LS: "LDREX.LS", + LDREX_GE: "LDREX.GE", + LDREX_LT: "LDREX.LT", + LDREX_GT: "LDREX.GT", + LDREX_LE: "LDREX.LE", + LDREX: "LDREX", + LDREX_ZZ: "LDREX.ZZ", + LDREXB_EQ: "LDREXB.EQ", + LDREXB_NE: "LDREXB.NE", + LDREXB_CS: "LDREXB.CS", + LDREXB_CC: "LDREXB.CC", + LDREXB_MI: "LDREXB.MI", + LDREXB_PL: "LDREXB.PL", + LDREXB_VS: "LDREXB.VS", + LDREXB_VC: "LDREXB.VC", + LDREXB_HI: "LDREXB.HI", + LDREXB_LS: "LDREXB.LS", + LDREXB_GE: "LDREXB.GE", + LDREXB_LT: "LDREXB.LT", + LDREXB_GT: "LDREXB.GT", + LDREXB_LE: "LDREXB.LE", + LDREXB: "LDREXB", + LDREXB_ZZ: "LDREXB.ZZ", + LDREXD_EQ: "LDREXD.EQ", + LDREXD_NE: "LDREXD.NE", + LDREXD_CS: "LDREXD.CS", + LDREXD_CC: "LDREXD.CC", + LDREXD_MI: "LDREXD.MI", + LDREXD_PL: "LDREXD.PL", + LDREXD_VS: "LDREXD.VS", + LDREXD_VC: "LDREXD.VC", + LDREXD_HI: "LDREXD.HI", + LDREXD_LS: "LDREXD.LS", + LDREXD_GE: "LDREXD.GE", + LDREXD_LT: "LDREXD.LT", + LDREXD_GT: "LDREXD.GT", + LDREXD_LE: "LDREXD.LE", + LDREXD: "LDREXD", + LDREXD_ZZ: "LDREXD.ZZ", + LDREXH_EQ: "LDREXH.EQ", + LDREXH_NE: "LDREXH.NE", + LDREXH_CS: "LDREXH.CS", + LDREXH_CC: "LDREXH.CC", + LDREXH_MI: "LDREXH.MI", + LDREXH_PL: "LDREXH.PL", + LDREXH_VS: "LDREXH.VS", + LDREXH_VC: "LDREXH.VC", + LDREXH_HI: "LDREXH.HI", + LDREXH_LS: "LDREXH.LS", + LDREXH_GE: "LDREXH.GE", + LDREXH_LT: "LDREXH.LT", + LDREXH_GT: "LDREXH.GT", + LDREXH_LE: "LDREXH.LE", + LDREXH: "LDREXH", + LDREXH_ZZ: "LDREXH.ZZ", + LDRH_EQ: "LDRH.EQ", + LDRH_NE: "LDRH.NE", + LDRH_CS: "LDRH.CS", + LDRH_CC: "LDRH.CC", + LDRH_MI: "LDRH.MI", + LDRH_PL: "LDRH.PL", + LDRH_VS: "LDRH.VS", + LDRH_VC: "LDRH.VC", + LDRH_HI: "LDRH.HI", + LDRH_LS: "LDRH.LS", + LDRH_GE: "LDRH.GE", + LDRH_LT: "LDRH.LT", + LDRH_GT: "LDRH.GT", + LDRH_LE: "LDRH.LE", + LDRH: "LDRH", + LDRH_ZZ: "LDRH.ZZ", + LDRHT_EQ: "LDRHT.EQ", + LDRHT_NE: "LDRHT.NE", + LDRHT_CS: "LDRHT.CS", + LDRHT_CC: "LDRHT.CC", + LDRHT_MI: "LDRHT.MI", + LDRHT_PL: "LDRHT.PL", + LDRHT_VS: "LDRHT.VS", + LDRHT_VC: "LDRHT.VC", + LDRHT_HI: "LDRHT.HI", + LDRHT_LS: "LDRHT.LS", + LDRHT_GE: "LDRHT.GE", + LDRHT_LT: "LDRHT.LT", + LDRHT_GT: "LDRHT.GT", + LDRHT_LE: "LDRHT.LE", + LDRHT: "LDRHT", + LDRHT_ZZ: "LDRHT.ZZ", + LDRSB_EQ: "LDRSB.EQ", + LDRSB_NE: "LDRSB.NE", + LDRSB_CS: "LDRSB.CS", + LDRSB_CC: "LDRSB.CC", + LDRSB_MI: "LDRSB.MI", + LDRSB_PL: "LDRSB.PL", + LDRSB_VS: "LDRSB.VS", + LDRSB_VC: "LDRSB.VC", + LDRSB_HI: "LDRSB.HI", + LDRSB_LS: "LDRSB.LS", + LDRSB_GE: "LDRSB.GE", + LDRSB_LT: "LDRSB.LT", + LDRSB_GT: "LDRSB.GT", + LDRSB_LE: "LDRSB.LE", + LDRSB: "LDRSB", + LDRSB_ZZ: "LDRSB.ZZ", + LDRSBT_EQ: "LDRSBT.EQ", + LDRSBT_NE: "LDRSBT.NE", + LDRSBT_CS: "LDRSBT.CS", + LDRSBT_CC: "LDRSBT.CC", + LDRSBT_MI: "LDRSBT.MI", + LDRSBT_PL: "LDRSBT.PL", + LDRSBT_VS: "LDRSBT.VS", + LDRSBT_VC: "LDRSBT.VC", + LDRSBT_HI: "LDRSBT.HI", + LDRSBT_LS: "LDRSBT.LS", + LDRSBT_GE: "LDRSBT.GE", + LDRSBT_LT: "LDRSBT.LT", + LDRSBT_GT: "LDRSBT.GT", + LDRSBT_LE: "LDRSBT.LE", + LDRSBT: "LDRSBT", + LDRSBT_ZZ: "LDRSBT.ZZ", + LDRSH_EQ: "LDRSH.EQ", + LDRSH_NE: "LDRSH.NE", + LDRSH_CS: "LDRSH.CS", + LDRSH_CC: "LDRSH.CC", + LDRSH_MI: "LDRSH.MI", + LDRSH_PL: "LDRSH.PL", + LDRSH_VS: "LDRSH.VS", + LDRSH_VC: "LDRSH.VC", + LDRSH_HI: "LDRSH.HI", + LDRSH_LS: "LDRSH.LS", + LDRSH_GE: "LDRSH.GE", + LDRSH_LT: "LDRSH.LT", + LDRSH_GT: "LDRSH.GT", + LDRSH_LE: "LDRSH.LE", + LDRSH: "LDRSH", + LDRSH_ZZ: "LDRSH.ZZ", + LDRSHT_EQ: "LDRSHT.EQ", + LDRSHT_NE: "LDRSHT.NE", + LDRSHT_CS: "LDRSHT.CS", + LDRSHT_CC: "LDRSHT.CC", + LDRSHT_MI: "LDRSHT.MI", + LDRSHT_PL: "LDRSHT.PL", + LDRSHT_VS: "LDRSHT.VS", + LDRSHT_VC: "LDRSHT.VC", + LDRSHT_HI: "LDRSHT.HI", + LDRSHT_LS: "LDRSHT.LS", + LDRSHT_GE: "LDRSHT.GE", + LDRSHT_LT: "LDRSHT.LT", + LDRSHT_GT: "LDRSHT.GT", + LDRSHT_LE: "LDRSHT.LE", + LDRSHT: "LDRSHT", + LDRSHT_ZZ: "LDRSHT.ZZ", + LDRT_EQ: "LDRT.EQ", + LDRT_NE: "LDRT.NE", + LDRT_CS: "LDRT.CS", + LDRT_CC: "LDRT.CC", + LDRT_MI: "LDRT.MI", + LDRT_PL: "LDRT.PL", + LDRT_VS: "LDRT.VS", + LDRT_VC: "LDRT.VC", + LDRT_HI: "LDRT.HI", + LDRT_LS: "LDRT.LS", + LDRT_GE: "LDRT.GE", + LDRT_LT: "LDRT.LT", + LDRT_GT: "LDRT.GT", + LDRT_LE: "LDRT.LE", + LDRT: "LDRT", + LDRT_ZZ: "LDRT.ZZ", + LSL_EQ: "LSL.EQ", + LSL_NE: "LSL.NE", + LSL_CS: "LSL.CS", + LSL_CC: "LSL.CC", + LSL_MI: "LSL.MI", + LSL_PL: "LSL.PL", + LSL_VS: "LSL.VS", + LSL_VC: "LSL.VC", + LSL_HI: "LSL.HI", + LSL_LS: "LSL.LS", + LSL_GE: "LSL.GE", + LSL_LT: "LSL.LT", + LSL_GT: "LSL.GT", + LSL_LE: "LSL.LE", + LSL: "LSL", + LSL_ZZ: "LSL.ZZ", + LSL_S_EQ: "LSL.S.EQ", + LSL_S_NE: "LSL.S.NE", + LSL_S_CS: "LSL.S.CS", + LSL_S_CC: "LSL.S.CC", + LSL_S_MI: "LSL.S.MI", + LSL_S_PL: "LSL.S.PL", + LSL_S_VS: "LSL.S.VS", + LSL_S_VC: "LSL.S.VC", + LSL_S_HI: "LSL.S.HI", + LSL_S_LS: "LSL.S.LS", + LSL_S_GE: "LSL.S.GE", + LSL_S_LT: "LSL.S.LT", + LSL_S_GT: "LSL.S.GT", + LSL_S_LE: "LSL.S.LE", + LSL_S: "LSL.S", + LSL_S_ZZ: "LSL.S.ZZ", + LSR_EQ: "LSR.EQ", + LSR_NE: "LSR.NE", + LSR_CS: "LSR.CS", + LSR_CC: "LSR.CC", + LSR_MI: "LSR.MI", + LSR_PL: "LSR.PL", + LSR_VS: "LSR.VS", + LSR_VC: "LSR.VC", + LSR_HI: "LSR.HI", + LSR_LS: "LSR.LS", + LSR_GE: "LSR.GE", + LSR_LT: "LSR.LT", + LSR_GT: "LSR.GT", + LSR_LE: "LSR.LE", + LSR: "LSR", + LSR_ZZ: "LSR.ZZ", + LSR_S_EQ: "LSR.S.EQ", + LSR_S_NE: "LSR.S.NE", + LSR_S_CS: "LSR.S.CS", + LSR_S_CC: "LSR.S.CC", + LSR_S_MI: "LSR.S.MI", + LSR_S_PL: "LSR.S.PL", + LSR_S_VS: "LSR.S.VS", + LSR_S_VC: "LSR.S.VC", + LSR_S_HI: "LSR.S.HI", + LSR_S_LS: "LSR.S.LS", + LSR_S_GE: "LSR.S.GE", + LSR_S_LT: "LSR.S.LT", + LSR_S_GT: "LSR.S.GT", + LSR_S_LE: "LSR.S.LE", + LSR_S: "LSR.S", + LSR_S_ZZ: "LSR.S.ZZ", + MLA_EQ: "MLA.EQ", + MLA_NE: "MLA.NE", + MLA_CS: "MLA.CS", + MLA_CC: "MLA.CC", + MLA_MI: "MLA.MI", + MLA_PL: "MLA.PL", + MLA_VS: "MLA.VS", + MLA_VC: "MLA.VC", + MLA_HI: "MLA.HI", + MLA_LS: "MLA.LS", + MLA_GE: "MLA.GE", + MLA_LT: "MLA.LT", + MLA_GT: "MLA.GT", + MLA_LE: "MLA.LE", + MLA: "MLA", + MLA_ZZ: "MLA.ZZ", + MLA_S_EQ: "MLA.S.EQ", + MLA_S_NE: "MLA.S.NE", + MLA_S_CS: "MLA.S.CS", + MLA_S_CC: "MLA.S.CC", + MLA_S_MI: "MLA.S.MI", + MLA_S_PL: "MLA.S.PL", + MLA_S_VS: "MLA.S.VS", + MLA_S_VC: "MLA.S.VC", + MLA_S_HI: "MLA.S.HI", + MLA_S_LS: "MLA.S.LS", + MLA_S_GE: "MLA.S.GE", + MLA_S_LT: "MLA.S.LT", + MLA_S_GT: "MLA.S.GT", + MLA_S_LE: "MLA.S.LE", + MLA_S: "MLA.S", + MLA_S_ZZ: "MLA.S.ZZ", + MLS_EQ: "MLS.EQ", + MLS_NE: "MLS.NE", + MLS_CS: "MLS.CS", + MLS_CC: "MLS.CC", + MLS_MI: "MLS.MI", + MLS_PL: "MLS.PL", + MLS_VS: "MLS.VS", + MLS_VC: "MLS.VC", + MLS_HI: "MLS.HI", + MLS_LS: "MLS.LS", + MLS_GE: "MLS.GE", + MLS_LT: "MLS.LT", + MLS_GT: "MLS.GT", + MLS_LE: "MLS.LE", + MLS: "MLS", + MLS_ZZ: "MLS.ZZ", + MOV_EQ: "MOV.EQ", + MOV_NE: "MOV.NE", + MOV_CS: "MOV.CS", + MOV_CC: "MOV.CC", + MOV_MI: "MOV.MI", + MOV_PL: "MOV.PL", + MOV_VS: "MOV.VS", + MOV_VC: "MOV.VC", + MOV_HI: "MOV.HI", + MOV_LS: "MOV.LS", + MOV_GE: "MOV.GE", + MOV_LT: "MOV.LT", + MOV_GT: "MOV.GT", + MOV_LE: "MOV.LE", + MOV: "MOV", + MOV_ZZ: "MOV.ZZ", + MOV_S_EQ: "MOV.S.EQ", + MOV_S_NE: "MOV.S.NE", + MOV_S_CS: "MOV.S.CS", + MOV_S_CC: "MOV.S.CC", + MOV_S_MI: "MOV.S.MI", + MOV_S_PL: "MOV.S.PL", + MOV_S_VS: "MOV.S.VS", + MOV_S_VC: "MOV.S.VC", + MOV_S_HI: "MOV.S.HI", + MOV_S_LS: "MOV.S.LS", + MOV_S_GE: "MOV.S.GE", + MOV_S_LT: "MOV.S.LT", + MOV_S_GT: "MOV.S.GT", + MOV_S_LE: "MOV.S.LE", + MOV_S: "MOV.S", + MOV_S_ZZ: "MOV.S.ZZ", + MOVT_EQ: "MOVT.EQ", + MOVT_NE: "MOVT.NE", + MOVT_CS: "MOVT.CS", + MOVT_CC: "MOVT.CC", + MOVT_MI: "MOVT.MI", + MOVT_PL: "MOVT.PL", + MOVT_VS: "MOVT.VS", + MOVT_VC: "MOVT.VC", + MOVT_HI: "MOVT.HI", + MOVT_LS: "MOVT.LS", + MOVT_GE: "MOVT.GE", + MOVT_LT: "MOVT.LT", + MOVT_GT: "MOVT.GT", + MOVT_LE: "MOVT.LE", + MOVT: "MOVT", + MOVT_ZZ: "MOVT.ZZ", + MOVW_EQ: "MOVW.EQ", + MOVW_NE: "MOVW.NE", + MOVW_CS: "MOVW.CS", + MOVW_CC: "MOVW.CC", + MOVW_MI: "MOVW.MI", + MOVW_PL: "MOVW.PL", + MOVW_VS: "MOVW.VS", + MOVW_VC: "MOVW.VC", + MOVW_HI: "MOVW.HI", + MOVW_LS: "MOVW.LS", + MOVW_GE: "MOVW.GE", + MOVW_LT: "MOVW.LT", + MOVW_GT: "MOVW.GT", + MOVW_LE: "MOVW.LE", + MOVW: "MOVW", + MOVW_ZZ: "MOVW.ZZ", + MRS_EQ: "MRS.EQ", + MRS_NE: "MRS.NE", + MRS_CS: "MRS.CS", + MRS_CC: "MRS.CC", + MRS_MI: "MRS.MI", + MRS_PL: "MRS.PL", + MRS_VS: "MRS.VS", + MRS_VC: "MRS.VC", + MRS_HI: "MRS.HI", + MRS_LS: "MRS.LS", + MRS_GE: "MRS.GE", + MRS_LT: "MRS.LT", + MRS_GT: "MRS.GT", + MRS_LE: "MRS.LE", + MRS: "MRS", + MRS_ZZ: "MRS.ZZ", + MSR_EQ: "MSR.EQ", + MSR_NE: "MSR.NE", + MSR_CS: "MSR.CS", + MSR_CC: "MSR.CC", + MSR_MI: "MSR.MI", + MSR_PL: "MSR.PL", + MSR_VS: "MSR.VS", + MSR_VC: "MSR.VC", + MSR_HI: "MSR.HI", + MSR_LS: "MSR.LS", + MSR_GE: "MSR.GE", + MSR_LT: "MSR.LT", + MSR_GT: "MSR.GT", + MSR_LE: "MSR.LE", + MSR: "MSR", + MSR_ZZ: "MSR.ZZ", + MUL_EQ: "MUL.EQ", + MUL_NE: "MUL.NE", + MUL_CS: "MUL.CS", + MUL_CC: "MUL.CC", + MUL_MI: "MUL.MI", + MUL_PL: "MUL.PL", + MUL_VS: "MUL.VS", + MUL_VC: "MUL.VC", + MUL_HI: "MUL.HI", + MUL_LS: "MUL.LS", + MUL_GE: "MUL.GE", + MUL_LT: "MUL.LT", + MUL_GT: "MUL.GT", + MUL_LE: "MUL.LE", + MUL: "MUL", + MUL_ZZ: "MUL.ZZ", + MUL_S_EQ: "MUL.S.EQ", + MUL_S_NE: "MUL.S.NE", + MUL_S_CS: "MUL.S.CS", + MUL_S_CC: "MUL.S.CC", + MUL_S_MI: "MUL.S.MI", + MUL_S_PL: "MUL.S.PL", + MUL_S_VS: "MUL.S.VS", + MUL_S_VC: "MUL.S.VC", + MUL_S_HI: "MUL.S.HI", + MUL_S_LS: "MUL.S.LS", + MUL_S_GE: "MUL.S.GE", + MUL_S_LT: "MUL.S.LT", + MUL_S_GT: "MUL.S.GT", + MUL_S_LE: "MUL.S.LE", + MUL_S: "MUL.S", + MUL_S_ZZ: "MUL.S.ZZ", + MVN_EQ: "MVN.EQ", + MVN_NE: "MVN.NE", + MVN_CS: "MVN.CS", + MVN_CC: "MVN.CC", + MVN_MI: "MVN.MI", + MVN_PL: "MVN.PL", + MVN_VS: "MVN.VS", + MVN_VC: "MVN.VC", + MVN_HI: "MVN.HI", + MVN_LS: "MVN.LS", + MVN_GE: "MVN.GE", + MVN_LT: "MVN.LT", + MVN_GT: "MVN.GT", + MVN_LE: "MVN.LE", + MVN: "MVN", + MVN_ZZ: "MVN.ZZ", + MVN_S_EQ: "MVN.S.EQ", + MVN_S_NE: "MVN.S.NE", + MVN_S_CS: "MVN.S.CS", + MVN_S_CC: "MVN.S.CC", + MVN_S_MI: "MVN.S.MI", + MVN_S_PL: "MVN.S.PL", + MVN_S_VS: "MVN.S.VS", + MVN_S_VC: "MVN.S.VC", + MVN_S_HI: "MVN.S.HI", + MVN_S_LS: "MVN.S.LS", + MVN_S_GE: "MVN.S.GE", + MVN_S_LT: "MVN.S.LT", + MVN_S_GT: "MVN.S.GT", + MVN_S_LE: "MVN.S.LE", + MVN_S: "MVN.S", + MVN_S_ZZ: "MVN.S.ZZ", + NOP_EQ: "NOP.EQ", + NOP_NE: "NOP.NE", + NOP_CS: "NOP.CS", + NOP_CC: "NOP.CC", + NOP_MI: "NOP.MI", + NOP_PL: "NOP.PL", + NOP_VS: "NOP.VS", + NOP_VC: "NOP.VC", + NOP_HI: "NOP.HI", + NOP_LS: "NOP.LS", + NOP_GE: "NOP.GE", + NOP_LT: "NOP.LT", + NOP_GT: "NOP.GT", + NOP_LE: "NOP.LE", + NOP: "NOP", + NOP_ZZ: "NOP.ZZ", + ORR_EQ: "ORR.EQ", + ORR_NE: "ORR.NE", + ORR_CS: "ORR.CS", + ORR_CC: "ORR.CC", + ORR_MI: "ORR.MI", + ORR_PL: "ORR.PL", + ORR_VS: "ORR.VS", + ORR_VC: "ORR.VC", + ORR_HI: "ORR.HI", + ORR_LS: "ORR.LS", + ORR_GE: "ORR.GE", + ORR_LT: "ORR.LT", + ORR_GT: "ORR.GT", + ORR_LE: "ORR.LE", + ORR: "ORR", + ORR_ZZ: "ORR.ZZ", + ORR_S_EQ: "ORR.S.EQ", + ORR_S_NE: "ORR.S.NE", + ORR_S_CS: "ORR.S.CS", + ORR_S_CC: "ORR.S.CC", + ORR_S_MI: "ORR.S.MI", + ORR_S_PL: "ORR.S.PL", + ORR_S_VS: "ORR.S.VS", + ORR_S_VC: "ORR.S.VC", + ORR_S_HI: "ORR.S.HI", + ORR_S_LS: "ORR.S.LS", + ORR_S_GE: "ORR.S.GE", + ORR_S_LT: "ORR.S.LT", + ORR_S_GT: "ORR.S.GT", + ORR_S_LE: "ORR.S.LE", + ORR_S: "ORR.S", + ORR_S_ZZ: "ORR.S.ZZ", + PKHBT_EQ: "PKHBT.EQ", + PKHBT_NE: "PKHBT.NE", + PKHBT_CS: "PKHBT.CS", + PKHBT_CC: "PKHBT.CC", + PKHBT_MI: "PKHBT.MI", + PKHBT_PL: "PKHBT.PL", + PKHBT_VS: "PKHBT.VS", + PKHBT_VC: "PKHBT.VC", + PKHBT_HI: "PKHBT.HI", + PKHBT_LS: "PKHBT.LS", + PKHBT_GE: "PKHBT.GE", + PKHBT_LT: "PKHBT.LT", + PKHBT_GT: "PKHBT.GT", + PKHBT_LE: "PKHBT.LE", + PKHBT: "PKHBT", + PKHBT_ZZ: "PKHBT.ZZ", + PKHTB_EQ: "PKHTB.EQ", + PKHTB_NE: "PKHTB.NE", + PKHTB_CS: "PKHTB.CS", + PKHTB_CC: "PKHTB.CC", + PKHTB_MI: "PKHTB.MI", + PKHTB_PL: "PKHTB.PL", + PKHTB_VS: "PKHTB.VS", + PKHTB_VC: "PKHTB.VC", + PKHTB_HI: "PKHTB.HI", + PKHTB_LS: "PKHTB.LS", + PKHTB_GE: "PKHTB.GE", + PKHTB_LT: "PKHTB.LT", + PKHTB_GT: "PKHTB.GT", + PKHTB_LE: "PKHTB.LE", + PKHTB: "PKHTB", + PKHTB_ZZ: "PKHTB.ZZ", + PLD_W: "PLD.W", + PLD: "PLD", + PLI: "PLI", + POP_EQ: "POP.EQ", + POP_NE: "POP.NE", + POP_CS: "POP.CS", + POP_CC: "POP.CC", + POP_MI: "POP.MI", + POP_PL: "POP.PL", + POP_VS: "POP.VS", + POP_VC: "POP.VC", + POP_HI: "POP.HI", + POP_LS: "POP.LS", + POP_GE: "POP.GE", + POP_LT: "POP.LT", + POP_GT: "POP.GT", + POP_LE: "POP.LE", + POP: "POP", + POP_ZZ: "POP.ZZ", + PUSH_EQ: "PUSH.EQ", + PUSH_NE: "PUSH.NE", + PUSH_CS: "PUSH.CS", + PUSH_CC: "PUSH.CC", + PUSH_MI: "PUSH.MI", + PUSH_PL: "PUSH.PL", + PUSH_VS: "PUSH.VS", + PUSH_VC: "PUSH.VC", + PUSH_HI: "PUSH.HI", + PUSH_LS: "PUSH.LS", + PUSH_GE: "PUSH.GE", + PUSH_LT: "PUSH.LT", + PUSH_GT: "PUSH.GT", + PUSH_LE: "PUSH.LE", + PUSH: "PUSH", + PUSH_ZZ: "PUSH.ZZ", + QADD_EQ: "QADD.EQ", + QADD_NE: "QADD.NE", + QADD_CS: "QADD.CS", + QADD_CC: "QADD.CC", + QADD_MI: "QADD.MI", + QADD_PL: "QADD.PL", + QADD_VS: "QADD.VS", + QADD_VC: "QADD.VC", + QADD_HI: "QADD.HI", + QADD_LS: "QADD.LS", + QADD_GE: "QADD.GE", + QADD_LT: "QADD.LT", + QADD_GT: "QADD.GT", + QADD_LE: "QADD.LE", + QADD: "QADD", + QADD_ZZ: "QADD.ZZ", + QADD16_EQ: "QADD16.EQ", + QADD16_NE: "QADD16.NE", + QADD16_CS: "QADD16.CS", + QADD16_CC: "QADD16.CC", + QADD16_MI: "QADD16.MI", + QADD16_PL: "QADD16.PL", + QADD16_VS: "QADD16.VS", + QADD16_VC: "QADD16.VC", + QADD16_HI: "QADD16.HI", + QADD16_LS: "QADD16.LS", + QADD16_GE: "QADD16.GE", + QADD16_LT: "QADD16.LT", + QADD16_GT: "QADD16.GT", + QADD16_LE: "QADD16.LE", + QADD16: "QADD16", + QADD16_ZZ: "QADD16.ZZ", + QADD8_EQ: "QADD8.EQ", + QADD8_NE: "QADD8.NE", + QADD8_CS: "QADD8.CS", + QADD8_CC: "QADD8.CC", + QADD8_MI: "QADD8.MI", + QADD8_PL: "QADD8.PL", + QADD8_VS: "QADD8.VS", + QADD8_VC: "QADD8.VC", + QADD8_HI: "QADD8.HI", + QADD8_LS: "QADD8.LS", + QADD8_GE: "QADD8.GE", + QADD8_LT: "QADD8.LT", + QADD8_GT: "QADD8.GT", + QADD8_LE: "QADD8.LE", + QADD8: "QADD8", + QADD8_ZZ: "QADD8.ZZ", + QASX_EQ: "QASX.EQ", + QASX_NE: "QASX.NE", + QASX_CS: "QASX.CS", + QASX_CC: "QASX.CC", + QASX_MI: "QASX.MI", + QASX_PL: "QASX.PL", + QASX_VS: "QASX.VS", + QASX_VC: "QASX.VC", + QASX_HI: "QASX.HI", + QASX_LS: "QASX.LS", + QASX_GE: "QASX.GE", + QASX_LT: "QASX.LT", + QASX_GT: "QASX.GT", + QASX_LE: "QASX.LE", + QASX: "QASX", + QASX_ZZ: "QASX.ZZ", + QDADD_EQ: "QDADD.EQ", + QDADD_NE: "QDADD.NE", + QDADD_CS: "QDADD.CS", + QDADD_CC: "QDADD.CC", + QDADD_MI: "QDADD.MI", + QDADD_PL: "QDADD.PL", + QDADD_VS: "QDADD.VS", + QDADD_VC: "QDADD.VC", + QDADD_HI: "QDADD.HI", + QDADD_LS: "QDADD.LS", + QDADD_GE: "QDADD.GE", + QDADD_LT: "QDADD.LT", + QDADD_GT: "QDADD.GT", + QDADD_LE: "QDADD.LE", + QDADD: "QDADD", + QDADD_ZZ: "QDADD.ZZ", + QDSUB_EQ: "QDSUB.EQ", + QDSUB_NE: "QDSUB.NE", + QDSUB_CS: "QDSUB.CS", + QDSUB_CC: "QDSUB.CC", + QDSUB_MI: "QDSUB.MI", + QDSUB_PL: "QDSUB.PL", + QDSUB_VS: "QDSUB.VS", + QDSUB_VC: "QDSUB.VC", + QDSUB_HI: "QDSUB.HI", + QDSUB_LS: "QDSUB.LS", + QDSUB_GE: "QDSUB.GE", + QDSUB_LT: "QDSUB.LT", + QDSUB_GT: "QDSUB.GT", + QDSUB_LE: "QDSUB.LE", + QDSUB: "QDSUB", + QDSUB_ZZ: "QDSUB.ZZ", + QSAX_EQ: "QSAX.EQ", + QSAX_NE: "QSAX.NE", + QSAX_CS: "QSAX.CS", + QSAX_CC: "QSAX.CC", + QSAX_MI: "QSAX.MI", + QSAX_PL: "QSAX.PL", + QSAX_VS: "QSAX.VS", + QSAX_VC: "QSAX.VC", + QSAX_HI: "QSAX.HI", + QSAX_LS: "QSAX.LS", + QSAX_GE: "QSAX.GE", + QSAX_LT: "QSAX.LT", + QSAX_GT: "QSAX.GT", + QSAX_LE: "QSAX.LE", + QSAX: "QSAX", + QSAX_ZZ: "QSAX.ZZ", + QSUB_EQ: "QSUB.EQ", + QSUB_NE: "QSUB.NE", + QSUB_CS: "QSUB.CS", + QSUB_CC: "QSUB.CC", + QSUB_MI: "QSUB.MI", + QSUB_PL: "QSUB.PL", + QSUB_VS: "QSUB.VS", + QSUB_VC: "QSUB.VC", + QSUB_HI: "QSUB.HI", + QSUB_LS: "QSUB.LS", + QSUB_GE: "QSUB.GE", + QSUB_LT: "QSUB.LT", + QSUB_GT: "QSUB.GT", + QSUB_LE: "QSUB.LE", + QSUB: "QSUB", + QSUB_ZZ: "QSUB.ZZ", + QSUB16_EQ: "QSUB16.EQ", + QSUB16_NE: "QSUB16.NE", + QSUB16_CS: "QSUB16.CS", + QSUB16_CC: "QSUB16.CC", + QSUB16_MI: "QSUB16.MI", + QSUB16_PL: "QSUB16.PL", + QSUB16_VS: "QSUB16.VS", + QSUB16_VC: "QSUB16.VC", + QSUB16_HI: "QSUB16.HI", + QSUB16_LS: "QSUB16.LS", + QSUB16_GE: "QSUB16.GE", + QSUB16_LT: "QSUB16.LT", + QSUB16_GT: "QSUB16.GT", + QSUB16_LE: "QSUB16.LE", + QSUB16: "QSUB16", + QSUB16_ZZ: "QSUB16.ZZ", + QSUB8_EQ: "QSUB8.EQ", + QSUB8_NE: "QSUB8.NE", + QSUB8_CS: "QSUB8.CS", + QSUB8_CC: "QSUB8.CC", + QSUB8_MI: "QSUB8.MI", + QSUB8_PL: "QSUB8.PL", + QSUB8_VS: "QSUB8.VS", + QSUB8_VC: "QSUB8.VC", + QSUB8_HI: "QSUB8.HI", + QSUB8_LS: "QSUB8.LS", + QSUB8_GE: "QSUB8.GE", + QSUB8_LT: "QSUB8.LT", + QSUB8_GT: "QSUB8.GT", + QSUB8_LE: "QSUB8.LE", + QSUB8: "QSUB8", + QSUB8_ZZ: "QSUB8.ZZ", + RBIT_EQ: "RBIT.EQ", + RBIT_NE: "RBIT.NE", + RBIT_CS: "RBIT.CS", + RBIT_CC: "RBIT.CC", + RBIT_MI: "RBIT.MI", + RBIT_PL: "RBIT.PL", + RBIT_VS: "RBIT.VS", + RBIT_VC: "RBIT.VC", + RBIT_HI: "RBIT.HI", + RBIT_LS: "RBIT.LS", + RBIT_GE: "RBIT.GE", + RBIT_LT: "RBIT.LT", + RBIT_GT: "RBIT.GT", + RBIT_LE: "RBIT.LE", + RBIT: "RBIT", + RBIT_ZZ: "RBIT.ZZ", + REV_EQ: "REV.EQ", + REV_NE: "REV.NE", + REV_CS: "REV.CS", + REV_CC: "REV.CC", + REV_MI: "REV.MI", + REV_PL: "REV.PL", + REV_VS: "REV.VS", + REV_VC: "REV.VC", + REV_HI: "REV.HI", + REV_LS: "REV.LS", + REV_GE: "REV.GE", + REV_LT: "REV.LT", + REV_GT: "REV.GT", + REV_LE: "REV.LE", + REV: "REV", + REV_ZZ: "REV.ZZ", + REV16_EQ: "REV16.EQ", + REV16_NE: "REV16.NE", + REV16_CS: "REV16.CS", + REV16_CC: "REV16.CC", + REV16_MI: "REV16.MI", + REV16_PL: "REV16.PL", + REV16_VS: "REV16.VS", + REV16_VC: "REV16.VC", + REV16_HI: "REV16.HI", + REV16_LS: "REV16.LS", + REV16_GE: "REV16.GE", + REV16_LT: "REV16.LT", + REV16_GT: "REV16.GT", + REV16_LE: "REV16.LE", + REV16: "REV16", + REV16_ZZ: "REV16.ZZ", + REVSH_EQ: "REVSH.EQ", + REVSH_NE: "REVSH.NE", + REVSH_CS: "REVSH.CS", + REVSH_CC: "REVSH.CC", + REVSH_MI: "REVSH.MI", + REVSH_PL: "REVSH.PL", + REVSH_VS: "REVSH.VS", + REVSH_VC: "REVSH.VC", + REVSH_HI: "REVSH.HI", + REVSH_LS: "REVSH.LS", + REVSH_GE: "REVSH.GE", + REVSH_LT: "REVSH.LT", + REVSH_GT: "REVSH.GT", + REVSH_LE: "REVSH.LE", + REVSH: "REVSH", + REVSH_ZZ: "REVSH.ZZ", + ROR_EQ: "ROR.EQ", + ROR_NE: "ROR.NE", + ROR_CS: "ROR.CS", + ROR_CC: "ROR.CC", + ROR_MI: "ROR.MI", + ROR_PL: "ROR.PL", + ROR_VS: "ROR.VS", + ROR_VC: "ROR.VC", + ROR_HI: "ROR.HI", + ROR_LS: "ROR.LS", + ROR_GE: "ROR.GE", + ROR_LT: "ROR.LT", + ROR_GT: "ROR.GT", + ROR_LE: "ROR.LE", + ROR: "ROR", + ROR_ZZ: "ROR.ZZ", + ROR_S_EQ: "ROR.S.EQ", + ROR_S_NE: "ROR.S.NE", + ROR_S_CS: "ROR.S.CS", + ROR_S_CC: "ROR.S.CC", + ROR_S_MI: "ROR.S.MI", + ROR_S_PL: "ROR.S.PL", + ROR_S_VS: "ROR.S.VS", + ROR_S_VC: "ROR.S.VC", + ROR_S_HI: "ROR.S.HI", + ROR_S_LS: "ROR.S.LS", + ROR_S_GE: "ROR.S.GE", + ROR_S_LT: "ROR.S.LT", + ROR_S_GT: "ROR.S.GT", + ROR_S_LE: "ROR.S.LE", + ROR_S: "ROR.S", + ROR_S_ZZ: "ROR.S.ZZ", + RRX_EQ: "RRX.EQ", + RRX_NE: "RRX.NE", + RRX_CS: "RRX.CS", + RRX_CC: "RRX.CC", + RRX_MI: "RRX.MI", + RRX_PL: "RRX.PL", + RRX_VS: "RRX.VS", + RRX_VC: "RRX.VC", + RRX_HI: "RRX.HI", + RRX_LS: "RRX.LS", + RRX_GE: "RRX.GE", + RRX_LT: "RRX.LT", + RRX_GT: "RRX.GT", + RRX_LE: "RRX.LE", + RRX: "RRX", + RRX_ZZ: "RRX.ZZ", + RRX_S_EQ: "RRX.S.EQ", + RRX_S_NE: "RRX.S.NE", + RRX_S_CS: "RRX.S.CS", + RRX_S_CC: "RRX.S.CC", + RRX_S_MI: "RRX.S.MI", + RRX_S_PL: "RRX.S.PL", + RRX_S_VS: "RRX.S.VS", + RRX_S_VC: "RRX.S.VC", + RRX_S_HI: "RRX.S.HI", + RRX_S_LS: "RRX.S.LS", + RRX_S_GE: "RRX.S.GE", + RRX_S_LT: "RRX.S.LT", + RRX_S_GT: "RRX.S.GT", + RRX_S_LE: "RRX.S.LE", + RRX_S: "RRX.S", + RRX_S_ZZ: "RRX.S.ZZ", + RSB_EQ: "RSB.EQ", + RSB_NE: "RSB.NE", + RSB_CS: "RSB.CS", + RSB_CC: "RSB.CC", + RSB_MI: "RSB.MI", + RSB_PL: "RSB.PL", + RSB_VS: "RSB.VS", + RSB_VC: "RSB.VC", + RSB_HI: "RSB.HI", + RSB_LS: "RSB.LS", + RSB_GE: "RSB.GE", + RSB_LT: "RSB.LT", + RSB_GT: "RSB.GT", + RSB_LE: "RSB.LE", + RSB: "RSB", + RSB_ZZ: "RSB.ZZ", + RSB_S_EQ: "RSB.S.EQ", + RSB_S_NE: "RSB.S.NE", + RSB_S_CS: "RSB.S.CS", + RSB_S_CC: "RSB.S.CC", + RSB_S_MI: "RSB.S.MI", + RSB_S_PL: "RSB.S.PL", + RSB_S_VS: "RSB.S.VS", + RSB_S_VC: "RSB.S.VC", + RSB_S_HI: "RSB.S.HI", + RSB_S_LS: "RSB.S.LS", + RSB_S_GE: "RSB.S.GE", + RSB_S_LT: "RSB.S.LT", + RSB_S_GT: "RSB.S.GT", + RSB_S_LE: "RSB.S.LE", + RSB_S: "RSB.S", + RSB_S_ZZ: "RSB.S.ZZ", + RSC_EQ: "RSC.EQ", + RSC_NE: "RSC.NE", + RSC_CS: "RSC.CS", + RSC_CC: "RSC.CC", + RSC_MI: "RSC.MI", + RSC_PL: "RSC.PL", + RSC_VS: "RSC.VS", + RSC_VC: "RSC.VC", + RSC_HI: "RSC.HI", + RSC_LS: "RSC.LS", + RSC_GE: "RSC.GE", + RSC_LT: "RSC.LT", + RSC_GT: "RSC.GT", + RSC_LE: "RSC.LE", + RSC: "RSC", + RSC_ZZ: "RSC.ZZ", + RSC_S_EQ: "RSC.S.EQ", + RSC_S_NE: "RSC.S.NE", + RSC_S_CS: "RSC.S.CS", + RSC_S_CC: "RSC.S.CC", + RSC_S_MI: "RSC.S.MI", + RSC_S_PL: "RSC.S.PL", + RSC_S_VS: "RSC.S.VS", + RSC_S_VC: "RSC.S.VC", + RSC_S_HI: "RSC.S.HI", + RSC_S_LS: "RSC.S.LS", + RSC_S_GE: "RSC.S.GE", + RSC_S_LT: "RSC.S.LT", + RSC_S_GT: "RSC.S.GT", + RSC_S_LE: "RSC.S.LE", + RSC_S: "RSC.S", + RSC_S_ZZ: "RSC.S.ZZ", + SADD16_EQ: "SADD16.EQ", + SADD16_NE: "SADD16.NE", + SADD16_CS: "SADD16.CS", + SADD16_CC: "SADD16.CC", + SADD16_MI: "SADD16.MI", + SADD16_PL: "SADD16.PL", + SADD16_VS: "SADD16.VS", + SADD16_VC: "SADD16.VC", + SADD16_HI: "SADD16.HI", + SADD16_LS: "SADD16.LS", + SADD16_GE: "SADD16.GE", + SADD16_LT: "SADD16.LT", + SADD16_GT: "SADD16.GT", + SADD16_LE: "SADD16.LE", + SADD16: "SADD16", + SADD16_ZZ: "SADD16.ZZ", + SADD8_EQ: "SADD8.EQ", + SADD8_NE: "SADD8.NE", + SADD8_CS: "SADD8.CS", + SADD8_CC: "SADD8.CC", + SADD8_MI: "SADD8.MI", + SADD8_PL: "SADD8.PL", + SADD8_VS: "SADD8.VS", + SADD8_VC: "SADD8.VC", + SADD8_HI: "SADD8.HI", + SADD8_LS: "SADD8.LS", + SADD8_GE: "SADD8.GE", + SADD8_LT: "SADD8.LT", + SADD8_GT: "SADD8.GT", + SADD8_LE: "SADD8.LE", + SADD8: "SADD8", + SADD8_ZZ: "SADD8.ZZ", + SASX_EQ: "SASX.EQ", + SASX_NE: "SASX.NE", + SASX_CS: "SASX.CS", + SASX_CC: "SASX.CC", + SASX_MI: "SASX.MI", + SASX_PL: "SASX.PL", + SASX_VS: "SASX.VS", + SASX_VC: "SASX.VC", + SASX_HI: "SASX.HI", + SASX_LS: "SASX.LS", + SASX_GE: "SASX.GE", + SASX_LT: "SASX.LT", + SASX_GT: "SASX.GT", + SASX_LE: "SASX.LE", + SASX: "SASX", + SASX_ZZ: "SASX.ZZ", + SBC_EQ: "SBC.EQ", + SBC_NE: "SBC.NE", + SBC_CS: "SBC.CS", + SBC_CC: "SBC.CC", + SBC_MI: "SBC.MI", + SBC_PL: "SBC.PL", + SBC_VS: "SBC.VS", + SBC_VC: "SBC.VC", + SBC_HI: "SBC.HI", + SBC_LS: "SBC.LS", + SBC_GE: "SBC.GE", + SBC_LT: "SBC.LT", + SBC_GT: "SBC.GT", + SBC_LE: "SBC.LE", + SBC: "SBC", + SBC_ZZ: "SBC.ZZ", + SBC_S_EQ: "SBC.S.EQ", + SBC_S_NE: "SBC.S.NE", + SBC_S_CS: "SBC.S.CS", + SBC_S_CC: "SBC.S.CC", + SBC_S_MI: "SBC.S.MI", + SBC_S_PL: "SBC.S.PL", + SBC_S_VS: "SBC.S.VS", + SBC_S_VC: "SBC.S.VC", + SBC_S_HI: "SBC.S.HI", + SBC_S_LS: "SBC.S.LS", + SBC_S_GE: "SBC.S.GE", + SBC_S_LT: "SBC.S.LT", + SBC_S_GT: "SBC.S.GT", + SBC_S_LE: "SBC.S.LE", + SBC_S: "SBC.S", + SBC_S_ZZ: "SBC.S.ZZ", + SBFX_EQ: "SBFX.EQ", + SBFX_NE: "SBFX.NE", + SBFX_CS: "SBFX.CS", + SBFX_CC: "SBFX.CC", + SBFX_MI: "SBFX.MI", + SBFX_PL: "SBFX.PL", + SBFX_VS: "SBFX.VS", + SBFX_VC: "SBFX.VC", + SBFX_HI: "SBFX.HI", + SBFX_LS: "SBFX.LS", + SBFX_GE: "SBFX.GE", + SBFX_LT: "SBFX.LT", + SBFX_GT: "SBFX.GT", + SBFX_LE: "SBFX.LE", + SBFX: "SBFX", + SBFX_ZZ: "SBFX.ZZ", + SDIV_EQ: "SDIV.EQ", + SDIV_NE: "SDIV.NE", + SDIV_CS: "SDIV.CS", + SDIV_CC: "SDIV.CC", + SDIV_MI: "SDIV.MI", + SDIV_PL: "SDIV.PL", + SDIV_VS: "SDIV.VS", + SDIV_VC: "SDIV.VC", + SDIV_HI: "SDIV.HI", + SDIV_LS: "SDIV.LS", + SDIV_GE: "SDIV.GE", + SDIV_LT: "SDIV.LT", + SDIV_GT: "SDIV.GT", + SDIV_LE: "SDIV.LE", + SDIV: "SDIV", + SDIV_ZZ: "SDIV.ZZ", + SEL_EQ: "SEL.EQ", + SEL_NE: "SEL.NE", + SEL_CS: "SEL.CS", + SEL_CC: "SEL.CC", + SEL_MI: "SEL.MI", + SEL_PL: "SEL.PL", + SEL_VS: "SEL.VS", + SEL_VC: "SEL.VC", + SEL_HI: "SEL.HI", + SEL_LS: "SEL.LS", + SEL_GE: "SEL.GE", + SEL_LT: "SEL.LT", + SEL_GT: "SEL.GT", + SEL_LE: "SEL.LE", + SEL: "SEL", + SEL_ZZ: "SEL.ZZ", + SETEND: "SETEND", + SEV_EQ: "SEV.EQ", + SEV_NE: "SEV.NE", + SEV_CS: "SEV.CS", + SEV_CC: "SEV.CC", + SEV_MI: "SEV.MI", + SEV_PL: "SEV.PL", + SEV_VS: "SEV.VS", + SEV_VC: "SEV.VC", + SEV_HI: "SEV.HI", + SEV_LS: "SEV.LS", + SEV_GE: "SEV.GE", + SEV_LT: "SEV.LT", + SEV_GT: "SEV.GT", + SEV_LE: "SEV.LE", + SEV: "SEV", + SEV_ZZ: "SEV.ZZ", + SHADD16_EQ: "SHADD16.EQ", + SHADD16_NE: "SHADD16.NE", + SHADD16_CS: "SHADD16.CS", + SHADD16_CC: "SHADD16.CC", + SHADD16_MI: "SHADD16.MI", + SHADD16_PL: "SHADD16.PL", + SHADD16_VS: "SHADD16.VS", + SHADD16_VC: "SHADD16.VC", + SHADD16_HI: "SHADD16.HI", + SHADD16_LS: "SHADD16.LS", + SHADD16_GE: "SHADD16.GE", + SHADD16_LT: "SHADD16.LT", + SHADD16_GT: "SHADD16.GT", + SHADD16_LE: "SHADD16.LE", + SHADD16: "SHADD16", + SHADD16_ZZ: "SHADD16.ZZ", + SHADD8_EQ: "SHADD8.EQ", + SHADD8_NE: "SHADD8.NE", + SHADD8_CS: "SHADD8.CS", + SHADD8_CC: "SHADD8.CC", + SHADD8_MI: "SHADD8.MI", + SHADD8_PL: "SHADD8.PL", + SHADD8_VS: "SHADD8.VS", + SHADD8_VC: "SHADD8.VC", + SHADD8_HI: "SHADD8.HI", + SHADD8_LS: "SHADD8.LS", + SHADD8_GE: "SHADD8.GE", + SHADD8_LT: "SHADD8.LT", + SHADD8_GT: "SHADD8.GT", + SHADD8_LE: "SHADD8.LE", + SHADD8: "SHADD8", + SHADD8_ZZ: "SHADD8.ZZ", + SHASX_EQ: "SHASX.EQ", + SHASX_NE: "SHASX.NE", + SHASX_CS: "SHASX.CS", + SHASX_CC: "SHASX.CC", + SHASX_MI: "SHASX.MI", + SHASX_PL: "SHASX.PL", + SHASX_VS: "SHASX.VS", + SHASX_VC: "SHASX.VC", + SHASX_HI: "SHASX.HI", + SHASX_LS: "SHASX.LS", + SHASX_GE: "SHASX.GE", + SHASX_LT: "SHASX.LT", + SHASX_GT: "SHASX.GT", + SHASX_LE: "SHASX.LE", + SHASX: "SHASX", + SHASX_ZZ: "SHASX.ZZ", + SHSAX_EQ: "SHSAX.EQ", + SHSAX_NE: "SHSAX.NE", + SHSAX_CS: "SHSAX.CS", + SHSAX_CC: "SHSAX.CC", + SHSAX_MI: "SHSAX.MI", + SHSAX_PL: "SHSAX.PL", + SHSAX_VS: "SHSAX.VS", + SHSAX_VC: "SHSAX.VC", + SHSAX_HI: "SHSAX.HI", + SHSAX_LS: "SHSAX.LS", + SHSAX_GE: "SHSAX.GE", + SHSAX_LT: "SHSAX.LT", + SHSAX_GT: "SHSAX.GT", + SHSAX_LE: "SHSAX.LE", + SHSAX: "SHSAX", + SHSAX_ZZ: "SHSAX.ZZ", + SHSUB16_EQ: "SHSUB16.EQ", + SHSUB16_NE: "SHSUB16.NE", + SHSUB16_CS: "SHSUB16.CS", + SHSUB16_CC: "SHSUB16.CC", + SHSUB16_MI: "SHSUB16.MI", + SHSUB16_PL: "SHSUB16.PL", + SHSUB16_VS: "SHSUB16.VS", + SHSUB16_VC: "SHSUB16.VC", + SHSUB16_HI: "SHSUB16.HI", + SHSUB16_LS: "SHSUB16.LS", + SHSUB16_GE: "SHSUB16.GE", + SHSUB16_LT: "SHSUB16.LT", + SHSUB16_GT: "SHSUB16.GT", + SHSUB16_LE: "SHSUB16.LE", + SHSUB16: "SHSUB16", + SHSUB16_ZZ: "SHSUB16.ZZ", + SHSUB8_EQ: "SHSUB8.EQ", + SHSUB8_NE: "SHSUB8.NE", + SHSUB8_CS: "SHSUB8.CS", + SHSUB8_CC: "SHSUB8.CC", + SHSUB8_MI: "SHSUB8.MI", + SHSUB8_PL: "SHSUB8.PL", + SHSUB8_VS: "SHSUB8.VS", + SHSUB8_VC: "SHSUB8.VC", + SHSUB8_HI: "SHSUB8.HI", + SHSUB8_LS: "SHSUB8.LS", + SHSUB8_GE: "SHSUB8.GE", + SHSUB8_LT: "SHSUB8.LT", + SHSUB8_GT: "SHSUB8.GT", + SHSUB8_LE: "SHSUB8.LE", + SHSUB8: "SHSUB8", + SHSUB8_ZZ: "SHSUB8.ZZ", + SMLABB_EQ: "SMLABB.EQ", + SMLABB_NE: "SMLABB.NE", + SMLABB_CS: "SMLABB.CS", + SMLABB_CC: "SMLABB.CC", + SMLABB_MI: "SMLABB.MI", + SMLABB_PL: "SMLABB.PL", + SMLABB_VS: "SMLABB.VS", + SMLABB_VC: "SMLABB.VC", + SMLABB_HI: "SMLABB.HI", + SMLABB_LS: "SMLABB.LS", + SMLABB_GE: "SMLABB.GE", + SMLABB_LT: "SMLABB.LT", + SMLABB_GT: "SMLABB.GT", + SMLABB_LE: "SMLABB.LE", + SMLABB: "SMLABB", + SMLABB_ZZ: "SMLABB.ZZ", + SMLABT_EQ: "SMLABT.EQ", + SMLABT_NE: "SMLABT.NE", + SMLABT_CS: "SMLABT.CS", + SMLABT_CC: "SMLABT.CC", + SMLABT_MI: "SMLABT.MI", + SMLABT_PL: "SMLABT.PL", + SMLABT_VS: "SMLABT.VS", + SMLABT_VC: "SMLABT.VC", + SMLABT_HI: "SMLABT.HI", + SMLABT_LS: "SMLABT.LS", + SMLABT_GE: "SMLABT.GE", + SMLABT_LT: "SMLABT.LT", + SMLABT_GT: "SMLABT.GT", + SMLABT_LE: "SMLABT.LE", + SMLABT: "SMLABT", + SMLABT_ZZ: "SMLABT.ZZ", + SMLATB_EQ: "SMLATB.EQ", + SMLATB_NE: "SMLATB.NE", + SMLATB_CS: "SMLATB.CS", + SMLATB_CC: "SMLATB.CC", + SMLATB_MI: "SMLATB.MI", + SMLATB_PL: "SMLATB.PL", + SMLATB_VS: "SMLATB.VS", + SMLATB_VC: "SMLATB.VC", + SMLATB_HI: "SMLATB.HI", + SMLATB_LS: "SMLATB.LS", + SMLATB_GE: "SMLATB.GE", + SMLATB_LT: "SMLATB.LT", + SMLATB_GT: "SMLATB.GT", + SMLATB_LE: "SMLATB.LE", + SMLATB: "SMLATB", + SMLATB_ZZ: "SMLATB.ZZ", + SMLATT_EQ: "SMLATT.EQ", + SMLATT_NE: "SMLATT.NE", + SMLATT_CS: "SMLATT.CS", + SMLATT_CC: "SMLATT.CC", + SMLATT_MI: "SMLATT.MI", + SMLATT_PL: "SMLATT.PL", + SMLATT_VS: "SMLATT.VS", + SMLATT_VC: "SMLATT.VC", + SMLATT_HI: "SMLATT.HI", + SMLATT_LS: "SMLATT.LS", + SMLATT_GE: "SMLATT.GE", + SMLATT_LT: "SMLATT.LT", + SMLATT_GT: "SMLATT.GT", + SMLATT_LE: "SMLATT.LE", + SMLATT: "SMLATT", + SMLATT_ZZ: "SMLATT.ZZ", + SMLAD_EQ: "SMLAD.EQ", + SMLAD_NE: "SMLAD.NE", + SMLAD_CS: "SMLAD.CS", + SMLAD_CC: "SMLAD.CC", + SMLAD_MI: "SMLAD.MI", + SMLAD_PL: "SMLAD.PL", + SMLAD_VS: "SMLAD.VS", + SMLAD_VC: "SMLAD.VC", + SMLAD_HI: "SMLAD.HI", + SMLAD_LS: "SMLAD.LS", + SMLAD_GE: "SMLAD.GE", + SMLAD_LT: "SMLAD.LT", + SMLAD_GT: "SMLAD.GT", + SMLAD_LE: "SMLAD.LE", + SMLAD: "SMLAD", + SMLAD_ZZ: "SMLAD.ZZ", + SMLAD_X_EQ: "SMLAD.X.EQ", + SMLAD_X_NE: "SMLAD.X.NE", + SMLAD_X_CS: "SMLAD.X.CS", + SMLAD_X_CC: "SMLAD.X.CC", + SMLAD_X_MI: "SMLAD.X.MI", + SMLAD_X_PL: "SMLAD.X.PL", + SMLAD_X_VS: "SMLAD.X.VS", + SMLAD_X_VC: "SMLAD.X.VC", + SMLAD_X_HI: "SMLAD.X.HI", + SMLAD_X_LS: "SMLAD.X.LS", + SMLAD_X_GE: "SMLAD.X.GE", + SMLAD_X_LT: "SMLAD.X.LT", + SMLAD_X_GT: "SMLAD.X.GT", + SMLAD_X_LE: "SMLAD.X.LE", + SMLAD_X: "SMLAD.X", + SMLAD_X_ZZ: "SMLAD.X.ZZ", + SMLAL_EQ: "SMLAL.EQ", + SMLAL_NE: "SMLAL.NE", + SMLAL_CS: "SMLAL.CS", + SMLAL_CC: "SMLAL.CC", + SMLAL_MI: "SMLAL.MI", + SMLAL_PL: "SMLAL.PL", + SMLAL_VS: "SMLAL.VS", + SMLAL_VC: "SMLAL.VC", + SMLAL_HI: "SMLAL.HI", + SMLAL_LS: "SMLAL.LS", + SMLAL_GE: "SMLAL.GE", + SMLAL_LT: "SMLAL.LT", + SMLAL_GT: "SMLAL.GT", + SMLAL_LE: "SMLAL.LE", + SMLAL: "SMLAL", + SMLAL_ZZ: "SMLAL.ZZ", + SMLAL_S_EQ: "SMLAL.S.EQ", + SMLAL_S_NE: "SMLAL.S.NE", + SMLAL_S_CS: "SMLAL.S.CS", + SMLAL_S_CC: "SMLAL.S.CC", + SMLAL_S_MI: "SMLAL.S.MI", + SMLAL_S_PL: "SMLAL.S.PL", + SMLAL_S_VS: "SMLAL.S.VS", + SMLAL_S_VC: "SMLAL.S.VC", + SMLAL_S_HI: "SMLAL.S.HI", + SMLAL_S_LS: "SMLAL.S.LS", + SMLAL_S_GE: "SMLAL.S.GE", + SMLAL_S_LT: "SMLAL.S.LT", + SMLAL_S_GT: "SMLAL.S.GT", + SMLAL_S_LE: "SMLAL.S.LE", + SMLAL_S: "SMLAL.S", + SMLAL_S_ZZ: "SMLAL.S.ZZ", + SMLALBB_EQ: "SMLALBB.EQ", + SMLALBB_NE: "SMLALBB.NE", + SMLALBB_CS: "SMLALBB.CS", + SMLALBB_CC: "SMLALBB.CC", + SMLALBB_MI: "SMLALBB.MI", + SMLALBB_PL: "SMLALBB.PL", + SMLALBB_VS: "SMLALBB.VS", + SMLALBB_VC: "SMLALBB.VC", + SMLALBB_HI: "SMLALBB.HI", + SMLALBB_LS: "SMLALBB.LS", + SMLALBB_GE: "SMLALBB.GE", + SMLALBB_LT: "SMLALBB.LT", + SMLALBB_GT: "SMLALBB.GT", + SMLALBB_LE: "SMLALBB.LE", + SMLALBB: "SMLALBB", + SMLALBB_ZZ: "SMLALBB.ZZ", + SMLALBT_EQ: "SMLALBT.EQ", + SMLALBT_NE: "SMLALBT.NE", + SMLALBT_CS: "SMLALBT.CS", + SMLALBT_CC: "SMLALBT.CC", + SMLALBT_MI: "SMLALBT.MI", + SMLALBT_PL: "SMLALBT.PL", + SMLALBT_VS: "SMLALBT.VS", + SMLALBT_VC: "SMLALBT.VC", + SMLALBT_HI: "SMLALBT.HI", + SMLALBT_LS: "SMLALBT.LS", + SMLALBT_GE: "SMLALBT.GE", + SMLALBT_LT: "SMLALBT.LT", + SMLALBT_GT: "SMLALBT.GT", + SMLALBT_LE: "SMLALBT.LE", + SMLALBT: "SMLALBT", + SMLALBT_ZZ: "SMLALBT.ZZ", + SMLALTB_EQ: "SMLALTB.EQ", + SMLALTB_NE: "SMLALTB.NE", + SMLALTB_CS: "SMLALTB.CS", + SMLALTB_CC: "SMLALTB.CC", + SMLALTB_MI: "SMLALTB.MI", + SMLALTB_PL: "SMLALTB.PL", + SMLALTB_VS: "SMLALTB.VS", + SMLALTB_VC: "SMLALTB.VC", + SMLALTB_HI: "SMLALTB.HI", + SMLALTB_LS: "SMLALTB.LS", + SMLALTB_GE: "SMLALTB.GE", + SMLALTB_LT: "SMLALTB.LT", + SMLALTB_GT: "SMLALTB.GT", + SMLALTB_LE: "SMLALTB.LE", + SMLALTB: "SMLALTB", + SMLALTB_ZZ: "SMLALTB.ZZ", + SMLALTT_EQ: "SMLALTT.EQ", + SMLALTT_NE: "SMLALTT.NE", + SMLALTT_CS: "SMLALTT.CS", + SMLALTT_CC: "SMLALTT.CC", + SMLALTT_MI: "SMLALTT.MI", + SMLALTT_PL: "SMLALTT.PL", + SMLALTT_VS: "SMLALTT.VS", + SMLALTT_VC: "SMLALTT.VC", + SMLALTT_HI: "SMLALTT.HI", + SMLALTT_LS: "SMLALTT.LS", + SMLALTT_GE: "SMLALTT.GE", + SMLALTT_LT: "SMLALTT.LT", + SMLALTT_GT: "SMLALTT.GT", + SMLALTT_LE: "SMLALTT.LE", + SMLALTT: "SMLALTT", + SMLALTT_ZZ: "SMLALTT.ZZ", + SMLALD_EQ: "SMLALD.EQ", + SMLALD_NE: "SMLALD.NE", + SMLALD_CS: "SMLALD.CS", + SMLALD_CC: "SMLALD.CC", + SMLALD_MI: "SMLALD.MI", + SMLALD_PL: "SMLALD.PL", + SMLALD_VS: "SMLALD.VS", + SMLALD_VC: "SMLALD.VC", + SMLALD_HI: "SMLALD.HI", + SMLALD_LS: "SMLALD.LS", + SMLALD_GE: "SMLALD.GE", + SMLALD_LT: "SMLALD.LT", + SMLALD_GT: "SMLALD.GT", + SMLALD_LE: "SMLALD.LE", + SMLALD: "SMLALD", + SMLALD_ZZ: "SMLALD.ZZ", + SMLALD_X_EQ: "SMLALD.X.EQ", + SMLALD_X_NE: "SMLALD.X.NE", + SMLALD_X_CS: "SMLALD.X.CS", + SMLALD_X_CC: "SMLALD.X.CC", + SMLALD_X_MI: "SMLALD.X.MI", + SMLALD_X_PL: "SMLALD.X.PL", + SMLALD_X_VS: "SMLALD.X.VS", + SMLALD_X_VC: "SMLALD.X.VC", + SMLALD_X_HI: "SMLALD.X.HI", + SMLALD_X_LS: "SMLALD.X.LS", + SMLALD_X_GE: "SMLALD.X.GE", + SMLALD_X_LT: "SMLALD.X.LT", + SMLALD_X_GT: "SMLALD.X.GT", + SMLALD_X_LE: "SMLALD.X.LE", + SMLALD_X: "SMLALD.X", + SMLALD_X_ZZ: "SMLALD.X.ZZ", + SMLAWB_EQ: "SMLAWB.EQ", + SMLAWB_NE: "SMLAWB.NE", + SMLAWB_CS: "SMLAWB.CS", + SMLAWB_CC: "SMLAWB.CC", + SMLAWB_MI: "SMLAWB.MI", + SMLAWB_PL: "SMLAWB.PL", + SMLAWB_VS: "SMLAWB.VS", + SMLAWB_VC: "SMLAWB.VC", + SMLAWB_HI: "SMLAWB.HI", + SMLAWB_LS: "SMLAWB.LS", + SMLAWB_GE: "SMLAWB.GE", + SMLAWB_LT: "SMLAWB.LT", + SMLAWB_GT: "SMLAWB.GT", + SMLAWB_LE: "SMLAWB.LE", + SMLAWB: "SMLAWB", + SMLAWB_ZZ: "SMLAWB.ZZ", + SMLAWT_EQ: "SMLAWT.EQ", + SMLAWT_NE: "SMLAWT.NE", + SMLAWT_CS: "SMLAWT.CS", + SMLAWT_CC: "SMLAWT.CC", + SMLAWT_MI: "SMLAWT.MI", + SMLAWT_PL: "SMLAWT.PL", + SMLAWT_VS: "SMLAWT.VS", + SMLAWT_VC: "SMLAWT.VC", + SMLAWT_HI: "SMLAWT.HI", + SMLAWT_LS: "SMLAWT.LS", + SMLAWT_GE: "SMLAWT.GE", + SMLAWT_LT: "SMLAWT.LT", + SMLAWT_GT: "SMLAWT.GT", + SMLAWT_LE: "SMLAWT.LE", + SMLAWT: "SMLAWT", + SMLAWT_ZZ: "SMLAWT.ZZ", + SMLSD_EQ: "SMLSD.EQ", + SMLSD_NE: "SMLSD.NE", + SMLSD_CS: "SMLSD.CS", + SMLSD_CC: "SMLSD.CC", + SMLSD_MI: "SMLSD.MI", + SMLSD_PL: "SMLSD.PL", + SMLSD_VS: "SMLSD.VS", + SMLSD_VC: "SMLSD.VC", + SMLSD_HI: "SMLSD.HI", + SMLSD_LS: "SMLSD.LS", + SMLSD_GE: "SMLSD.GE", + SMLSD_LT: "SMLSD.LT", + SMLSD_GT: "SMLSD.GT", + SMLSD_LE: "SMLSD.LE", + SMLSD: "SMLSD", + SMLSD_ZZ: "SMLSD.ZZ", + SMLSD_X_EQ: "SMLSD.X.EQ", + SMLSD_X_NE: "SMLSD.X.NE", + SMLSD_X_CS: "SMLSD.X.CS", + SMLSD_X_CC: "SMLSD.X.CC", + SMLSD_X_MI: "SMLSD.X.MI", + SMLSD_X_PL: "SMLSD.X.PL", + SMLSD_X_VS: "SMLSD.X.VS", + SMLSD_X_VC: "SMLSD.X.VC", + SMLSD_X_HI: "SMLSD.X.HI", + SMLSD_X_LS: "SMLSD.X.LS", + SMLSD_X_GE: "SMLSD.X.GE", + SMLSD_X_LT: "SMLSD.X.LT", + SMLSD_X_GT: "SMLSD.X.GT", + SMLSD_X_LE: "SMLSD.X.LE", + SMLSD_X: "SMLSD.X", + SMLSD_X_ZZ: "SMLSD.X.ZZ", + SMLSLD_EQ: "SMLSLD.EQ", + SMLSLD_NE: "SMLSLD.NE", + SMLSLD_CS: "SMLSLD.CS", + SMLSLD_CC: "SMLSLD.CC", + SMLSLD_MI: "SMLSLD.MI", + SMLSLD_PL: "SMLSLD.PL", + SMLSLD_VS: "SMLSLD.VS", + SMLSLD_VC: "SMLSLD.VC", + SMLSLD_HI: "SMLSLD.HI", + SMLSLD_LS: "SMLSLD.LS", + SMLSLD_GE: "SMLSLD.GE", + SMLSLD_LT: "SMLSLD.LT", + SMLSLD_GT: "SMLSLD.GT", + SMLSLD_LE: "SMLSLD.LE", + SMLSLD: "SMLSLD", + SMLSLD_ZZ: "SMLSLD.ZZ", + SMLSLD_X_EQ: "SMLSLD.X.EQ", + SMLSLD_X_NE: "SMLSLD.X.NE", + SMLSLD_X_CS: "SMLSLD.X.CS", + SMLSLD_X_CC: "SMLSLD.X.CC", + SMLSLD_X_MI: "SMLSLD.X.MI", + SMLSLD_X_PL: "SMLSLD.X.PL", + SMLSLD_X_VS: "SMLSLD.X.VS", + SMLSLD_X_VC: "SMLSLD.X.VC", + SMLSLD_X_HI: "SMLSLD.X.HI", + SMLSLD_X_LS: "SMLSLD.X.LS", + SMLSLD_X_GE: "SMLSLD.X.GE", + SMLSLD_X_LT: "SMLSLD.X.LT", + SMLSLD_X_GT: "SMLSLD.X.GT", + SMLSLD_X_LE: "SMLSLD.X.LE", + SMLSLD_X: "SMLSLD.X", + SMLSLD_X_ZZ: "SMLSLD.X.ZZ", + SMMLA_EQ: "SMMLA.EQ", + SMMLA_NE: "SMMLA.NE", + SMMLA_CS: "SMMLA.CS", + SMMLA_CC: "SMMLA.CC", + SMMLA_MI: "SMMLA.MI", + SMMLA_PL: "SMMLA.PL", + SMMLA_VS: "SMMLA.VS", + SMMLA_VC: "SMMLA.VC", + SMMLA_HI: "SMMLA.HI", + SMMLA_LS: "SMMLA.LS", + SMMLA_GE: "SMMLA.GE", + SMMLA_LT: "SMMLA.LT", + SMMLA_GT: "SMMLA.GT", + SMMLA_LE: "SMMLA.LE", + SMMLA: "SMMLA", + SMMLA_ZZ: "SMMLA.ZZ", + SMMLA_R_EQ: "SMMLA.R.EQ", + SMMLA_R_NE: "SMMLA.R.NE", + SMMLA_R_CS: "SMMLA.R.CS", + SMMLA_R_CC: "SMMLA.R.CC", + SMMLA_R_MI: "SMMLA.R.MI", + SMMLA_R_PL: "SMMLA.R.PL", + SMMLA_R_VS: "SMMLA.R.VS", + SMMLA_R_VC: "SMMLA.R.VC", + SMMLA_R_HI: "SMMLA.R.HI", + SMMLA_R_LS: "SMMLA.R.LS", + SMMLA_R_GE: "SMMLA.R.GE", + SMMLA_R_LT: "SMMLA.R.LT", + SMMLA_R_GT: "SMMLA.R.GT", + SMMLA_R_LE: "SMMLA.R.LE", + SMMLA_R: "SMMLA.R", + SMMLA_R_ZZ: "SMMLA.R.ZZ", + SMMLS_EQ: "SMMLS.EQ", + SMMLS_NE: "SMMLS.NE", + SMMLS_CS: "SMMLS.CS", + SMMLS_CC: "SMMLS.CC", + SMMLS_MI: "SMMLS.MI", + SMMLS_PL: "SMMLS.PL", + SMMLS_VS: "SMMLS.VS", + SMMLS_VC: "SMMLS.VC", + SMMLS_HI: "SMMLS.HI", + SMMLS_LS: "SMMLS.LS", + SMMLS_GE: "SMMLS.GE", + SMMLS_LT: "SMMLS.LT", + SMMLS_GT: "SMMLS.GT", + SMMLS_LE: "SMMLS.LE", + SMMLS: "SMMLS", + SMMLS_ZZ: "SMMLS.ZZ", + SMMLS_R_EQ: "SMMLS.R.EQ", + SMMLS_R_NE: "SMMLS.R.NE", + SMMLS_R_CS: "SMMLS.R.CS", + SMMLS_R_CC: "SMMLS.R.CC", + SMMLS_R_MI: "SMMLS.R.MI", + SMMLS_R_PL: "SMMLS.R.PL", + SMMLS_R_VS: "SMMLS.R.VS", + SMMLS_R_VC: "SMMLS.R.VC", + SMMLS_R_HI: "SMMLS.R.HI", + SMMLS_R_LS: "SMMLS.R.LS", + SMMLS_R_GE: "SMMLS.R.GE", + SMMLS_R_LT: "SMMLS.R.LT", + SMMLS_R_GT: "SMMLS.R.GT", + SMMLS_R_LE: "SMMLS.R.LE", + SMMLS_R: "SMMLS.R", + SMMLS_R_ZZ: "SMMLS.R.ZZ", + SMMUL_EQ: "SMMUL.EQ", + SMMUL_NE: "SMMUL.NE", + SMMUL_CS: "SMMUL.CS", + SMMUL_CC: "SMMUL.CC", + SMMUL_MI: "SMMUL.MI", + SMMUL_PL: "SMMUL.PL", + SMMUL_VS: "SMMUL.VS", + SMMUL_VC: "SMMUL.VC", + SMMUL_HI: "SMMUL.HI", + SMMUL_LS: "SMMUL.LS", + SMMUL_GE: "SMMUL.GE", + SMMUL_LT: "SMMUL.LT", + SMMUL_GT: "SMMUL.GT", + SMMUL_LE: "SMMUL.LE", + SMMUL: "SMMUL", + SMMUL_ZZ: "SMMUL.ZZ", + SMMUL_R_EQ: "SMMUL.R.EQ", + SMMUL_R_NE: "SMMUL.R.NE", + SMMUL_R_CS: "SMMUL.R.CS", + SMMUL_R_CC: "SMMUL.R.CC", + SMMUL_R_MI: "SMMUL.R.MI", + SMMUL_R_PL: "SMMUL.R.PL", + SMMUL_R_VS: "SMMUL.R.VS", + SMMUL_R_VC: "SMMUL.R.VC", + SMMUL_R_HI: "SMMUL.R.HI", + SMMUL_R_LS: "SMMUL.R.LS", + SMMUL_R_GE: "SMMUL.R.GE", + SMMUL_R_LT: "SMMUL.R.LT", + SMMUL_R_GT: "SMMUL.R.GT", + SMMUL_R_LE: "SMMUL.R.LE", + SMMUL_R: "SMMUL.R", + SMMUL_R_ZZ: "SMMUL.R.ZZ", + SMUAD_EQ: "SMUAD.EQ", + SMUAD_NE: "SMUAD.NE", + SMUAD_CS: "SMUAD.CS", + SMUAD_CC: "SMUAD.CC", + SMUAD_MI: "SMUAD.MI", + SMUAD_PL: "SMUAD.PL", + SMUAD_VS: "SMUAD.VS", + SMUAD_VC: "SMUAD.VC", + SMUAD_HI: "SMUAD.HI", + SMUAD_LS: "SMUAD.LS", + SMUAD_GE: "SMUAD.GE", + SMUAD_LT: "SMUAD.LT", + SMUAD_GT: "SMUAD.GT", + SMUAD_LE: "SMUAD.LE", + SMUAD: "SMUAD", + SMUAD_ZZ: "SMUAD.ZZ", + SMUAD_X_EQ: "SMUAD.X.EQ", + SMUAD_X_NE: "SMUAD.X.NE", + SMUAD_X_CS: "SMUAD.X.CS", + SMUAD_X_CC: "SMUAD.X.CC", + SMUAD_X_MI: "SMUAD.X.MI", + SMUAD_X_PL: "SMUAD.X.PL", + SMUAD_X_VS: "SMUAD.X.VS", + SMUAD_X_VC: "SMUAD.X.VC", + SMUAD_X_HI: "SMUAD.X.HI", + SMUAD_X_LS: "SMUAD.X.LS", + SMUAD_X_GE: "SMUAD.X.GE", + SMUAD_X_LT: "SMUAD.X.LT", + SMUAD_X_GT: "SMUAD.X.GT", + SMUAD_X_LE: "SMUAD.X.LE", + SMUAD_X: "SMUAD.X", + SMUAD_X_ZZ: "SMUAD.X.ZZ", + SMULBB_EQ: "SMULBB.EQ", + SMULBB_NE: "SMULBB.NE", + SMULBB_CS: "SMULBB.CS", + SMULBB_CC: "SMULBB.CC", + SMULBB_MI: "SMULBB.MI", + SMULBB_PL: "SMULBB.PL", + SMULBB_VS: "SMULBB.VS", + SMULBB_VC: "SMULBB.VC", + SMULBB_HI: "SMULBB.HI", + SMULBB_LS: "SMULBB.LS", + SMULBB_GE: "SMULBB.GE", + SMULBB_LT: "SMULBB.LT", + SMULBB_GT: "SMULBB.GT", + SMULBB_LE: "SMULBB.LE", + SMULBB: "SMULBB", + SMULBB_ZZ: "SMULBB.ZZ", + SMULBT_EQ: "SMULBT.EQ", + SMULBT_NE: "SMULBT.NE", + SMULBT_CS: "SMULBT.CS", + SMULBT_CC: "SMULBT.CC", + SMULBT_MI: "SMULBT.MI", + SMULBT_PL: "SMULBT.PL", + SMULBT_VS: "SMULBT.VS", + SMULBT_VC: "SMULBT.VC", + SMULBT_HI: "SMULBT.HI", + SMULBT_LS: "SMULBT.LS", + SMULBT_GE: "SMULBT.GE", + SMULBT_LT: "SMULBT.LT", + SMULBT_GT: "SMULBT.GT", + SMULBT_LE: "SMULBT.LE", + SMULBT: "SMULBT", + SMULBT_ZZ: "SMULBT.ZZ", + SMULTB_EQ: "SMULTB.EQ", + SMULTB_NE: "SMULTB.NE", + SMULTB_CS: "SMULTB.CS", + SMULTB_CC: "SMULTB.CC", + SMULTB_MI: "SMULTB.MI", + SMULTB_PL: "SMULTB.PL", + SMULTB_VS: "SMULTB.VS", + SMULTB_VC: "SMULTB.VC", + SMULTB_HI: "SMULTB.HI", + SMULTB_LS: "SMULTB.LS", + SMULTB_GE: "SMULTB.GE", + SMULTB_LT: "SMULTB.LT", + SMULTB_GT: "SMULTB.GT", + SMULTB_LE: "SMULTB.LE", + SMULTB: "SMULTB", + SMULTB_ZZ: "SMULTB.ZZ", + SMULTT_EQ: "SMULTT.EQ", + SMULTT_NE: "SMULTT.NE", + SMULTT_CS: "SMULTT.CS", + SMULTT_CC: "SMULTT.CC", + SMULTT_MI: "SMULTT.MI", + SMULTT_PL: "SMULTT.PL", + SMULTT_VS: "SMULTT.VS", + SMULTT_VC: "SMULTT.VC", + SMULTT_HI: "SMULTT.HI", + SMULTT_LS: "SMULTT.LS", + SMULTT_GE: "SMULTT.GE", + SMULTT_LT: "SMULTT.LT", + SMULTT_GT: "SMULTT.GT", + SMULTT_LE: "SMULTT.LE", + SMULTT: "SMULTT", + SMULTT_ZZ: "SMULTT.ZZ", + SMULL_EQ: "SMULL.EQ", + SMULL_NE: "SMULL.NE", + SMULL_CS: "SMULL.CS", + SMULL_CC: "SMULL.CC", + SMULL_MI: "SMULL.MI", + SMULL_PL: "SMULL.PL", + SMULL_VS: "SMULL.VS", + SMULL_VC: "SMULL.VC", + SMULL_HI: "SMULL.HI", + SMULL_LS: "SMULL.LS", + SMULL_GE: "SMULL.GE", + SMULL_LT: "SMULL.LT", + SMULL_GT: "SMULL.GT", + SMULL_LE: "SMULL.LE", + SMULL: "SMULL", + SMULL_ZZ: "SMULL.ZZ", + SMULL_S_EQ: "SMULL.S.EQ", + SMULL_S_NE: "SMULL.S.NE", + SMULL_S_CS: "SMULL.S.CS", + SMULL_S_CC: "SMULL.S.CC", + SMULL_S_MI: "SMULL.S.MI", + SMULL_S_PL: "SMULL.S.PL", + SMULL_S_VS: "SMULL.S.VS", + SMULL_S_VC: "SMULL.S.VC", + SMULL_S_HI: "SMULL.S.HI", + SMULL_S_LS: "SMULL.S.LS", + SMULL_S_GE: "SMULL.S.GE", + SMULL_S_LT: "SMULL.S.LT", + SMULL_S_GT: "SMULL.S.GT", + SMULL_S_LE: "SMULL.S.LE", + SMULL_S: "SMULL.S", + SMULL_S_ZZ: "SMULL.S.ZZ", + SMULWB_EQ: "SMULWB.EQ", + SMULWB_NE: "SMULWB.NE", + SMULWB_CS: "SMULWB.CS", + SMULWB_CC: "SMULWB.CC", + SMULWB_MI: "SMULWB.MI", + SMULWB_PL: "SMULWB.PL", + SMULWB_VS: "SMULWB.VS", + SMULWB_VC: "SMULWB.VC", + SMULWB_HI: "SMULWB.HI", + SMULWB_LS: "SMULWB.LS", + SMULWB_GE: "SMULWB.GE", + SMULWB_LT: "SMULWB.LT", + SMULWB_GT: "SMULWB.GT", + SMULWB_LE: "SMULWB.LE", + SMULWB: "SMULWB", + SMULWB_ZZ: "SMULWB.ZZ", + SMULWT_EQ: "SMULWT.EQ", + SMULWT_NE: "SMULWT.NE", + SMULWT_CS: "SMULWT.CS", + SMULWT_CC: "SMULWT.CC", + SMULWT_MI: "SMULWT.MI", + SMULWT_PL: "SMULWT.PL", + SMULWT_VS: "SMULWT.VS", + SMULWT_VC: "SMULWT.VC", + SMULWT_HI: "SMULWT.HI", + SMULWT_LS: "SMULWT.LS", + SMULWT_GE: "SMULWT.GE", + SMULWT_LT: "SMULWT.LT", + SMULWT_GT: "SMULWT.GT", + SMULWT_LE: "SMULWT.LE", + SMULWT: "SMULWT", + SMULWT_ZZ: "SMULWT.ZZ", + SMUSD_EQ: "SMUSD.EQ", + SMUSD_NE: "SMUSD.NE", + SMUSD_CS: "SMUSD.CS", + SMUSD_CC: "SMUSD.CC", + SMUSD_MI: "SMUSD.MI", + SMUSD_PL: "SMUSD.PL", + SMUSD_VS: "SMUSD.VS", + SMUSD_VC: "SMUSD.VC", + SMUSD_HI: "SMUSD.HI", + SMUSD_LS: "SMUSD.LS", + SMUSD_GE: "SMUSD.GE", + SMUSD_LT: "SMUSD.LT", + SMUSD_GT: "SMUSD.GT", + SMUSD_LE: "SMUSD.LE", + SMUSD: "SMUSD", + SMUSD_ZZ: "SMUSD.ZZ", + SMUSD_X_EQ: "SMUSD.X.EQ", + SMUSD_X_NE: "SMUSD.X.NE", + SMUSD_X_CS: "SMUSD.X.CS", + SMUSD_X_CC: "SMUSD.X.CC", + SMUSD_X_MI: "SMUSD.X.MI", + SMUSD_X_PL: "SMUSD.X.PL", + SMUSD_X_VS: "SMUSD.X.VS", + SMUSD_X_VC: "SMUSD.X.VC", + SMUSD_X_HI: "SMUSD.X.HI", + SMUSD_X_LS: "SMUSD.X.LS", + SMUSD_X_GE: "SMUSD.X.GE", + SMUSD_X_LT: "SMUSD.X.LT", + SMUSD_X_GT: "SMUSD.X.GT", + SMUSD_X_LE: "SMUSD.X.LE", + SMUSD_X: "SMUSD.X", + SMUSD_X_ZZ: "SMUSD.X.ZZ", + SSAT_EQ: "SSAT.EQ", + SSAT_NE: "SSAT.NE", + SSAT_CS: "SSAT.CS", + SSAT_CC: "SSAT.CC", + SSAT_MI: "SSAT.MI", + SSAT_PL: "SSAT.PL", + SSAT_VS: "SSAT.VS", + SSAT_VC: "SSAT.VC", + SSAT_HI: "SSAT.HI", + SSAT_LS: "SSAT.LS", + SSAT_GE: "SSAT.GE", + SSAT_LT: "SSAT.LT", + SSAT_GT: "SSAT.GT", + SSAT_LE: "SSAT.LE", + SSAT: "SSAT", + SSAT_ZZ: "SSAT.ZZ", + SSAT16_EQ: "SSAT16.EQ", + SSAT16_NE: "SSAT16.NE", + SSAT16_CS: "SSAT16.CS", + SSAT16_CC: "SSAT16.CC", + SSAT16_MI: "SSAT16.MI", + SSAT16_PL: "SSAT16.PL", + SSAT16_VS: "SSAT16.VS", + SSAT16_VC: "SSAT16.VC", + SSAT16_HI: "SSAT16.HI", + SSAT16_LS: "SSAT16.LS", + SSAT16_GE: "SSAT16.GE", + SSAT16_LT: "SSAT16.LT", + SSAT16_GT: "SSAT16.GT", + SSAT16_LE: "SSAT16.LE", + SSAT16: "SSAT16", + SSAT16_ZZ: "SSAT16.ZZ", + SSAX_EQ: "SSAX.EQ", + SSAX_NE: "SSAX.NE", + SSAX_CS: "SSAX.CS", + SSAX_CC: "SSAX.CC", + SSAX_MI: "SSAX.MI", + SSAX_PL: "SSAX.PL", + SSAX_VS: "SSAX.VS", + SSAX_VC: "SSAX.VC", + SSAX_HI: "SSAX.HI", + SSAX_LS: "SSAX.LS", + SSAX_GE: "SSAX.GE", + SSAX_LT: "SSAX.LT", + SSAX_GT: "SSAX.GT", + SSAX_LE: "SSAX.LE", + SSAX: "SSAX", + SSAX_ZZ: "SSAX.ZZ", + SSUB16_EQ: "SSUB16.EQ", + SSUB16_NE: "SSUB16.NE", + SSUB16_CS: "SSUB16.CS", + SSUB16_CC: "SSUB16.CC", + SSUB16_MI: "SSUB16.MI", + SSUB16_PL: "SSUB16.PL", + SSUB16_VS: "SSUB16.VS", + SSUB16_VC: "SSUB16.VC", + SSUB16_HI: "SSUB16.HI", + SSUB16_LS: "SSUB16.LS", + SSUB16_GE: "SSUB16.GE", + SSUB16_LT: "SSUB16.LT", + SSUB16_GT: "SSUB16.GT", + SSUB16_LE: "SSUB16.LE", + SSUB16: "SSUB16", + SSUB16_ZZ: "SSUB16.ZZ", + SSUB8_EQ: "SSUB8.EQ", + SSUB8_NE: "SSUB8.NE", + SSUB8_CS: "SSUB8.CS", + SSUB8_CC: "SSUB8.CC", + SSUB8_MI: "SSUB8.MI", + SSUB8_PL: "SSUB8.PL", + SSUB8_VS: "SSUB8.VS", + SSUB8_VC: "SSUB8.VC", + SSUB8_HI: "SSUB8.HI", + SSUB8_LS: "SSUB8.LS", + SSUB8_GE: "SSUB8.GE", + SSUB8_LT: "SSUB8.LT", + SSUB8_GT: "SSUB8.GT", + SSUB8_LE: "SSUB8.LE", + SSUB8: "SSUB8", + SSUB8_ZZ: "SSUB8.ZZ", + STM_EQ: "STM.EQ", + STM_NE: "STM.NE", + STM_CS: "STM.CS", + STM_CC: "STM.CC", + STM_MI: "STM.MI", + STM_PL: "STM.PL", + STM_VS: "STM.VS", + STM_VC: "STM.VC", + STM_HI: "STM.HI", + STM_LS: "STM.LS", + STM_GE: "STM.GE", + STM_LT: "STM.LT", + STM_GT: "STM.GT", + STM_LE: "STM.LE", + STM: "STM", + STM_ZZ: "STM.ZZ", + STMDA_EQ: "STMDA.EQ", + STMDA_NE: "STMDA.NE", + STMDA_CS: "STMDA.CS", + STMDA_CC: "STMDA.CC", + STMDA_MI: "STMDA.MI", + STMDA_PL: "STMDA.PL", + STMDA_VS: "STMDA.VS", + STMDA_VC: "STMDA.VC", + STMDA_HI: "STMDA.HI", + STMDA_LS: "STMDA.LS", + STMDA_GE: "STMDA.GE", + STMDA_LT: "STMDA.LT", + STMDA_GT: "STMDA.GT", + STMDA_LE: "STMDA.LE", + STMDA: "STMDA", + STMDA_ZZ: "STMDA.ZZ", + STMDB_EQ: "STMDB.EQ", + STMDB_NE: "STMDB.NE", + STMDB_CS: "STMDB.CS", + STMDB_CC: "STMDB.CC", + STMDB_MI: "STMDB.MI", + STMDB_PL: "STMDB.PL", + STMDB_VS: "STMDB.VS", + STMDB_VC: "STMDB.VC", + STMDB_HI: "STMDB.HI", + STMDB_LS: "STMDB.LS", + STMDB_GE: "STMDB.GE", + STMDB_LT: "STMDB.LT", + STMDB_GT: "STMDB.GT", + STMDB_LE: "STMDB.LE", + STMDB: "STMDB", + STMDB_ZZ: "STMDB.ZZ", + STMIB_EQ: "STMIB.EQ", + STMIB_NE: "STMIB.NE", + STMIB_CS: "STMIB.CS", + STMIB_CC: "STMIB.CC", + STMIB_MI: "STMIB.MI", + STMIB_PL: "STMIB.PL", + STMIB_VS: "STMIB.VS", + STMIB_VC: "STMIB.VC", + STMIB_HI: "STMIB.HI", + STMIB_LS: "STMIB.LS", + STMIB_GE: "STMIB.GE", + STMIB_LT: "STMIB.LT", + STMIB_GT: "STMIB.GT", + STMIB_LE: "STMIB.LE", + STMIB: "STMIB", + STMIB_ZZ: "STMIB.ZZ", + STR_EQ: "STR.EQ", + STR_NE: "STR.NE", + STR_CS: "STR.CS", + STR_CC: "STR.CC", + STR_MI: "STR.MI", + STR_PL: "STR.PL", + STR_VS: "STR.VS", + STR_VC: "STR.VC", + STR_HI: "STR.HI", + STR_LS: "STR.LS", + STR_GE: "STR.GE", + STR_LT: "STR.LT", + STR_GT: "STR.GT", + STR_LE: "STR.LE", + STR: "STR", + STR_ZZ: "STR.ZZ", + STRB_EQ: "STRB.EQ", + STRB_NE: "STRB.NE", + STRB_CS: "STRB.CS", + STRB_CC: "STRB.CC", + STRB_MI: "STRB.MI", + STRB_PL: "STRB.PL", + STRB_VS: "STRB.VS", + STRB_VC: "STRB.VC", + STRB_HI: "STRB.HI", + STRB_LS: "STRB.LS", + STRB_GE: "STRB.GE", + STRB_LT: "STRB.LT", + STRB_GT: "STRB.GT", + STRB_LE: "STRB.LE", + STRB: "STRB", + STRB_ZZ: "STRB.ZZ", + STRBT_EQ: "STRBT.EQ", + STRBT_NE: "STRBT.NE", + STRBT_CS: "STRBT.CS", + STRBT_CC: "STRBT.CC", + STRBT_MI: "STRBT.MI", + STRBT_PL: "STRBT.PL", + STRBT_VS: "STRBT.VS", + STRBT_VC: "STRBT.VC", + STRBT_HI: "STRBT.HI", + STRBT_LS: "STRBT.LS", + STRBT_GE: "STRBT.GE", + STRBT_LT: "STRBT.LT", + STRBT_GT: "STRBT.GT", + STRBT_LE: "STRBT.LE", + STRBT: "STRBT", + STRBT_ZZ: "STRBT.ZZ", + STRD_EQ: "STRD.EQ", + STRD_NE: "STRD.NE", + STRD_CS: "STRD.CS", + STRD_CC: "STRD.CC", + STRD_MI: "STRD.MI", + STRD_PL: "STRD.PL", + STRD_VS: "STRD.VS", + STRD_VC: "STRD.VC", + STRD_HI: "STRD.HI", + STRD_LS: "STRD.LS", + STRD_GE: "STRD.GE", + STRD_LT: "STRD.LT", + STRD_GT: "STRD.GT", + STRD_LE: "STRD.LE", + STRD: "STRD", + STRD_ZZ: "STRD.ZZ", + STREX_EQ: "STREX.EQ", + STREX_NE: "STREX.NE", + STREX_CS: "STREX.CS", + STREX_CC: "STREX.CC", + STREX_MI: "STREX.MI", + STREX_PL: "STREX.PL", + STREX_VS: "STREX.VS", + STREX_VC: "STREX.VC", + STREX_HI: "STREX.HI", + STREX_LS: "STREX.LS", + STREX_GE: "STREX.GE", + STREX_LT: "STREX.LT", + STREX_GT: "STREX.GT", + STREX_LE: "STREX.LE", + STREX: "STREX", + STREX_ZZ: "STREX.ZZ", + STREXB_EQ: "STREXB.EQ", + STREXB_NE: "STREXB.NE", + STREXB_CS: "STREXB.CS", + STREXB_CC: "STREXB.CC", + STREXB_MI: "STREXB.MI", + STREXB_PL: "STREXB.PL", + STREXB_VS: "STREXB.VS", + STREXB_VC: "STREXB.VC", + STREXB_HI: "STREXB.HI", + STREXB_LS: "STREXB.LS", + STREXB_GE: "STREXB.GE", + STREXB_LT: "STREXB.LT", + STREXB_GT: "STREXB.GT", + STREXB_LE: "STREXB.LE", + STREXB: "STREXB", + STREXB_ZZ: "STREXB.ZZ", + STREXD_EQ: "STREXD.EQ", + STREXD_NE: "STREXD.NE", + STREXD_CS: "STREXD.CS", + STREXD_CC: "STREXD.CC", + STREXD_MI: "STREXD.MI", + STREXD_PL: "STREXD.PL", + STREXD_VS: "STREXD.VS", + STREXD_VC: "STREXD.VC", + STREXD_HI: "STREXD.HI", + STREXD_LS: "STREXD.LS", + STREXD_GE: "STREXD.GE", + STREXD_LT: "STREXD.LT", + STREXD_GT: "STREXD.GT", + STREXD_LE: "STREXD.LE", + STREXD: "STREXD", + STREXD_ZZ: "STREXD.ZZ", + STREXH_EQ: "STREXH.EQ", + STREXH_NE: "STREXH.NE", + STREXH_CS: "STREXH.CS", + STREXH_CC: "STREXH.CC", + STREXH_MI: "STREXH.MI", + STREXH_PL: "STREXH.PL", + STREXH_VS: "STREXH.VS", + STREXH_VC: "STREXH.VC", + STREXH_HI: "STREXH.HI", + STREXH_LS: "STREXH.LS", + STREXH_GE: "STREXH.GE", + STREXH_LT: "STREXH.LT", + STREXH_GT: "STREXH.GT", + STREXH_LE: "STREXH.LE", + STREXH: "STREXH", + STREXH_ZZ: "STREXH.ZZ", + STRH_EQ: "STRH.EQ", + STRH_NE: "STRH.NE", + STRH_CS: "STRH.CS", + STRH_CC: "STRH.CC", + STRH_MI: "STRH.MI", + STRH_PL: "STRH.PL", + STRH_VS: "STRH.VS", + STRH_VC: "STRH.VC", + STRH_HI: "STRH.HI", + STRH_LS: "STRH.LS", + STRH_GE: "STRH.GE", + STRH_LT: "STRH.LT", + STRH_GT: "STRH.GT", + STRH_LE: "STRH.LE", + STRH: "STRH", + STRH_ZZ: "STRH.ZZ", + STRHT_EQ: "STRHT.EQ", + STRHT_NE: "STRHT.NE", + STRHT_CS: "STRHT.CS", + STRHT_CC: "STRHT.CC", + STRHT_MI: "STRHT.MI", + STRHT_PL: "STRHT.PL", + STRHT_VS: "STRHT.VS", + STRHT_VC: "STRHT.VC", + STRHT_HI: "STRHT.HI", + STRHT_LS: "STRHT.LS", + STRHT_GE: "STRHT.GE", + STRHT_LT: "STRHT.LT", + STRHT_GT: "STRHT.GT", + STRHT_LE: "STRHT.LE", + STRHT: "STRHT", + STRHT_ZZ: "STRHT.ZZ", + STRT_EQ: "STRT.EQ", + STRT_NE: "STRT.NE", + STRT_CS: "STRT.CS", + STRT_CC: "STRT.CC", + STRT_MI: "STRT.MI", + STRT_PL: "STRT.PL", + STRT_VS: "STRT.VS", + STRT_VC: "STRT.VC", + STRT_HI: "STRT.HI", + STRT_LS: "STRT.LS", + STRT_GE: "STRT.GE", + STRT_LT: "STRT.LT", + STRT_GT: "STRT.GT", + STRT_LE: "STRT.LE", + STRT: "STRT", + STRT_ZZ: "STRT.ZZ", + SUB_EQ: "SUB.EQ", + SUB_NE: "SUB.NE", + SUB_CS: "SUB.CS", + SUB_CC: "SUB.CC", + SUB_MI: "SUB.MI", + SUB_PL: "SUB.PL", + SUB_VS: "SUB.VS", + SUB_VC: "SUB.VC", + SUB_HI: "SUB.HI", + SUB_LS: "SUB.LS", + SUB_GE: "SUB.GE", + SUB_LT: "SUB.LT", + SUB_GT: "SUB.GT", + SUB_LE: "SUB.LE", + SUB: "SUB", + SUB_ZZ: "SUB.ZZ", + SUB_S_EQ: "SUB.S.EQ", + SUB_S_NE: "SUB.S.NE", + SUB_S_CS: "SUB.S.CS", + SUB_S_CC: "SUB.S.CC", + SUB_S_MI: "SUB.S.MI", + SUB_S_PL: "SUB.S.PL", + SUB_S_VS: "SUB.S.VS", + SUB_S_VC: "SUB.S.VC", + SUB_S_HI: "SUB.S.HI", + SUB_S_LS: "SUB.S.LS", + SUB_S_GE: "SUB.S.GE", + SUB_S_LT: "SUB.S.LT", + SUB_S_GT: "SUB.S.GT", + SUB_S_LE: "SUB.S.LE", + SUB_S: "SUB.S", + SUB_S_ZZ: "SUB.S.ZZ", + SVC_EQ: "SVC.EQ", + SVC_NE: "SVC.NE", + SVC_CS: "SVC.CS", + SVC_CC: "SVC.CC", + SVC_MI: "SVC.MI", + SVC_PL: "SVC.PL", + SVC_VS: "SVC.VS", + SVC_VC: "SVC.VC", + SVC_HI: "SVC.HI", + SVC_LS: "SVC.LS", + SVC_GE: "SVC.GE", + SVC_LT: "SVC.LT", + SVC_GT: "SVC.GT", + SVC_LE: "SVC.LE", + SVC: "SVC", + SVC_ZZ: "SVC.ZZ", + SWP_EQ: "SWP.EQ", + SWP_NE: "SWP.NE", + SWP_CS: "SWP.CS", + SWP_CC: "SWP.CC", + SWP_MI: "SWP.MI", + SWP_PL: "SWP.PL", + SWP_VS: "SWP.VS", + SWP_VC: "SWP.VC", + SWP_HI: "SWP.HI", + SWP_LS: "SWP.LS", + SWP_GE: "SWP.GE", + SWP_LT: "SWP.LT", + SWP_GT: "SWP.GT", + SWP_LE: "SWP.LE", + SWP: "SWP", + SWP_ZZ: "SWP.ZZ", + SWP_B_EQ: "SWP.B.EQ", + SWP_B_NE: "SWP.B.NE", + SWP_B_CS: "SWP.B.CS", + SWP_B_CC: "SWP.B.CC", + SWP_B_MI: "SWP.B.MI", + SWP_B_PL: "SWP.B.PL", + SWP_B_VS: "SWP.B.VS", + SWP_B_VC: "SWP.B.VC", + SWP_B_HI: "SWP.B.HI", + SWP_B_LS: "SWP.B.LS", + SWP_B_GE: "SWP.B.GE", + SWP_B_LT: "SWP.B.LT", + SWP_B_GT: "SWP.B.GT", + SWP_B_LE: "SWP.B.LE", + SWP_B: "SWP.B", + SWP_B_ZZ: "SWP.B.ZZ", + SXTAB_EQ: "SXTAB.EQ", + SXTAB_NE: "SXTAB.NE", + SXTAB_CS: "SXTAB.CS", + SXTAB_CC: "SXTAB.CC", + SXTAB_MI: "SXTAB.MI", + SXTAB_PL: "SXTAB.PL", + SXTAB_VS: "SXTAB.VS", + SXTAB_VC: "SXTAB.VC", + SXTAB_HI: "SXTAB.HI", + SXTAB_LS: "SXTAB.LS", + SXTAB_GE: "SXTAB.GE", + SXTAB_LT: "SXTAB.LT", + SXTAB_GT: "SXTAB.GT", + SXTAB_LE: "SXTAB.LE", + SXTAB: "SXTAB", + SXTAB_ZZ: "SXTAB.ZZ", + SXTAB16_EQ: "SXTAB16.EQ", + SXTAB16_NE: "SXTAB16.NE", + SXTAB16_CS: "SXTAB16.CS", + SXTAB16_CC: "SXTAB16.CC", + SXTAB16_MI: "SXTAB16.MI", + SXTAB16_PL: "SXTAB16.PL", + SXTAB16_VS: "SXTAB16.VS", + SXTAB16_VC: "SXTAB16.VC", + SXTAB16_HI: "SXTAB16.HI", + SXTAB16_LS: "SXTAB16.LS", + SXTAB16_GE: "SXTAB16.GE", + SXTAB16_LT: "SXTAB16.LT", + SXTAB16_GT: "SXTAB16.GT", + SXTAB16_LE: "SXTAB16.LE", + SXTAB16: "SXTAB16", + SXTAB16_ZZ: "SXTAB16.ZZ", + SXTAH_EQ: "SXTAH.EQ", + SXTAH_NE: "SXTAH.NE", + SXTAH_CS: "SXTAH.CS", + SXTAH_CC: "SXTAH.CC", + SXTAH_MI: "SXTAH.MI", + SXTAH_PL: "SXTAH.PL", + SXTAH_VS: "SXTAH.VS", + SXTAH_VC: "SXTAH.VC", + SXTAH_HI: "SXTAH.HI", + SXTAH_LS: "SXTAH.LS", + SXTAH_GE: "SXTAH.GE", + SXTAH_LT: "SXTAH.LT", + SXTAH_GT: "SXTAH.GT", + SXTAH_LE: "SXTAH.LE", + SXTAH: "SXTAH", + SXTAH_ZZ: "SXTAH.ZZ", + SXTB_EQ: "SXTB.EQ", + SXTB_NE: "SXTB.NE", + SXTB_CS: "SXTB.CS", + SXTB_CC: "SXTB.CC", + SXTB_MI: "SXTB.MI", + SXTB_PL: "SXTB.PL", + SXTB_VS: "SXTB.VS", + SXTB_VC: "SXTB.VC", + SXTB_HI: "SXTB.HI", + SXTB_LS: "SXTB.LS", + SXTB_GE: "SXTB.GE", + SXTB_LT: "SXTB.LT", + SXTB_GT: "SXTB.GT", + SXTB_LE: "SXTB.LE", + SXTB: "SXTB", + SXTB_ZZ: "SXTB.ZZ", + SXTB16_EQ: "SXTB16.EQ", + SXTB16_NE: "SXTB16.NE", + SXTB16_CS: "SXTB16.CS", + SXTB16_CC: "SXTB16.CC", + SXTB16_MI: "SXTB16.MI", + SXTB16_PL: "SXTB16.PL", + SXTB16_VS: "SXTB16.VS", + SXTB16_VC: "SXTB16.VC", + SXTB16_HI: "SXTB16.HI", + SXTB16_LS: "SXTB16.LS", + SXTB16_GE: "SXTB16.GE", + SXTB16_LT: "SXTB16.LT", + SXTB16_GT: "SXTB16.GT", + SXTB16_LE: "SXTB16.LE", + SXTB16: "SXTB16", + SXTB16_ZZ: "SXTB16.ZZ", + SXTH_EQ: "SXTH.EQ", + SXTH_NE: "SXTH.NE", + SXTH_CS: "SXTH.CS", + SXTH_CC: "SXTH.CC", + SXTH_MI: "SXTH.MI", + SXTH_PL: "SXTH.PL", + SXTH_VS: "SXTH.VS", + SXTH_VC: "SXTH.VC", + SXTH_HI: "SXTH.HI", + SXTH_LS: "SXTH.LS", + SXTH_GE: "SXTH.GE", + SXTH_LT: "SXTH.LT", + SXTH_GT: "SXTH.GT", + SXTH_LE: "SXTH.LE", + SXTH: "SXTH", + SXTH_ZZ: "SXTH.ZZ", + TEQ_EQ: "TEQ.EQ", + TEQ_NE: "TEQ.NE", + TEQ_CS: "TEQ.CS", + TEQ_CC: "TEQ.CC", + TEQ_MI: "TEQ.MI", + TEQ_PL: "TEQ.PL", + TEQ_VS: "TEQ.VS", + TEQ_VC: "TEQ.VC", + TEQ_HI: "TEQ.HI", + TEQ_LS: "TEQ.LS", + TEQ_GE: "TEQ.GE", + TEQ_LT: "TEQ.LT", + TEQ_GT: "TEQ.GT", + TEQ_LE: "TEQ.LE", + TEQ: "TEQ", + TEQ_ZZ: "TEQ.ZZ", + TST_EQ: "TST.EQ", + TST_NE: "TST.NE", + TST_CS: "TST.CS", + TST_CC: "TST.CC", + TST_MI: "TST.MI", + TST_PL: "TST.PL", + TST_VS: "TST.VS", + TST_VC: "TST.VC", + TST_HI: "TST.HI", + TST_LS: "TST.LS", + TST_GE: "TST.GE", + TST_LT: "TST.LT", + TST_GT: "TST.GT", + TST_LE: "TST.LE", + TST: "TST", + TST_ZZ: "TST.ZZ", + UADD16_EQ: "UADD16.EQ", + UADD16_NE: "UADD16.NE", + UADD16_CS: "UADD16.CS", + UADD16_CC: "UADD16.CC", + UADD16_MI: "UADD16.MI", + UADD16_PL: "UADD16.PL", + UADD16_VS: "UADD16.VS", + UADD16_VC: "UADD16.VC", + UADD16_HI: "UADD16.HI", + UADD16_LS: "UADD16.LS", + UADD16_GE: "UADD16.GE", + UADD16_LT: "UADD16.LT", + UADD16_GT: "UADD16.GT", + UADD16_LE: "UADD16.LE", + UADD16: "UADD16", + UADD16_ZZ: "UADD16.ZZ", + UADD8_EQ: "UADD8.EQ", + UADD8_NE: "UADD8.NE", + UADD8_CS: "UADD8.CS", + UADD8_CC: "UADD8.CC", + UADD8_MI: "UADD8.MI", + UADD8_PL: "UADD8.PL", + UADD8_VS: "UADD8.VS", + UADD8_VC: "UADD8.VC", + UADD8_HI: "UADD8.HI", + UADD8_LS: "UADD8.LS", + UADD8_GE: "UADD8.GE", + UADD8_LT: "UADD8.LT", + UADD8_GT: "UADD8.GT", + UADD8_LE: "UADD8.LE", + UADD8: "UADD8", + UADD8_ZZ: "UADD8.ZZ", + UASX_EQ: "UASX.EQ", + UASX_NE: "UASX.NE", + UASX_CS: "UASX.CS", + UASX_CC: "UASX.CC", + UASX_MI: "UASX.MI", + UASX_PL: "UASX.PL", + UASX_VS: "UASX.VS", + UASX_VC: "UASX.VC", + UASX_HI: "UASX.HI", + UASX_LS: "UASX.LS", + UASX_GE: "UASX.GE", + UASX_LT: "UASX.LT", + UASX_GT: "UASX.GT", + UASX_LE: "UASX.LE", + UASX: "UASX", + UASX_ZZ: "UASX.ZZ", + UBFX_EQ: "UBFX.EQ", + UBFX_NE: "UBFX.NE", + UBFX_CS: "UBFX.CS", + UBFX_CC: "UBFX.CC", + UBFX_MI: "UBFX.MI", + UBFX_PL: "UBFX.PL", + UBFX_VS: "UBFX.VS", + UBFX_VC: "UBFX.VC", + UBFX_HI: "UBFX.HI", + UBFX_LS: "UBFX.LS", + UBFX_GE: "UBFX.GE", + UBFX_LT: "UBFX.LT", + UBFX_GT: "UBFX.GT", + UBFX_LE: "UBFX.LE", + UBFX: "UBFX", + UBFX_ZZ: "UBFX.ZZ", + UDIV_EQ: "UDIV.EQ", + UDIV_NE: "UDIV.NE", + UDIV_CS: "UDIV.CS", + UDIV_CC: "UDIV.CC", + UDIV_MI: "UDIV.MI", + UDIV_PL: "UDIV.PL", + UDIV_VS: "UDIV.VS", + UDIV_VC: "UDIV.VC", + UDIV_HI: "UDIV.HI", + UDIV_LS: "UDIV.LS", + UDIV_GE: "UDIV.GE", + UDIV_LT: "UDIV.LT", + UDIV_GT: "UDIV.GT", + UDIV_LE: "UDIV.LE", + UDIV: "UDIV", + UDIV_ZZ: "UDIV.ZZ", + UHADD16_EQ: "UHADD16.EQ", + UHADD16_NE: "UHADD16.NE", + UHADD16_CS: "UHADD16.CS", + UHADD16_CC: "UHADD16.CC", + UHADD16_MI: "UHADD16.MI", + UHADD16_PL: "UHADD16.PL", + UHADD16_VS: "UHADD16.VS", + UHADD16_VC: "UHADD16.VC", + UHADD16_HI: "UHADD16.HI", + UHADD16_LS: "UHADD16.LS", + UHADD16_GE: "UHADD16.GE", + UHADD16_LT: "UHADD16.LT", + UHADD16_GT: "UHADD16.GT", + UHADD16_LE: "UHADD16.LE", + UHADD16: "UHADD16", + UHADD16_ZZ: "UHADD16.ZZ", + UHADD8_EQ: "UHADD8.EQ", + UHADD8_NE: "UHADD8.NE", + UHADD8_CS: "UHADD8.CS", + UHADD8_CC: "UHADD8.CC", + UHADD8_MI: "UHADD8.MI", + UHADD8_PL: "UHADD8.PL", + UHADD8_VS: "UHADD8.VS", + UHADD8_VC: "UHADD8.VC", + UHADD8_HI: "UHADD8.HI", + UHADD8_LS: "UHADD8.LS", + UHADD8_GE: "UHADD8.GE", + UHADD8_LT: "UHADD8.LT", + UHADD8_GT: "UHADD8.GT", + UHADD8_LE: "UHADD8.LE", + UHADD8: "UHADD8", + UHADD8_ZZ: "UHADD8.ZZ", + UHASX_EQ: "UHASX.EQ", + UHASX_NE: "UHASX.NE", + UHASX_CS: "UHASX.CS", + UHASX_CC: "UHASX.CC", + UHASX_MI: "UHASX.MI", + UHASX_PL: "UHASX.PL", + UHASX_VS: "UHASX.VS", + UHASX_VC: "UHASX.VC", + UHASX_HI: "UHASX.HI", + UHASX_LS: "UHASX.LS", + UHASX_GE: "UHASX.GE", + UHASX_LT: "UHASX.LT", + UHASX_GT: "UHASX.GT", + UHASX_LE: "UHASX.LE", + UHASX: "UHASX", + UHASX_ZZ: "UHASX.ZZ", + UHSAX_EQ: "UHSAX.EQ", + UHSAX_NE: "UHSAX.NE", + UHSAX_CS: "UHSAX.CS", + UHSAX_CC: "UHSAX.CC", + UHSAX_MI: "UHSAX.MI", + UHSAX_PL: "UHSAX.PL", + UHSAX_VS: "UHSAX.VS", + UHSAX_VC: "UHSAX.VC", + UHSAX_HI: "UHSAX.HI", + UHSAX_LS: "UHSAX.LS", + UHSAX_GE: "UHSAX.GE", + UHSAX_LT: "UHSAX.LT", + UHSAX_GT: "UHSAX.GT", + UHSAX_LE: "UHSAX.LE", + UHSAX: "UHSAX", + UHSAX_ZZ: "UHSAX.ZZ", + UHSUB16_EQ: "UHSUB16.EQ", + UHSUB16_NE: "UHSUB16.NE", + UHSUB16_CS: "UHSUB16.CS", + UHSUB16_CC: "UHSUB16.CC", + UHSUB16_MI: "UHSUB16.MI", + UHSUB16_PL: "UHSUB16.PL", + UHSUB16_VS: "UHSUB16.VS", + UHSUB16_VC: "UHSUB16.VC", + UHSUB16_HI: "UHSUB16.HI", + UHSUB16_LS: "UHSUB16.LS", + UHSUB16_GE: "UHSUB16.GE", + UHSUB16_LT: "UHSUB16.LT", + UHSUB16_GT: "UHSUB16.GT", + UHSUB16_LE: "UHSUB16.LE", + UHSUB16: "UHSUB16", + UHSUB16_ZZ: "UHSUB16.ZZ", + UHSUB8_EQ: "UHSUB8.EQ", + UHSUB8_NE: "UHSUB8.NE", + UHSUB8_CS: "UHSUB8.CS", + UHSUB8_CC: "UHSUB8.CC", + UHSUB8_MI: "UHSUB8.MI", + UHSUB8_PL: "UHSUB8.PL", + UHSUB8_VS: "UHSUB8.VS", + UHSUB8_VC: "UHSUB8.VC", + UHSUB8_HI: "UHSUB8.HI", + UHSUB8_LS: "UHSUB8.LS", + UHSUB8_GE: "UHSUB8.GE", + UHSUB8_LT: "UHSUB8.LT", + UHSUB8_GT: "UHSUB8.GT", + UHSUB8_LE: "UHSUB8.LE", + UHSUB8: "UHSUB8", + UHSUB8_ZZ: "UHSUB8.ZZ", + UMAAL_EQ: "UMAAL.EQ", + UMAAL_NE: "UMAAL.NE", + UMAAL_CS: "UMAAL.CS", + UMAAL_CC: "UMAAL.CC", + UMAAL_MI: "UMAAL.MI", + UMAAL_PL: "UMAAL.PL", + UMAAL_VS: "UMAAL.VS", + UMAAL_VC: "UMAAL.VC", + UMAAL_HI: "UMAAL.HI", + UMAAL_LS: "UMAAL.LS", + UMAAL_GE: "UMAAL.GE", + UMAAL_LT: "UMAAL.LT", + UMAAL_GT: "UMAAL.GT", + UMAAL_LE: "UMAAL.LE", + UMAAL: "UMAAL", + UMAAL_ZZ: "UMAAL.ZZ", + UMLAL_EQ: "UMLAL.EQ", + UMLAL_NE: "UMLAL.NE", + UMLAL_CS: "UMLAL.CS", + UMLAL_CC: "UMLAL.CC", + UMLAL_MI: "UMLAL.MI", + UMLAL_PL: "UMLAL.PL", + UMLAL_VS: "UMLAL.VS", + UMLAL_VC: "UMLAL.VC", + UMLAL_HI: "UMLAL.HI", + UMLAL_LS: "UMLAL.LS", + UMLAL_GE: "UMLAL.GE", + UMLAL_LT: "UMLAL.LT", + UMLAL_GT: "UMLAL.GT", + UMLAL_LE: "UMLAL.LE", + UMLAL: "UMLAL", + UMLAL_ZZ: "UMLAL.ZZ", + UMLAL_S_EQ: "UMLAL.S.EQ", + UMLAL_S_NE: "UMLAL.S.NE", + UMLAL_S_CS: "UMLAL.S.CS", + UMLAL_S_CC: "UMLAL.S.CC", + UMLAL_S_MI: "UMLAL.S.MI", + UMLAL_S_PL: "UMLAL.S.PL", + UMLAL_S_VS: "UMLAL.S.VS", + UMLAL_S_VC: "UMLAL.S.VC", + UMLAL_S_HI: "UMLAL.S.HI", + UMLAL_S_LS: "UMLAL.S.LS", + UMLAL_S_GE: "UMLAL.S.GE", + UMLAL_S_LT: "UMLAL.S.LT", + UMLAL_S_GT: "UMLAL.S.GT", + UMLAL_S_LE: "UMLAL.S.LE", + UMLAL_S: "UMLAL.S", + UMLAL_S_ZZ: "UMLAL.S.ZZ", + UMULL_EQ: "UMULL.EQ", + UMULL_NE: "UMULL.NE", + UMULL_CS: "UMULL.CS", + UMULL_CC: "UMULL.CC", + UMULL_MI: "UMULL.MI", + UMULL_PL: "UMULL.PL", + UMULL_VS: "UMULL.VS", + UMULL_VC: "UMULL.VC", + UMULL_HI: "UMULL.HI", + UMULL_LS: "UMULL.LS", + UMULL_GE: "UMULL.GE", + UMULL_LT: "UMULL.LT", + UMULL_GT: "UMULL.GT", + UMULL_LE: "UMULL.LE", + UMULL: "UMULL", + UMULL_ZZ: "UMULL.ZZ", + UMULL_S_EQ: "UMULL.S.EQ", + UMULL_S_NE: "UMULL.S.NE", + UMULL_S_CS: "UMULL.S.CS", + UMULL_S_CC: "UMULL.S.CC", + UMULL_S_MI: "UMULL.S.MI", + UMULL_S_PL: "UMULL.S.PL", + UMULL_S_VS: "UMULL.S.VS", + UMULL_S_VC: "UMULL.S.VC", + UMULL_S_HI: "UMULL.S.HI", + UMULL_S_LS: "UMULL.S.LS", + UMULL_S_GE: "UMULL.S.GE", + UMULL_S_LT: "UMULL.S.LT", + UMULL_S_GT: "UMULL.S.GT", + UMULL_S_LE: "UMULL.S.LE", + UMULL_S: "UMULL.S", + UMULL_S_ZZ: "UMULL.S.ZZ", + UNDEF: "UNDEF", + UQADD16_EQ: "UQADD16.EQ", + UQADD16_NE: "UQADD16.NE", + UQADD16_CS: "UQADD16.CS", + UQADD16_CC: "UQADD16.CC", + UQADD16_MI: "UQADD16.MI", + UQADD16_PL: "UQADD16.PL", + UQADD16_VS: "UQADD16.VS", + UQADD16_VC: "UQADD16.VC", + UQADD16_HI: "UQADD16.HI", + UQADD16_LS: "UQADD16.LS", + UQADD16_GE: "UQADD16.GE", + UQADD16_LT: "UQADD16.LT", + UQADD16_GT: "UQADD16.GT", + UQADD16_LE: "UQADD16.LE", + UQADD16: "UQADD16", + UQADD16_ZZ: "UQADD16.ZZ", + UQADD8_EQ: "UQADD8.EQ", + UQADD8_NE: "UQADD8.NE", + UQADD8_CS: "UQADD8.CS", + UQADD8_CC: "UQADD8.CC", + UQADD8_MI: "UQADD8.MI", + UQADD8_PL: "UQADD8.PL", + UQADD8_VS: "UQADD8.VS", + UQADD8_VC: "UQADD8.VC", + UQADD8_HI: "UQADD8.HI", + UQADD8_LS: "UQADD8.LS", + UQADD8_GE: "UQADD8.GE", + UQADD8_LT: "UQADD8.LT", + UQADD8_GT: "UQADD8.GT", + UQADD8_LE: "UQADD8.LE", + UQADD8: "UQADD8", + UQADD8_ZZ: "UQADD8.ZZ", + UQASX_EQ: "UQASX.EQ", + UQASX_NE: "UQASX.NE", + UQASX_CS: "UQASX.CS", + UQASX_CC: "UQASX.CC", + UQASX_MI: "UQASX.MI", + UQASX_PL: "UQASX.PL", + UQASX_VS: "UQASX.VS", + UQASX_VC: "UQASX.VC", + UQASX_HI: "UQASX.HI", + UQASX_LS: "UQASX.LS", + UQASX_GE: "UQASX.GE", + UQASX_LT: "UQASX.LT", + UQASX_GT: "UQASX.GT", + UQASX_LE: "UQASX.LE", + UQASX: "UQASX", + UQASX_ZZ: "UQASX.ZZ", + UQSAX_EQ: "UQSAX.EQ", + UQSAX_NE: "UQSAX.NE", + UQSAX_CS: "UQSAX.CS", + UQSAX_CC: "UQSAX.CC", + UQSAX_MI: "UQSAX.MI", + UQSAX_PL: "UQSAX.PL", + UQSAX_VS: "UQSAX.VS", + UQSAX_VC: "UQSAX.VC", + UQSAX_HI: "UQSAX.HI", + UQSAX_LS: "UQSAX.LS", + UQSAX_GE: "UQSAX.GE", + UQSAX_LT: "UQSAX.LT", + UQSAX_GT: "UQSAX.GT", + UQSAX_LE: "UQSAX.LE", + UQSAX: "UQSAX", + UQSAX_ZZ: "UQSAX.ZZ", + UQSUB16_EQ: "UQSUB16.EQ", + UQSUB16_NE: "UQSUB16.NE", + UQSUB16_CS: "UQSUB16.CS", + UQSUB16_CC: "UQSUB16.CC", + UQSUB16_MI: "UQSUB16.MI", + UQSUB16_PL: "UQSUB16.PL", + UQSUB16_VS: "UQSUB16.VS", + UQSUB16_VC: "UQSUB16.VC", + UQSUB16_HI: "UQSUB16.HI", + UQSUB16_LS: "UQSUB16.LS", + UQSUB16_GE: "UQSUB16.GE", + UQSUB16_LT: "UQSUB16.LT", + UQSUB16_GT: "UQSUB16.GT", + UQSUB16_LE: "UQSUB16.LE", + UQSUB16: "UQSUB16", + UQSUB16_ZZ: "UQSUB16.ZZ", + UQSUB8_EQ: "UQSUB8.EQ", + UQSUB8_NE: "UQSUB8.NE", + UQSUB8_CS: "UQSUB8.CS", + UQSUB8_CC: "UQSUB8.CC", + UQSUB8_MI: "UQSUB8.MI", + UQSUB8_PL: "UQSUB8.PL", + UQSUB8_VS: "UQSUB8.VS", + UQSUB8_VC: "UQSUB8.VC", + UQSUB8_HI: "UQSUB8.HI", + UQSUB8_LS: "UQSUB8.LS", + UQSUB8_GE: "UQSUB8.GE", + UQSUB8_LT: "UQSUB8.LT", + UQSUB8_GT: "UQSUB8.GT", + UQSUB8_LE: "UQSUB8.LE", + UQSUB8: "UQSUB8", + UQSUB8_ZZ: "UQSUB8.ZZ", + USAD8_EQ: "USAD8.EQ", + USAD8_NE: "USAD8.NE", + USAD8_CS: "USAD8.CS", + USAD8_CC: "USAD8.CC", + USAD8_MI: "USAD8.MI", + USAD8_PL: "USAD8.PL", + USAD8_VS: "USAD8.VS", + USAD8_VC: "USAD8.VC", + USAD8_HI: "USAD8.HI", + USAD8_LS: "USAD8.LS", + USAD8_GE: "USAD8.GE", + USAD8_LT: "USAD8.LT", + USAD8_GT: "USAD8.GT", + USAD8_LE: "USAD8.LE", + USAD8: "USAD8", + USAD8_ZZ: "USAD8.ZZ", + USADA8_EQ: "USADA8.EQ", + USADA8_NE: "USADA8.NE", + USADA8_CS: "USADA8.CS", + USADA8_CC: "USADA8.CC", + USADA8_MI: "USADA8.MI", + USADA8_PL: "USADA8.PL", + USADA8_VS: "USADA8.VS", + USADA8_VC: "USADA8.VC", + USADA8_HI: "USADA8.HI", + USADA8_LS: "USADA8.LS", + USADA8_GE: "USADA8.GE", + USADA8_LT: "USADA8.LT", + USADA8_GT: "USADA8.GT", + USADA8_LE: "USADA8.LE", + USADA8: "USADA8", + USADA8_ZZ: "USADA8.ZZ", + USAT_EQ: "USAT.EQ", + USAT_NE: "USAT.NE", + USAT_CS: "USAT.CS", + USAT_CC: "USAT.CC", + USAT_MI: "USAT.MI", + USAT_PL: "USAT.PL", + USAT_VS: "USAT.VS", + USAT_VC: "USAT.VC", + USAT_HI: "USAT.HI", + USAT_LS: "USAT.LS", + USAT_GE: "USAT.GE", + USAT_LT: "USAT.LT", + USAT_GT: "USAT.GT", + USAT_LE: "USAT.LE", + USAT: "USAT", + USAT_ZZ: "USAT.ZZ", + USAT16_EQ: "USAT16.EQ", + USAT16_NE: "USAT16.NE", + USAT16_CS: "USAT16.CS", + USAT16_CC: "USAT16.CC", + USAT16_MI: "USAT16.MI", + USAT16_PL: "USAT16.PL", + USAT16_VS: "USAT16.VS", + USAT16_VC: "USAT16.VC", + USAT16_HI: "USAT16.HI", + USAT16_LS: "USAT16.LS", + USAT16_GE: "USAT16.GE", + USAT16_LT: "USAT16.LT", + USAT16_GT: "USAT16.GT", + USAT16_LE: "USAT16.LE", + USAT16: "USAT16", + USAT16_ZZ: "USAT16.ZZ", + USAX_EQ: "USAX.EQ", + USAX_NE: "USAX.NE", + USAX_CS: "USAX.CS", + USAX_CC: "USAX.CC", + USAX_MI: "USAX.MI", + USAX_PL: "USAX.PL", + USAX_VS: "USAX.VS", + USAX_VC: "USAX.VC", + USAX_HI: "USAX.HI", + USAX_LS: "USAX.LS", + USAX_GE: "USAX.GE", + USAX_LT: "USAX.LT", + USAX_GT: "USAX.GT", + USAX_LE: "USAX.LE", + USAX: "USAX", + USAX_ZZ: "USAX.ZZ", + USUB16_EQ: "USUB16.EQ", + USUB16_NE: "USUB16.NE", + USUB16_CS: "USUB16.CS", + USUB16_CC: "USUB16.CC", + USUB16_MI: "USUB16.MI", + USUB16_PL: "USUB16.PL", + USUB16_VS: "USUB16.VS", + USUB16_VC: "USUB16.VC", + USUB16_HI: "USUB16.HI", + USUB16_LS: "USUB16.LS", + USUB16_GE: "USUB16.GE", + USUB16_LT: "USUB16.LT", + USUB16_GT: "USUB16.GT", + USUB16_LE: "USUB16.LE", + USUB16: "USUB16", + USUB16_ZZ: "USUB16.ZZ", + USUB8_EQ: "USUB8.EQ", + USUB8_NE: "USUB8.NE", + USUB8_CS: "USUB8.CS", + USUB8_CC: "USUB8.CC", + USUB8_MI: "USUB8.MI", + USUB8_PL: "USUB8.PL", + USUB8_VS: "USUB8.VS", + USUB8_VC: "USUB8.VC", + USUB8_HI: "USUB8.HI", + USUB8_LS: "USUB8.LS", + USUB8_GE: "USUB8.GE", + USUB8_LT: "USUB8.LT", + USUB8_GT: "USUB8.GT", + USUB8_LE: "USUB8.LE", + USUB8: "USUB8", + USUB8_ZZ: "USUB8.ZZ", + UXTAB_EQ: "UXTAB.EQ", + UXTAB_NE: "UXTAB.NE", + UXTAB_CS: "UXTAB.CS", + UXTAB_CC: "UXTAB.CC", + UXTAB_MI: "UXTAB.MI", + UXTAB_PL: "UXTAB.PL", + UXTAB_VS: "UXTAB.VS", + UXTAB_VC: "UXTAB.VC", + UXTAB_HI: "UXTAB.HI", + UXTAB_LS: "UXTAB.LS", + UXTAB_GE: "UXTAB.GE", + UXTAB_LT: "UXTAB.LT", + UXTAB_GT: "UXTAB.GT", + UXTAB_LE: "UXTAB.LE", + UXTAB: "UXTAB", + UXTAB_ZZ: "UXTAB.ZZ", + UXTAB16_EQ: "UXTAB16.EQ", + UXTAB16_NE: "UXTAB16.NE", + UXTAB16_CS: "UXTAB16.CS", + UXTAB16_CC: "UXTAB16.CC", + UXTAB16_MI: "UXTAB16.MI", + UXTAB16_PL: "UXTAB16.PL", + UXTAB16_VS: "UXTAB16.VS", + UXTAB16_VC: "UXTAB16.VC", + UXTAB16_HI: "UXTAB16.HI", + UXTAB16_LS: "UXTAB16.LS", + UXTAB16_GE: "UXTAB16.GE", + UXTAB16_LT: "UXTAB16.LT", + UXTAB16_GT: "UXTAB16.GT", + UXTAB16_LE: "UXTAB16.LE", + UXTAB16: "UXTAB16", + UXTAB16_ZZ: "UXTAB16.ZZ", + UXTAH_EQ: "UXTAH.EQ", + UXTAH_NE: "UXTAH.NE", + UXTAH_CS: "UXTAH.CS", + UXTAH_CC: "UXTAH.CC", + UXTAH_MI: "UXTAH.MI", + UXTAH_PL: "UXTAH.PL", + UXTAH_VS: "UXTAH.VS", + UXTAH_VC: "UXTAH.VC", + UXTAH_HI: "UXTAH.HI", + UXTAH_LS: "UXTAH.LS", + UXTAH_GE: "UXTAH.GE", + UXTAH_LT: "UXTAH.LT", + UXTAH_GT: "UXTAH.GT", + UXTAH_LE: "UXTAH.LE", + UXTAH: "UXTAH", + UXTAH_ZZ: "UXTAH.ZZ", + UXTB_EQ: "UXTB.EQ", + UXTB_NE: "UXTB.NE", + UXTB_CS: "UXTB.CS", + UXTB_CC: "UXTB.CC", + UXTB_MI: "UXTB.MI", + UXTB_PL: "UXTB.PL", + UXTB_VS: "UXTB.VS", + UXTB_VC: "UXTB.VC", + UXTB_HI: "UXTB.HI", + UXTB_LS: "UXTB.LS", + UXTB_GE: "UXTB.GE", + UXTB_LT: "UXTB.LT", + UXTB_GT: "UXTB.GT", + UXTB_LE: "UXTB.LE", + UXTB: "UXTB", + UXTB_ZZ: "UXTB.ZZ", + UXTB16_EQ: "UXTB16.EQ", + UXTB16_NE: "UXTB16.NE", + UXTB16_CS: "UXTB16.CS", + UXTB16_CC: "UXTB16.CC", + UXTB16_MI: "UXTB16.MI", + UXTB16_PL: "UXTB16.PL", + UXTB16_VS: "UXTB16.VS", + UXTB16_VC: "UXTB16.VC", + UXTB16_HI: "UXTB16.HI", + UXTB16_LS: "UXTB16.LS", + UXTB16_GE: "UXTB16.GE", + UXTB16_LT: "UXTB16.LT", + UXTB16_GT: "UXTB16.GT", + UXTB16_LE: "UXTB16.LE", + UXTB16: "UXTB16", + UXTB16_ZZ: "UXTB16.ZZ", + UXTH_EQ: "UXTH.EQ", + UXTH_NE: "UXTH.NE", + UXTH_CS: "UXTH.CS", + UXTH_CC: "UXTH.CC", + UXTH_MI: "UXTH.MI", + UXTH_PL: "UXTH.PL", + UXTH_VS: "UXTH.VS", + UXTH_VC: "UXTH.VC", + UXTH_HI: "UXTH.HI", + UXTH_LS: "UXTH.LS", + UXTH_GE: "UXTH.GE", + UXTH_LT: "UXTH.LT", + UXTH_GT: "UXTH.GT", + UXTH_LE: "UXTH.LE", + UXTH: "UXTH", + UXTH_ZZ: "UXTH.ZZ", + VABS_EQ_F32: "VABS.EQ.F32", + VABS_NE_F32: "VABS.NE.F32", + VABS_CS_F32: "VABS.CS.F32", + VABS_CC_F32: "VABS.CC.F32", + VABS_MI_F32: "VABS.MI.F32", + VABS_PL_F32: "VABS.PL.F32", + VABS_VS_F32: "VABS.VS.F32", + VABS_VC_F32: "VABS.VC.F32", + VABS_HI_F32: "VABS.HI.F32", + VABS_LS_F32: "VABS.LS.F32", + VABS_GE_F32: "VABS.GE.F32", + VABS_LT_F32: "VABS.LT.F32", + VABS_GT_F32: "VABS.GT.F32", + VABS_LE_F32: "VABS.LE.F32", + VABS_F32: "VABS.F32", + VABS_ZZ_F32: "VABS.ZZ.F32", + VABS_EQ_F64: "VABS.EQ.F64", + VABS_NE_F64: "VABS.NE.F64", + VABS_CS_F64: "VABS.CS.F64", + VABS_CC_F64: "VABS.CC.F64", + VABS_MI_F64: "VABS.MI.F64", + VABS_PL_F64: "VABS.PL.F64", + VABS_VS_F64: "VABS.VS.F64", + VABS_VC_F64: "VABS.VC.F64", + VABS_HI_F64: "VABS.HI.F64", + VABS_LS_F64: "VABS.LS.F64", + VABS_GE_F64: "VABS.GE.F64", + VABS_LT_F64: "VABS.LT.F64", + VABS_GT_F64: "VABS.GT.F64", + VABS_LE_F64: "VABS.LE.F64", + VABS_F64: "VABS.F64", + VABS_ZZ_F64: "VABS.ZZ.F64", + VADD_EQ_F32: "VADD.EQ.F32", + VADD_NE_F32: "VADD.NE.F32", + VADD_CS_F32: "VADD.CS.F32", + VADD_CC_F32: "VADD.CC.F32", + VADD_MI_F32: "VADD.MI.F32", + VADD_PL_F32: "VADD.PL.F32", + VADD_VS_F32: "VADD.VS.F32", + VADD_VC_F32: "VADD.VC.F32", + VADD_HI_F32: "VADD.HI.F32", + VADD_LS_F32: "VADD.LS.F32", + VADD_GE_F32: "VADD.GE.F32", + VADD_LT_F32: "VADD.LT.F32", + VADD_GT_F32: "VADD.GT.F32", + VADD_LE_F32: "VADD.LE.F32", + VADD_F32: "VADD.F32", + VADD_ZZ_F32: "VADD.ZZ.F32", + VADD_EQ_F64: "VADD.EQ.F64", + VADD_NE_F64: "VADD.NE.F64", + VADD_CS_F64: "VADD.CS.F64", + VADD_CC_F64: "VADD.CC.F64", + VADD_MI_F64: "VADD.MI.F64", + VADD_PL_F64: "VADD.PL.F64", + VADD_VS_F64: "VADD.VS.F64", + VADD_VC_F64: "VADD.VC.F64", + VADD_HI_F64: "VADD.HI.F64", + VADD_LS_F64: "VADD.LS.F64", + VADD_GE_F64: "VADD.GE.F64", + VADD_LT_F64: "VADD.LT.F64", + VADD_GT_F64: "VADD.GT.F64", + VADD_LE_F64: "VADD.LE.F64", + VADD_F64: "VADD.F64", + VADD_ZZ_F64: "VADD.ZZ.F64", + VCMP_EQ_F32: "VCMP.EQ.F32", + VCMP_NE_F32: "VCMP.NE.F32", + VCMP_CS_F32: "VCMP.CS.F32", + VCMP_CC_F32: "VCMP.CC.F32", + VCMP_MI_F32: "VCMP.MI.F32", + VCMP_PL_F32: "VCMP.PL.F32", + VCMP_VS_F32: "VCMP.VS.F32", + VCMP_VC_F32: "VCMP.VC.F32", + VCMP_HI_F32: "VCMP.HI.F32", + VCMP_LS_F32: "VCMP.LS.F32", + VCMP_GE_F32: "VCMP.GE.F32", + VCMP_LT_F32: "VCMP.LT.F32", + VCMP_GT_F32: "VCMP.GT.F32", + VCMP_LE_F32: "VCMP.LE.F32", + VCMP_F32: "VCMP.F32", + VCMP_ZZ_F32: "VCMP.ZZ.F32", + VCMP_EQ_F64: "VCMP.EQ.F64", + VCMP_NE_F64: "VCMP.NE.F64", + VCMP_CS_F64: "VCMP.CS.F64", + VCMP_CC_F64: "VCMP.CC.F64", + VCMP_MI_F64: "VCMP.MI.F64", + VCMP_PL_F64: "VCMP.PL.F64", + VCMP_VS_F64: "VCMP.VS.F64", + VCMP_VC_F64: "VCMP.VC.F64", + VCMP_HI_F64: "VCMP.HI.F64", + VCMP_LS_F64: "VCMP.LS.F64", + VCMP_GE_F64: "VCMP.GE.F64", + VCMP_LT_F64: "VCMP.LT.F64", + VCMP_GT_F64: "VCMP.GT.F64", + VCMP_LE_F64: "VCMP.LE.F64", + VCMP_F64: "VCMP.F64", + VCMP_ZZ_F64: "VCMP.ZZ.F64", + VCMP_E_EQ_F32: "VCMP.E.EQ.F32", + VCMP_E_NE_F32: "VCMP.E.NE.F32", + VCMP_E_CS_F32: "VCMP.E.CS.F32", + VCMP_E_CC_F32: "VCMP.E.CC.F32", + VCMP_E_MI_F32: "VCMP.E.MI.F32", + VCMP_E_PL_F32: "VCMP.E.PL.F32", + VCMP_E_VS_F32: "VCMP.E.VS.F32", + VCMP_E_VC_F32: "VCMP.E.VC.F32", + VCMP_E_HI_F32: "VCMP.E.HI.F32", + VCMP_E_LS_F32: "VCMP.E.LS.F32", + VCMP_E_GE_F32: "VCMP.E.GE.F32", + VCMP_E_LT_F32: "VCMP.E.LT.F32", + VCMP_E_GT_F32: "VCMP.E.GT.F32", + VCMP_E_LE_F32: "VCMP.E.LE.F32", + VCMP_E_F32: "VCMP.E.F32", + VCMP_E_ZZ_F32: "VCMP.E.ZZ.F32", + VCMP_E_EQ_F64: "VCMP.E.EQ.F64", + VCMP_E_NE_F64: "VCMP.E.NE.F64", + VCMP_E_CS_F64: "VCMP.E.CS.F64", + VCMP_E_CC_F64: "VCMP.E.CC.F64", + VCMP_E_MI_F64: "VCMP.E.MI.F64", + VCMP_E_PL_F64: "VCMP.E.PL.F64", + VCMP_E_VS_F64: "VCMP.E.VS.F64", + VCMP_E_VC_F64: "VCMP.E.VC.F64", + VCMP_E_HI_F64: "VCMP.E.HI.F64", + VCMP_E_LS_F64: "VCMP.E.LS.F64", + VCMP_E_GE_F64: "VCMP.E.GE.F64", + VCMP_E_LT_F64: "VCMP.E.LT.F64", + VCMP_E_GT_F64: "VCMP.E.GT.F64", + VCMP_E_LE_F64: "VCMP.E.LE.F64", + VCMP_E_F64: "VCMP.E.F64", + VCMP_E_ZZ_F64: "VCMP.E.ZZ.F64", + VCVT_EQ_F32_FXS16: "VCVT.EQ.F32.FXS16", + VCVT_NE_F32_FXS16: "VCVT.NE.F32.FXS16", + VCVT_CS_F32_FXS16: "VCVT.CS.F32.FXS16", + VCVT_CC_F32_FXS16: "VCVT.CC.F32.FXS16", + VCVT_MI_F32_FXS16: "VCVT.MI.F32.FXS16", + VCVT_PL_F32_FXS16: "VCVT.PL.F32.FXS16", + VCVT_VS_F32_FXS16: "VCVT.VS.F32.FXS16", + VCVT_VC_F32_FXS16: "VCVT.VC.F32.FXS16", + VCVT_HI_F32_FXS16: "VCVT.HI.F32.FXS16", + VCVT_LS_F32_FXS16: "VCVT.LS.F32.FXS16", + VCVT_GE_F32_FXS16: "VCVT.GE.F32.FXS16", + VCVT_LT_F32_FXS16: "VCVT.LT.F32.FXS16", + VCVT_GT_F32_FXS16: "VCVT.GT.F32.FXS16", + VCVT_LE_F32_FXS16: "VCVT.LE.F32.FXS16", + VCVT_F32_FXS16: "VCVT.F32.FXS16", + VCVT_ZZ_F32_FXS16: "VCVT.ZZ.F32.FXS16", + VCVT_EQ_F32_FXS32: "VCVT.EQ.F32.FXS32", + VCVT_NE_F32_FXS32: "VCVT.NE.F32.FXS32", + VCVT_CS_F32_FXS32: "VCVT.CS.F32.FXS32", + VCVT_CC_F32_FXS32: "VCVT.CC.F32.FXS32", + VCVT_MI_F32_FXS32: "VCVT.MI.F32.FXS32", + VCVT_PL_F32_FXS32: "VCVT.PL.F32.FXS32", + VCVT_VS_F32_FXS32: "VCVT.VS.F32.FXS32", + VCVT_VC_F32_FXS32: "VCVT.VC.F32.FXS32", + VCVT_HI_F32_FXS32: "VCVT.HI.F32.FXS32", + VCVT_LS_F32_FXS32: "VCVT.LS.F32.FXS32", + VCVT_GE_F32_FXS32: "VCVT.GE.F32.FXS32", + VCVT_LT_F32_FXS32: "VCVT.LT.F32.FXS32", + VCVT_GT_F32_FXS32: "VCVT.GT.F32.FXS32", + VCVT_LE_F32_FXS32: "VCVT.LE.F32.FXS32", + VCVT_F32_FXS32: "VCVT.F32.FXS32", + VCVT_ZZ_F32_FXS32: "VCVT.ZZ.F32.FXS32", + VCVT_EQ_F32_FXU16: "VCVT.EQ.F32.FXU16", + VCVT_NE_F32_FXU16: "VCVT.NE.F32.FXU16", + VCVT_CS_F32_FXU16: "VCVT.CS.F32.FXU16", + VCVT_CC_F32_FXU16: "VCVT.CC.F32.FXU16", + VCVT_MI_F32_FXU16: "VCVT.MI.F32.FXU16", + VCVT_PL_F32_FXU16: "VCVT.PL.F32.FXU16", + VCVT_VS_F32_FXU16: "VCVT.VS.F32.FXU16", + VCVT_VC_F32_FXU16: "VCVT.VC.F32.FXU16", + VCVT_HI_F32_FXU16: "VCVT.HI.F32.FXU16", + VCVT_LS_F32_FXU16: "VCVT.LS.F32.FXU16", + VCVT_GE_F32_FXU16: "VCVT.GE.F32.FXU16", + VCVT_LT_F32_FXU16: "VCVT.LT.F32.FXU16", + VCVT_GT_F32_FXU16: "VCVT.GT.F32.FXU16", + VCVT_LE_F32_FXU16: "VCVT.LE.F32.FXU16", + VCVT_F32_FXU16: "VCVT.F32.FXU16", + VCVT_ZZ_F32_FXU16: "VCVT.ZZ.F32.FXU16", + VCVT_EQ_F32_FXU32: "VCVT.EQ.F32.FXU32", + VCVT_NE_F32_FXU32: "VCVT.NE.F32.FXU32", + VCVT_CS_F32_FXU32: "VCVT.CS.F32.FXU32", + VCVT_CC_F32_FXU32: "VCVT.CC.F32.FXU32", + VCVT_MI_F32_FXU32: "VCVT.MI.F32.FXU32", + VCVT_PL_F32_FXU32: "VCVT.PL.F32.FXU32", + VCVT_VS_F32_FXU32: "VCVT.VS.F32.FXU32", + VCVT_VC_F32_FXU32: "VCVT.VC.F32.FXU32", + VCVT_HI_F32_FXU32: "VCVT.HI.F32.FXU32", + VCVT_LS_F32_FXU32: "VCVT.LS.F32.FXU32", + VCVT_GE_F32_FXU32: "VCVT.GE.F32.FXU32", + VCVT_LT_F32_FXU32: "VCVT.LT.F32.FXU32", + VCVT_GT_F32_FXU32: "VCVT.GT.F32.FXU32", + VCVT_LE_F32_FXU32: "VCVT.LE.F32.FXU32", + VCVT_F32_FXU32: "VCVT.F32.FXU32", + VCVT_ZZ_F32_FXU32: "VCVT.ZZ.F32.FXU32", + VCVT_EQ_F64_FXS16: "VCVT.EQ.F64.FXS16", + VCVT_NE_F64_FXS16: "VCVT.NE.F64.FXS16", + VCVT_CS_F64_FXS16: "VCVT.CS.F64.FXS16", + VCVT_CC_F64_FXS16: "VCVT.CC.F64.FXS16", + VCVT_MI_F64_FXS16: "VCVT.MI.F64.FXS16", + VCVT_PL_F64_FXS16: "VCVT.PL.F64.FXS16", + VCVT_VS_F64_FXS16: "VCVT.VS.F64.FXS16", + VCVT_VC_F64_FXS16: "VCVT.VC.F64.FXS16", + VCVT_HI_F64_FXS16: "VCVT.HI.F64.FXS16", + VCVT_LS_F64_FXS16: "VCVT.LS.F64.FXS16", + VCVT_GE_F64_FXS16: "VCVT.GE.F64.FXS16", + VCVT_LT_F64_FXS16: "VCVT.LT.F64.FXS16", + VCVT_GT_F64_FXS16: "VCVT.GT.F64.FXS16", + VCVT_LE_F64_FXS16: "VCVT.LE.F64.FXS16", + VCVT_F64_FXS16: "VCVT.F64.FXS16", + VCVT_ZZ_F64_FXS16: "VCVT.ZZ.F64.FXS16", + VCVT_EQ_F64_FXS32: "VCVT.EQ.F64.FXS32", + VCVT_NE_F64_FXS32: "VCVT.NE.F64.FXS32", + VCVT_CS_F64_FXS32: "VCVT.CS.F64.FXS32", + VCVT_CC_F64_FXS32: "VCVT.CC.F64.FXS32", + VCVT_MI_F64_FXS32: "VCVT.MI.F64.FXS32", + VCVT_PL_F64_FXS32: "VCVT.PL.F64.FXS32", + VCVT_VS_F64_FXS32: "VCVT.VS.F64.FXS32", + VCVT_VC_F64_FXS32: "VCVT.VC.F64.FXS32", + VCVT_HI_F64_FXS32: "VCVT.HI.F64.FXS32", + VCVT_LS_F64_FXS32: "VCVT.LS.F64.FXS32", + VCVT_GE_F64_FXS32: "VCVT.GE.F64.FXS32", + VCVT_LT_F64_FXS32: "VCVT.LT.F64.FXS32", + VCVT_GT_F64_FXS32: "VCVT.GT.F64.FXS32", + VCVT_LE_F64_FXS32: "VCVT.LE.F64.FXS32", + VCVT_F64_FXS32: "VCVT.F64.FXS32", + VCVT_ZZ_F64_FXS32: "VCVT.ZZ.F64.FXS32", + VCVT_EQ_F64_FXU16: "VCVT.EQ.F64.FXU16", + VCVT_NE_F64_FXU16: "VCVT.NE.F64.FXU16", + VCVT_CS_F64_FXU16: "VCVT.CS.F64.FXU16", + VCVT_CC_F64_FXU16: "VCVT.CC.F64.FXU16", + VCVT_MI_F64_FXU16: "VCVT.MI.F64.FXU16", + VCVT_PL_F64_FXU16: "VCVT.PL.F64.FXU16", + VCVT_VS_F64_FXU16: "VCVT.VS.F64.FXU16", + VCVT_VC_F64_FXU16: "VCVT.VC.F64.FXU16", + VCVT_HI_F64_FXU16: "VCVT.HI.F64.FXU16", + VCVT_LS_F64_FXU16: "VCVT.LS.F64.FXU16", + VCVT_GE_F64_FXU16: "VCVT.GE.F64.FXU16", + VCVT_LT_F64_FXU16: "VCVT.LT.F64.FXU16", + VCVT_GT_F64_FXU16: "VCVT.GT.F64.FXU16", + VCVT_LE_F64_FXU16: "VCVT.LE.F64.FXU16", + VCVT_F64_FXU16: "VCVT.F64.FXU16", + VCVT_ZZ_F64_FXU16: "VCVT.ZZ.F64.FXU16", + VCVT_EQ_F64_FXU32: "VCVT.EQ.F64.FXU32", + VCVT_NE_F64_FXU32: "VCVT.NE.F64.FXU32", + VCVT_CS_F64_FXU32: "VCVT.CS.F64.FXU32", + VCVT_CC_F64_FXU32: "VCVT.CC.F64.FXU32", + VCVT_MI_F64_FXU32: "VCVT.MI.F64.FXU32", + VCVT_PL_F64_FXU32: "VCVT.PL.F64.FXU32", + VCVT_VS_F64_FXU32: "VCVT.VS.F64.FXU32", + VCVT_VC_F64_FXU32: "VCVT.VC.F64.FXU32", + VCVT_HI_F64_FXU32: "VCVT.HI.F64.FXU32", + VCVT_LS_F64_FXU32: "VCVT.LS.F64.FXU32", + VCVT_GE_F64_FXU32: "VCVT.GE.F64.FXU32", + VCVT_LT_F64_FXU32: "VCVT.LT.F64.FXU32", + VCVT_GT_F64_FXU32: "VCVT.GT.F64.FXU32", + VCVT_LE_F64_FXU32: "VCVT.LE.F64.FXU32", + VCVT_F64_FXU32: "VCVT.F64.FXU32", + VCVT_ZZ_F64_FXU32: "VCVT.ZZ.F64.FXU32", + VCVT_EQ_F32_U32: "VCVT.EQ.F32.U32", + VCVT_NE_F32_U32: "VCVT.NE.F32.U32", + VCVT_CS_F32_U32: "VCVT.CS.F32.U32", + VCVT_CC_F32_U32: "VCVT.CC.F32.U32", + VCVT_MI_F32_U32: "VCVT.MI.F32.U32", + VCVT_PL_F32_U32: "VCVT.PL.F32.U32", + VCVT_VS_F32_U32: "VCVT.VS.F32.U32", + VCVT_VC_F32_U32: "VCVT.VC.F32.U32", + VCVT_HI_F32_U32: "VCVT.HI.F32.U32", + VCVT_LS_F32_U32: "VCVT.LS.F32.U32", + VCVT_GE_F32_U32: "VCVT.GE.F32.U32", + VCVT_LT_F32_U32: "VCVT.LT.F32.U32", + VCVT_GT_F32_U32: "VCVT.GT.F32.U32", + VCVT_LE_F32_U32: "VCVT.LE.F32.U32", + VCVT_F32_U32: "VCVT.F32.U32", + VCVT_ZZ_F32_U32: "VCVT.ZZ.F32.U32", + VCVT_EQ_F32_S32: "VCVT.EQ.F32.S32", + VCVT_NE_F32_S32: "VCVT.NE.F32.S32", + VCVT_CS_F32_S32: "VCVT.CS.F32.S32", + VCVT_CC_F32_S32: "VCVT.CC.F32.S32", + VCVT_MI_F32_S32: "VCVT.MI.F32.S32", + VCVT_PL_F32_S32: "VCVT.PL.F32.S32", + VCVT_VS_F32_S32: "VCVT.VS.F32.S32", + VCVT_VC_F32_S32: "VCVT.VC.F32.S32", + VCVT_HI_F32_S32: "VCVT.HI.F32.S32", + VCVT_LS_F32_S32: "VCVT.LS.F32.S32", + VCVT_GE_F32_S32: "VCVT.GE.F32.S32", + VCVT_LT_F32_S32: "VCVT.LT.F32.S32", + VCVT_GT_F32_S32: "VCVT.GT.F32.S32", + VCVT_LE_F32_S32: "VCVT.LE.F32.S32", + VCVT_F32_S32: "VCVT.F32.S32", + VCVT_ZZ_F32_S32: "VCVT.ZZ.F32.S32", + VCVT_EQ_F64_U32: "VCVT.EQ.F64.U32", + VCVT_NE_F64_U32: "VCVT.NE.F64.U32", + VCVT_CS_F64_U32: "VCVT.CS.F64.U32", + VCVT_CC_F64_U32: "VCVT.CC.F64.U32", + VCVT_MI_F64_U32: "VCVT.MI.F64.U32", + VCVT_PL_F64_U32: "VCVT.PL.F64.U32", + VCVT_VS_F64_U32: "VCVT.VS.F64.U32", + VCVT_VC_F64_U32: "VCVT.VC.F64.U32", + VCVT_HI_F64_U32: "VCVT.HI.F64.U32", + VCVT_LS_F64_U32: "VCVT.LS.F64.U32", + VCVT_GE_F64_U32: "VCVT.GE.F64.U32", + VCVT_LT_F64_U32: "VCVT.LT.F64.U32", + VCVT_GT_F64_U32: "VCVT.GT.F64.U32", + VCVT_LE_F64_U32: "VCVT.LE.F64.U32", + VCVT_F64_U32: "VCVT.F64.U32", + VCVT_ZZ_F64_U32: "VCVT.ZZ.F64.U32", + VCVT_EQ_F64_S32: "VCVT.EQ.F64.S32", + VCVT_NE_F64_S32: "VCVT.NE.F64.S32", + VCVT_CS_F64_S32: "VCVT.CS.F64.S32", + VCVT_CC_F64_S32: "VCVT.CC.F64.S32", + VCVT_MI_F64_S32: "VCVT.MI.F64.S32", + VCVT_PL_F64_S32: "VCVT.PL.F64.S32", + VCVT_VS_F64_S32: "VCVT.VS.F64.S32", + VCVT_VC_F64_S32: "VCVT.VC.F64.S32", + VCVT_HI_F64_S32: "VCVT.HI.F64.S32", + VCVT_LS_F64_S32: "VCVT.LS.F64.S32", + VCVT_GE_F64_S32: "VCVT.GE.F64.S32", + VCVT_LT_F64_S32: "VCVT.LT.F64.S32", + VCVT_GT_F64_S32: "VCVT.GT.F64.S32", + VCVT_LE_F64_S32: "VCVT.LE.F64.S32", + VCVT_F64_S32: "VCVT.F64.S32", + VCVT_ZZ_F64_S32: "VCVT.ZZ.F64.S32", + VCVT_EQ_F64_F32: "VCVT.EQ.F64.F32", + VCVT_NE_F64_F32: "VCVT.NE.F64.F32", + VCVT_CS_F64_F32: "VCVT.CS.F64.F32", + VCVT_CC_F64_F32: "VCVT.CC.F64.F32", + VCVT_MI_F64_F32: "VCVT.MI.F64.F32", + VCVT_PL_F64_F32: "VCVT.PL.F64.F32", + VCVT_VS_F64_F32: "VCVT.VS.F64.F32", + VCVT_VC_F64_F32: "VCVT.VC.F64.F32", + VCVT_HI_F64_F32: "VCVT.HI.F64.F32", + VCVT_LS_F64_F32: "VCVT.LS.F64.F32", + VCVT_GE_F64_F32: "VCVT.GE.F64.F32", + VCVT_LT_F64_F32: "VCVT.LT.F64.F32", + VCVT_GT_F64_F32: "VCVT.GT.F64.F32", + VCVT_LE_F64_F32: "VCVT.LE.F64.F32", + VCVT_F64_F32: "VCVT.F64.F32", + VCVT_ZZ_F64_F32: "VCVT.ZZ.F64.F32", + VCVT_EQ_F32_F64: "VCVT.EQ.F32.F64", + VCVT_NE_F32_F64: "VCVT.NE.F32.F64", + VCVT_CS_F32_F64: "VCVT.CS.F32.F64", + VCVT_CC_F32_F64: "VCVT.CC.F32.F64", + VCVT_MI_F32_F64: "VCVT.MI.F32.F64", + VCVT_PL_F32_F64: "VCVT.PL.F32.F64", + VCVT_VS_F32_F64: "VCVT.VS.F32.F64", + VCVT_VC_F32_F64: "VCVT.VC.F32.F64", + VCVT_HI_F32_F64: "VCVT.HI.F32.F64", + VCVT_LS_F32_F64: "VCVT.LS.F32.F64", + VCVT_GE_F32_F64: "VCVT.GE.F32.F64", + VCVT_LT_F32_F64: "VCVT.LT.F32.F64", + VCVT_GT_F32_F64: "VCVT.GT.F32.F64", + VCVT_LE_F32_F64: "VCVT.LE.F32.F64", + VCVT_F32_F64: "VCVT.F32.F64", + VCVT_ZZ_F32_F64: "VCVT.ZZ.F32.F64", + VCVT_EQ_FXS16_F32: "VCVT.EQ.FXS16.F32", + VCVT_NE_FXS16_F32: "VCVT.NE.FXS16.F32", + VCVT_CS_FXS16_F32: "VCVT.CS.FXS16.F32", + VCVT_CC_FXS16_F32: "VCVT.CC.FXS16.F32", + VCVT_MI_FXS16_F32: "VCVT.MI.FXS16.F32", + VCVT_PL_FXS16_F32: "VCVT.PL.FXS16.F32", + VCVT_VS_FXS16_F32: "VCVT.VS.FXS16.F32", + VCVT_VC_FXS16_F32: "VCVT.VC.FXS16.F32", + VCVT_HI_FXS16_F32: "VCVT.HI.FXS16.F32", + VCVT_LS_FXS16_F32: "VCVT.LS.FXS16.F32", + VCVT_GE_FXS16_F32: "VCVT.GE.FXS16.F32", + VCVT_LT_FXS16_F32: "VCVT.LT.FXS16.F32", + VCVT_GT_FXS16_F32: "VCVT.GT.FXS16.F32", + VCVT_LE_FXS16_F32: "VCVT.LE.FXS16.F32", + VCVT_FXS16_F32: "VCVT.FXS16.F32", + VCVT_ZZ_FXS16_F32: "VCVT.ZZ.FXS16.F32", + VCVT_EQ_FXS16_F64: "VCVT.EQ.FXS16.F64", + VCVT_NE_FXS16_F64: "VCVT.NE.FXS16.F64", + VCVT_CS_FXS16_F64: "VCVT.CS.FXS16.F64", + VCVT_CC_FXS16_F64: "VCVT.CC.FXS16.F64", + VCVT_MI_FXS16_F64: "VCVT.MI.FXS16.F64", + VCVT_PL_FXS16_F64: "VCVT.PL.FXS16.F64", + VCVT_VS_FXS16_F64: "VCVT.VS.FXS16.F64", + VCVT_VC_FXS16_F64: "VCVT.VC.FXS16.F64", + VCVT_HI_FXS16_F64: "VCVT.HI.FXS16.F64", + VCVT_LS_FXS16_F64: "VCVT.LS.FXS16.F64", + VCVT_GE_FXS16_F64: "VCVT.GE.FXS16.F64", + VCVT_LT_FXS16_F64: "VCVT.LT.FXS16.F64", + VCVT_GT_FXS16_F64: "VCVT.GT.FXS16.F64", + VCVT_LE_FXS16_F64: "VCVT.LE.FXS16.F64", + VCVT_FXS16_F64: "VCVT.FXS16.F64", + VCVT_ZZ_FXS16_F64: "VCVT.ZZ.FXS16.F64", + VCVT_EQ_FXS32_F32: "VCVT.EQ.FXS32.F32", + VCVT_NE_FXS32_F32: "VCVT.NE.FXS32.F32", + VCVT_CS_FXS32_F32: "VCVT.CS.FXS32.F32", + VCVT_CC_FXS32_F32: "VCVT.CC.FXS32.F32", + VCVT_MI_FXS32_F32: "VCVT.MI.FXS32.F32", + VCVT_PL_FXS32_F32: "VCVT.PL.FXS32.F32", + VCVT_VS_FXS32_F32: "VCVT.VS.FXS32.F32", + VCVT_VC_FXS32_F32: "VCVT.VC.FXS32.F32", + VCVT_HI_FXS32_F32: "VCVT.HI.FXS32.F32", + VCVT_LS_FXS32_F32: "VCVT.LS.FXS32.F32", + VCVT_GE_FXS32_F32: "VCVT.GE.FXS32.F32", + VCVT_LT_FXS32_F32: "VCVT.LT.FXS32.F32", + VCVT_GT_FXS32_F32: "VCVT.GT.FXS32.F32", + VCVT_LE_FXS32_F32: "VCVT.LE.FXS32.F32", + VCVT_FXS32_F32: "VCVT.FXS32.F32", + VCVT_ZZ_FXS32_F32: "VCVT.ZZ.FXS32.F32", + VCVT_EQ_FXS32_F64: "VCVT.EQ.FXS32.F64", + VCVT_NE_FXS32_F64: "VCVT.NE.FXS32.F64", + VCVT_CS_FXS32_F64: "VCVT.CS.FXS32.F64", + VCVT_CC_FXS32_F64: "VCVT.CC.FXS32.F64", + VCVT_MI_FXS32_F64: "VCVT.MI.FXS32.F64", + VCVT_PL_FXS32_F64: "VCVT.PL.FXS32.F64", + VCVT_VS_FXS32_F64: "VCVT.VS.FXS32.F64", + VCVT_VC_FXS32_F64: "VCVT.VC.FXS32.F64", + VCVT_HI_FXS32_F64: "VCVT.HI.FXS32.F64", + VCVT_LS_FXS32_F64: "VCVT.LS.FXS32.F64", + VCVT_GE_FXS32_F64: "VCVT.GE.FXS32.F64", + VCVT_LT_FXS32_F64: "VCVT.LT.FXS32.F64", + VCVT_GT_FXS32_F64: "VCVT.GT.FXS32.F64", + VCVT_LE_FXS32_F64: "VCVT.LE.FXS32.F64", + VCVT_FXS32_F64: "VCVT.FXS32.F64", + VCVT_ZZ_FXS32_F64: "VCVT.ZZ.FXS32.F64", + VCVT_EQ_FXU16_F32: "VCVT.EQ.FXU16.F32", + VCVT_NE_FXU16_F32: "VCVT.NE.FXU16.F32", + VCVT_CS_FXU16_F32: "VCVT.CS.FXU16.F32", + VCVT_CC_FXU16_F32: "VCVT.CC.FXU16.F32", + VCVT_MI_FXU16_F32: "VCVT.MI.FXU16.F32", + VCVT_PL_FXU16_F32: "VCVT.PL.FXU16.F32", + VCVT_VS_FXU16_F32: "VCVT.VS.FXU16.F32", + VCVT_VC_FXU16_F32: "VCVT.VC.FXU16.F32", + VCVT_HI_FXU16_F32: "VCVT.HI.FXU16.F32", + VCVT_LS_FXU16_F32: "VCVT.LS.FXU16.F32", + VCVT_GE_FXU16_F32: "VCVT.GE.FXU16.F32", + VCVT_LT_FXU16_F32: "VCVT.LT.FXU16.F32", + VCVT_GT_FXU16_F32: "VCVT.GT.FXU16.F32", + VCVT_LE_FXU16_F32: "VCVT.LE.FXU16.F32", + VCVT_FXU16_F32: "VCVT.FXU16.F32", + VCVT_ZZ_FXU16_F32: "VCVT.ZZ.FXU16.F32", + VCVT_EQ_FXU16_F64: "VCVT.EQ.FXU16.F64", + VCVT_NE_FXU16_F64: "VCVT.NE.FXU16.F64", + VCVT_CS_FXU16_F64: "VCVT.CS.FXU16.F64", + VCVT_CC_FXU16_F64: "VCVT.CC.FXU16.F64", + VCVT_MI_FXU16_F64: "VCVT.MI.FXU16.F64", + VCVT_PL_FXU16_F64: "VCVT.PL.FXU16.F64", + VCVT_VS_FXU16_F64: "VCVT.VS.FXU16.F64", + VCVT_VC_FXU16_F64: "VCVT.VC.FXU16.F64", + VCVT_HI_FXU16_F64: "VCVT.HI.FXU16.F64", + VCVT_LS_FXU16_F64: "VCVT.LS.FXU16.F64", + VCVT_GE_FXU16_F64: "VCVT.GE.FXU16.F64", + VCVT_LT_FXU16_F64: "VCVT.LT.FXU16.F64", + VCVT_GT_FXU16_F64: "VCVT.GT.FXU16.F64", + VCVT_LE_FXU16_F64: "VCVT.LE.FXU16.F64", + VCVT_FXU16_F64: "VCVT.FXU16.F64", + VCVT_ZZ_FXU16_F64: "VCVT.ZZ.FXU16.F64", + VCVT_EQ_FXU32_F32: "VCVT.EQ.FXU32.F32", + VCVT_NE_FXU32_F32: "VCVT.NE.FXU32.F32", + VCVT_CS_FXU32_F32: "VCVT.CS.FXU32.F32", + VCVT_CC_FXU32_F32: "VCVT.CC.FXU32.F32", + VCVT_MI_FXU32_F32: "VCVT.MI.FXU32.F32", + VCVT_PL_FXU32_F32: "VCVT.PL.FXU32.F32", + VCVT_VS_FXU32_F32: "VCVT.VS.FXU32.F32", + VCVT_VC_FXU32_F32: "VCVT.VC.FXU32.F32", + VCVT_HI_FXU32_F32: "VCVT.HI.FXU32.F32", + VCVT_LS_FXU32_F32: "VCVT.LS.FXU32.F32", + VCVT_GE_FXU32_F32: "VCVT.GE.FXU32.F32", + VCVT_LT_FXU32_F32: "VCVT.LT.FXU32.F32", + VCVT_GT_FXU32_F32: "VCVT.GT.FXU32.F32", + VCVT_LE_FXU32_F32: "VCVT.LE.FXU32.F32", + VCVT_FXU32_F32: "VCVT.FXU32.F32", + VCVT_ZZ_FXU32_F32: "VCVT.ZZ.FXU32.F32", + VCVT_EQ_FXU32_F64: "VCVT.EQ.FXU32.F64", + VCVT_NE_FXU32_F64: "VCVT.NE.FXU32.F64", + VCVT_CS_FXU32_F64: "VCVT.CS.FXU32.F64", + VCVT_CC_FXU32_F64: "VCVT.CC.FXU32.F64", + VCVT_MI_FXU32_F64: "VCVT.MI.FXU32.F64", + VCVT_PL_FXU32_F64: "VCVT.PL.FXU32.F64", + VCVT_VS_FXU32_F64: "VCVT.VS.FXU32.F64", + VCVT_VC_FXU32_F64: "VCVT.VC.FXU32.F64", + VCVT_HI_FXU32_F64: "VCVT.HI.FXU32.F64", + VCVT_LS_FXU32_F64: "VCVT.LS.FXU32.F64", + VCVT_GE_FXU32_F64: "VCVT.GE.FXU32.F64", + VCVT_LT_FXU32_F64: "VCVT.LT.FXU32.F64", + VCVT_GT_FXU32_F64: "VCVT.GT.FXU32.F64", + VCVT_LE_FXU32_F64: "VCVT.LE.FXU32.F64", + VCVT_FXU32_F64: "VCVT.FXU32.F64", + VCVT_ZZ_FXU32_F64: "VCVT.ZZ.FXU32.F64", + VCVTB_EQ_F32_F16: "VCVTB.EQ.F32.F16", + VCVTB_NE_F32_F16: "VCVTB.NE.F32.F16", + VCVTB_CS_F32_F16: "VCVTB.CS.F32.F16", + VCVTB_CC_F32_F16: "VCVTB.CC.F32.F16", + VCVTB_MI_F32_F16: "VCVTB.MI.F32.F16", + VCVTB_PL_F32_F16: "VCVTB.PL.F32.F16", + VCVTB_VS_F32_F16: "VCVTB.VS.F32.F16", + VCVTB_VC_F32_F16: "VCVTB.VC.F32.F16", + VCVTB_HI_F32_F16: "VCVTB.HI.F32.F16", + VCVTB_LS_F32_F16: "VCVTB.LS.F32.F16", + VCVTB_GE_F32_F16: "VCVTB.GE.F32.F16", + VCVTB_LT_F32_F16: "VCVTB.LT.F32.F16", + VCVTB_GT_F32_F16: "VCVTB.GT.F32.F16", + VCVTB_LE_F32_F16: "VCVTB.LE.F32.F16", + VCVTB_F32_F16: "VCVTB.F32.F16", + VCVTB_ZZ_F32_F16: "VCVTB.ZZ.F32.F16", + VCVTB_EQ_F16_F32: "VCVTB.EQ.F16.F32", + VCVTB_NE_F16_F32: "VCVTB.NE.F16.F32", + VCVTB_CS_F16_F32: "VCVTB.CS.F16.F32", + VCVTB_CC_F16_F32: "VCVTB.CC.F16.F32", + VCVTB_MI_F16_F32: "VCVTB.MI.F16.F32", + VCVTB_PL_F16_F32: "VCVTB.PL.F16.F32", + VCVTB_VS_F16_F32: "VCVTB.VS.F16.F32", + VCVTB_VC_F16_F32: "VCVTB.VC.F16.F32", + VCVTB_HI_F16_F32: "VCVTB.HI.F16.F32", + VCVTB_LS_F16_F32: "VCVTB.LS.F16.F32", + VCVTB_GE_F16_F32: "VCVTB.GE.F16.F32", + VCVTB_LT_F16_F32: "VCVTB.LT.F16.F32", + VCVTB_GT_F16_F32: "VCVTB.GT.F16.F32", + VCVTB_LE_F16_F32: "VCVTB.LE.F16.F32", + VCVTB_F16_F32: "VCVTB.F16.F32", + VCVTB_ZZ_F16_F32: "VCVTB.ZZ.F16.F32", + VCVTT_EQ_F32_F16: "VCVTT.EQ.F32.F16", + VCVTT_NE_F32_F16: "VCVTT.NE.F32.F16", + VCVTT_CS_F32_F16: "VCVTT.CS.F32.F16", + VCVTT_CC_F32_F16: "VCVTT.CC.F32.F16", + VCVTT_MI_F32_F16: "VCVTT.MI.F32.F16", + VCVTT_PL_F32_F16: "VCVTT.PL.F32.F16", + VCVTT_VS_F32_F16: "VCVTT.VS.F32.F16", + VCVTT_VC_F32_F16: "VCVTT.VC.F32.F16", + VCVTT_HI_F32_F16: "VCVTT.HI.F32.F16", + VCVTT_LS_F32_F16: "VCVTT.LS.F32.F16", + VCVTT_GE_F32_F16: "VCVTT.GE.F32.F16", + VCVTT_LT_F32_F16: "VCVTT.LT.F32.F16", + VCVTT_GT_F32_F16: "VCVTT.GT.F32.F16", + VCVTT_LE_F32_F16: "VCVTT.LE.F32.F16", + VCVTT_F32_F16: "VCVTT.F32.F16", + VCVTT_ZZ_F32_F16: "VCVTT.ZZ.F32.F16", + VCVTT_EQ_F16_F32: "VCVTT.EQ.F16.F32", + VCVTT_NE_F16_F32: "VCVTT.NE.F16.F32", + VCVTT_CS_F16_F32: "VCVTT.CS.F16.F32", + VCVTT_CC_F16_F32: "VCVTT.CC.F16.F32", + VCVTT_MI_F16_F32: "VCVTT.MI.F16.F32", + VCVTT_PL_F16_F32: "VCVTT.PL.F16.F32", + VCVTT_VS_F16_F32: "VCVTT.VS.F16.F32", + VCVTT_VC_F16_F32: "VCVTT.VC.F16.F32", + VCVTT_HI_F16_F32: "VCVTT.HI.F16.F32", + VCVTT_LS_F16_F32: "VCVTT.LS.F16.F32", + VCVTT_GE_F16_F32: "VCVTT.GE.F16.F32", + VCVTT_LT_F16_F32: "VCVTT.LT.F16.F32", + VCVTT_GT_F16_F32: "VCVTT.GT.F16.F32", + VCVTT_LE_F16_F32: "VCVTT.LE.F16.F32", + VCVTT_F16_F32: "VCVTT.F16.F32", + VCVTT_ZZ_F16_F32: "VCVTT.ZZ.F16.F32", + VCVTR_EQ_U32_F32: "VCVTR.EQ.U32.F32", + VCVTR_NE_U32_F32: "VCVTR.NE.U32.F32", + VCVTR_CS_U32_F32: "VCVTR.CS.U32.F32", + VCVTR_CC_U32_F32: "VCVTR.CC.U32.F32", + VCVTR_MI_U32_F32: "VCVTR.MI.U32.F32", + VCVTR_PL_U32_F32: "VCVTR.PL.U32.F32", + VCVTR_VS_U32_F32: "VCVTR.VS.U32.F32", + VCVTR_VC_U32_F32: "VCVTR.VC.U32.F32", + VCVTR_HI_U32_F32: "VCVTR.HI.U32.F32", + VCVTR_LS_U32_F32: "VCVTR.LS.U32.F32", + VCVTR_GE_U32_F32: "VCVTR.GE.U32.F32", + VCVTR_LT_U32_F32: "VCVTR.LT.U32.F32", + VCVTR_GT_U32_F32: "VCVTR.GT.U32.F32", + VCVTR_LE_U32_F32: "VCVTR.LE.U32.F32", + VCVTR_U32_F32: "VCVTR.U32.F32", + VCVTR_ZZ_U32_F32: "VCVTR.ZZ.U32.F32", + VCVTR_EQ_U32_F64: "VCVTR.EQ.U32.F64", + VCVTR_NE_U32_F64: "VCVTR.NE.U32.F64", + VCVTR_CS_U32_F64: "VCVTR.CS.U32.F64", + VCVTR_CC_U32_F64: "VCVTR.CC.U32.F64", + VCVTR_MI_U32_F64: "VCVTR.MI.U32.F64", + VCVTR_PL_U32_F64: "VCVTR.PL.U32.F64", + VCVTR_VS_U32_F64: "VCVTR.VS.U32.F64", + VCVTR_VC_U32_F64: "VCVTR.VC.U32.F64", + VCVTR_HI_U32_F64: "VCVTR.HI.U32.F64", + VCVTR_LS_U32_F64: "VCVTR.LS.U32.F64", + VCVTR_GE_U32_F64: "VCVTR.GE.U32.F64", + VCVTR_LT_U32_F64: "VCVTR.LT.U32.F64", + VCVTR_GT_U32_F64: "VCVTR.GT.U32.F64", + VCVTR_LE_U32_F64: "VCVTR.LE.U32.F64", + VCVTR_U32_F64: "VCVTR.U32.F64", + VCVTR_ZZ_U32_F64: "VCVTR.ZZ.U32.F64", + VCVTR_EQ_S32_F32: "VCVTR.EQ.S32.F32", + VCVTR_NE_S32_F32: "VCVTR.NE.S32.F32", + VCVTR_CS_S32_F32: "VCVTR.CS.S32.F32", + VCVTR_CC_S32_F32: "VCVTR.CC.S32.F32", + VCVTR_MI_S32_F32: "VCVTR.MI.S32.F32", + VCVTR_PL_S32_F32: "VCVTR.PL.S32.F32", + VCVTR_VS_S32_F32: "VCVTR.VS.S32.F32", + VCVTR_VC_S32_F32: "VCVTR.VC.S32.F32", + VCVTR_HI_S32_F32: "VCVTR.HI.S32.F32", + VCVTR_LS_S32_F32: "VCVTR.LS.S32.F32", + VCVTR_GE_S32_F32: "VCVTR.GE.S32.F32", + VCVTR_LT_S32_F32: "VCVTR.LT.S32.F32", + VCVTR_GT_S32_F32: "VCVTR.GT.S32.F32", + VCVTR_LE_S32_F32: "VCVTR.LE.S32.F32", + VCVTR_S32_F32: "VCVTR.S32.F32", + VCVTR_ZZ_S32_F32: "VCVTR.ZZ.S32.F32", + VCVTR_EQ_S32_F64: "VCVTR.EQ.S32.F64", + VCVTR_NE_S32_F64: "VCVTR.NE.S32.F64", + VCVTR_CS_S32_F64: "VCVTR.CS.S32.F64", + VCVTR_CC_S32_F64: "VCVTR.CC.S32.F64", + VCVTR_MI_S32_F64: "VCVTR.MI.S32.F64", + VCVTR_PL_S32_F64: "VCVTR.PL.S32.F64", + VCVTR_VS_S32_F64: "VCVTR.VS.S32.F64", + VCVTR_VC_S32_F64: "VCVTR.VC.S32.F64", + VCVTR_HI_S32_F64: "VCVTR.HI.S32.F64", + VCVTR_LS_S32_F64: "VCVTR.LS.S32.F64", + VCVTR_GE_S32_F64: "VCVTR.GE.S32.F64", + VCVTR_LT_S32_F64: "VCVTR.LT.S32.F64", + VCVTR_GT_S32_F64: "VCVTR.GT.S32.F64", + VCVTR_LE_S32_F64: "VCVTR.LE.S32.F64", + VCVTR_S32_F64: "VCVTR.S32.F64", + VCVTR_ZZ_S32_F64: "VCVTR.ZZ.S32.F64", + VCVT_EQ_U32_F32: "VCVT.EQ.U32.F32", + VCVT_NE_U32_F32: "VCVT.NE.U32.F32", + VCVT_CS_U32_F32: "VCVT.CS.U32.F32", + VCVT_CC_U32_F32: "VCVT.CC.U32.F32", + VCVT_MI_U32_F32: "VCVT.MI.U32.F32", + VCVT_PL_U32_F32: "VCVT.PL.U32.F32", + VCVT_VS_U32_F32: "VCVT.VS.U32.F32", + VCVT_VC_U32_F32: "VCVT.VC.U32.F32", + VCVT_HI_U32_F32: "VCVT.HI.U32.F32", + VCVT_LS_U32_F32: "VCVT.LS.U32.F32", + VCVT_GE_U32_F32: "VCVT.GE.U32.F32", + VCVT_LT_U32_F32: "VCVT.LT.U32.F32", + VCVT_GT_U32_F32: "VCVT.GT.U32.F32", + VCVT_LE_U32_F32: "VCVT.LE.U32.F32", + VCVT_U32_F32: "VCVT.U32.F32", + VCVT_ZZ_U32_F32: "VCVT.ZZ.U32.F32", + VCVT_EQ_U32_F64: "VCVT.EQ.U32.F64", + VCVT_NE_U32_F64: "VCVT.NE.U32.F64", + VCVT_CS_U32_F64: "VCVT.CS.U32.F64", + VCVT_CC_U32_F64: "VCVT.CC.U32.F64", + VCVT_MI_U32_F64: "VCVT.MI.U32.F64", + VCVT_PL_U32_F64: "VCVT.PL.U32.F64", + VCVT_VS_U32_F64: "VCVT.VS.U32.F64", + VCVT_VC_U32_F64: "VCVT.VC.U32.F64", + VCVT_HI_U32_F64: "VCVT.HI.U32.F64", + VCVT_LS_U32_F64: "VCVT.LS.U32.F64", + VCVT_GE_U32_F64: "VCVT.GE.U32.F64", + VCVT_LT_U32_F64: "VCVT.LT.U32.F64", + VCVT_GT_U32_F64: "VCVT.GT.U32.F64", + VCVT_LE_U32_F64: "VCVT.LE.U32.F64", + VCVT_U32_F64: "VCVT.U32.F64", + VCVT_ZZ_U32_F64: "VCVT.ZZ.U32.F64", + VCVT_EQ_S32_F32: "VCVT.EQ.S32.F32", + VCVT_NE_S32_F32: "VCVT.NE.S32.F32", + VCVT_CS_S32_F32: "VCVT.CS.S32.F32", + VCVT_CC_S32_F32: "VCVT.CC.S32.F32", + VCVT_MI_S32_F32: "VCVT.MI.S32.F32", + VCVT_PL_S32_F32: "VCVT.PL.S32.F32", + VCVT_VS_S32_F32: "VCVT.VS.S32.F32", + VCVT_VC_S32_F32: "VCVT.VC.S32.F32", + VCVT_HI_S32_F32: "VCVT.HI.S32.F32", + VCVT_LS_S32_F32: "VCVT.LS.S32.F32", + VCVT_GE_S32_F32: "VCVT.GE.S32.F32", + VCVT_LT_S32_F32: "VCVT.LT.S32.F32", + VCVT_GT_S32_F32: "VCVT.GT.S32.F32", + VCVT_LE_S32_F32: "VCVT.LE.S32.F32", + VCVT_S32_F32: "VCVT.S32.F32", + VCVT_ZZ_S32_F32: "VCVT.ZZ.S32.F32", + VCVT_EQ_S32_F64: "VCVT.EQ.S32.F64", + VCVT_NE_S32_F64: "VCVT.NE.S32.F64", + VCVT_CS_S32_F64: "VCVT.CS.S32.F64", + VCVT_CC_S32_F64: "VCVT.CC.S32.F64", + VCVT_MI_S32_F64: "VCVT.MI.S32.F64", + VCVT_PL_S32_F64: "VCVT.PL.S32.F64", + VCVT_VS_S32_F64: "VCVT.VS.S32.F64", + VCVT_VC_S32_F64: "VCVT.VC.S32.F64", + VCVT_HI_S32_F64: "VCVT.HI.S32.F64", + VCVT_LS_S32_F64: "VCVT.LS.S32.F64", + VCVT_GE_S32_F64: "VCVT.GE.S32.F64", + VCVT_LT_S32_F64: "VCVT.LT.S32.F64", + VCVT_GT_S32_F64: "VCVT.GT.S32.F64", + VCVT_LE_S32_F64: "VCVT.LE.S32.F64", + VCVT_S32_F64: "VCVT.S32.F64", + VCVT_ZZ_S32_F64: "VCVT.ZZ.S32.F64", + VDIV_EQ_F32: "VDIV.EQ.F32", + VDIV_NE_F32: "VDIV.NE.F32", + VDIV_CS_F32: "VDIV.CS.F32", + VDIV_CC_F32: "VDIV.CC.F32", + VDIV_MI_F32: "VDIV.MI.F32", + VDIV_PL_F32: "VDIV.PL.F32", + VDIV_VS_F32: "VDIV.VS.F32", + VDIV_VC_F32: "VDIV.VC.F32", + VDIV_HI_F32: "VDIV.HI.F32", + VDIV_LS_F32: "VDIV.LS.F32", + VDIV_GE_F32: "VDIV.GE.F32", + VDIV_LT_F32: "VDIV.LT.F32", + VDIV_GT_F32: "VDIV.GT.F32", + VDIV_LE_F32: "VDIV.LE.F32", + VDIV_F32: "VDIV.F32", + VDIV_ZZ_F32: "VDIV.ZZ.F32", + VDIV_EQ_F64: "VDIV.EQ.F64", + VDIV_NE_F64: "VDIV.NE.F64", + VDIV_CS_F64: "VDIV.CS.F64", + VDIV_CC_F64: "VDIV.CC.F64", + VDIV_MI_F64: "VDIV.MI.F64", + VDIV_PL_F64: "VDIV.PL.F64", + VDIV_VS_F64: "VDIV.VS.F64", + VDIV_VC_F64: "VDIV.VC.F64", + VDIV_HI_F64: "VDIV.HI.F64", + VDIV_LS_F64: "VDIV.LS.F64", + VDIV_GE_F64: "VDIV.GE.F64", + VDIV_LT_F64: "VDIV.LT.F64", + VDIV_GT_F64: "VDIV.GT.F64", + VDIV_LE_F64: "VDIV.LE.F64", + VDIV_F64: "VDIV.F64", + VDIV_ZZ_F64: "VDIV.ZZ.F64", + VLDR_EQ: "VLDR.EQ", + VLDR_NE: "VLDR.NE", + VLDR_CS: "VLDR.CS", + VLDR_CC: "VLDR.CC", + VLDR_MI: "VLDR.MI", + VLDR_PL: "VLDR.PL", + VLDR_VS: "VLDR.VS", + VLDR_VC: "VLDR.VC", + VLDR_HI: "VLDR.HI", + VLDR_LS: "VLDR.LS", + VLDR_GE: "VLDR.GE", + VLDR_LT: "VLDR.LT", + VLDR_GT: "VLDR.GT", + VLDR_LE: "VLDR.LE", + VLDR: "VLDR", + VLDR_ZZ: "VLDR.ZZ", + VMLA_EQ_F32: "VMLA.EQ.F32", + VMLA_NE_F32: "VMLA.NE.F32", + VMLA_CS_F32: "VMLA.CS.F32", + VMLA_CC_F32: "VMLA.CC.F32", + VMLA_MI_F32: "VMLA.MI.F32", + VMLA_PL_F32: "VMLA.PL.F32", + VMLA_VS_F32: "VMLA.VS.F32", + VMLA_VC_F32: "VMLA.VC.F32", + VMLA_HI_F32: "VMLA.HI.F32", + VMLA_LS_F32: "VMLA.LS.F32", + VMLA_GE_F32: "VMLA.GE.F32", + VMLA_LT_F32: "VMLA.LT.F32", + VMLA_GT_F32: "VMLA.GT.F32", + VMLA_LE_F32: "VMLA.LE.F32", + VMLA_F32: "VMLA.F32", + VMLA_ZZ_F32: "VMLA.ZZ.F32", + VMLA_EQ_F64: "VMLA.EQ.F64", + VMLA_NE_F64: "VMLA.NE.F64", + VMLA_CS_F64: "VMLA.CS.F64", + VMLA_CC_F64: "VMLA.CC.F64", + VMLA_MI_F64: "VMLA.MI.F64", + VMLA_PL_F64: "VMLA.PL.F64", + VMLA_VS_F64: "VMLA.VS.F64", + VMLA_VC_F64: "VMLA.VC.F64", + VMLA_HI_F64: "VMLA.HI.F64", + VMLA_LS_F64: "VMLA.LS.F64", + VMLA_GE_F64: "VMLA.GE.F64", + VMLA_LT_F64: "VMLA.LT.F64", + VMLA_GT_F64: "VMLA.GT.F64", + VMLA_LE_F64: "VMLA.LE.F64", + VMLA_F64: "VMLA.F64", + VMLA_ZZ_F64: "VMLA.ZZ.F64", + VMLS_EQ_F32: "VMLS.EQ.F32", + VMLS_NE_F32: "VMLS.NE.F32", + VMLS_CS_F32: "VMLS.CS.F32", + VMLS_CC_F32: "VMLS.CC.F32", + VMLS_MI_F32: "VMLS.MI.F32", + VMLS_PL_F32: "VMLS.PL.F32", + VMLS_VS_F32: "VMLS.VS.F32", + VMLS_VC_F32: "VMLS.VC.F32", + VMLS_HI_F32: "VMLS.HI.F32", + VMLS_LS_F32: "VMLS.LS.F32", + VMLS_GE_F32: "VMLS.GE.F32", + VMLS_LT_F32: "VMLS.LT.F32", + VMLS_GT_F32: "VMLS.GT.F32", + VMLS_LE_F32: "VMLS.LE.F32", + VMLS_F32: "VMLS.F32", + VMLS_ZZ_F32: "VMLS.ZZ.F32", + VMLS_EQ_F64: "VMLS.EQ.F64", + VMLS_NE_F64: "VMLS.NE.F64", + VMLS_CS_F64: "VMLS.CS.F64", + VMLS_CC_F64: "VMLS.CC.F64", + VMLS_MI_F64: "VMLS.MI.F64", + VMLS_PL_F64: "VMLS.PL.F64", + VMLS_VS_F64: "VMLS.VS.F64", + VMLS_VC_F64: "VMLS.VC.F64", + VMLS_HI_F64: "VMLS.HI.F64", + VMLS_LS_F64: "VMLS.LS.F64", + VMLS_GE_F64: "VMLS.GE.F64", + VMLS_LT_F64: "VMLS.LT.F64", + VMLS_GT_F64: "VMLS.GT.F64", + VMLS_LE_F64: "VMLS.LE.F64", + VMLS_F64: "VMLS.F64", + VMLS_ZZ_F64: "VMLS.ZZ.F64", + VMOV_EQ: "VMOV.EQ", + VMOV_NE: "VMOV.NE", + VMOV_CS: "VMOV.CS", + VMOV_CC: "VMOV.CC", + VMOV_MI: "VMOV.MI", + VMOV_PL: "VMOV.PL", + VMOV_VS: "VMOV.VS", + VMOV_VC: "VMOV.VC", + VMOV_HI: "VMOV.HI", + VMOV_LS: "VMOV.LS", + VMOV_GE: "VMOV.GE", + VMOV_LT: "VMOV.LT", + VMOV_GT: "VMOV.GT", + VMOV_LE: "VMOV.LE", + VMOV: "VMOV", + VMOV_ZZ: "VMOV.ZZ", + VMOV_EQ_32: "VMOV.EQ.32", + VMOV_NE_32: "VMOV.NE.32", + VMOV_CS_32: "VMOV.CS.32", + VMOV_CC_32: "VMOV.CC.32", + VMOV_MI_32: "VMOV.MI.32", + VMOV_PL_32: "VMOV.PL.32", + VMOV_VS_32: "VMOV.VS.32", + VMOV_VC_32: "VMOV.VC.32", + VMOV_HI_32: "VMOV.HI.32", + VMOV_LS_32: "VMOV.LS.32", + VMOV_GE_32: "VMOV.GE.32", + VMOV_LT_32: "VMOV.LT.32", + VMOV_GT_32: "VMOV.GT.32", + VMOV_LE_32: "VMOV.LE.32", + VMOV_32: "VMOV.32", + VMOV_ZZ_32: "VMOV.ZZ.32", + VMOV_EQ_F32: "VMOV.EQ.F32", + VMOV_NE_F32: "VMOV.NE.F32", + VMOV_CS_F32: "VMOV.CS.F32", + VMOV_CC_F32: "VMOV.CC.F32", + VMOV_MI_F32: "VMOV.MI.F32", + VMOV_PL_F32: "VMOV.PL.F32", + VMOV_VS_F32: "VMOV.VS.F32", + VMOV_VC_F32: "VMOV.VC.F32", + VMOV_HI_F32: "VMOV.HI.F32", + VMOV_LS_F32: "VMOV.LS.F32", + VMOV_GE_F32: "VMOV.GE.F32", + VMOV_LT_F32: "VMOV.LT.F32", + VMOV_GT_F32: "VMOV.GT.F32", + VMOV_LE_F32: "VMOV.LE.F32", + VMOV_F32: "VMOV.F32", + VMOV_ZZ_F32: "VMOV.ZZ.F32", + VMOV_EQ_F64: "VMOV.EQ.F64", + VMOV_NE_F64: "VMOV.NE.F64", + VMOV_CS_F64: "VMOV.CS.F64", + VMOV_CC_F64: "VMOV.CC.F64", + VMOV_MI_F64: "VMOV.MI.F64", + VMOV_PL_F64: "VMOV.PL.F64", + VMOV_VS_F64: "VMOV.VS.F64", + VMOV_VC_F64: "VMOV.VC.F64", + VMOV_HI_F64: "VMOV.HI.F64", + VMOV_LS_F64: "VMOV.LS.F64", + VMOV_GE_F64: "VMOV.GE.F64", + VMOV_LT_F64: "VMOV.LT.F64", + VMOV_GT_F64: "VMOV.GT.F64", + VMOV_LE_F64: "VMOV.LE.F64", + VMOV_F64: "VMOV.F64", + VMOV_ZZ_F64: "VMOV.ZZ.F64", + VMRS_EQ: "VMRS.EQ", + VMRS_NE: "VMRS.NE", + VMRS_CS: "VMRS.CS", + VMRS_CC: "VMRS.CC", + VMRS_MI: "VMRS.MI", + VMRS_PL: "VMRS.PL", + VMRS_VS: "VMRS.VS", + VMRS_VC: "VMRS.VC", + VMRS_HI: "VMRS.HI", + VMRS_LS: "VMRS.LS", + VMRS_GE: "VMRS.GE", + VMRS_LT: "VMRS.LT", + VMRS_GT: "VMRS.GT", + VMRS_LE: "VMRS.LE", + VMRS: "VMRS", + VMRS_ZZ: "VMRS.ZZ", + VMSR_EQ: "VMSR.EQ", + VMSR_NE: "VMSR.NE", + VMSR_CS: "VMSR.CS", + VMSR_CC: "VMSR.CC", + VMSR_MI: "VMSR.MI", + VMSR_PL: "VMSR.PL", + VMSR_VS: "VMSR.VS", + VMSR_VC: "VMSR.VC", + VMSR_HI: "VMSR.HI", + VMSR_LS: "VMSR.LS", + VMSR_GE: "VMSR.GE", + VMSR_LT: "VMSR.LT", + VMSR_GT: "VMSR.GT", + VMSR_LE: "VMSR.LE", + VMSR: "VMSR", + VMSR_ZZ: "VMSR.ZZ", + VMUL_EQ_F32: "VMUL.EQ.F32", + VMUL_NE_F32: "VMUL.NE.F32", + VMUL_CS_F32: "VMUL.CS.F32", + VMUL_CC_F32: "VMUL.CC.F32", + VMUL_MI_F32: "VMUL.MI.F32", + VMUL_PL_F32: "VMUL.PL.F32", + VMUL_VS_F32: "VMUL.VS.F32", + VMUL_VC_F32: "VMUL.VC.F32", + VMUL_HI_F32: "VMUL.HI.F32", + VMUL_LS_F32: "VMUL.LS.F32", + VMUL_GE_F32: "VMUL.GE.F32", + VMUL_LT_F32: "VMUL.LT.F32", + VMUL_GT_F32: "VMUL.GT.F32", + VMUL_LE_F32: "VMUL.LE.F32", + VMUL_F32: "VMUL.F32", + VMUL_ZZ_F32: "VMUL.ZZ.F32", + VMUL_EQ_F64: "VMUL.EQ.F64", + VMUL_NE_F64: "VMUL.NE.F64", + VMUL_CS_F64: "VMUL.CS.F64", + VMUL_CC_F64: "VMUL.CC.F64", + VMUL_MI_F64: "VMUL.MI.F64", + VMUL_PL_F64: "VMUL.PL.F64", + VMUL_VS_F64: "VMUL.VS.F64", + VMUL_VC_F64: "VMUL.VC.F64", + VMUL_HI_F64: "VMUL.HI.F64", + VMUL_LS_F64: "VMUL.LS.F64", + VMUL_GE_F64: "VMUL.GE.F64", + VMUL_LT_F64: "VMUL.LT.F64", + VMUL_GT_F64: "VMUL.GT.F64", + VMUL_LE_F64: "VMUL.LE.F64", + VMUL_F64: "VMUL.F64", + VMUL_ZZ_F64: "VMUL.ZZ.F64", + VNEG_EQ_F32: "VNEG.EQ.F32", + VNEG_NE_F32: "VNEG.NE.F32", + VNEG_CS_F32: "VNEG.CS.F32", + VNEG_CC_F32: "VNEG.CC.F32", + VNEG_MI_F32: "VNEG.MI.F32", + VNEG_PL_F32: "VNEG.PL.F32", + VNEG_VS_F32: "VNEG.VS.F32", + VNEG_VC_F32: "VNEG.VC.F32", + VNEG_HI_F32: "VNEG.HI.F32", + VNEG_LS_F32: "VNEG.LS.F32", + VNEG_GE_F32: "VNEG.GE.F32", + VNEG_LT_F32: "VNEG.LT.F32", + VNEG_GT_F32: "VNEG.GT.F32", + VNEG_LE_F32: "VNEG.LE.F32", + VNEG_F32: "VNEG.F32", + VNEG_ZZ_F32: "VNEG.ZZ.F32", + VNEG_EQ_F64: "VNEG.EQ.F64", + VNEG_NE_F64: "VNEG.NE.F64", + VNEG_CS_F64: "VNEG.CS.F64", + VNEG_CC_F64: "VNEG.CC.F64", + VNEG_MI_F64: "VNEG.MI.F64", + VNEG_PL_F64: "VNEG.PL.F64", + VNEG_VS_F64: "VNEG.VS.F64", + VNEG_VC_F64: "VNEG.VC.F64", + VNEG_HI_F64: "VNEG.HI.F64", + VNEG_LS_F64: "VNEG.LS.F64", + VNEG_GE_F64: "VNEG.GE.F64", + VNEG_LT_F64: "VNEG.LT.F64", + VNEG_GT_F64: "VNEG.GT.F64", + VNEG_LE_F64: "VNEG.LE.F64", + VNEG_F64: "VNEG.F64", + VNEG_ZZ_F64: "VNEG.ZZ.F64", + VNMLS_EQ_F32: "VNMLS.EQ.F32", + VNMLS_NE_F32: "VNMLS.NE.F32", + VNMLS_CS_F32: "VNMLS.CS.F32", + VNMLS_CC_F32: "VNMLS.CC.F32", + VNMLS_MI_F32: "VNMLS.MI.F32", + VNMLS_PL_F32: "VNMLS.PL.F32", + VNMLS_VS_F32: "VNMLS.VS.F32", + VNMLS_VC_F32: "VNMLS.VC.F32", + VNMLS_HI_F32: "VNMLS.HI.F32", + VNMLS_LS_F32: "VNMLS.LS.F32", + VNMLS_GE_F32: "VNMLS.GE.F32", + VNMLS_LT_F32: "VNMLS.LT.F32", + VNMLS_GT_F32: "VNMLS.GT.F32", + VNMLS_LE_F32: "VNMLS.LE.F32", + VNMLS_F32: "VNMLS.F32", + VNMLS_ZZ_F32: "VNMLS.ZZ.F32", + VNMLS_EQ_F64: "VNMLS.EQ.F64", + VNMLS_NE_F64: "VNMLS.NE.F64", + VNMLS_CS_F64: "VNMLS.CS.F64", + VNMLS_CC_F64: "VNMLS.CC.F64", + VNMLS_MI_F64: "VNMLS.MI.F64", + VNMLS_PL_F64: "VNMLS.PL.F64", + VNMLS_VS_F64: "VNMLS.VS.F64", + VNMLS_VC_F64: "VNMLS.VC.F64", + VNMLS_HI_F64: "VNMLS.HI.F64", + VNMLS_LS_F64: "VNMLS.LS.F64", + VNMLS_GE_F64: "VNMLS.GE.F64", + VNMLS_LT_F64: "VNMLS.LT.F64", + VNMLS_GT_F64: "VNMLS.GT.F64", + VNMLS_LE_F64: "VNMLS.LE.F64", + VNMLS_F64: "VNMLS.F64", + VNMLS_ZZ_F64: "VNMLS.ZZ.F64", + VNMLA_EQ_F32: "VNMLA.EQ.F32", + VNMLA_NE_F32: "VNMLA.NE.F32", + VNMLA_CS_F32: "VNMLA.CS.F32", + VNMLA_CC_F32: "VNMLA.CC.F32", + VNMLA_MI_F32: "VNMLA.MI.F32", + VNMLA_PL_F32: "VNMLA.PL.F32", + VNMLA_VS_F32: "VNMLA.VS.F32", + VNMLA_VC_F32: "VNMLA.VC.F32", + VNMLA_HI_F32: "VNMLA.HI.F32", + VNMLA_LS_F32: "VNMLA.LS.F32", + VNMLA_GE_F32: "VNMLA.GE.F32", + VNMLA_LT_F32: "VNMLA.LT.F32", + VNMLA_GT_F32: "VNMLA.GT.F32", + VNMLA_LE_F32: "VNMLA.LE.F32", + VNMLA_F32: "VNMLA.F32", + VNMLA_ZZ_F32: "VNMLA.ZZ.F32", + VNMLA_EQ_F64: "VNMLA.EQ.F64", + VNMLA_NE_F64: "VNMLA.NE.F64", + VNMLA_CS_F64: "VNMLA.CS.F64", + VNMLA_CC_F64: "VNMLA.CC.F64", + VNMLA_MI_F64: "VNMLA.MI.F64", + VNMLA_PL_F64: "VNMLA.PL.F64", + VNMLA_VS_F64: "VNMLA.VS.F64", + VNMLA_VC_F64: "VNMLA.VC.F64", + VNMLA_HI_F64: "VNMLA.HI.F64", + VNMLA_LS_F64: "VNMLA.LS.F64", + VNMLA_GE_F64: "VNMLA.GE.F64", + VNMLA_LT_F64: "VNMLA.LT.F64", + VNMLA_GT_F64: "VNMLA.GT.F64", + VNMLA_LE_F64: "VNMLA.LE.F64", + VNMLA_F64: "VNMLA.F64", + VNMLA_ZZ_F64: "VNMLA.ZZ.F64", + VNMUL_EQ_F32: "VNMUL.EQ.F32", + VNMUL_NE_F32: "VNMUL.NE.F32", + VNMUL_CS_F32: "VNMUL.CS.F32", + VNMUL_CC_F32: "VNMUL.CC.F32", + VNMUL_MI_F32: "VNMUL.MI.F32", + VNMUL_PL_F32: "VNMUL.PL.F32", + VNMUL_VS_F32: "VNMUL.VS.F32", + VNMUL_VC_F32: "VNMUL.VC.F32", + VNMUL_HI_F32: "VNMUL.HI.F32", + VNMUL_LS_F32: "VNMUL.LS.F32", + VNMUL_GE_F32: "VNMUL.GE.F32", + VNMUL_LT_F32: "VNMUL.LT.F32", + VNMUL_GT_F32: "VNMUL.GT.F32", + VNMUL_LE_F32: "VNMUL.LE.F32", + VNMUL_F32: "VNMUL.F32", + VNMUL_ZZ_F32: "VNMUL.ZZ.F32", + VNMUL_EQ_F64: "VNMUL.EQ.F64", + VNMUL_NE_F64: "VNMUL.NE.F64", + VNMUL_CS_F64: "VNMUL.CS.F64", + VNMUL_CC_F64: "VNMUL.CC.F64", + VNMUL_MI_F64: "VNMUL.MI.F64", + VNMUL_PL_F64: "VNMUL.PL.F64", + VNMUL_VS_F64: "VNMUL.VS.F64", + VNMUL_VC_F64: "VNMUL.VC.F64", + VNMUL_HI_F64: "VNMUL.HI.F64", + VNMUL_LS_F64: "VNMUL.LS.F64", + VNMUL_GE_F64: "VNMUL.GE.F64", + VNMUL_LT_F64: "VNMUL.LT.F64", + VNMUL_GT_F64: "VNMUL.GT.F64", + VNMUL_LE_F64: "VNMUL.LE.F64", + VNMUL_F64: "VNMUL.F64", + VNMUL_ZZ_F64: "VNMUL.ZZ.F64", + VSQRT_EQ_F32: "VSQRT.EQ.F32", + VSQRT_NE_F32: "VSQRT.NE.F32", + VSQRT_CS_F32: "VSQRT.CS.F32", + VSQRT_CC_F32: "VSQRT.CC.F32", + VSQRT_MI_F32: "VSQRT.MI.F32", + VSQRT_PL_F32: "VSQRT.PL.F32", + VSQRT_VS_F32: "VSQRT.VS.F32", + VSQRT_VC_F32: "VSQRT.VC.F32", + VSQRT_HI_F32: "VSQRT.HI.F32", + VSQRT_LS_F32: "VSQRT.LS.F32", + VSQRT_GE_F32: "VSQRT.GE.F32", + VSQRT_LT_F32: "VSQRT.LT.F32", + VSQRT_GT_F32: "VSQRT.GT.F32", + VSQRT_LE_F32: "VSQRT.LE.F32", + VSQRT_F32: "VSQRT.F32", + VSQRT_ZZ_F32: "VSQRT.ZZ.F32", + VSQRT_EQ_F64: "VSQRT.EQ.F64", + VSQRT_NE_F64: "VSQRT.NE.F64", + VSQRT_CS_F64: "VSQRT.CS.F64", + VSQRT_CC_F64: "VSQRT.CC.F64", + VSQRT_MI_F64: "VSQRT.MI.F64", + VSQRT_PL_F64: "VSQRT.PL.F64", + VSQRT_VS_F64: "VSQRT.VS.F64", + VSQRT_VC_F64: "VSQRT.VC.F64", + VSQRT_HI_F64: "VSQRT.HI.F64", + VSQRT_LS_F64: "VSQRT.LS.F64", + VSQRT_GE_F64: "VSQRT.GE.F64", + VSQRT_LT_F64: "VSQRT.LT.F64", + VSQRT_GT_F64: "VSQRT.GT.F64", + VSQRT_LE_F64: "VSQRT.LE.F64", + VSQRT_F64: "VSQRT.F64", + VSQRT_ZZ_F64: "VSQRT.ZZ.F64", + VSTR_EQ: "VSTR.EQ", + VSTR_NE: "VSTR.NE", + VSTR_CS: "VSTR.CS", + VSTR_CC: "VSTR.CC", + VSTR_MI: "VSTR.MI", + VSTR_PL: "VSTR.PL", + VSTR_VS: "VSTR.VS", + VSTR_VC: "VSTR.VC", + VSTR_HI: "VSTR.HI", + VSTR_LS: "VSTR.LS", + VSTR_GE: "VSTR.GE", + VSTR_LT: "VSTR.LT", + VSTR_GT: "VSTR.GT", + VSTR_LE: "VSTR.LE", + VSTR: "VSTR", + VSTR_ZZ: "VSTR.ZZ", + VSUB_EQ_F32: "VSUB.EQ.F32", + VSUB_NE_F32: "VSUB.NE.F32", + VSUB_CS_F32: "VSUB.CS.F32", + VSUB_CC_F32: "VSUB.CC.F32", + VSUB_MI_F32: "VSUB.MI.F32", + VSUB_PL_F32: "VSUB.PL.F32", + VSUB_VS_F32: "VSUB.VS.F32", + VSUB_VC_F32: "VSUB.VC.F32", + VSUB_HI_F32: "VSUB.HI.F32", + VSUB_LS_F32: "VSUB.LS.F32", + VSUB_GE_F32: "VSUB.GE.F32", + VSUB_LT_F32: "VSUB.LT.F32", + VSUB_GT_F32: "VSUB.GT.F32", + VSUB_LE_F32: "VSUB.LE.F32", + VSUB_F32: "VSUB.F32", + VSUB_ZZ_F32: "VSUB.ZZ.F32", + VSUB_EQ_F64: "VSUB.EQ.F64", + VSUB_NE_F64: "VSUB.NE.F64", + VSUB_CS_F64: "VSUB.CS.F64", + VSUB_CC_F64: "VSUB.CC.F64", + VSUB_MI_F64: "VSUB.MI.F64", + VSUB_PL_F64: "VSUB.PL.F64", + VSUB_VS_F64: "VSUB.VS.F64", + VSUB_VC_F64: "VSUB.VC.F64", + VSUB_HI_F64: "VSUB.HI.F64", + VSUB_LS_F64: "VSUB.LS.F64", + VSUB_GE_F64: "VSUB.GE.F64", + VSUB_LT_F64: "VSUB.LT.F64", + VSUB_GT_F64: "VSUB.GT.F64", + VSUB_LE_F64: "VSUB.LE.F64", + VSUB_F64: "VSUB.F64", + VSUB_ZZ_F64: "VSUB.ZZ.F64", + WFE_EQ: "WFE.EQ", + WFE_NE: "WFE.NE", + WFE_CS: "WFE.CS", + WFE_CC: "WFE.CC", + WFE_MI: "WFE.MI", + WFE_PL: "WFE.PL", + WFE_VS: "WFE.VS", + WFE_VC: "WFE.VC", + WFE_HI: "WFE.HI", + WFE_LS: "WFE.LS", + WFE_GE: "WFE.GE", + WFE_LT: "WFE.LT", + WFE_GT: "WFE.GT", + WFE_LE: "WFE.LE", + WFE: "WFE", + WFE_ZZ: "WFE.ZZ", + WFI_EQ: "WFI.EQ", + WFI_NE: "WFI.NE", + WFI_CS: "WFI.CS", + WFI_CC: "WFI.CC", + WFI_MI: "WFI.MI", + WFI_PL: "WFI.PL", + WFI_VS: "WFI.VS", + WFI_VC: "WFI.VC", + WFI_HI: "WFI.HI", + WFI_LS: "WFI.LS", + WFI_GE: "WFI.GE", + WFI_LT: "WFI.LT", + WFI_GT: "WFI.GT", + WFI_LE: "WFI.LE", + WFI: "WFI", + WFI_ZZ: "WFI.ZZ", + YIELD_EQ: "YIELD.EQ", + YIELD_NE: "YIELD.NE", + YIELD_CS: "YIELD.CS", + YIELD_CC: "YIELD.CC", + YIELD_MI: "YIELD.MI", + YIELD_PL: "YIELD.PL", + YIELD_VS: "YIELD.VS", + YIELD_VC: "YIELD.VC", + YIELD_HI: "YIELD.HI", + YIELD_LS: "YIELD.LS", + YIELD_GE: "YIELD.GE", + YIELD_LT: "YIELD.LT", + YIELD_GT: "YIELD.GT", + YIELD_LE: "YIELD.LE", + YIELD: "YIELD", + YIELD_ZZ: "YIELD.ZZ", +} + +var instFormats = [...]instFormat{ + {0x0fe00000, 0x02a00000, 2, ADC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // ADC{S} ,,# cond:4|0|0|1|0|1|0|1|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00a00010, 4, ADC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // ADC{S} ,,, cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00a00000, 2, ADC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // ADC{S} ,,{,} cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fe00000, 0x02800000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // ADD{S} ,,# cond:4|0|0|1|0|1|0|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00800010, 4, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // ADD{S} ,,, cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00800000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // ADD{S} ,,{,} cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fef0000, 0x028d0000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_SP, arg_const}}, // ADD{S} ,SP,# cond:4|0|0|1|0|1|0|0|S|1|1|0|1|Rd:4|imm12:12 + {0x0fef0010, 0x008d0000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_SP, arg_R_shift_imm}}, // ADD{S} ,SP,{,} cond:4|0|0|0|0|1|0|0|S|1|1|0|1|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fe00000, 0x02000000, 2, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // AND{S} ,,# cond:4|0|0|1|0|0|0|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00000010, 4, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // AND{S} ,,, cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00000000, 2, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // AND{S} ,,{,} cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fef0070, 0x01a00040, 4, ASR_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_0, arg_imm5_32}}, // ASR{S} ,,# cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|1|0|0|Rm:4 + {0x0fef00f0, 0x01a00050, 4, ASR_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_0, arg_R_8}}, // ASR{S} ,, cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|1|0|1|Rn:4 + {0x0f000000, 0x0a000000, 4, B_EQ, 0x1c04, instArgs{arg_label24}}, // B cond:4|1|0|1|0|imm24:24 + {0x0fe0007f, 0x07c0001f, 4, BFC_EQ, 0x1c04, instArgs{arg_R_12, arg_imm5, arg_lsb_width}}, // BFC ,#,# cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|1|1|1|1 + {0x0fe00070, 0x07c00010, 2, BFI_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0, arg_imm5, arg_lsb_width}}, // BFI ,,#,# cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|Rn:4 + {0x0fe00000, 0x03c00000, 2, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // BIC{S} ,,# cond:4|0|0|1|1|1|1|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x01c00010, 4, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // BIC{S} ,,, cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x01c00000, 2, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // BIC{S} ,,{,} cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0ff000f0, 0x01200070, 4, BKPT_EQ, 0x1c04, instArgs{arg_imm_12at8_4at0}}, // BKPT # cond:4|0|0|0|1|0|0|1|0|imm12:12|0|1|1|1|imm4:4 + {0x0f000000, 0x0b000000, 4, BL_EQ, 0x1c04, instArgs{arg_label24}}, // BL cond:4|1|0|1|1|imm24:24 + {0xfe000000, 0xfa000000, 4, BLX, 0x0, instArgs{arg_label24H}}, // BLX 1|1|1|1|1|0|1|H|imm24:24 + {0x0ffffff0, 0x012fff30, 4, BLX_EQ, 0x1c04, instArgs{arg_R_0}}, // BLX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4 + {0x0ff000f0, 0x012fff30, 3, BLX_EQ, 0x1c04, instArgs{arg_R_0}}, // BLX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4 + {0x0ffffff0, 0x012fff10, 4, BX_EQ, 0x1c04, instArgs{arg_R_0}}, // BX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff000f0, 0x012fff10, 3, BX_EQ, 0x1c04, instArgs{arg_R_0}}, // BX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ffffff0, 0x012fff20, 4, BXJ_EQ, 0x1c04, instArgs{arg_R_0}}, // BXJ cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4 + {0x0ff000f0, 0x012fff20, 3, BXJ_EQ, 0x1c04, instArgs{arg_R_0}}, // BXJ cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4 + {0xffffffff, 0xf57ff01f, 4, CLREX, 0x0, instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1) + {0xfff000f0, 0xf57ff01f, 3, CLREX, 0x0, instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1) + {0x0fff0ff0, 0x016f0f10, 4, CLZ_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0}}, // CLZ , cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff000f0, 0x016f0f10, 3, CLZ_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0}}, // CLZ , cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff0f000, 0x03700000, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMN ,# cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff00000, 0x03700000, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMN ,# cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff0f090, 0x01700010, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMN ,, cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff00090, 0x01700010, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMN ,, cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff0f010, 0x01700000, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMN ,{,} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff00010, 0x01700000, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMN ,{,} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff0f000, 0x03500000, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMP ,# cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff00000, 0x03500000, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMP ,# cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff0f090, 0x01500010, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMP ,, cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff00090, 0x01500010, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMP ,, cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff0f010, 0x01500000, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMP ,{,} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff00010, 0x01500000, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMP ,{,} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ffffff0, 0x0320f0f0, 4, DBG_EQ, 0x1c04, instArgs{arg_option}}, // DBG #