├── .github ├── CODE_OF_CONDUCT.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── config.yml │ └── feature.yaml ├── stale.yml └── workflows │ └── go.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── cmds.go ├── doc.go ├── export.go ├── fat.go ├── file.go ├── file_test.go ├── go.mod ├── go.sum ├── internal ├── obscuretestdata │ └── obscuretestdata.go ├── saferio │ └── io.go └── testdata │ ├── clang-386-darwin-exec-with-rpath.base64 │ ├── clang-386-darwin.obj.base64 │ ├── clang-amd64-darwin-exec-with-rpath.base64 │ ├── clang-amd64-darwin.obj.base64 │ ├── dic.cc │ ├── dic.o │ ├── fat-gcc-386-amd64-darwin-exec.base64 │ ├── gcc-386-darwin-exec.base64 │ ├── gcc-amd64-darwin-exec-debug.base64 │ ├── gcc-amd64-darwin-exec.base64 │ ├── hello.c │ └── test.swift ├── macho.go ├── objc.go ├── pkg ├── codesign │ ├── codesign.go │ └── types │ │ ├── blob.go │ │ ├── directory.go │ │ ├── launch_const.go │ │ └── requirement.go ├── cpio │ └── cpio.go ├── fixupchains │ ├── fixupchains.go │ ├── imports.go │ └── types.go ├── trie │ └── trie.go └── xar │ ├── types.go │ └── xar.go ├── swift.go ├── toc.go └── types ├── commands.go ├── commands_string.go ├── cpu.go ├── flags.go ├── header.go ├── header_string.go ├── nlist.go ├── objc ├── category.go ├── class.go ├── objc.go ├── protocol.go ├── type_encoding.go └── type_encoding_test.go ├── reloc.go ├── reloc_string.go ├── section.go ├── swift ├── README.md ├── accessible_funcs.go ├── associated_type.go ├── builtin_type.go ├── capture.go ├── capture_string.go ├── field.go ├── field_string.go ├── mangling.go ├── metadata.go ├── metadata_string.go ├── multi_payload_enum.go ├── protocols.go ├── protocols_string.go ├── relative_pointer.go ├── replacements.go ├── swift.go ├── swift_string.go ├── type_anon.go ├── type_class.go ├── type_enum.go ├── type_ext.go ├── type_mod.go ├── type_struct.go ├── types.go └── types_string.go ├── types.go └── types_string.go /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: blacktop_ 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | labels: [bug, triage] 4 | assignees: 5 | - blacktop 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this bug report! Please fill the form below. 11 | - type: textarea 12 | id: what-happened 13 | attributes: 14 | label: What happened? 15 | description: Also tell us, what did you expect to happen? 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: reproducible 20 | attributes: 21 | label: How can we reproduce this? 22 | description: Please share the exact command you ran and what firmware or MachO you were analyzing. Links to failing `go-macho` runs and etc are also helpful. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: go-macho-version 27 | attributes: 28 | label: go-macho version 29 | description: "go-macho version" 30 | render: bash 31 | validations: 32 | required: true 33 | - type: checkboxes 34 | id: search 35 | attributes: 36 | label: Search 37 | options: 38 | - label: I did search for other open and closed issues before opening this 39 | required: true 40 | - type: checkboxes 41 | id: terms 42 | attributes: 43 | label: Code of Conduct 44 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/blacktop/go-macho/blob/master/.github/CODE_OF_CONDUCT.md) 45 | options: 46 | - label: I agree to follow this project's Code of Conduct 47 | required: true 48 | - type: textarea 49 | id: ctx 50 | attributes: 51 | label: Additional context 52 | description: Anything else you would like to add 53 | validations: 54 | required: false 55 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/blacktop/go-macho/discussions 5 | about: Ask questions and discuss with other community members 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Request a new feature and/or enhancement to an existing feature 3 | labels: [enhancement, triage] 4 | assignees: 5 | - blacktop 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this feature request! Please fill the form below. 11 | - type: textarea 12 | id: is-it-a-problem 13 | attributes: 14 | label: Is your feature request related to a problem? Please describe. 15 | description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: solution 20 | attributes: 21 | label: Describe the solution you'd like 22 | description: A clear and concise description of what you want to happen. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: alternatives 27 | attributes: 28 | label: Describe alternatives you've considered 29 | description: A clear and concise description of any alternative solutions or features you've considered. 30 | validations: 31 | required: true 32 | - type: checkboxes 33 | id: search 34 | attributes: 35 | label: Search 36 | options: 37 | - label: I did search for other open and closed issues before opening this 38 | required: true 39 | - type: checkboxes 40 | id: terms 41 | attributes: 42 | label: Code of Conduct 43 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/blacktop/go-macho/blob/master/.github/CODE_OF_CONDUCT.md) 44 | options: 45 | - label: I agree to follow this project's Code of Conduct 46 | required: true 47 | - type: textarea 48 | id: ctx 49 | attributes: 50 | label: Additional context 51 | description: Anything else you would like to add 52 | validations: 53 | required: false 54 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 14 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | name: Build 13 | runs-on: macos-latest 14 | steps: 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v4 18 | with: 19 | go-version: "stable" 20 | 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | 26 | - name: Test 27 | run: go test 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | .vscode 18 | *.plist 19 | changelog.yml 20 | .chglog.yml 21 | __debug_* 22 | test* 23 | CHANGELOG.md 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2024 blacktop 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | REPO=blacktop 2 | NAME=go-macho 3 | VERSION=$(shell svu current) 4 | NEXT_VERSION:=$(shell svu patch) 5 | 6 | GIT_COMMIT=$(git rev-parse HEAD) 7 | GIT_DIRTY=$(test -n "`git status --porcelain`" && echo "+CHANGES" || true) 8 | GIT_DESCRIBE=$(git describe --tags) 9 | 10 | .PHONY: dev-deps 11 | dev-deps: ## Install the dev dependencies 12 | @brew install gh 13 | @go install github.com/goreleaser/chglog/cmd/chglog@latest 14 | @go install github.com/caarlos0/svu@v1.4.1 15 | 16 | .PHONY: bump 17 | bump: ## Incriment version patch number 18 | @echo " > Bumping VERSION" 19 | @chglog add --version ${NEXT_VERSION} 20 | 21 | .PHONY: changelog 22 | changelog: bump ## Create a new CHANGELOG.md 23 | @echo " > Creating CHANGELOG.md" 24 | @chglog format --template release > CHANGELOG.md 25 | 26 | .PHONY: release 27 | release: changelog ## Create a new release from the VERSION 28 | @echo " > Creating Release" 29 | @gh release create ${NEXT_VERSION} -F CHANGELOG.md 30 | 31 | .PHONY: destroy 32 | destroy: ## Remove release from the VERSION 33 | @echo " > Deleting Release" 34 | git tag -d ${VERSION} 35 | git push origin :refs/tags/${VERSION} 36 | 37 | # Absolutely awesome: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html 38 | help: 39 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 40 | 41 | .DEFAULT_GOAL := help -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-macho 2 | 3 | [![Go](https://github.com/blacktop/go-macho/workflows/Go/badge.svg?branch=master)](https://github.com/blacktop/go-macho/actions) [![Go Reference](https://pkg.go.dev/badge/github.com/blacktop/go-macho.svg)](https://pkg.go.dev/github.com/blacktop/go-macho) [![License](http://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org) 4 | 5 | > Package macho implements access to and creation of Mach-O object files. 6 | 7 | --- 8 | 9 | ## Why 🤔 10 | 11 | This package goes beyond the Go's `debug/macho` to: 12 | 13 | - Cover ALL load commands and architectures 14 | - Provide nice summary string output 15 | - Allow for creating custom MachO files 16 | - Parse Objective-C runtime information 17 | - Parse Swift runtime information 18 | - Read/Write code signature information 19 | - Parse fixup chain information 20 | 21 | ## Install 22 | 23 | ```bash 24 | $ go get github.com/blacktop/go-macho 25 | ``` 26 | 27 | ## Getting Started 28 | 29 | ```go 30 | package main 31 | 32 | import "github.com/blacktop/go-macho" 33 | 34 | func main() { 35 | m, err := macho.Open("/path/to/macho") 36 | if err != nil { 37 | panic(err) 38 | } 39 | defer m.Close() 40 | 41 | fmt.Println(m.FileTOC.String()) 42 | } 43 | ``` 44 | 45 | ## License 46 | 47 | MIT Copyright (c) 2020-2024 **blacktop** 48 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Only the last stable version at any given point. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | Vulnerabilies can be disclosed in private using GitHub advisories: https://github.com/blacktop/go-macho/security 10 | 11 | Thanks! 12 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package macho implements access to and creation of Mach-O object files. 3 | */ 4 | package macho 5 | -------------------------------------------------------------------------------- /fat.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package macho 6 | 7 | import ( 8 | "bytes" 9 | "encoding/binary" 10 | "fmt" 11 | "io" 12 | "os" 13 | 14 | "github.com/blacktop/go-macho/internal/saferio" 15 | "github.com/blacktop/go-macho/types" 16 | ) 17 | 18 | const ( 19 | alignBits = 14 20 | align = 1 << alignBits 21 | ) 22 | 23 | // A FatFile is a Mach-O universal binary that contains at least one architecture. 24 | type FatFile struct { 25 | FatHeader 26 | closer io.Closer 27 | } 28 | 29 | type FatHeader struct { 30 | Magic types.Magic 31 | Count uint32 32 | Arches []FatArch 33 | } 34 | 35 | // A FatArchHeader represents a fat header for a specific image architecture. 36 | type FatArchHeader struct { 37 | CPU types.CPU 38 | SubCPU types.CPUSubtype 39 | Offset uint32 40 | Size uint32 41 | Align uint32 42 | } 43 | 44 | const fatArchHeaderSize = 5 * 4 45 | 46 | // A FatArch is a Mach-O File inside a FatFile. 47 | type FatArch struct { 48 | FatArchHeader 49 | *File 50 | data []byte 51 | } 52 | 53 | // ErrNotFat is returned from NewFatFile or OpenFat when the file is not a 54 | // universal binary but may be a thin binary, based on its magic number. 55 | var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil} 56 | 57 | // NewFatFile creates a new FatFile for accessing all the Mach-O images in a 58 | // universal binary. The Mach-O binary is expected to start at position 0 in 59 | // the ReaderAt. 60 | func NewFatFile(r io.ReaderAt) (*FatFile, error) { 61 | var ff FatFile 62 | sr := io.NewSectionReader(r, 0, 1<<63-1) 63 | 64 | // Read the fat_header struct, which is always in big endian. 65 | // Start with the magic number. 66 | err := binary.Read(sr, binary.BigEndian, &ff.Magic) 67 | if err != nil { 68 | return nil, &FormatError{0, "error reading magic number", nil} 69 | } else if ff.Magic != types.MagicFat { 70 | // See if this is a Mach-O file via its magic number. The magic 71 | // must be converted to little endian first though. 72 | var buf [4]byte 73 | binary.BigEndian.PutUint32(buf[:], ff.Magic.Int()) 74 | leMagic := binary.LittleEndian.Uint32(buf[:]) 75 | if leMagic == types.Magic32.Int() || leMagic == types.Magic64.Int() { 76 | return nil, ErrNotFat 77 | } 78 | return nil, &FormatError{0, "invalid magic number", nil} 79 | 80 | } 81 | offset := int64(4) 82 | 83 | // Read the number of FatArchHeaders that come after the fat_header. 84 | var narch uint32 85 | err = binary.Read(sr, binary.BigEndian, &narch) 86 | if err != nil { 87 | return nil, &FormatError{offset, "invalid fat_header", nil} 88 | } 89 | offset += 4 90 | 91 | if narch < 1 { 92 | return nil, &FormatError{offset, "file contains no images", nil} 93 | } 94 | 95 | // Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure 96 | // there are not duplicate architectures. 97 | seenArches := make(map[uint64]bool) 98 | // Make sure that all images are for the same MH_ type. 99 | var machoType types.HeaderFileType 100 | 101 | // Following the fat_header comes narch fat_arch structs that index 102 | // Mach-O images further in the file. 103 | c := saferio.SliceCap[FatArch](uint64(narch)) 104 | if c < 0 { 105 | return nil, &FormatError{offset, "too many images", nil} 106 | } 107 | ff.Arches = make([]FatArch, 0, c) 108 | for i := uint32(0); i < narch; i++ { 109 | var fa FatArch 110 | err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader) 111 | if err != nil { 112 | return nil, &FormatError{offset, "invalid fat_arch header", nil} 113 | } 114 | offset += fatArchHeaderSize 115 | 116 | fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size)) 117 | fa.File, err = NewFile(fr) 118 | if err != nil { 119 | return nil, err 120 | } 121 | 122 | // Make sure the architecture for this image is not duplicate. 123 | seenArch := (uint64(fa.CPU) << 32) | uint64(fa.SubCPU) 124 | if o, k := seenArches[seenArch]; o || k { 125 | return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.CPU, fa.SubCPU), nil} 126 | } 127 | seenArches[seenArch] = true 128 | 129 | // Make sure the Mach-O type matches that of the first image. 130 | if i == 0 { 131 | machoType = fa.Type 132 | } else { 133 | if fa.Type != machoType { 134 | 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} 135 | } 136 | } 137 | ff.Arches = append(ff.Arches, fa) 138 | } 139 | 140 | return &ff, nil 141 | } 142 | 143 | // OpenFat opens the named file using os.Open and prepares it for use as a Mach-O 144 | // universal binary. 145 | func OpenFat(name string) (*FatFile, error) { 146 | f, err := os.Open(name) 147 | if err != nil { 148 | return nil, err 149 | } 150 | ff, err := NewFatFile(f) 151 | if err != nil { 152 | f.Close() 153 | return nil, err 154 | } 155 | ff.closer = f 156 | return ff, nil 157 | } 158 | 159 | func CreateFat(name string, files ...string) (*FatFile, error) { 160 | 161 | fat := &FatFile{ 162 | FatHeader: FatHeader{ 163 | Magic: types.MagicFat, 164 | }, 165 | } 166 | 167 | offset := int64(align) 168 | 169 | for _, f := range files { 170 | data, err := os.ReadFile(f) 171 | if err != nil { 172 | return nil, fmt.Errorf("failed to read binary %s: %w", f, err) 173 | } 174 | 175 | m, err := NewFile(bytes.NewReader(data)) 176 | if err != nil { 177 | return nil, fmt.Errorf("failed to parse MachO %s: %w", f, err) 178 | } 179 | defer m.Close() 180 | 181 | fat.Count++ 182 | 183 | fat.Arches = append(fat.Arches, FatArch{ 184 | FatArchHeader: FatArchHeader{ 185 | CPU: m.CPU, 186 | SubCPU: m.SubCPU, 187 | Offset: uint32(offset), 188 | Size: uint32(len(data)), 189 | Align: alignBits, 190 | }, 191 | File: m, 192 | data: data, 193 | }) 194 | 195 | offset += int64(len(data)) 196 | offset = (offset + align - 1) / align * align 197 | } 198 | 199 | out, err := os.Create(name) 200 | if err != nil { 201 | return nil, fmt.Errorf("failed to create file %s: %w", name, err) 202 | } 203 | fat.closer = out 204 | 205 | if err := binary.Write(out, binary.BigEndian, fat.FatHeader.Magic); err != nil { 206 | return nil, fmt.Errorf("failed to write fat header magic to file: %w", err) 207 | } 208 | if err := binary.Write(out, binary.BigEndian, fat.FatHeader.Count); err != nil { 209 | return nil, fmt.Errorf("failed to write fat header count to file: %w", err) 210 | } 211 | for _, farch := range fat.Arches { 212 | if err := binary.Write(out, binary.BigEndian, farch.FatArchHeader); err != nil { 213 | return nil, fmt.Errorf("failed to write fat header arch %s header to file: %w", farch.CPU, err) 214 | } 215 | } 216 | 217 | offset, _ = out.Seek(0, io.SeekCurrent) 218 | 219 | for _, farch := range fat.Arches { 220 | if offset < int64(farch.Offset) { 221 | if _, err := out.Write(make([]byte, int64(farch.Offset)-offset)); err != nil { 222 | return nil, fmt.Errorf("failed to write to file: %w", err) 223 | } 224 | offset = int64(farch.Offset) 225 | } 226 | if _, err := out.Write(farch.data); err != nil { 227 | return nil, fmt.Errorf("failed to write to file: %w", err) 228 | } 229 | offset += int64(len(farch.data)) 230 | } 231 | 232 | return fat, nil 233 | } 234 | 235 | // func (ff *FatFile) Save(name string) error { 236 | // return nil 237 | // } 238 | 239 | // Close with close the Mach-O Fat file. 240 | func (ff *FatFile) Close() error { 241 | var err error 242 | if ff.closer != nil { 243 | err = ff.closer.Close() 244 | ff.closer = nil 245 | } 246 | return err 247 | } 248 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/blacktop/go-macho 2 | 3 | go 1.19 4 | 5 | require github.com/blacktop/go-dwarf v1.0.14 6 | 7 | // replace github.com/blacktop/go-dwarf => ../go-dwarf 8 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/blacktop/go-dwarf v1.0.14 h1:OjmzfSgg/qAKckn2tWFebcgKgJ7HOqCj7bS+CiE1lrY= 2 | github.com/blacktop/go-dwarf v1.0.14/go.mod h1:4W2FKgSFYcZLDwnR7k+apv5i3nrau4NGl9N6VQ9DSTo= 3 | -------------------------------------------------------------------------------- /internal/obscuretestdata/obscuretestdata.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package obscuretestdata contains functionality used by tests to more easily 6 | // work with testdata that must be obscured primarily due to 7 | // golang.org/issue/34986. 8 | package obscuretestdata 9 | 10 | import ( 11 | "encoding/base64" 12 | "io" 13 | "os" 14 | ) 15 | 16 | // Rot13 returns the rot13 encoding or decoding of its input. 17 | func Rot13(data []byte) []byte { 18 | out := make([]byte, len(data)) 19 | copy(out, data) 20 | for i, c := range out { 21 | switch { 22 | case 'A' <= c && c <= 'M' || 'a' <= c && c <= 'm': 23 | out[i] = c + 13 24 | case 'N' <= c && c <= 'Z' || 'n' <= c && c <= 'z': 25 | out[i] = c - 13 26 | } 27 | } 28 | return out 29 | } 30 | 31 | // DecodeToTempFile decodes the named file to a temporary location. 32 | // If successful, it returns the path of the decoded file. 33 | // The caller is responsible for ensuring that the temporary file is removed. 34 | func DecodeToTempFile(name string) (path string, err error) { 35 | f, err := os.Open(name) 36 | if err != nil { 37 | return "", err 38 | } 39 | defer f.Close() 40 | 41 | tmp, err := os.CreateTemp("", "obscuretestdata-decoded-") 42 | if err != nil { 43 | return "", err 44 | } 45 | if _, err := io.Copy(tmp, base64.NewDecoder(base64.StdEncoding, f)); err != nil { 46 | tmp.Close() 47 | os.Remove(tmp.Name()) 48 | return "", err 49 | } 50 | if err := tmp.Close(); err != nil { 51 | os.Remove(tmp.Name()) 52 | return "", err 53 | } 54 | return tmp.Name(), nil 55 | } 56 | 57 | // ReadFile reads the named file and returns its decoded contents. 58 | func ReadFile(name string) ([]byte, error) { 59 | f, err := os.Open(name) 60 | if err != nil { 61 | return nil, err 62 | } 63 | defer f.Close() 64 | return io.ReadAll(base64.NewDecoder(base64.StdEncoding, f)) 65 | } 66 | -------------------------------------------------------------------------------- /internal/saferio/io.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package saferio provides I/O functions that avoid allocating large 6 | // amounts of memory unnecessarily. This is intended for packages that 7 | // read data from an [io.Reader] where the size is part of the input 8 | // data but the input may be corrupt, or may be provided by an 9 | // untrustworthy attacker. 10 | package saferio 11 | 12 | import ( 13 | "io" 14 | "unsafe" 15 | ) 16 | 17 | // chunk is an arbitrary limit on how much memory we are willing 18 | // to allocate without concern. 19 | const chunk = 10 << 20 // 10M 20 | 21 | // ReadData reads n bytes from the input stream, but avoids allocating 22 | // all n bytes if n is large. This avoids crashing the program by 23 | // allocating all n bytes in cases where n is incorrect. 24 | // 25 | // The error is io.EOF only if no bytes were read. 26 | // If an io.EOF happens after reading some but not all the bytes, 27 | // ReadData returns io.ErrUnexpectedEOF. 28 | func ReadData(r io.Reader, n uint64) ([]byte, error) { 29 | if int64(n) < 0 || n != uint64(int(n)) { 30 | // n is too large to fit in int, so we can't allocate 31 | // a buffer large enough. Treat this as a read failure. 32 | return nil, io.ErrUnexpectedEOF 33 | } 34 | 35 | if n < chunk { 36 | buf := make([]byte, n) 37 | _, err := io.ReadFull(r, buf) 38 | if err != nil { 39 | return nil, err 40 | } 41 | return buf, nil 42 | } 43 | 44 | var buf []byte 45 | buf1 := make([]byte, chunk) 46 | for n > 0 { 47 | next := n 48 | if next > chunk { 49 | next = chunk 50 | } 51 | _, err := io.ReadFull(r, buf1[:next]) 52 | if err != nil { 53 | if len(buf) > 0 && err == io.EOF { 54 | err = io.ErrUnexpectedEOF 55 | } 56 | return nil, err 57 | } 58 | buf = append(buf, buf1[:next]...) 59 | n -= next 60 | } 61 | return buf, nil 62 | } 63 | 64 | // ReadDataAt reads n bytes from the input stream at off, but avoids 65 | // allocating all n bytes if n is large. This avoids crashing the program 66 | // by allocating all n bytes in cases where n is incorrect. 67 | func ReadDataAt(r io.ReaderAt, n uint64, off int64) ([]byte, error) { 68 | if int64(n) < 0 || n != uint64(int(n)) { 69 | // n is too large to fit in int, so we can't allocate 70 | // a buffer large enough. Treat this as a read failure. 71 | return nil, io.ErrUnexpectedEOF 72 | } 73 | 74 | if n < chunk { 75 | buf := make([]byte, n) 76 | _, err := r.ReadAt(buf, off) 77 | if err != nil { 78 | // io.SectionReader can return EOF for n == 0, 79 | // but for our purposes that is a success. 80 | if err != io.EOF || n > 0 { 81 | return nil, err 82 | } 83 | } 84 | return buf, nil 85 | } 86 | 87 | var buf []byte 88 | buf1 := make([]byte, chunk) 89 | for n > 0 { 90 | next := n 91 | if next > chunk { 92 | next = chunk 93 | } 94 | _, err := r.ReadAt(buf1[:next], off) 95 | if err != nil { 96 | return nil, err 97 | } 98 | buf = append(buf, buf1[:next]...) 99 | n -= next 100 | off += int64(next) 101 | } 102 | return buf, nil 103 | } 104 | 105 | // SliceCapWithSize returns the capacity to use when allocating a slice. 106 | // After the slice is allocated with the capacity, it should be 107 | // built using append. This will avoid allocating too much memory 108 | // if the capacity is large and incorrect. 109 | // 110 | // A negative result means that the value is always too big. 111 | func SliceCapWithSize(size, c uint64) int { 112 | if int64(c) < 0 || c != uint64(int(c)) { 113 | return -1 114 | } 115 | if size > 0 && c > (1<<64-1)/size { 116 | return -1 117 | } 118 | if c*size > chunk { 119 | c = chunk / size 120 | if c == 0 { 121 | c = 1 122 | } 123 | } 124 | return int(c) 125 | } 126 | 127 | // SliceCap is like SliceCapWithSize but using generics. 128 | func SliceCap[E any](c uint64) int { 129 | var v E 130 | size := uint64(unsafe.Sizeof(v)) 131 | return SliceCapWithSize(size, c) 132 | } 133 | -------------------------------------------------------------------------------- /internal/testdata/clang-386-darwin-exec-with-rpath.base64: -------------------------------------------------------------------------------- 1 | zvrt/gcAAAADAAAAAgAAABAAAAAsBAAAhQAgAQEAAAA4AAAAX19QQUdFWkVSTwAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAIwBAABfX1RFWFQAAAAAAAAAAAAAABAAAAAQAAAAAAAAABAAAAcAAAAFAAAABQAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAAGAfAAAtAAAAYA8AAAQAAAAAAAAAAAAAAAAEAIAAAAAAAAAAAF9fc3ltYm9sX3N0dWIAAABfX1RFWFQAAAAAAAAAAAAAjh8AAAYAAACODwAAAQAAAAAAAAAAAAAACAUAgAAAAAAGAAAAX19zdHViX2hlbHBlcgAAAF9fVEVYVAAAAAAAAAAAAACUHwAAFgAAAJQPAAACAAAAAAAAAAAAAAAABQCAAAAAAAAAAABfX2NzdHJpbmcAAAAAAAAAX19URVhUAAAAAAAAAAAAAKofAAAOAAAAqg8AAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAF9fdW53aW5kX2luZm8AAABfX1RFWFQAAAAAAAAAAAAAuB8AAEgAAAC4DwAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAMAAAABfX0RBVEEAAAAAAAAAAAAAACAAAAAQAAAAEAAAABAAAAcAAAADAAAAAgAAAAAAAABfX25sX3N5bWJvbF9wdHIAX19EQVRBAAAAAAAAAAAAAAAgAAAIAAAAABAAAAIAAAAAAAAAAAAAAAYAAAABAAAAAAAAAF9fbGFfc3ltYm9sX3B0cgBfX0RBVEEAAAAAAAAAAAAACCAAAAQAAAAIEAAAAgAAAAAAAAAAAAAABwAAAAMAAAAAAAAAAQAAADgAAABfX0xJTktFRElUAAAAAAAAADAAAAAQAAAAIAAA4AAAAAcAAAABAAAAAAAAAAAAAAAiAACAMAAAAAAgAAAQAAAAECAAABgAAAAAAAAAAAAAACggAAAQAAAAOCAAACwAAAACAAAAGAAAAGggAAAEAAAAqCAAADgAAAALAAAAUAAAAAAAAAAAAAAAAAAAAAIAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJggAAAEAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAcAAAADAAAAC91c3IvbGliL2R5bGQAAAAbAAAAGAAAABvekfnOVjeLrRdKs5wg1L0kAAAAEAAAAAAMCgAADAoAKgAAABAAAAAAAAAAAAAAACgAAIAYAAAAYA8AAAAAAAAAAAAAAAAAAAwAAAA0AAAAGAAAAAIAAAACPNYEAAABAC91c3IvbGliL2xpYlN5c3RlbS5CLmR5bGliAAAcAACAGAAAAAwAAAAvbXkvcnBhdGgAAAAmAAAAEAAAAGQgAAAEAAAAKQAAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVYnlg+wY6AAAAABYjYA/AAAAx0X8AAAAAIkEJOgNAAAAMcmJRfiJyIPEGF3DkP8lCCAAAGgEIAAA/yUAIAAAkGgAAAAA6er///9oZWxsbywgd29ybGQKAAEAAAAcAAAAAAAAABwAAAAAAAAAHAAAAAIAAABgDwAANAAAADQAAACODwAAAAAAADQAAAADAAAADAABABAAAQAAAAAAAAAAAAAAAAAAAAAAoB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARIghREiGQH3ABcAJRAAAAEUBkeWxkX3N0dWJfYmluZGVyAFFyAJAAcggRQF9wcmludGYAkAAAAAABXwAFAAJfbWhfZXhlY3V0ZV9oZWFkZXIAIW1haW4AJQIAAAADAOAeAAAA4B4AAAIAAAAPARAAABAAABYAAAAPAQAAYB8AABwAAAABAAABAAAAACQAAAABAAABAAAAAAIAAAADAAAAAAAAQAIAAAAgAF9fbWhfZXhlY3V0ZV9oZWFkZXIAX21haW4AX3ByaW50ZgBkeWxkX3N0dWJfYmluZGVyAAAAAA== 2 | -------------------------------------------------------------------------------- /internal/testdata/clang-386-darwin.obj.base64: -------------------------------------------------------------------------------- 1 | zvrt/gcAAAADAAAAAQAAAAQAAAA4AQAAACAAAAEAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7AAAAVAEAADsAAAAHAAAABwAAAAIAAAAAAAAAX190ZXh0AAAAAAAAAAAAAF9fVEVYVAAAAAAAAAAAAAAAAAAALQAAAFQBAAAEAAAAkAEAAAMAAAAABACAAAAAAAAAAABfX2NzdHJpbmcAAAAAAAAAX19URVhUAAAAAAAAAAAAAC0AAAAOAAAAgQEAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAACQAAAAQAAAAAAwKAAAAAAACAAAAGAAAAKgBAAACAAAAwAEAABAAAAALAAAAUAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFWJ5YPsGOgAAAAAWI2AIgAAAMdF/AAAAACJBCTo3////zHJiUX4iciDxBhdw2hlbGxvLCB3b3JsZAoAAB0AAAABAAANDgAApC0AAAAAAAChCwAAAAEAAAAPAQAAAAAAAAcAAAABAAAAAAAAAABfbWFpbgBfcHJpbnRmAAA= 2 | -------------------------------------------------------------------------------- /internal/testdata/clang-amd64-darwin.obj.base64: -------------------------------------------------------------------------------- 1 | z/rt/gcAAAEDAAAAAQAAAAQAAAAAAgAAACAAAAAAAAAZAAAAiAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAAAAIAIAAAAAAACYAAAAAAAAAAcAAAAHAAAABAAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAAAAAAAAAAAAAKgAAAAAAAAAgAgAABAAAALgCAAACAAAAAAQAgAAAAAAAAAAAAAAAAF9fY3N0cmluZwAAAAAAAABfX1RFWFQAAAAAAAAAAAAAKgAAAAAAAAAOAAAAAAAAAEoCAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAX19jb21wYWN0X3Vud2luZF9fTEQAAAAAAAAAAAAAAAA4AAAAAAAAACAAAAAAAAAAWAIAAAMAAADIAgAAAQAAAAAAAAIAAAAAAAAAAAAAAABfX2VoX2ZyYW1lAAAAAAAAX19URVhUAAAAAAAAAAAAAFgAAAAAAAAAQAAAAAAAAAB4AgAAAwAAAAAAAAAAAAAACwAAaAAAAAAAAAAAAAAAACQAAAAQAAAAAAwKAAAAAAACAAAAGAAAANACAAACAAAA8AIAABAAAAALAAAAUAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVIieVIg+wQSI09GwAAAMdF/AAAAACwAOgAAAAAMcmJRfiJyEiDxBBdw2hlbGxvLCB3b3JsZAoAAAAAAAAAAAAqAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAF6UgABeBABEAwHCJABAAAkAAAAHAAAAIj/////////KgAAAAAAAAAAQQ4QhgJDDQYAAAAAAAAAGQAAAAEAAC0LAAAAAgAAFQAAAAABAAAGAQAAAA8BAAAAAAAAAAAAAAcAAAABAAAAAAAAAAAAAAAAX21haW4AX3ByaW50ZgAA 2 | -------------------------------------------------------------------------------- /internal/testdata/dic.cc: -------------------------------------------------------------------------------- 1 | __attribute__((noinline)) inline int sw(int i) 2 | { 3 | switch (i) 4 | { 5 | case 0: 6 | return 3443; 7 | case 1: 8 | return 3453; 9 | case 2: 10 | return 3353; 11 | case 3: 12 | return 4353; 13 | default: 14 | return -1; 15 | } 16 | } 17 | 18 | void ref() 19 | { 20 | sw(2); 21 | } -------------------------------------------------------------------------------- /internal/testdata/dic.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blacktop/go-macho/39172847b002a43259d61a332bd3e8ee8f6a31ee/internal/testdata/dic.o -------------------------------------------------------------------------------- /internal/testdata/gcc-amd64-darwin-exec-debug.base64: -------------------------------------------------------------------------------- 1 | z/rt/gcAAAEDAACACgAAAAQAAACgBQAAAAAAAAAAAAAbAAAAGAAAACIO+tkFWYMH+V6fhzclOW8ZAAAA2AEAAF9fVEVYVAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAFAAAABQAAAAAAAABfX3RleHQAAAAAAAAAAAAAX19URVhUAAAAAAAAAAAAABQPAAABAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAQAgAAAAAAAAAAAAAAAAF9fc3ltYm9sX3N0dWIxAABfX1RFWFQAAAAAAAAAAAAAgQ8AAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBACAAAAAAAYAAAAAAAAAX19zdHViX2hlbHBlcgAAAF9fVEVYVAAAAAAAAAAAAACQDwAAAQAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfX2NzdHJpbmcAAAAAAAAAX19URVhUAAAAAAAAAAAAAKgPAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAF9fZWhfZnJhbWUAAAAAAABfX1RFWFQAAAAAAAAAAAAAuA8AAAEAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAALAABgAAAAAAAAAAAAAAAAGQAAADgBAABfX0RBVEEAAAAAAAAAAAAAABAAAAEAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAwAAAAMAAAAAAAAAX19kYXRhAAAAAAAAAAAAAF9fREFUQQAAAAAAAAAAAAAAEAAAAQAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfX2R5bGQAAAAAAAAAAAAAX19EQVRBAAAAAAAAAAAAACAQAAABAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9fbGFfc3ltYm9sX3B0cgBfX0RBVEEAAAAAAAAAAAAAWBAAAAEAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAHAAAAAgAAAAAAAAAAAAAAGQAAAHgCAABfX0RXQVJGAAAAAAAAAAAAACAAAAEAAAAAEAAAAAAAAAAQAAAAAAAAvAEAAAAAAAAHAAAAAwAAAAcAAAAAAAAAX19kZWJ1Z19hYmJyZXYAAF9fRFdBUkYAAAAAAAAAAAAAIAAAAQAAADYAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfX2RlYnVnX2FyYW5nZXMAX19EV0FSRgAAAAAAAAAAADYgAAABAAAAMAAAAAAAAAA2EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9fZGVidWdfZnJhbWUAAABfX0RXQVJGAAAAAAAAAAAAZiAAAAEAAABAAAAAAAAAAGYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX19kZWJ1Z19pbmZvAAAAAF9fRFdBUkYAAAAAAAAAAACmIAAAAQAAAFQAAAAAAAAAphAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfX2RlYnVnX2xpbmUAAAAAX19EV0FSRgAAAAAAAAAAAPogAAABAAAARwAAAAAAAAD6EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9fZGVidWdfcHVibmFtZXNfX0RXQVJGAAAAAAAAAAAAQSEAAAEAAAAbAAAAAAAAAEERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX19kZWJ1Z19zdHIAAAAAAF9fRFdBUkYAAAAAAAAAAABcIQAAAQAAAGAAAAAAAAAAXBEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAERASUOEwsDDhsOEQESARAGAAACJAALCz4LAw4AAAMuAD8MAw46CzsLJwxJExEBEgFACgAAACwAAAACAAAAAAAIAAAAAABqDwAAAQAAABcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAD/////AQABeBAMBwiQAQAAAAAAACQAAAAAAAAAag8AAAEAAAAXAAAAAAAAAAQBAAAADhCGAgQDAAAADQZQAAAAAgAAAAAACAEBAAAAASUAAAAtAAAAag8AAAEAAACBDwAAAQAAAAAAAAACBAVXAAAAAwFbAAAAAQMBLQAAAGoPAAABAAAAgQ8AAAEAAAABVgBDAAAAAgAbAAAAAQH29QoAAQEBAQAAAAEAaGVsbG8uYwAAAAAAAAkCag8AAAEAAAADAhQDAQIEAQMBAgwBAwECBQECAgABARcAAAACAAAAAABUAAAANAAAAG1haW4AAAAAAABHTlUgQyA0LjAuMSAoQXBwbGUgSW5jLiBidWlsZCA1NDg0KQBoZWxsby5jAC9ob21lL3JzYy9nby9zcmMvcGtnL2RlYnVnL21hY2hvL3Rlc3RkYXRhAGludABtYWluAA== 2 | -------------------------------------------------------------------------------- /internal/testdata/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | main(void) 5 | { 6 | printf("hello, world\n"); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /internal/testdata/test.swift: -------------------------------------------------------------------------------- 1 | enum MyEnum: String { 2 | case A = "testaaaabbbbccccddddeeeeffff" 3 | case B 4 | case C 5 | } 6 | 7 | struct Name { 8 | var a: MyEnum 9 | var b: MyEnum 10 | } 11 | 12 | var name = Name(a: .A, b: .B) 13 | 14 | func greet(person: String) -> String { 15 | let greeting = "Hello, " + person + "!" 16 | return greeting 17 | } 18 | 19 | print(greet(person: "world")) -------------------------------------------------------------------------------- /macho.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Mach-O header data structures 6 | // Originally at: 7 | // http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html (since deleted by Apple) 8 | // Archived copy at: 9 | // https://web.archive.org/web/20090819232456/http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/index.html 10 | // For cloned PDF see: 11 | // https://github.com/aidansteele/osx-abi-macho-file-format-reference 12 | 13 | package macho 14 | 15 | import ( 16 | "fmt" 17 | "strings" 18 | ) 19 | 20 | // Regs386 is the Mach-O 386 register structure. 21 | type Regs386 struct { 22 | AX uint32 23 | BX uint32 24 | CX uint32 25 | DX uint32 26 | DI uint32 27 | SI uint32 28 | BP uint32 29 | SP uint32 30 | SS uint32 31 | FLAGS uint32 32 | IP uint32 33 | CS uint32 34 | DS uint32 35 | ES uint32 36 | FS uint32 37 | GS uint32 38 | } 39 | 40 | func (r Regs386) String(padding int) string { 41 | return fmt.Sprintf( 42 | "%seax 0x%08x ebx 0x%08x ecx 0x%08x edx 0x%08x\n"+ 43 | "%sedi 0x%08x esi 0x%08x ebp 0x%08x esp 0x%08x\n"+ 44 | "%sss 0x%08x eflags 0x%08x eip 0x%08x cs 0x%08x\n"+ 45 | "%sds 0x%08x es 0x%08x fs 0x%08x gs 0x%08x\n", 46 | strings.Repeat(" ", padding), r.AX, r.BX, r.CX, r.DX, 47 | strings.Repeat(" ", padding), r.DI, r.SI, r.BP, r.SP, 48 | strings.Repeat(" ", padding), r.SS, r.FLAGS, r.IP, r.CS, 49 | strings.Repeat(" ", padding), r.DS, r.ES, r.FS, r.GS) 50 | } 51 | 52 | // RegsAMD64 is the Mach-O AMD64 register structure. 53 | type RegsAMD64 struct { 54 | AX uint64 55 | BX uint64 56 | CX uint64 57 | DX uint64 58 | DI uint64 59 | SI uint64 60 | BP uint64 61 | SP uint64 62 | R8 uint64 63 | R9 uint64 64 | R10 uint64 65 | R11 uint64 66 | R12 uint64 67 | R13 uint64 68 | R14 uint64 69 | R15 uint64 70 | IP uint64 71 | FLAGS uint64 72 | CS uint64 73 | FS uint64 74 | GS uint64 75 | } 76 | 77 | func (r RegsAMD64) String(padding int) string { 78 | return fmt.Sprintf( 79 | "%s rax %#016x rbx %#016x rcx %#016x\n"+ 80 | "%s rdx %#016x rdi %#016x rsi %#016x\n"+ 81 | "%s rbp %#016x rsp %#016x r8 %#016x\n"+ 82 | "%s r9 %#016x r10 %#016x r11 %#016x\n"+ 83 | "%s r12 %#016x r13 %#016x r14 %#016x\n"+ 84 | "%s r15 %#016x rip %#016x\n"+ 85 | "%srflags %#016x cs %#016x fs %#016x\n"+ 86 | "%s gs %#016x\n", 87 | strings.Repeat(" ", padding), r.AX, r.BX, r.CX, 88 | strings.Repeat(" ", padding), r.DX, r.DI, r.SI, 89 | strings.Repeat(" ", padding), r.BP, r.SP, r.R8, 90 | strings.Repeat(" ", padding), r.R9, r.R10, r.R11, 91 | strings.Repeat(" ", padding), r.R12, r.R13, r.R14, 92 | strings.Repeat(" ", padding), r.R15, r.IP, 93 | strings.Repeat(" ", padding), r.FLAGS, r.CS, r.FS, 94 | strings.Repeat(" ", padding), r.GS) 95 | } 96 | 97 | // RegsARM is the Mach-O ARM register structure. 98 | type RegsARM struct { 99 | R0 uint32 100 | R1 uint32 101 | R2 uint32 102 | R3 uint32 103 | R4 uint32 104 | R5 uint32 105 | R6 uint32 106 | R7 uint32 107 | R8 uint32 108 | R9 uint32 109 | R10 uint32 110 | R11 uint32 111 | R12 uint32 112 | SP uint32 113 | LR uint32 114 | PC uint32 115 | CPSR uint32 116 | } 117 | 118 | func (r RegsARM) OnlyEntry() bool { 119 | return r.R0 == 0 && r.R1 == 0 && r.R2 == 0 && r.R3 == 0 && 120 | r.R4 == 0 && r.R5 == 0 && r.R6 == 0 && r.R7 == 0 && 121 | r.R8 == 0 && r.R9 == 0 && r.R10 == 0 && r.R11 == 0 && 122 | r.R12 == 0 && r.SP == 0 && r.LR == 0 && r.PC != 0 && 123 | r.CPSR == 0 124 | } 125 | 126 | func (r RegsARM) String(padding int) string { 127 | return fmt.Sprintf( 128 | "%s r0 %#08x r1 %#08x r2 %#08x r3 %#08x\n"+ 129 | "%s r4 %#08x r5 %#08x r6 %#08x r7 %#08x\n"+ 130 | "%s r8 %#08x r9 %#08x r10 %#08x r11 %#08x\n"+ 131 | "%s r12 %#08x sp %#08x lr %#08x pc %#08x\n"+ 132 | "%scpsr %#08x", 133 | strings.Repeat(" ", padding), r.R0, r.R1, r.R2, r.R3, 134 | strings.Repeat(" ", padding), r.R4, r.R5, r.R6, r.R7, 135 | strings.Repeat(" ", padding), r.R8, r.R9, r.R10, r.R11, 136 | strings.Repeat(" ", padding), r.R12, r.SP, r.LR, r.PC, 137 | strings.Repeat(" ", padding), r.CPSR) 138 | } 139 | 140 | // RegsARM64 is the Mach-O ARM 64 register structure. 141 | type RegsARM64 struct { 142 | X0 uint64 /* General purpose registers x0-x28 */ 143 | X1 uint64 144 | X2 uint64 145 | X3 uint64 146 | X4 uint64 147 | X5 uint64 148 | X6 uint64 149 | X7 uint64 150 | X8 uint64 151 | X9 uint64 152 | X10 uint64 153 | X11 uint64 154 | X12 uint64 155 | X13 uint64 156 | X14 uint64 157 | X15 uint64 158 | X16 uint64 159 | X17 uint64 160 | X18 uint64 161 | X19 uint64 162 | X20 uint64 163 | X21 uint64 164 | X22 uint64 165 | X23 uint64 166 | X24 uint64 167 | X25 uint64 168 | X26 uint64 169 | X27 uint64 170 | X28 uint64 171 | FP uint64 /* Frame pointer x29 */ 172 | LR uint64 /* Link register x30 */ 173 | SP uint64 /* Stack pointer x31 */ 174 | PC uint64 /* Program counter */ 175 | CPSR uint32 /* Current program status register */ 176 | PAD uint32 /* Same size for 32-bit or 64-bit clients */ 177 | } 178 | 179 | func (r RegsARM64) OnlyEntry() bool { 180 | return r.X0 == 0 && r.X1 == 0 && r.X2 == 0 && r.X3 == 0 && 181 | r.X4 == 0 && r.X5 == 0 && r.X6 == 0 && r.X7 == 0 && 182 | r.X8 == 0 && r.X9 == 0 && r.X10 == 0 && r.X11 == 0 && 183 | r.X12 == 0 && r.X13 == 0 && r.X14 == 0 && r.X15 == 0 && 184 | r.X16 == 0 && r.X17 == 0 && r.X18 == 0 && r.X19 == 0 && 185 | r.X20 == 0 && r.X21 == 0 && r.X22 == 0 && r.X23 == 0 && 186 | r.X24 == 0 && r.X25 == 0 && r.X26 == 0 && r.X27 == 0 && 187 | r.X28 == 0 && r.FP == 0 && r.LR == 0 && r.SP == 0 && 188 | r.PC != 0 && r.CPSR == 0 && r.PAD == 0 189 | } 190 | 191 | func (r RegsARM64) String(padding int) string { 192 | return fmt.Sprintf( 193 | "%s x0: %#016x x1: %#016x x2: %#016x x3: %#016x\n"+ 194 | "%s x4: %#016x x5: %#016x x6: %#016x x7: %#016x\n"+ 195 | "%s x8: %#016x x9: %#016x x10: %#016x x11: %#016x\n"+ 196 | "%sx12: %#016x x13: %#016x x14: %#016x x15: %#016x\n"+ 197 | "%sx16: %#016x x17: %#016x x18: %#016x x19: %#016x\n"+ 198 | "%sx20: %#016x x21: %#016x x22: %#016x x23: %#016x\n"+ 199 | "%sx24: %#016x x25: %#016x x26: %#016x x27: %#016x\n"+ 200 | "%sx28: %#016x fp: %#016x lr: %#016x\n"+ 201 | "%s sp: %#016x pc: %#016x cpsr: %#08x\n"+ 202 | "%sesr: %#08x", 203 | strings.Repeat(" ", padding), r.X0, r.X1, r.X2, r.X3, 204 | strings.Repeat(" ", padding), r.X4, r.X5, r.X6, r.X7, 205 | strings.Repeat(" ", padding), r.X8, r.X9, r.X10, r.X11, 206 | strings.Repeat(" ", padding), r.X12, r.X13, r.X14, r.X15, 207 | strings.Repeat(" ", padding), r.X16, r.X17, r.X18, r.X19, 208 | strings.Repeat(" ", padding), r.X20, r.X21, r.X22, r.X23, 209 | strings.Repeat(" ", padding), r.X24, r.X25, r.X26, r.X27, 210 | strings.Repeat(" ", padding), r.X28, r.FP, r.LR, 211 | strings.Repeat(" ", padding), r.SP, r.PC, r.CPSR, 212 | strings.Repeat(" ", padding), r.PAD) 213 | } 214 | 215 | type ArmExceptionState struct { 216 | FAR uint32 /* Virtual Fault Address */ 217 | ESR uint32 /* Exception syndrome */ 218 | Exception uint32 /* number of arm exception taken */ 219 | } 220 | 221 | func (r ArmExceptionState) String(padding int) string { 222 | return fmt.Sprintf( 223 | "%sfar: %#08x esr: %#08x exception: %#08x", 224 | strings.Repeat(" ", padding), r.FAR, r.ESR, r.Exception) 225 | } 226 | 227 | type ArmExceptionState64 struct { 228 | FAR uint64 /* Virtual Fault Address */ 229 | ESR uint32 /* Exception syndrome */ 230 | Exception uint32 /* number of arm exception taken */ 231 | } 232 | 233 | func (r ArmExceptionState64) String(padding int) string { 234 | return fmt.Sprintf( 235 | "%sfar: %#016x esr: %#08x exception: %#08x", 236 | strings.Repeat(" ", padding), r.FAR, r.ESR, r.Exception) 237 | } 238 | -------------------------------------------------------------------------------- /pkg/codesign/types/launch_const.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/asn1" 5 | "fmt" 6 | ) 7 | 8 | // LaunchContraints is the ASN.1 DER structure for launch constraints 9 | type LaunchContraints struct { 10 | Count int64 `json:"appl"` 11 | CCAT int64 `json:"ccat"` 12 | COMP int64 `json:"comp"` 13 | Requirements map[string]any `json:"reqs"` 14 | Version int64 `json:"vers"` 15 | } 16 | 17 | const typeAppl = "application,tag:16" 18 | const typeCont = "tag:16" 19 | 20 | type contraint struct { 21 | Raw asn1.RawContent 22 | Key string `asn1:"utf8"` 23 | Val asn1.RawValue 24 | } 25 | 26 | type launchContraints struct { 27 | Raw asn1.RawContent 28 | Count int64 29 | Fields []contraint `asn1:"tag:16"` 30 | } 31 | 32 | // Entitlement https://developer.apple.com/documentation/security/defining_launch_environment_and_library_constraints#4180790 33 | type Entitlement struct { 34 | Raw asn1.RawContent 35 | Operation int64 36 | Value asn1.RawValue 37 | } 38 | 39 | func checkInteger(bytes []byte) error { 40 | if len(bytes) == 0 { 41 | return fmt.Errorf("empty integer") 42 | } 43 | if len(bytes) == 1 { 44 | return nil 45 | } 46 | if (bytes[0] == 0 && bytes[1]&0x80 == 0) || (bytes[0] == 0xff && bytes[1]&0x80 == 0x80) { 47 | return fmt.Errorf("integer not minimally-encoded") 48 | } 49 | return nil 50 | } 51 | 52 | func parseInt64(bytes []byte) (ret int64, err error) { 53 | err = checkInteger(bytes) 54 | if err != nil { 55 | return 56 | } 57 | if len(bytes) > 8 { 58 | // We'll overflow an int64 in this case. 59 | err = fmt.Errorf("integer too large") 60 | return 61 | } 62 | for bytesRead := 0; bytesRead < len(bytes); bytesRead++ { 63 | ret <<= 8 64 | ret |= int64(bytes[bytesRead]) 65 | } 66 | 67 | // Shift up and down in order to sign extend the result. 68 | ret <<= 64 - uint8(len(bytes))*8 69 | ret >>= 64 - uint8(len(bytes))*8 70 | return 71 | } 72 | 73 | func parseBool(bytes []byte) (ret bool, err error) { 74 | if len(bytes) != 1 { 75 | err = fmt.Errorf("invalid boolean") 76 | return 77 | } 78 | // DER demands that "If the encoding represents the boolean value TRUE, 79 | // its single contents octet shall have all eight bits set to one." 80 | // Thus only 0 and 255 are valid encoded values. 81 | switch bytes[0] { 82 | case 0: 83 | ret = false 84 | case 0xff: 85 | ret = true 86 | default: 87 | err = fmt.Errorf("invalid boolean") 88 | } 89 | return 90 | } 91 | 92 | func getValue(val asn1.RawValue) (any, error) { 93 | switch val.Tag { 94 | case asn1.TagBoolean: 95 | return parseBool(val.Bytes) 96 | case asn1.TagInteger: 97 | return parseInt64(val.Bytes) 98 | case asn1.TagUTF8String: 99 | return string(val.Bytes), nil 100 | default: 101 | return nil, fmt.Errorf("getValue: unsupported asn1 raw value tag %d (notify author)", val.Tag) 102 | } 103 | } 104 | 105 | func parseReqs(data []byte) (req map[string]any, err error) { 106 | var prop contraint 107 | 108 | req = make(map[string]any) 109 | 110 | for len(data) > 0 { 111 | var peek asn1.RawValue 112 | if _, err = asn1.Unmarshal(data, &peek); err != nil { 113 | return nil, fmt.Errorf("failed to ASN.1 parse launch contraint property: %v", err) 114 | } 115 | 116 | data, err = asn1.Unmarshal(data, &prop) 117 | if err != nil { 118 | return nil, fmt.Errorf("failed to ASN.1 parse launch contraint property: %v", err) 119 | } 120 | 121 | if prop.Val.IsCompound { 122 | if prop.Val.Class == asn1.ClassContextSpecific { 123 | req[prop.Key], err = parseReqs(prop.Val.Bytes) 124 | if err != nil { 125 | return nil, err 126 | } 127 | } else { 128 | switch prop.Key { 129 | case "$and-array": 130 | var andArray []asn1.RawValue 131 | data, err = asn1.Unmarshal(prop.Val.FullBytes, &andArray) 132 | if err != nil { 133 | return nil, fmt.Errorf("failed to ASN.1 parse launch contraint '$and-array' properties: %v", err) 134 | } 135 | req[prop.Key] = make([]any, 0, len(andArray)) 136 | for _, and := range andArray { 137 | r, err := parseReqs(and.FullBytes) 138 | if err != nil { 139 | return nil, err 140 | } 141 | req[prop.Key] = append(req[prop.Key].([]any), r) 142 | } 143 | case "$or-array": 144 | var orArray []asn1.RawValue 145 | data, err = asn1.Unmarshal(prop.Val.FullBytes, &orArray) 146 | if err != nil { 147 | return nil, fmt.Errorf("failed to ASN.1 parse launch contraint '$or-array' properties: %v", err) 148 | } 149 | req[prop.Key] = make([]any, 0, len(orArray)) 150 | for _, or := range orArray { 151 | r, err := parseReqs(or.FullBytes) 152 | if err != nil { 153 | return nil, err 154 | } 155 | req[prop.Key] = append(req[prop.Key].([]any), r) 156 | } 157 | case "$query": 158 | var query []Entitlement 159 | data, err = asn1.Unmarshal(prop.Val.FullBytes, &query) 160 | if err != nil { 161 | return nil, fmt.Errorf("failed to ASN.1 parse launch contraint '$query' properties: %v", err) 162 | } 163 | req[prop.Key] = make([][]any, 0, len(query)) 164 | for _, q := range query { 165 | val, err := getValue(q.Value) 166 | if err != nil { 167 | return nil, err 168 | } 169 | req[prop.Key] = append(req[prop.Key].([][]any), []any{q.Operation, val}) 170 | } 171 | case "$in": 172 | var ins []asn1.RawValue 173 | data, err = asn1.Unmarshal(prop.Val.FullBytes, &ins) 174 | if err != nil { 175 | return nil, fmt.Errorf("failed to ASN.1 parse launch contraint '$in' properties: %v", err) 176 | } 177 | req[prop.Key] = make([]any, 0, len(ins)) 178 | for _, in := range ins { 179 | val, err := getValue(in) 180 | if err != nil { 181 | return nil, err 182 | } 183 | req[prop.Key] = append(req[prop.Key].([]any), val) 184 | } 185 | default: 186 | return nil, fmt.Errorf("unsupported requirement key %s (notify author)", prop.Key) 187 | } 188 | } 189 | } else { 190 | val, err := getValue(prop.Val) 191 | if err != nil { 192 | return nil, err 193 | } 194 | req[prop.Key] = val 195 | } 196 | } 197 | 198 | return req, nil 199 | } 200 | 201 | // ParseLaunchContraints parses the launch constraint bytes 202 | func ParseLaunchContraints(data []byte) (*LaunchContraints, error) { 203 | var err error 204 | 205 | lc := &LaunchContraints{ 206 | Requirements: make(map[string]any), 207 | } 208 | 209 | var l launchContraints 210 | data, err = asn1.UnmarshalWithParams(data, &l, typeAppl) 211 | if err != nil { 212 | return nil, fmt.Errorf("failed to ASN.1 parse launch contraint inner data: %v", err) 213 | } 214 | 215 | lc.Count = l.Count 216 | 217 | for _, field := range l.Fields { 218 | switch field.Key { 219 | case "ccat": 220 | i, err := parseInt64(field.Val.Bytes) 221 | if err != nil { 222 | return nil, err 223 | } 224 | lc.CCAT = i 225 | case "comp": 226 | i, err := parseInt64(field.Val.Bytes) 227 | if err != nil { 228 | return nil, err 229 | } 230 | lc.COMP = i 231 | case "reqs": 232 | reqs, err := parseReqs(field.Val.Bytes) 233 | if err != nil { 234 | return nil, err 235 | } 236 | for k, v := range reqs { 237 | lc.Requirements[k] = v 238 | } 239 | case "vers": 240 | i, err := parseInt64(field.Val.Bytes) 241 | if err != nil { 242 | return nil, err 243 | } 244 | lc.Version = i 245 | default: 246 | return nil, fmt.Errorf("unsupported launch contraint field %s (notify author)", field.Key) 247 | } 248 | } 249 | 250 | return lc, nil 251 | } 252 | -------------------------------------------------------------------------------- /pkg/cpio/cpio.go: -------------------------------------------------------------------------------- 1 | package cpio 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | "io/fs" 8 | "os" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | const ( 14 | Magic = "070707" 15 | Trailer = "TRAILER!!!" 16 | hdrSize = 76 17 | ) 18 | 19 | // https://www.mkssoftware.com/docs/man4/cpio.4.asp 20 | type Header struct { 21 | Magic [6]byte 22 | Dev [6]byte 23 | Ino [6]byte 24 | Mode [6]byte 25 | UID [6]byte 26 | GID [6]byte 27 | NLink [6]byte 28 | RDev [6]byte 29 | MTime [11]byte 30 | NameSize [6]byte 31 | FileSize [11]byte 32 | } 33 | 34 | type FileInfo struct { 35 | DeviceNo uint64 36 | Inode uint64 37 | Mode fs.FileMode 38 | Uid int 39 | Gid int 40 | NLink int 41 | RDev int 42 | Mtime time.Time 43 | } 44 | 45 | type File struct { 46 | Info FileInfo 47 | Name string 48 | Size int64 49 | 50 | offset int64 51 | length int64 52 | heap io.ReaderAt 53 | } 54 | 55 | type Reader struct { 56 | Files map[string]*File 57 | 58 | r io.ReaderAt 59 | size int64 60 | heapOffset int64 61 | } 62 | 63 | // A ReadCloser is a [Reader] that must be closed when no longer needed. 64 | type ReadCloser struct { 65 | f *os.File 66 | Reader 67 | } 68 | 69 | // OpenReader will open the CPIO file specified by name and return a Reader. 70 | func Open(name string) (*ReadCloser, error) { 71 | f, err := os.Open(name) 72 | if err != nil { 73 | return nil, err 74 | } 75 | fi, err := f.Stat() 76 | if err != nil { 77 | f.Close() 78 | return nil, err 79 | } 80 | r := new(ReadCloser) 81 | if err = r.init(f, fi.Size()); err != nil { 82 | f.Close() 83 | return nil, err 84 | } 85 | r.f = f 86 | return r, err 87 | } 88 | 89 | // NewReader will create a new Reader from the given io.ReaderAt and size. 90 | func NewReader(r io.ReaderAt, size int64) (*Reader, error) { 91 | if size < 0 { 92 | return nil, fmt.Errorf("cpio: size cannot be negative") 93 | } 94 | cr := new(Reader) 95 | var err error 96 | if err = cr.init(r, size); err != nil { 97 | return nil, err 98 | } 99 | return cr, err 100 | } 101 | 102 | func (r *ReadCloser) Close() error { 103 | if r.f != nil { 104 | return r.f.Close() 105 | } 106 | return nil 107 | } 108 | 109 | // allOctal reports whether x is entirely ASCII octal digits. 110 | func allOctal(x []byte) bool { 111 | for _, b := range x { 112 | if b < '0' || '7' < b { 113 | return false 114 | } 115 | } 116 | return true 117 | } 118 | 119 | // parseOctal converts an octal byte slice to uint64 120 | func parseOctal(b []byte) uint64 { 121 | var sum uint64 122 | for _, c := range b { 123 | if c == 0 { 124 | break 125 | } 126 | sum = sum*8 + uint64(c-'0') 127 | } 128 | return sum 129 | } 130 | 131 | func (r *Reader) init(rdr io.ReaderAt, size int64) error { 132 | r.r = rdr 133 | r.size = size 134 | r.Files = make(map[string]*File) 135 | 136 | var offset int64 137 | for { 138 | // Read header 139 | var header Header 140 | err := binary.Read(io.NewSectionReader(r.r, offset, hdrSize), binary.BigEndian, &header) 141 | if err != nil { 142 | if err == io.EOF { 143 | break 144 | } 145 | return err 146 | } 147 | 148 | offset += hdrSize 149 | 150 | // Verify magic number and header fields are valid octal 151 | if !allOctal(header.Magic[:]) || string(header.Magic[:]) != Magic { 152 | return fmt.Errorf("cpio: invalid magic number: %s", string(header.Magic[:])) 153 | } 154 | 155 | // Parse header fields 156 | nameSize := parseOctal(header.NameSize[:]) 157 | fileSize := parseOctal(header.FileSize[:]) 158 | 159 | // Validate sizes 160 | if nameSize == 0 { 161 | return fmt.Errorf("cpio: invalid name size") 162 | } 163 | if offset+int64(nameSize) > size { 164 | return fmt.Errorf("cpio: name too long") 165 | } 166 | 167 | // Read filename 168 | nameBuf := make([]byte, nameSize) 169 | if _, err := r.r.ReadAt(nameBuf, offset); err != nil { 170 | return err 171 | } 172 | offset += int64(nameSize) 173 | name := string(nameBuf[:nameSize-1]) // Remove null terminator 174 | 175 | // Check for trailer 176 | // The MKS cpio page says "TRAILER!!" 177 | // but the Apple pkg files use "TRAILER!!!". 178 | if name == Trailer { 179 | break 180 | } 181 | 182 | mode := parseOctal(header.Mode[:]) 183 | fmode := fs.FileMode(mode & 0777) 184 | if mode&040000 != 0 { 185 | fmode |= fs.ModeDir 186 | } 187 | 188 | if fmode&fs.ModeDir != 0 { 189 | r.heapOffset = offset 190 | continue 191 | } 192 | 193 | // Add to files map using inode as key 194 | r.Files[strings.TrimPrefix(name, ".")] = &File{ 195 | Info: FileInfo{ 196 | DeviceNo: parseOctal(header.Dev[:]), 197 | Inode: parseOctal(header.Ino[:]), 198 | Mode: fmode, 199 | Uid: int(parseOctal(header.UID[:])), 200 | Gid: int(parseOctal(header.GID[:])), 201 | NLink: int(parseOctal(header.NLink[:])), 202 | RDev: int(parseOctal(header.RDev[:])), 203 | Mtime: time.Unix(int64(int64(parseOctal(header.MTime[:]))), 0), 204 | }, 205 | Name: strings.TrimPrefix(name, "."), 206 | Size: int64(fileSize), 207 | offset: offset, 208 | length: int64(fileSize), 209 | heap: r.r, 210 | } 211 | 212 | // Move to next file 213 | offset += int64(fileSize) 214 | r.heapOffset = offset 215 | } 216 | 217 | return nil 218 | } 219 | 220 | func (f *File) OpenRaw() (*io.SectionReader, error) { 221 | if f.heap == nil { 222 | return nil, fmt.Errorf("cpio: file has no heap") 223 | } 224 | return io.NewSectionReader(f.heap, f.offset, f.length), nil 225 | } 226 | 227 | // Multiple files may be read concurrently. 228 | func (f *File) Open() (io.ReadCloser, error) { 229 | if f.heap == nil { 230 | return nil, fmt.Errorf("cpio: file has no heap") 231 | } 232 | 233 | return &fileReader{ 234 | f: f, 235 | offset: 0, 236 | }, nil 237 | } 238 | 239 | type fileReader struct { 240 | f *File 241 | offset int64 242 | } 243 | 244 | func (fr *fileReader) Read(p []byte) (n int, err error) { 245 | if fr.offset >= fr.f.length { 246 | return 0, io.EOF 247 | } 248 | 249 | n = int(fr.f.length - fr.offset) 250 | if len(p) < n { 251 | n = len(p) 252 | } 253 | 254 | if _, err := fr.f.heap.ReadAt(p[:n], fr.f.offset+fr.offset); err != nil { 255 | return 0, err 256 | } 257 | 258 | fr.offset += int64(n) 259 | return n, nil 260 | } 261 | 262 | func (fr *fileReader) Close() error { 263 | return nil 264 | } 265 | -------------------------------------------------------------------------------- /pkg/fixupchains/imports.go: -------------------------------------------------------------------------------- 1 | package fixupchains 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/blacktop/go-macho/types" 7 | ) 8 | 9 | // ImportFormat are values for dyld_chained_fixups_header.imports_format 10 | type ImportFormat uint32 11 | 12 | const ( 13 | DC_IMPORT ImportFormat = 1 14 | DC_IMPORT_ADDEND ImportFormat = 2 15 | DC_IMPORT_ADDEND64 ImportFormat = 3 16 | ) 17 | 18 | type Import interface { 19 | LibOrdinal() int 20 | WeakImport() bool 21 | NameOffset() uint64 22 | Addend() uint64 23 | } 24 | 25 | type DcfImport struct { 26 | Name string 27 | Import 28 | } 29 | 30 | func (i DcfImport) String() string { 31 | return fmt.Sprintf("%s, %s", i.Import, i.Name) 32 | } 33 | 34 | // DYLD_CHAINED_IMPORT 35 | type DyldChainedImport uint32 36 | 37 | func (d DyldChainedImport) LibOrdinal() int { 38 | return int(int8(types.ExtractBits(uint64(d), 0, 8))) 39 | } 40 | func (d DyldChainedImport) WeakImport() bool { 41 | return types.ExtractBits(uint64(d), 8, 1) == 1 42 | } 43 | func (d DyldChainedImport) NameOffset() uint64 { 44 | return types.ExtractBits(uint64(d), 9, 23) 45 | } 46 | func (d DyldChainedImport) Addend() uint64 { 47 | return 0 48 | } 49 | func (i DyldChainedImport) String() string { 50 | return fmt.Sprintf("lib ordinal: %2d, is_weak: %t", i.LibOrdinal(), i.WeakImport()) 51 | } 52 | 53 | // DYLD_CHAINED_IMPORT_ADDEND 54 | type DyldChainedImportAddend struct { 55 | Import DyldChainedImport 56 | AddendVal int32 57 | } 58 | 59 | func (d DyldChainedImportAddend) LibOrdinal() int { 60 | return d.Import.LibOrdinal() 61 | } 62 | func (d DyldChainedImportAddend) WeakImport() bool { 63 | return d.Import.WeakImport() 64 | } 65 | func (d DyldChainedImportAddend) NameOffset() uint64 { 66 | return d.Import.NameOffset() 67 | } 68 | func (d DyldChainedImportAddend) Addend() uint64 { 69 | return uint64(d.AddendVal) 70 | } 71 | 72 | func (i DyldChainedImportAddend) String() string { 73 | return fmt.Sprintf("lib ordinal: %2d, is_weak: %t, addend: %#x", i.LibOrdinal(), i.WeakImport(), i.Addend()) 74 | } 75 | 76 | type DyldChainedImport64 uint64 77 | 78 | func (d DyldChainedImport64) LibOrdinal() int { 79 | return int(int16(types.ExtractBits(uint64(d), 0, 16))) 80 | } 81 | func (d DyldChainedImport64) WeakImport() bool { 82 | return types.ExtractBits(uint64(d), 16, 1) == 1 83 | } 84 | func (d DyldChainedImport64) Reserved() uint64 { 85 | return types.ExtractBits(uint64(d), 17, 15) 86 | } 87 | func (d DyldChainedImport64) NameOffset() uint64 { 88 | return types.ExtractBits(uint64(d), 32, 32) 89 | } 90 | func (d DyldChainedImport64) Addend() uint64 { 91 | return 0 92 | } 93 | func (i DyldChainedImport64) String() string { 94 | return fmt.Sprintf("lib ordinal: %2d, is_weak: %t", i.LibOrdinal(), i.WeakImport()) 95 | } 96 | 97 | // DYLD_CHAINED_IMPORT_ADDEND64 98 | type DyldChainedImportAddend64 struct { 99 | Import DyldChainedImport64 100 | AddendVal uint64 101 | } 102 | 103 | func (d DyldChainedImportAddend64) LibOrdinal() int { 104 | return d.Import.LibOrdinal() 105 | } 106 | func (d DyldChainedImportAddend64) WeakImport() bool { 107 | return d.Import.WeakImport() 108 | } 109 | func (d DyldChainedImportAddend64) NameOffset() uint64 { 110 | return d.Import.NameOffset() 111 | } 112 | func (d DyldChainedImportAddend64) Addend() uint64 { 113 | return d.AddendVal 114 | } 115 | func (i DyldChainedImportAddend64) String() string { 116 | return fmt.Sprintf("lib ordinal: %2d, is_weak: %t, addend: %#x", i.LibOrdinal(), i.WeakImport(), i.Addend()) 117 | } 118 | -------------------------------------------------------------------------------- /pkg/trie/trie.go: -------------------------------------------------------------------------------- 1 | package trie 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "io" 8 | "path/filepath" 9 | 10 | "github.com/blacktop/go-macho/types" 11 | ) 12 | 13 | type Node struct { 14 | Offset uint64 15 | Data []byte 16 | } 17 | 18 | type TrieExport struct { 19 | Name string 20 | ReExport string 21 | Flags types.ExportFlag 22 | Other uint64 23 | Address uint64 24 | FoundInDylib string 25 | } 26 | 27 | func (e TrieExport) Type() string { 28 | if e.Flags.ReExport() { 29 | if len(e.ReExport) == 0 { 30 | return fmt.Sprintf("from %s", filepath.Base(e.FoundInDylib)) 31 | } else { 32 | return fmt.Sprintf("%s re-exported from %s", e.ReExport, filepath.Base(e.FoundInDylib)) 33 | } 34 | } else if e.Flags.StubAndResolver() { 35 | return fmt.Sprintf("resolver=%#8x", e.Other) 36 | } 37 | return e.Flags.String() 38 | } 39 | 40 | func (e TrieExport) String() string { 41 | return fmt.Sprintf("%#09x:\t(%s)\t%s", e.Address, e.Type(), e.Name) 42 | } 43 | 44 | func ReadUleb128(r *bytes.Reader) (uint64, error) { 45 | var result uint64 46 | var shift uint64 47 | 48 | for { 49 | b, err := r.ReadByte() 50 | if err == io.EOF { 51 | return 0, err 52 | } 53 | if err != nil { 54 | return 0, fmt.Errorf("could not parse ULEB128 value: %v", err) 55 | } 56 | 57 | result |= uint64((uint(b) & 0x7f) << shift) 58 | 59 | // If high order bit is 1. 60 | if (b & 0x80) == 0 { 61 | break 62 | } 63 | 64 | shift += 7 65 | } 66 | 67 | return result, nil 68 | } 69 | 70 | func ReadSleb128(r *bytes.Reader) (int64, error) { 71 | var result int64 72 | var shift uint64 73 | 74 | for { 75 | b, err := r.ReadByte() 76 | if err == io.EOF { 77 | return 0, err 78 | } 79 | if err != nil { 80 | return 0, fmt.Errorf("could not parse SLEB128 value: %v", err) 81 | } 82 | 83 | result |= int64((int64(b) & 0x7f) << shift) 84 | shift += 7 85 | 86 | // If high order bit is 1. 87 | if (b & 0x80) == 0 { 88 | if (shift < 64) && ((b & 0x40) > 0) { 89 | result |= -(1 << shift) 90 | } 91 | 92 | break 93 | } 94 | } 95 | 96 | return result, nil 97 | } 98 | 99 | func ReadUleb128FromBuffer(buf *bytes.Buffer) (uint64, int, error) { 100 | 101 | var ( 102 | result uint64 103 | shift uint64 104 | length int 105 | ) 106 | 107 | if buf.Len() == 0 { 108 | return 0, 0, nil 109 | } 110 | 111 | for { 112 | b, err := buf.ReadByte() 113 | if err != nil { 114 | return 0, 0, fmt.Errorf("could not parse ULEB128 value: %v", err) 115 | } 116 | length++ 117 | 118 | result |= uint64((uint(b) & 0x7f) << shift) 119 | 120 | // If high order bit is 1. 121 | if (b & 0x80) == 0 { 122 | break 123 | } 124 | 125 | shift += 7 126 | } 127 | 128 | return result, length, nil 129 | } 130 | 131 | // EncodeUleb128 encodes input to the Unsigned Little Endian Base 128 format 132 | func EncodeUleb128(out io.ByteWriter, x uint64) { 133 | for { 134 | b := byte(x & 0x7f) 135 | x = x >> 7 136 | if x != 0 { 137 | b = b | 0x80 138 | } 139 | out.WriteByte(b) 140 | if x == 0 { 141 | break 142 | } 143 | } 144 | } 145 | 146 | // EncodeSleb128 encodes input to the Signed Little Endian Base 128 format 147 | func EncodeSleb128(out io.ByteWriter, x int64) { 148 | for { 149 | b := byte(x & 0x7f) 150 | x >>= 7 151 | 152 | signb := b & 0x40 153 | 154 | last := false 155 | if (x == 0 && signb == 0) || (x == -1 && signb != 0) { 156 | last = true 157 | } else { 158 | b = b | 0x80 159 | } 160 | out.WriteByte(b) 161 | 162 | if last { 163 | break 164 | } 165 | } 166 | } 167 | 168 | func ReadExport(r *bytes.Reader, symbol string, loadAddress uint64) (*TrieExport, error) { 169 | var symFlagInt, symValueInt, symOtherInt uint64 170 | var reExportSymBytes []byte 171 | var reExportSymName string 172 | 173 | symFlagInt, err := ReadUleb128(r) 174 | if err != nil { 175 | return nil, fmt.Errorf("could not parse ULEB128 symbol flag value: %v", err) 176 | } 177 | 178 | flags := types.ExportFlag(symFlagInt) 179 | 180 | if flags.ReExport() { 181 | symOtherInt, err = ReadUleb128(r) 182 | if err != nil { 183 | return nil, fmt.Errorf("could not parse ULEB128 symbol other reexport value: %v", err) 184 | } 185 | 186 | for { 187 | s, err := r.ReadByte() 188 | if err == io.EOF { 189 | break 190 | } 191 | if s == '\x00' { 192 | break 193 | } 194 | reExportSymBytes = append(reExportSymBytes, s) 195 | } 196 | 197 | } else if flags.StubAndResolver() { 198 | symOtherInt, err = ReadUleb128(r) 199 | if err != nil { 200 | return nil, fmt.Errorf("could not parse ULEB128 symbol other stub-n-resolver value: %v", err) 201 | } 202 | symOtherInt += loadAddress 203 | } 204 | 205 | symValueInt, err = ReadUleb128(r) 206 | if err != nil { 207 | return nil, fmt.Errorf("could not parse ULEB128 symbol value: %v", err) 208 | } 209 | 210 | if (flags.Regular() || flags.ThreadLocal()) && !flags.ReExport() { 211 | symValueInt += loadAddress 212 | } 213 | 214 | if len(reExportSymBytes) > 0 { 215 | reExportSymName = string(reExportSymBytes) 216 | } 217 | 218 | return &TrieExport{ 219 | Name: symbol, 220 | ReExport: reExportSymName, 221 | Flags: flags, 222 | Other: symOtherInt, 223 | Address: symValueInt, 224 | }, nil 225 | } 226 | 227 | func ParseTrieExports(r *bytes.Reader, loadAddress uint64) ([]TrieExport, error) { 228 | var exports []TrieExport 229 | 230 | nodes, err := ParseTrie(r) 231 | if err != nil { 232 | return nil, fmt.Errorf("could not parse trie: %v", err) 233 | } 234 | 235 | for _, node := range nodes { 236 | if _, err := r.Seek(int64(node.Offset), io.SeekStart); err != nil { 237 | return nil, fmt.Errorf("could not seek to trie node: %v", err) 238 | } 239 | export, err := ReadExport(r, string(node.Data), loadAddress) 240 | if err != nil { 241 | return nil, fmt.Errorf("could not read trie export metadata: %v", err) 242 | } 243 | exports = append(exports, *export) 244 | } 245 | 246 | return exports, nil 247 | } 248 | 249 | func ParseTrie(r *bytes.Reader) ([]Node, error) { 250 | data := make([]byte, 0, 32768) 251 | return parseTrie(r, 0, data) 252 | } 253 | 254 | func parseTrie(r *bytes.Reader, pos uint64, cummulativeString []byte) ([]Node, error) { 255 | 256 | var output []Node 257 | 258 | r.Seek(int64(pos), io.SeekStart) 259 | 260 | terminalSize, err := ReadUleb128(r) 261 | if err != nil { 262 | return nil, fmt.Errorf("could not parse ULEB128 terminalSize value: %v", err) 263 | } 264 | 265 | if terminalSize != 0 { 266 | off, err := r.Seek(0, io.SeekCurrent) 267 | if err != nil { 268 | return nil, fmt.Errorf("could not get current offset: %v", err) 269 | } 270 | output = append(output, Node{ 271 | Offset: uint64(off), 272 | Data: append([]byte{}, cummulativeString...), 273 | }) 274 | } 275 | 276 | r.Seek(int64(pos+terminalSize+1), io.SeekStart) 277 | 278 | childrenRemaining, err := r.ReadByte() 279 | if err != nil { 280 | return nil, fmt.Errorf("could not read childrenRemaining value: %v", err) 281 | } 282 | 283 | for i := 0; i < int(childrenRemaining); i++ { 284 | tmp := make([]byte, 0, 100) 285 | for { 286 | s, err := r.ReadByte() 287 | if err == io.EOF { 288 | break 289 | } 290 | if s == '\x00' { 291 | break 292 | } 293 | tmp = append(tmp, s) 294 | } 295 | 296 | childNodeOffset, err := ReadUleb128(r) 297 | if err != nil { 298 | return nil, fmt.Errorf("could not parse ULEB128 childNodeOffset value: %v", err) 299 | } 300 | 301 | curr, _ := r.Seek(0, io.SeekCurrent) 302 | 303 | nodes, err := parseTrie(r, childNodeOffset, append(cummulativeString, tmp...)) 304 | if err != nil { 305 | return nil, fmt.Errorf("could not parse trie (recursive call): %v", err) 306 | } 307 | 308 | r.Seek(curr, io.SeekStart) // reset the reader 309 | 310 | output = append(output, nodes...) 311 | } 312 | 313 | return output, nil 314 | } 315 | 316 | func WalkTrie(r *bytes.Reader, symbol string) (uint64, error) { 317 | 318 | var strIndex int 319 | var offset, nodeOffset uint64 320 | 321 | for { 322 | r.Seek(int64(offset), io.SeekStart) 323 | 324 | terminalSize, err := binary.ReadUvarint(r) 325 | if err != nil { 326 | return 0, fmt.Errorf("failed to read terminalSize value: %v", err) 327 | } 328 | 329 | r.Seek(int64(offset+1), io.SeekStart) 330 | 331 | if terminalSize > 127 { 332 | r.Seek(int64(offset), io.SeekStart) 333 | 334 | terminalSize, err = ReadUleb128(r) 335 | if err != nil { 336 | return 0, fmt.Errorf("could not parse ULEB128 terminalSize value: %v", err) 337 | } 338 | } 339 | 340 | if int(strIndex) == len(symbol) && (terminalSize != 0) { 341 | // skip over zero terminator 342 | r.Seek(int64(offset+1), io.SeekStart) 343 | return offset + 1, nil 344 | } 345 | 346 | r.Seek(int64(offset+terminalSize+1), io.SeekStart) 347 | 348 | childrenRemaining, err := r.ReadByte() 349 | if err == io.EOF { 350 | break 351 | } 352 | 353 | nodeOffset = 0 354 | 355 | for i := childrenRemaining; i > 0; i-- { 356 | searchStrIndex := strIndex 357 | wrongEdge := false 358 | 359 | for { 360 | c, err := r.ReadByte() 361 | if err == io.EOF { 362 | break 363 | } 364 | if err != nil { 365 | return 0, fmt.Errorf("could not read trie character: %v", err) 366 | } 367 | if c == '\x00' { 368 | break 369 | } 370 | if !wrongEdge { 371 | if searchStrIndex != len(symbol) && c != symbol[searchStrIndex] { 372 | wrongEdge = true 373 | } 374 | searchStrIndex++ 375 | if searchStrIndex > len(symbol) { 376 | return offset, fmt.Errorf("symbol not in trie") 377 | } 378 | } 379 | } 380 | 381 | if wrongEdge { // advance to next child 382 | // skip over last byte of uleb128 383 | _, err = ReadUleb128(r) 384 | if err != nil { 385 | return 0, fmt.Errorf("failed to skip ULEB128 value: %v", err) 386 | } 387 | } else { // the symbol so far matches this edge (child) 388 | // so advance to the child's node 389 | nodeOffset, err = ReadUleb128(r) 390 | if err != nil { 391 | return 0, fmt.Errorf("failed to read ULEB128 nodeOffset value: %v", err) 392 | } 393 | 394 | strIndex = searchStrIndex 395 | break 396 | } 397 | } 398 | 399 | if nodeOffset != 0 { 400 | offset = nodeOffset 401 | } else { 402 | break 403 | } 404 | } 405 | 406 | return offset, fmt.Errorf("symbol not in trie") 407 | } 408 | -------------------------------------------------------------------------------- /pkg/xar/types.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 Mikkel Krautz 2 | // The use of this source code is goverened by a BSD-style 3 | // license that can be found in the LICENSE-file. 4 | 5 | package xar 6 | 7 | import "encoding/xml" 8 | 9 | // This file implements the logic that translates a XAR TOC 10 | // to the internal format of this library. 11 | 12 | type xmlXar struct { 13 | XMLName xml.Name `xml:"xar"` 14 | Subdoc xmlSubdoc 15 | Toc xmlToc 16 | } 17 | 18 | type xmlSubdoc struct { 19 | XMLName xml.Name `xml:"subdoc"` 20 | Name string `xml:"subdoc_name,attr"` 21 | LinkOptions []string `xml:"link-options>option"` 22 | Dylibs []string `xml:"dylibs>lib"` 23 | SDKVersion string `xml:"sdkversion"` 24 | Platform string `xml:"platform"` 25 | HideSymbols int `xml:"hide-symbols"` 26 | Arch string `xml:"architecture"` 27 | Version string `xml:"version"` 28 | } 29 | 30 | type xmlChecksum struct { 31 | XMLName xml.Name `xml:"checksum"` 32 | Style string `xml:"style,attr"` 33 | Offset int64 `xml:"offset"` 34 | Size int64 `xml:"size"` 35 | } 36 | 37 | type xmlSignature struct { 38 | XMLName xml.Name `xml:"signature"` 39 | Style string `xml:"style,attr"` 40 | Offset int64 `xml:"offset"` 41 | Size int64 `xml:"size"` 42 | Certificates []string `xml:"KeyInfo>X509Data>X509Certificate"` 43 | } 44 | 45 | type xmlToc struct { 46 | XMLName xml.Name `xml:"toc"` 47 | CreationTime string `xml:"creation-time"` 48 | Checksum *xmlChecksum 49 | SignatureCreationTime int64 `xml:"signature-creation-time"` 50 | Signature *xmlSignature 51 | File []*xmlFile `xml:"file"` 52 | } 53 | 54 | type xmlFileChecksum struct { 55 | XMLName xml.Name 56 | Style string `xml:"style,attr"` 57 | Digest string `xml:",chardata"` 58 | } 59 | 60 | type xmlFinderCreateTime struct { 61 | XMLName xml.Name `xml:"FinderCreateTime"` 62 | Nanoseconds int64 `xml:"nanoseconds"` 63 | Time string `xml:"time"` 64 | } 65 | 66 | type xmlFileEncoding struct { 67 | XMLName xml.Name `xml:"encoding"` 68 | Style string `xml:"style,attr"` 69 | } 70 | 71 | type xmlFileData struct { 72 | XMLName xml.Name `xml:"data"` 73 | Length int64 `xml:"length"` 74 | Offset int64 `xml:"offset"` 75 | Size int64 `xml:"size"` 76 | Encoding xmlFileEncoding 77 | ArchivedChecksum xmlFileChecksum `xml:"archived-checksum"` 78 | ExtractedChecksum xmlFileChecksum `xml:"extracted-checksum"` 79 | } 80 | 81 | type xmlFile struct { 82 | XMLName xml.Name `xml:"file"` 83 | Id string `xml:"id,attr"` 84 | ClangArgs []string `xml:"clang>cmd"` 85 | FileType string `xml:"file-type"` 86 | Ctime string `xml:"ctime"` 87 | Mtime string `xml:"mtime"` 88 | Atime string `xml:"atime"` 89 | Group string `xml:"group"` 90 | Gid int `xml:"gid"` 91 | User string `xml:"user"` 92 | Uid int `xml:"uid"` 93 | Mode uint32 `xml:"mode"` 94 | DeviceNo uint64 `xml:"deviceno"` 95 | Inode uint64 `xml:"inode"` 96 | Type string `xml:"type"` 97 | Name string `xml:"name"` 98 | FinderCreateTime *xmlFinderCreateTime 99 | Data *xmlFileData 100 | File []*xmlFile `xml:"file"` 101 | } 102 | -------------------------------------------------------------------------------- /toc.go: -------------------------------------------------------------------------------- 1 | package macho 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/json" 6 | "fmt" 7 | "unsafe" 8 | 9 | "github.com/blacktop/go-macho/types" 10 | ) 11 | 12 | type FileTOC struct { 13 | types.FileHeader 14 | ByteOrder binary.ByteOrder 15 | Loads loads 16 | Sections []*types.Section 17 | functions []types.Function 18 | } 19 | 20 | func (t *FileTOC) AddLoad(l Load) uint32 { 21 | loadsz := t.LoadSize() 22 | t.Loads = append(t.Loads, l) 23 | t.NCommands++ 24 | t.SizeCommands += l.LoadSize() 25 | return t.LoadSize() - loadsz // delta 26 | } 27 | 28 | func (t *FileTOC) ModifySizeCommands(prev, curr int32) int32 { 29 | t.SizeCommands = uint32(int32(t.SizeCommands) + (curr - prev)) 30 | return curr - prev 31 | } 32 | 33 | func (t *FileTOC) RemoveLoad(l Load) error { 34 | if len(t.Loads) == 0 { 35 | return fmt.Errorf("no loads to remove") 36 | } 37 | for i, load := range t.Loads { 38 | if load == l { 39 | t.Loads = append(t.Loads[:i], t.Loads[i+1:]...) 40 | t.NCommands-- 41 | t.SizeCommands -= l.LoadSize() 42 | break 43 | } 44 | } 45 | return nil 46 | } 47 | 48 | // AddSegment adds segment s to the file table of contents, 49 | // and also zeroes out the segment information with the expectation 50 | // that this will be added next. 51 | func (t *FileTOC) AddSegment(s *Segment) { 52 | s.Nsect = 0 53 | s.Firstsect = 0 54 | t.AddLoad(s) 55 | } 56 | 57 | // AddSection adds section to the most recently added Segment 58 | func (t *FileTOC) AddSection(s *types.Section) { 59 | g := t.Loads[len(t.Loads)-1].(*Segment) 60 | if g.Nsect == 0 { 61 | g.Firstsect = uint32(len(t.Sections)) 62 | } 63 | g.Nsect++ 64 | t.Sections = append(t.Sections, s) 65 | sectionsize := uint32(unsafe.Sizeof(types.Section32{})) 66 | if g.Command() == types.LC_SEGMENT_64 { 67 | sectionsize = uint32(unsafe.Sizeof(types.Section64{})) 68 | } 69 | t.SizeCommands += sectionsize 70 | g.Len += sectionsize 71 | } 72 | 73 | // DerivedCopy returns a modified copy of the TOC, with empty loads and sections, 74 | // and with the specified header type and flags. 75 | func (t *FileTOC) DerivedCopy(Type types.HeaderFileType, Flags types.HeaderFlag) *FileTOC { 76 | h := t.FileHeader 77 | h.NCommands, h.SizeCommands, h.Type, h.Flags = 0, 0, Type, Flags 78 | 79 | return &FileTOC{FileHeader: h, ByteOrder: t.ByteOrder} 80 | } 81 | 82 | // TOCSize returns the size in bytes of the object file representation 83 | // of the header and Load Commands (including Segments and Sections, but 84 | // not their contents) at the beginning of a Mach-O file. This typically 85 | // overlaps the text segment in the object file. 86 | func (t *FileTOC) TOCSize() uint32 { 87 | return t.HdrSize() + t.LoadSize() 88 | } 89 | 90 | // LoadAlign returns the required alignment of Load commands in a binary. 91 | // This is used to add padding for necessary alignment. 92 | func (t *FileTOC) LoadAlign() uint64 { 93 | if t.Magic == types.Magic64 { 94 | return 8 95 | } 96 | return 4 97 | } 98 | 99 | // HdrSize returns the size in bytes of the Macho header for a given 100 | // magic number (where the magic number has been appropriately byte-swapped). 101 | func (t *FileTOC) HdrSize() uint32 { 102 | switch t.Magic { 103 | case types.Magic32: 104 | return types.FileHeaderSize32 105 | case types.Magic64: 106 | return types.FileHeaderSize64 107 | case types.MagicFat: 108 | panic("MagicFat not handled yet") 109 | default: 110 | panic(fmt.Sprintf("Unexpected magic number %#x, expected Mach-O object file", t.Magic)) 111 | } 112 | } 113 | 114 | // LoadSize returns the size of all the load commands in a file's table-of contents 115 | // (but not their associated data, e.g., sections and symbol tables) 116 | func (t *FileTOC) LoadSize() uint32 { 117 | cmdsz := uint32(0) 118 | for _, l := range t.Loads { 119 | s := l.LoadSize() 120 | cmdsz += s 121 | } 122 | return cmdsz 123 | } 124 | 125 | // FileSize returns the size in bytes of the header, load commands, and the 126 | // in-file contents of all the segments and sections included in those 127 | // load commands, accounting for their offsets within the file. 128 | func (t *FileTOC) FileSize() uint64 { 129 | sz := uint64(t.LoadSize()) // ought to be contained in text segment, but just in case. 130 | for _, l := range t.Loads { 131 | if s, ok := l.(*Segment); ok { 132 | if m := s.Offset + s.Filesz; m > sz { 133 | sz = m 134 | } 135 | } 136 | } 137 | return sz 138 | } 139 | 140 | func (t *FileTOC) String() string { 141 | return fmt.Sprintf("%s\n%s\n", t.FileHeader.String(), t.Loads.String()) 142 | } 143 | 144 | func (t *FileTOC) Print(printer func(t *FileTOC) string) string { 145 | return printer(t) 146 | } 147 | 148 | func (t *FileTOC) MarshalJSON() ([]byte, error) { 149 | return json.Marshal(&struct { 150 | Header types.FileHeader `json:"header"` 151 | Loads loads `json:"loads"` 152 | }{ 153 | Header: t.FileHeader, 154 | Loads: t.Loads, 155 | }) 156 | } 157 | 158 | type loads []Load 159 | 160 | // LoadsString returns a string representation of all the MachO's load commands 161 | func (ls loads) String() string { 162 | var loadsStr string 163 | for i, l := range ls { 164 | if sg, ok := l.(*Segment); ok { 165 | loadsStr += fmt.Sprintf("%03d: %s\n", i, sg) 166 | for _, sc := range sg.sections { 167 | loadsStr += fmt.Sprintf("%s\n", sc) 168 | } 169 | } else { 170 | if l != nil { 171 | loadsStr += fmt.Sprintf("%03d: %-28s%s\n", i, l.Command(), l.String()) 172 | } 173 | } 174 | } 175 | return loadsStr 176 | } 177 | -------------------------------------------------------------------------------- /types/commands_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=LoadCmd,X86ThreadFlavor,ArmThreadFlavor -output commands_string.go"; DO NOT EDIT. 2 | 3 | package types 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[LC_REQ_DYLD-2147483648] 12 | _ = x[LC_SEP-134217728] 13 | _ = x[LC_SEGMENT-1] 14 | _ = x[LC_SYMTAB-2] 15 | _ = x[LC_SYMSEG-3] 16 | _ = x[LC_THREAD-4] 17 | _ = x[LC_UNIXTHREAD-5] 18 | _ = x[LC_LOADFVMLIB-6] 19 | _ = x[LC_IDFVMLIB-7] 20 | _ = x[LC_IDENT-8] 21 | _ = x[LC_FVMFILE-9] 22 | _ = x[LC_PREPAGE-10] 23 | _ = x[LC_DYSYMTAB-11] 24 | _ = x[LC_LOAD_DYLIB-12] 25 | _ = x[LC_ID_DYLIB-13] 26 | _ = x[LC_LOAD_DYLINKER-14] 27 | _ = x[LC_ID_DYLINKER-15] 28 | _ = x[LC_PREBOUND_DYLIB-16] 29 | _ = x[LC_ROUTINES-17] 30 | _ = x[LC_SUB_FRAMEWORK-18] 31 | _ = x[LC_SUB_UMBRELLA-19] 32 | _ = x[LC_SUB_CLIENT-20] 33 | _ = x[LC_SUB_LIBRARY-21] 34 | _ = x[LC_TWOLEVEL_HINTS-22] 35 | _ = x[LC_PREBIND_CKSUM-23] 36 | _ = x[LC_LOAD_WEAK_DYLIB-2147483672] 37 | _ = x[LC_SEGMENT_64-25] 38 | _ = x[LC_ROUTINES_64-26] 39 | _ = x[LC_UUID-27] 40 | _ = x[LC_RPATH-2147483676] 41 | _ = x[LC_CODE_SIGNATURE-29] 42 | _ = x[LC_SEGMENT_SPLIT_INFO-30] 43 | _ = x[LC_REEXPORT_DYLIB-2147483679] 44 | _ = x[LC_LAZY_LOAD_DYLIB-32] 45 | _ = x[LC_ENCRYPTION_INFO-33] 46 | _ = x[LC_DYLD_INFO-34] 47 | _ = x[LC_DYLD_INFO_ONLY-2147483682] 48 | _ = x[LC_LOAD_UPWARD_DYLIB-2147483683] 49 | _ = x[LC_VERSION_MIN_MACOSX-36] 50 | _ = x[LC_VERSION_MIN_IPHONEOS-37] 51 | _ = x[LC_FUNCTION_STARTS-38] 52 | _ = x[LC_DYLD_ENVIRONMENT-39] 53 | _ = x[LC_MAIN-2147483688] 54 | _ = x[LC_DATA_IN_CODE-41] 55 | _ = x[LC_SOURCE_VERSION-42] 56 | _ = x[LC_DYLIB_CODE_SIGN_DRS-43] 57 | _ = x[LC_ENCRYPTION_INFO_64-44] 58 | _ = x[LC_LINKER_OPTION-45] 59 | _ = x[LC_LINKER_OPTIMIZATION_HINT-46] 60 | _ = x[LC_VERSION_MIN_TVOS-47] 61 | _ = x[LC_VERSION_MIN_WATCHOS-48] 62 | _ = x[LC_NOTE-49] 63 | _ = x[LC_BUILD_VERSION-50] 64 | _ = x[LC_DYLD_EXPORTS_TRIE-2147483699] 65 | _ = x[LC_DYLD_CHAINED_FIXUPS-2147483700] 66 | _ = x[LC_FILESET_ENTRY-2147483701] 67 | _ = x[LC_ATOM_INFO-54] 68 | _ = x[LC_SEP_CACHE_SLIDE-134217729] 69 | _ = x[LC_SEP_UNKNOWN_2-134217730] 70 | _ = x[LC_SEP_UNKNOWN_3-134217731] 71 | } 72 | 73 | const _LoadCmd_name = "LC_SEGMENTLC_SYMTABLC_SYMSEGLC_THREADLC_UNIXTHREADLC_LOADFVMLIBLC_IDFVMLIBLC_IDENTLC_FVMFILELC_PREPAGELC_DYSYMTABLC_LOAD_DYLIBLC_ID_DYLIBLC_LOAD_DYLINKERLC_ID_DYLINKERLC_PREBOUND_DYLIBLC_ROUTINESLC_SUB_FRAMEWORKLC_SUB_UMBRELLALC_SUB_CLIENTLC_SUB_LIBRARYLC_TWOLEVEL_HINTSLC_PREBIND_CKSUMLC_SEGMENT_64LC_ROUTINES_64LC_UUIDLC_CODE_SIGNATURELC_SEGMENT_SPLIT_INFOLC_LAZY_LOAD_DYLIBLC_ENCRYPTION_INFOLC_DYLD_INFOLC_VERSION_MIN_MACOSXLC_VERSION_MIN_IPHONEOSLC_FUNCTION_STARTSLC_DYLD_ENVIRONMENTLC_DATA_IN_CODELC_SOURCE_VERSIONLC_DYLIB_CODE_SIGN_DRSLC_ENCRYPTION_INFO_64LC_LINKER_OPTIONLC_LINKER_OPTIMIZATION_HINTLC_VERSION_MIN_TVOSLC_VERSION_MIN_WATCHOSLC_NOTELC_BUILD_VERSIONLC_ATOM_INFOLC_SEPLC_SEP_CACHE_SLIDELC_SEP_UNKNOWN_2LC_SEP_UNKNOWN_3LC_REQ_DYLDLC_LOAD_WEAK_DYLIBLC_RPATHLC_REEXPORT_DYLIBLC_DYLD_INFO_ONLYLC_LOAD_UPWARD_DYLIBLC_MAINLC_DYLD_EXPORTS_TRIELC_DYLD_CHAINED_FIXUPSLC_FILESET_ENTRY" 74 | 75 | var _LoadCmd_map = map[LoadCmd]string{ 76 | 1: _LoadCmd_name[0:10], 77 | 2: _LoadCmd_name[10:19], 78 | 3: _LoadCmd_name[19:28], 79 | 4: _LoadCmd_name[28:37], 80 | 5: _LoadCmd_name[37:50], 81 | 6: _LoadCmd_name[50:63], 82 | 7: _LoadCmd_name[63:74], 83 | 8: _LoadCmd_name[74:82], 84 | 9: _LoadCmd_name[82:92], 85 | 10: _LoadCmd_name[92:102], 86 | 11: _LoadCmd_name[102:113], 87 | 12: _LoadCmd_name[113:126], 88 | 13: _LoadCmd_name[126:137], 89 | 14: _LoadCmd_name[137:153], 90 | 15: _LoadCmd_name[153:167], 91 | 16: _LoadCmd_name[167:184], 92 | 17: _LoadCmd_name[184:195], 93 | 18: _LoadCmd_name[195:211], 94 | 19: _LoadCmd_name[211:226], 95 | 20: _LoadCmd_name[226:239], 96 | 21: _LoadCmd_name[239:253], 97 | 22: _LoadCmd_name[253:270], 98 | 23: _LoadCmd_name[270:286], 99 | 25: _LoadCmd_name[286:299], 100 | 26: _LoadCmd_name[299:313], 101 | 27: _LoadCmd_name[313:320], 102 | 29: _LoadCmd_name[320:337], 103 | 30: _LoadCmd_name[337:358], 104 | 32: _LoadCmd_name[358:376], 105 | 33: _LoadCmd_name[376:394], 106 | 34: _LoadCmd_name[394:406], 107 | 36: _LoadCmd_name[406:427], 108 | 37: _LoadCmd_name[427:450], 109 | 38: _LoadCmd_name[450:468], 110 | 39: _LoadCmd_name[468:487], 111 | 41: _LoadCmd_name[487:502], 112 | 42: _LoadCmd_name[502:519], 113 | 43: _LoadCmd_name[519:541], 114 | 44: _LoadCmd_name[541:562], 115 | 45: _LoadCmd_name[562:578], 116 | 46: _LoadCmd_name[578:605], 117 | 47: _LoadCmd_name[605:624], 118 | 48: _LoadCmd_name[624:646], 119 | 49: _LoadCmd_name[646:653], 120 | 50: _LoadCmd_name[653:669], 121 | 54: _LoadCmd_name[669:681], 122 | 134217728: _LoadCmd_name[681:687], 123 | 134217729: _LoadCmd_name[687:705], 124 | 134217730: _LoadCmd_name[705:721], 125 | 134217731: _LoadCmd_name[721:737], 126 | 2147483648: _LoadCmd_name[737:748], 127 | 2147483672: _LoadCmd_name[748:766], 128 | 2147483676: _LoadCmd_name[766:774], 129 | 2147483679: _LoadCmd_name[774:791], 130 | 2147483682: _LoadCmd_name[791:808], 131 | 2147483683: _LoadCmd_name[808:828], 132 | 2147483688: _LoadCmd_name[828:835], 133 | 2147483699: _LoadCmd_name[835:855], 134 | 2147483700: _LoadCmd_name[855:877], 135 | 2147483701: _LoadCmd_name[877:893], 136 | } 137 | 138 | func (i LoadCmd) String() string { 139 | if str, ok := _LoadCmd_map[i]; ok { 140 | return str 141 | } 142 | return "LoadCmd(" + strconv.FormatInt(int64(i), 10) + ")" 143 | } 144 | func _() { 145 | // An "invalid array index" compiler error signifies that the constant values have changed. 146 | // Re-run the stringer command to generate them again. 147 | var x [1]struct{} 148 | _ = x[X86_THREAD_STATE32-1] 149 | _ = x[X86_FLOAT_STATE32-2] 150 | _ = x[X86_EXCEPTION_STATE32-3] 151 | _ = x[X86_THREAD_STATE64-4] 152 | _ = x[X86_FLOAT_STATE64-5] 153 | _ = x[X86_EXCEPTION_STATE64-6] 154 | _ = x[X86_THREAD_STATE-7] 155 | _ = x[X86_FLOAT_STATE-8] 156 | _ = x[X86_EXCEPTION_STATE-9] 157 | _ = x[X86_DEBUG_STATE32-10] 158 | _ = x[X86_DEBUG_STATE64-11] 159 | _ = x[X86_DEBUG_STATE-12] 160 | _ = x[X86_THREAD_STATE_NONE-13] 161 | _ = x[X86_AVX_STATE32-16] 162 | _ = x[X86_AVX_STATE64-17] 163 | _ = x[X86_AVX_STATE-18] 164 | _ = x[X86_AVX512_STATE32-19] 165 | _ = x[X86_AVX512_STATE64-20] 166 | _ = x[X86_AVX512_STATE-21] 167 | _ = x[X86_PAGEIN_STATE-22] 168 | _ = x[X86_THREAD_FULL_STATE64-23] 169 | _ = x[X86_INSTRUCTION_STATE-24] 170 | _ = x[X86_LAST_BRANCH_STATE-25] 171 | } 172 | 173 | const ( 174 | _X86ThreadFlavor_name_0 = "X86_THREAD_STATE32X86_FLOAT_STATE32X86_EXCEPTION_STATE32X86_THREAD_STATE64X86_FLOAT_STATE64X86_EXCEPTION_STATE64X86_THREAD_STATEX86_FLOAT_STATEX86_EXCEPTION_STATEX86_DEBUG_STATE32X86_DEBUG_STATE64X86_DEBUG_STATEX86_THREAD_STATE_NONE" 175 | _X86ThreadFlavor_name_1 = "X86_AVX_STATE32X86_AVX_STATE64X86_AVX_STATEX86_AVX512_STATE32X86_AVX512_STATE64X86_AVX512_STATEX86_PAGEIN_STATEX86_THREAD_FULL_STATE64X86_INSTRUCTION_STATEX86_LAST_BRANCH_STATE" 176 | ) 177 | 178 | var ( 179 | _X86ThreadFlavor_index_0 = [...]uint8{0, 18, 35, 56, 74, 91, 112, 128, 143, 162, 179, 196, 211, 232} 180 | _X86ThreadFlavor_index_1 = [...]uint8{0, 15, 30, 43, 61, 79, 95, 111, 134, 155, 176} 181 | ) 182 | 183 | func (i X86ThreadFlavor) String() string { 184 | switch { 185 | case 1 <= i && i <= 13: 186 | i -= 1 187 | return _X86ThreadFlavor_name_0[_X86ThreadFlavor_index_0[i]:_X86ThreadFlavor_index_0[i+1]] 188 | case 16 <= i && i <= 25: 189 | i -= 16 190 | return _X86ThreadFlavor_name_1[_X86ThreadFlavor_index_1[i]:_X86ThreadFlavor_index_1[i+1]] 191 | default: 192 | return "X86ThreadFlavor(" + strconv.FormatInt(int64(i), 10) + ")" 193 | } 194 | } 195 | func _() { 196 | // An "invalid array index" compiler error signifies that the constant values have changed. 197 | // Re-run the stringer command to generate them again. 198 | var x [1]struct{} 199 | _ = x[ARM_THREAD_STATE-1] 200 | _ = x[ARM_UNIFIED_THREAD_STATE-1] 201 | _ = x[ARM_VFP_STATE-2] 202 | _ = x[ARM_EXCEPTION_STATE-3] 203 | _ = x[ARM_DEBUG_STATE-4] 204 | _ = x[ARM_THREAD_STATE_NONE-5] 205 | _ = x[ARM_THREAD_STATE64-6] 206 | _ = x[ARM_EXCEPTION_STATE64-7] 207 | _ = x[ARM_THREAD_STATE32-9] 208 | _ = x[ARM_DEBUG_STATE32-14] 209 | _ = x[ARM_DEBUG_STATE64-15] 210 | _ = x[ARM_NEON_STATE-16] 211 | _ = x[ARM_NEON_STATE64-17] 212 | _ = x[ARM_CPMU_STATE64-18] 213 | _ = x[ARM_PAGEIN_STATE-27] 214 | } 215 | 216 | const ( 217 | _ArmThreadFlavor_name_0 = "ARM_THREAD_STATEARM_VFP_STATEARM_EXCEPTION_STATEARM_DEBUG_STATEARM_THREAD_STATE_NONEARM_THREAD_STATE64ARM_EXCEPTION_STATE64" 218 | _ArmThreadFlavor_name_1 = "ARM_THREAD_STATE32" 219 | _ArmThreadFlavor_name_2 = "ARM_DEBUG_STATE32ARM_DEBUG_STATE64ARM_NEON_STATEARM_NEON_STATE64ARM_CPMU_STATE64" 220 | _ArmThreadFlavor_name_3 = "ARM_PAGEIN_STATE" 221 | ) 222 | 223 | var ( 224 | _ArmThreadFlavor_index_0 = [...]uint8{0, 16, 29, 48, 63, 84, 102, 123} 225 | _ArmThreadFlavor_index_2 = [...]uint8{0, 17, 34, 48, 64, 80} 226 | ) 227 | 228 | func (i ArmThreadFlavor) String() string { 229 | switch { 230 | case 1 <= i && i <= 7: 231 | i -= 1 232 | return _ArmThreadFlavor_name_0[_ArmThreadFlavor_index_0[i]:_ArmThreadFlavor_index_0[i+1]] 233 | case i == 9: 234 | return _ArmThreadFlavor_name_1 235 | case 14 <= i && i <= 18: 236 | i -= 14 237 | return _ArmThreadFlavor_name_2[_ArmThreadFlavor_index_2[i]:_ArmThreadFlavor_index_2[i+1]] 238 | case i == 27: 239 | return _ArmThreadFlavor_name_3 240 | default: 241 | return "ArmThreadFlavor(" + strconv.FormatInt(int64(i), 10) + ")" 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /types/cpu.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "fmt" 4 | 5 | // A CPU is a Mach-O cpu type. 6 | type CPU uint32 7 | 8 | const ( 9 | cpuArchMask = 0xff000000 // mask for architecture bits 10 | cpuArch64 = 0x01000000 // 64 bit ABI 11 | cpuArch6432 = 0x02000000 // ABI for 64-bit hardware with 32-bit types; LP32 12 | ) 13 | 14 | const ( 15 | CPUVax CPU = 1 16 | CPUMC680x0 CPU = 6 17 | CPUX86 CPU = 7 18 | CPUI386 CPU = CPUX86 /* compatibility */ 19 | CPUAmd64 CPU = CPUX86 | cpuArch64 20 | CPUMips CPU = 8 21 | CPUMc98000 CPU = 10 22 | CPUHppa CPU = 11 23 | CPUArm CPU = 12 24 | CPUArm64 CPU = CPUArm | cpuArch64 25 | CPUArm6432 CPU = CPUArm | cpuArch6432 26 | CPUMc88000 CPU = 13 27 | CPUSparc CPU = 14 28 | CPUI860 CPU = 15 29 | CPUPpc CPU = 18 30 | CPUPpc64 CPU = CPUPpc | cpuArch64 31 | ) 32 | 33 | var cpuStrings = []IntName{ 34 | {uint32(CPUVax), "VAX"}, 35 | {uint32(CPUMC680x0), "MC680x0"}, 36 | {uint32(CPUI386), "i386"}, 37 | {uint32(CPUAmd64), "Amd64"}, 38 | {uint32(CPUMips), "MIPS"}, 39 | {uint32(CPUMc98000), "MC98000"}, 40 | {uint32(CPUHppa), "HPPA"}, 41 | {uint32(CPUArm), "ARM"}, 42 | {uint32(CPUArm64), "AARCH64"}, 43 | {uint32(CPUArm6432), "ARM64_32"}, 44 | {uint32(CPUMc88000), "MC88000"}, 45 | {uint32(CPUSparc), "SPARC"}, 46 | {uint32(CPUI860), "i860"}, 47 | {uint32(CPUPpc), "PowerPC"}, 48 | {uint32(CPUPpc64), "PowerPC 64"}, 49 | } 50 | 51 | func (i CPU) String() string { return StringName(uint32(i), cpuStrings, false) } 52 | func (i CPU) GoString() string { return StringName(uint32(i), cpuStrings, true) } 53 | 54 | type CPUSubtype uint32 55 | 56 | // VAX subtypes 57 | const ( 58 | CPUSubtypeVaxAll CPUSubtype = 0 59 | CPUSubtypeVax780 CPUSubtype = 1 60 | CPUSubtypeVax785 CPUSubtype = 2 61 | CPUSubtypeVax750 CPUSubtype = 3 62 | CPUSubtypeVax730 CPUSubtype = 4 63 | CPUSubtypeUVaxI CPUSubtype = 5 64 | CPUSubtypeUVaxII CPUSubtype = 6 65 | CPUSubtypeVax8200 CPUSubtype = 7 66 | CPUSubtypeVax8500 CPUSubtype = 8 67 | CPUSubtypeVax8600 CPUSubtype = 9 68 | CPUSubtypeVax8650 CPUSubtype = 10 69 | CPUSubtypeVax8800 CPUSubtype = 11 70 | CPUSubtypeUVaxIII CPUSubtype = 12 71 | ) 72 | 73 | // 680x0 subtypes 74 | const ( 75 | CPUSubtypeMC680x0All CPUSubtype = 1 76 | CPUSubtypeMC68030 CPUSubtype = 1 77 | CPUSubtypeMC68040 CPUSubtype = 2 78 | CPUSubtypeMC68030Only CPUSubtype = 3 79 | ) 80 | 81 | // I386 subtypes 82 | const ( 83 | CPUSubtypeI386All CPUSubtype = 3 + 0<<4 84 | CPUSubtypeI386386 CPUSubtype = 3 + 0<<4 85 | CPUSubtypeI386486 CPUSubtype = 4 + 0<<4 86 | CPUSubtypeI386486SX CPUSubtype = 4 + 8<<4 87 | CPUSubtypeI386586 CPUSubtype = 5 + 0<<4 88 | CPUSubtypeI386Pent CPUSubtype = 5 + 0<<4 89 | CPUSubtypeI386PentPro CPUSubtype = 6 + 1<<4 90 | CPUSubtypeI386PentIIM3 CPUSubtype = 6 + 3<<4 91 | CPUSubtypeI386PentIIM5 CPUSubtype = 6 + 5<<4 92 | CPUSubtypeI386Celeron CPUSubtype = 7 + 6<<4 93 | CPUSubtypeI386CeleronMobile CPUSubtype = 7 + 7<<4 94 | CPUSubtypeI386Pentium3 CPUSubtype = 8 + 0<<4 95 | CPUSubtypeI386Pentium3M CPUSubtype = 8 + 1<<4 96 | CPUSubtypeI386Pentium3Xeon CPUSubtype = 8 + 2<<4 97 | CPUSubtypeI386PentiumM CPUSubtype = 9 + 0<<4 98 | CPUSubtypeI386Pentium4 CPUSubtype = 10 + 0<<4 99 | CPUSubtypeI386Pentium4M CPUSubtype = 10 + 1<<4 100 | CPUSubtypeI386Itanium CPUSubtype = 11 + 0<<4 101 | CPUSubtypeI386Itanium2 CPUSubtype = 11 + 1<<4 102 | CPUSubtypeI386Xeon CPUSubtype = 12 + 0<<4 103 | CPUSubtypeI386XeonMP CPUSubtype = 12 + 1<<4 104 | ) 105 | 106 | // X86 subtypes 107 | const ( 108 | CPUSubtypeX86All CPUSubtype = 3 109 | CPUSubtypeX8664All CPUSubtype = 3 110 | CPUSubtypeX86Arch1 CPUSubtype = 4 111 | CPUSubtypeX86_64H CPUSubtype = 8 112 | ) 113 | 114 | // Mips subtypes. 115 | const ( 116 | CPUSubtypeMipsAll CPUSubtype = 0 117 | CPUSubtypeMipsR2300 CPUSubtype = 1 118 | CPUSubtypeMipsR2600 CPUSubtype = 2 119 | CPUSubtypeMipsR2800 CPUSubtype = 3 120 | CPUSubtypeMipsR2000a CPUSubtype = 4 // pmax 121 | CPUSubtypeMipsR2000 CPUSubtype = 5 122 | CPUSubtypeMipsR3000a CPUSubtype = 6 // 3max 123 | CPUSubtypeMipsR3000 CPUSubtype = 7 124 | ) 125 | 126 | // MC98000 (PowerPC) subtypes 127 | const ( 128 | CPUSubtypeMc98000All CPUSubtype = 0 129 | CPUSubtypeMc98601 CPUSubtype = 1 130 | ) 131 | 132 | // HPPA subtypes for Hewlett-Packard HP-PA family of risc processors. Port by NeXT to 700 series. 133 | const ( 134 | CPUSubtypeHppaAll CPUSubtype = 0 135 | CPUSubtypeHppa7100 CPUSubtype = 0 // compat 136 | CPUSubtypeHppa7100LC CPUSubtype = 1 137 | ) 138 | 139 | // MC88000 subtypes 140 | const ( 141 | CPUSubtypeMc88000All CPUSubtype = 0 142 | CPUSubtypeMc88100 CPUSubtype = 1 143 | CPUSubtypeMc88110 CPUSubtype = 2 144 | ) 145 | 146 | // SPARC subtypes 147 | const ( 148 | CPUSubtypeSparcAll CPUSubtype = 0 149 | ) 150 | 151 | // I860 subtypes 152 | const ( 153 | CPUSubtypeI860All CPUSubtype = 0 154 | CPUSubtypeI860_860 CPUSubtype = 1 155 | ) 156 | 157 | // PowerPC subtypes 158 | const ( 159 | CPUSubtypePowerPCAll CPUSubtype = 0 160 | CPUSubtypePowerPC601 CPUSubtype = 1 161 | CPUSubtypePowerPC602 CPUSubtype = 2 162 | CPUSubtypePowerPC603 CPUSubtype = 3 163 | CPUSubtypePowerPC603e CPUSubtype = 4 164 | CPUSubtypePowerPC603ev CPUSubtype = 5 165 | CPUSubtypePowerPC604 CPUSubtype = 6 166 | CPUSubtypePowerPC604e CPUSubtype = 7 167 | CPUSubtypePowerPC620 CPUSubtype = 8 168 | CPUSubtypePowerPC750 CPUSubtype = 9 169 | CPUSubtypePowerPC7400 CPUSubtype = 10 170 | CPUSubtypePowerPC7450 CPUSubtype = 11 171 | CPUSubtypePowerPC970 CPUSubtype = 100 172 | ) 173 | 174 | // ARM subtypes 175 | const ( 176 | CPUSubtypeArmAll CPUSubtype = 0 177 | CPUSubtypeArmV4T CPUSubtype = 5 178 | CPUSubtypeArmV6 CPUSubtype = 6 179 | CPUSubtypeArmV5Tej CPUSubtype = 7 180 | CPUSubtypeArmXscale CPUSubtype = 8 181 | CPUSubtypeArmV7 CPUSubtype = 9 182 | CPUSubtypeArmV7F CPUSubtype = 10 183 | CPUSubtypeArmV7S CPUSubtype = 11 184 | CPUSubtypeArmV7K CPUSubtype = 12 185 | CPUSubtypeArmV8 CPUSubtype = 13 186 | CPUSubtypeArmV6M CPUSubtype = 14 187 | CPUSubtypeArmV7M CPUSubtype = 15 188 | CPUSubtypeArmV7Em CPUSubtype = 16 189 | CPUSubtypeArmV8M CPUSubtype = 17 190 | ) 191 | 192 | // ARM64 subtypes 193 | const ( 194 | CPUSubtypeArm64All CPUSubtype = 0 195 | CPUSubtypeArm64V8 CPUSubtype = 1 196 | CPUSubtypeArm64E CPUSubtype = 2 197 | ) 198 | 199 | // ARM64_32 subtypes 200 | const ( 201 | CPUSubtypeArm6432All CPUSubtype = 0 202 | CPUSubtypeArm6432V8 CPUSubtype = 1 203 | ) 204 | 205 | const ( 206 | /* Capability bits used in the definition of cpu_subtype. */ 207 | CpuSubtypeFeatureMask CPUSubtype = 0xff000000 /* mask for feature flags */ 208 | CpuSubtypeMask = CPUSubtype(^CpuSubtypeFeatureMask) /* mask for cpu subtype */ 209 | CpuSubtypeLib64 = 0x80000000 /* 64 bit libraries */ 210 | /* CPU subtype capability flags for ptrauth on arm64e platforms */ 211 | CpuSubtypeArm64PtrAuthMask = 0x0f000000 212 | /* CPU subtype capability flags for ptrauth on arm64e platforms, take 2 */ 213 | CpuSubtypeArm64eVersionedAbiMask = 0x80000000 214 | CpuSubtypeArm64eKernelAbiMask = 0x40000000 215 | CpuSubtypeArm64ePtrAuthMask = 0x3f000000 216 | /* 217 | * When selecting a slice, ANY will pick the slice with the best 218 | * grading for the selected cpu_type_t, unlike the "ALL" subtypes, 219 | * which are the slices that can run on any hardware for that cpu type. 220 | */ 221 | CpuSubtypeAny = -1 222 | ) 223 | 224 | var cpuSubtypeX86Strings = []IntName{ 225 | // {uint32(CPUSubtypeX86All), "x86"}, 226 | {uint32(CPUSubtypeX8664All), "x86_64"}, 227 | {uint32(CPUSubtypeX86Arch1), "x86 Arch1"}, 228 | {uint32(CPUSubtypeX86_64H), "x86_64 (Haswell)"}, 229 | } 230 | var cpuSubtypeArmStrings = []IntName{ 231 | {uint32(CPUSubtypeArmAll), "ARM"}, 232 | {uint32(CPUSubtypeArmV4T), "v4t"}, 233 | {uint32(CPUSubtypeArmV6), "v6"}, 234 | {uint32(CPUSubtypeArmV5Tej), "v5tej"}, 235 | {uint32(CPUSubtypeArmXscale), "XScale"}, 236 | {uint32(CPUSubtypeArmV7), "v7"}, 237 | {uint32(CPUSubtypeArmV7F), "v7f"}, 238 | {uint32(CPUSubtypeArmV7S), "v7s"}, 239 | {uint32(CPUSubtypeArmV7K), "v7k"}, 240 | {uint32(CPUSubtypeArmV8), "v8"}, 241 | {uint32(CPUSubtypeArmV6M), "v6m"}, 242 | {uint32(CPUSubtypeArmV7M), "v7m"}, 243 | {uint32(CPUSubtypeArmV7Em), "v7em"}, 244 | {uint32(CPUSubtypeArmV8M), "v8m"}, 245 | } 246 | var cpuSubtypeArm64Strings = []IntName{ 247 | {uint32(CPUSubtypeArm64All), "ARM64"}, 248 | {uint32(CPUSubtypeArm64V8), "v8"}, 249 | {uint32(CPUSubtypeArm64E), "ARM64e"}, 250 | {uint32(CPUSubtypeArm6432All), "ARM64_32"}, 251 | {uint32(CPUSubtypeArm6432V8), "v8"}, 252 | } 253 | 254 | func (st CPUSubtype) Capabilities(cpu CPU) string { 255 | switch cpu { 256 | case CPUArm64: 257 | caps := st & CpuSubtypeFeatureMask 258 | if caps > 0 { 259 | if (st & CpuSubtypeMask) == CpuSubtypeLib64 { // lib64 260 | return "LIB64" 261 | } else if (st & CpuSubtypeMask) == CPUSubtypeArm64E { // arm64e 262 | if (caps & CpuSubtypeArm64eKernelAbiMask) == 0 { 263 | return fmt.Sprintf("USR%02d", ((caps & CpuSubtypeArm64ePtrAuthMask) >> 24)) 264 | } 265 | return fmt.Sprintf("KER%02d", ((caps & CpuSubtypeArm64ePtrAuthMask) >> 24)) 266 | } else { // arm64 (v8/all) 267 | if (caps & CpuSubtypeArm64eKernelAbiMask) == 0 { 268 | return fmt.Sprintf("USR%02d", ((caps & CpuSubtypeArm64PtrAuthMask) >> 24)) 269 | } 270 | return fmt.Sprintf("KER%02d", ((caps & CpuSubtypeArm64PtrAuthMask) >> 24)) 271 | } 272 | } 273 | } 274 | return "" 275 | } 276 | 277 | func (st CPUSubtype) String(cpu CPU) string { 278 | switch cpu { 279 | case CPUI386: 280 | fallthrough 281 | case CPUAmd64: 282 | return StringName(uint32(st&CpuSubtypeMask), cpuSubtypeX86Strings, false) 283 | case CPUArm: 284 | return StringName(uint32(st&CpuSubtypeMask), cpuSubtypeArmStrings, false) 285 | case CPUArm64: 286 | return StringName(uint32(st&CpuSubtypeMask), cpuSubtypeArm64Strings, false) 287 | case CPUArm6432: 288 | return StringName(uint32(st&CpuSubtypeMask), cpuSubtypeArm64Strings, false) 289 | } 290 | return "UNKNOWN" 291 | } 292 | 293 | func (st CPUSubtype) GoString(cpu CPU) string { 294 | switch cpu { 295 | case CPUI386: 296 | fallthrough 297 | case CPUAmd64: 298 | return StringName(uint32(st&CpuSubtypeMask), cpuSubtypeX86Strings, true) 299 | case CPUArm: 300 | return StringName(uint32(st&CpuSubtypeMask), cpuSubtypeArmStrings, true) 301 | case CPUArm64: 302 | return StringName(uint32(st&CpuSubtypeMask), cpuSubtypeArm64Strings, true) 303 | case CPUArm6432: 304 | return StringName(uint32(st&CpuSubtypeMask), cpuSubtypeArm64Strings, true) 305 | } 306 | return "UNKNOWN" 307 | } 308 | -------------------------------------------------------------------------------- /types/flags.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | const ( 9 | /* The following are used to encode rebasing information */ 10 | REBASE_TYPE_POINTER = 1 11 | REBASE_TYPE_TEXT_ABSOLUTE32 = 2 12 | REBASE_TYPE_TEXT_PCREL32 = 3 13 | REBASE_OPCODE_MASK = 0xF0 14 | REBASE_IMMEDIATE_MASK = 0x0F 15 | REBASE_OPCODE_DONE = 0x00 16 | REBASE_OPCODE_SET_TYPE_IMM = 0x10 17 | REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x20 18 | REBASE_OPCODE_ADD_ADDR_ULEB = 0x30 19 | REBASE_OPCODE_ADD_ADDR_IMM_SCALED = 0x40 20 | REBASE_OPCODE_DO_REBASE_IMM_TIMES = 0x50 21 | REBASE_OPCODE_DO_REBASE_ULEB_TIMES = 0x60 22 | REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB = 0x70 23 | REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80 24 | ) 25 | 26 | type Rebase struct { 27 | Type uint8 28 | Segment string 29 | Section string 30 | Start uint64 31 | Offset uint64 32 | Value uint64 33 | } 34 | 35 | func (r Rebase) String() string { 36 | return fmt.Sprintf( 37 | "%-7s %-16s\t%#x %s %#x", 38 | r.Segment, 39 | r.Section, 40 | r.Start+r.Offset, 41 | getBindType(r.Type), 42 | r.Value, 43 | ) 44 | } 45 | 46 | const ( 47 | /* The following are used to encode binding information */ 48 | BIND_TYPE_POINTER = 1 49 | BIND_TYPE_TEXT_ABSOLUTE32 = 2 50 | BIND_TYPE_TEXT_PCREL32 = 3 51 | BIND_TYPE_THREADED_BIND = 100 52 | BIND_TYPE_THREADED_REBASE = 102 53 | BIND_SPECIAL_DYLIB_SELF = 0 54 | BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1 55 | BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2 56 | BIND_SPECIAL_DYLIB_WEAK_LOOKUP = -3 57 | BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1 58 | BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8 59 | BIND_OPCODE_MASK = 0xF0 60 | BIND_IMMEDIATE_MASK = 0x0F 61 | BIND_OPCODE_DONE = 0x00 62 | BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10 63 | BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20 64 | BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30 65 | BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40 66 | BIND_OPCODE_SET_TYPE_IMM = 0x50 67 | BIND_OPCODE_SET_ADDEND_SLEB = 0x60 68 | BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70 69 | BIND_OPCODE_ADD_ADDR_ULEB = 0x80 70 | BIND_OPCODE_DO_BIND = 0x90 71 | BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0 72 | BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0 73 | BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0 74 | BIND_OPCODE_THREADED = 0xD0 75 | BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00 76 | BIND_SUBOPCODE_THREADED_APPLY = 0x01 77 | ) 78 | 79 | type BindKind uint8 80 | 81 | const ( 82 | BIND_KIND BindKind = iota 83 | WEAK_KIND 84 | LAZY_KIND 85 | ) 86 | 87 | func (k BindKind) String() string { 88 | switch k { 89 | case BIND_KIND: 90 | return "BIND" 91 | case WEAK_KIND: 92 | return "WEAK" 93 | case LAZY_KIND: 94 | return "LAZY" 95 | } 96 | return "" 97 | } 98 | 99 | type Binds []Bind 100 | 101 | func (bs Binds) Search(name string) (*Bind, error) { 102 | for _, b := range bs { 103 | if b.Name == name { 104 | return &b, nil 105 | } 106 | } 107 | return nil, fmt.Errorf("%s not found in bind info", name) 108 | } 109 | 110 | type Bind struct { 111 | Name string 112 | Type uint8 113 | Kind BindKind 114 | Flags uint8 115 | Addend int64 116 | Segment string 117 | SegStart uint64 118 | SegOffset uint64 119 | Section string 120 | Start uint64 121 | Dylib string 122 | Value uint64 123 | } 124 | 125 | func (b Bind) Offset() uint64 { 126 | return b.SegStart + b.SegOffset 127 | } 128 | func (b Bind) String() string { 129 | return fmt.Sprintf( 130 | "%-7s %-16s %#x %-4s %-10s %5d %-25s\t%s%s", 131 | b.Segment, 132 | b.Section, 133 | b.Start+b.SegOffset, 134 | b.Kind, 135 | getBindType(b.Type), 136 | b.Addend, 137 | b.Dylib, 138 | b.Name, 139 | getBindFlag(b.Flags, b.Kind), 140 | ) 141 | } 142 | 143 | func getBindType(t uint8) string { 144 | switch t { 145 | case 0: 146 | return "" 147 | case BIND_TYPE_POINTER: 148 | return "pointer" 149 | case BIND_TYPE_TEXT_ABSOLUTE32: 150 | return "text abs32" 151 | case BIND_TYPE_TEXT_PCREL32: 152 | return "text rel32" 153 | case BIND_TYPE_THREADED_BIND: 154 | return "BIND_TYPE_THREADED_BIND" 155 | case BIND_TYPE_THREADED_REBASE: 156 | return "BIND_TYPE_THREADED_REBASE" 157 | } 158 | return fmt.Sprintf(" bad bind type %#02x", t) 159 | } 160 | func getBindFlag(f uint8, k BindKind) string { 161 | if f&BIND_SYMBOL_FLAGS_WEAK_IMPORT != 0 { 162 | return " (weak import)" 163 | } else if f&BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION != 0 { 164 | if k == WEAK_KIND { 165 | return " (strong)" 166 | } else { 167 | return "" 168 | } 169 | } else if f == 0 { 170 | return "" 171 | } 172 | 173 | return fmt.Sprintf("bad bind flag %#02x", f) 174 | } 175 | 176 | type SplitInfoKind uint64 177 | 178 | const ( 179 | DYLD_CACHE_ADJ_V2_FORMAT = 0x7F 180 | 181 | DYLD_CACHE_ADJ_V2_POINTER_32 SplitInfoKind = 0x01 182 | DYLD_CACHE_ADJ_V2_POINTER_64 SplitInfoKind = 0x02 183 | DYLD_CACHE_ADJ_V2_DELTA_32 SplitInfoKind = 0x03 184 | DYLD_CACHE_ADJ_V2_DELTA_64 SplitInfoKind = 0x04 185 | DYLD_CACHE_ADJ_V2_ARM64_ADRP SplitInfoKind = 0x05 186 | DYLD_CACHE_ADJ_V2_ARM64_OFF12 SplitInfoKind = 0x06 187 | DYLD_CACHE_ADJ_V2_ARM64_BR26 SplitInfoKind = 0x07 188 | DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT SplitInfoKind = 0x08 189 | DYLD_CACHE_ADJ_V2_ARM_BR24 SplitInfoKind = 0x09 190 | DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT SplitInfoKind = 0x0A 191 | DYLD_CACHE_ADJ_V2_THUMB_BR22 SplitInfoKind = 0x0B 192 | DYLD_CACHE_ADJ_V2_IMAGE_OFF_32 SplitInfoKind = 0x0C 193 | DYLD_CACHE_ADJ_V2_THREADED_POINTER_64 SplitInfoKind = 0x0D 194 | ) 195 | 196 | func (k SplitInfoKind) String() string { 197 | switch k { 198 | case DYLD_CACHE_ADJ_V2_POINTER_32: 199 | return "pointer_32" 200 | case DYLD_CACHE_ADJ_V2_POINTER_64: 201 | return "pointer_64" 202 | case DYLD_CACHE_ADJ_V2_DELTA_32: 203 | return "delta_32" 204 | case DYLD_CACHE_ADJ_V2_DELTA_64: 205 | return "delta_64" 206 | case DYLD_CACHE_ADJ_V2_ARM64_ADRP: 207 | return "arm64_adrp" 208 | case DYLD_CACHE_ADJ_V2_ARM64_OFF12: 209 | return "arm64_off_12" 210 | case DYLD_CACHE_ADJ_V2_ARM64_BR26: 211 | return "arm64_br_26" 212 | case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT: 213 | return "arm_movw_movt" 214 | case DYLD_CACHE_ADJ_V2_ARM_BR24: 215 | return "arm_br_24" 216 | case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT: 217 | return "thumb_movw_movt" 218 | case DYLD_CACHE_ADJ_V2_THUMB_BR22: 219 | return "thumb_br_22" 220 | case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32: 221 | return "image_off_32" 222 | case DYLD_CACHE_ADJ_V2_THREADED_POINTER_64: 223 | return "threaded_pointer_64" 224 | default: 225 | return fmt.Sprintf("unknown kind %#02x", k) 226 | } 227 | 228 | } 229 | 230 | type ExportFlag int 231 | 232 | const ( 233 | /* 234 | * The following are used on the flags byte of a terminal node 235 | * in the export information. 236 | */ 237 | EXPORT_SYMBOL_FLAGS_KIND_MASK ExportFlag = 0x03 238 | EXPORT_SYMBOL_FLAGS_KIND_REGULAR ExportFlag = 0x00 239 | EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL ExportFlag = 0x01 240 | EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE ExportFlag = 0x02 241 | EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION ExportFlag = 0x04 242 | EXPORT_SYMBOL_FLAGS_REEXPORT ExportFlag = 0x08 243 | EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ExportFlag = 0x10 244 | EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER ExportFlag = 0x20 245 | ) 246 | 247 | func (f ExportFlag) Regular() bool { 248 | return (f & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR 249 | } 250 | func (f ExportFlag) ThreadLocal() bool { 251 | return (f & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL 252 | } 253 | func (f ExportFlag) Absolute() bool { 254 | return (f & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 255 | } 256 | func (f ExportFlag) WeakDefinition() bool { 257 | return f == EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 258 | } 259 | func (f ExportFlag) ReExport() bool { 260 | return f == EXPORT_SYMBOL_FLAGS_REEXPORT 261 | } 262 | func (f ExportFlag) StubAndResolver() bool { 263 | return f == EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER 264 | } 265 | func (f ExportFlag) StaticResolver() bool { 266 | return f == EXPORT_SYMBOL_FLAGS_STATIC_RESOLVER 267 | } 268 | 269 | func (f ExportFlag) String() string { 270 | var fStr string 271 | if f.Regular() { 272 | fStr += "regular" 273 | if f.StubAndResolver() { 274 | fStr += "|has_resolver" 275 | } else if f.StaticResolver() { 276 | fStr += "|static_resolver" 277 | } else if f.WeakDefinition() { 278 | fStr += "|weak_def" 279 | } 280 | } else if f.ThreadLocal() { 281 | fStr += "per-thread" 282 | } else if f.Absolute() { 283 | fStr += "absolute" 284 | } else if f.ReExport() { 285 | fStr += "[re-export]" 286 | } 287 | return strings.TrimSpace(fStr) 288 | } 289 | -------------------------------------------------------------------------------- /types/header_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=HeaderFileType -trimprefix=MH_ -output header_string.go"; DO NOT EDIT. 2 | 3 | package types 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[MH_OBJECT-1] 12 | _ = x[MH_EXECUTE-2] 13 | _ = x[MH_FVMLIB-3] 14 | _ = x[MH_CORE-4] 15 | _ = x[MH_PRELOAD-5] 16 | _ = x[MH_DYLIB-6] 17 | _ = x[MH_DYLINKER-7] 18 | _ = x[MH_BUNDLE-8] 19 | _ = x[MH_DYLIB_STUB-9] 20 | _ = x[MH_DSYM-10] 21 | _ = x[MH_KEXT_BUNDLE-11] 22 | _ = x[MH_FILESET-12] 23 | _ = x[MH_GPU_EXECUTE-13] 24 | _ = x[MH_GPU_DYLIB-14] 25 | } 26 | 27 | const _HeaderFileType_name = "OBJECTEXECUTEFVMLIBCOREPRELOADDYLIBDYLINKERBUNDLEDYLIB_STUBDSYMKEXT_BUNDLEFILESETGPU_EXECUTEGPU_DYLIB" 28 | 29 | var _HeaderFileType_index = [...]uint8{0, 6, 13, 19, 23, 30, 35, 43, 49, 59, 63, 74, 81, 92, 101} 30 | 31 | func (i HeaderFileType) String() string { 32 | i -= 1 33 | if i >= HeaderFileType(len(_HeaderFileType_index)-1) { 34 | return "HeaderFileType(" + strconv.FormatInt(int64(i+1), 10) + ")" 35 | } 36 | return _HeaderFileType_name[_HeaderFileType_index[i]:_HeaderFileType_index[i+1]] 37 | } 38 | -------------------------------------------------------------------------------- /types/objc/category.go: -------------------------------------------------------------------------------- 1 | package objc 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | type CategoryT struct { 10 | NameVMAddr uint64 11 | ClsVMAddr uint64 12 | InstanceMethodsVMAddr uint64 13 | ClassMethodsVMAddr uint64 14 | ProtocolsVMAddr uint64 15 | InstancePropertiesVMAddr uint64 16 | } 17 | 18 | // Category represents an Objective-C category. 19 | type Category struct { 20 | Name string 21 | VMAddr uint64 22 | Class *Class 23 | Protocols []Protocol 24 | ClassMethods []Method 25 | InstanceMethods []Method 26 | Properties []Property 27 | CategoryT 28 | } 29 | 30 | func (c *Category) dump(verbose, addrs bool) string { 31 | var cMethods string 32 | var iMethods string 33 | 34 | var protos string 35 | if len(c.Protocols) > 0 { 36 | var prots []string 37 | for _, prot := range c.Protocols { 38 | prots = append(prots, prot.Name) 39 | } 40 | protos += fmt.Sprintf(" <%s>", strings.Join(prots, ", ")) 41 | } 42 | 43 | var className string 44 | if c.Class != nil { 45 | className = c.Class.Name + " " 46 | } 47 | 48 | var cat string 49 | if verbose { 50 | var comment string 51 | if addrs { 52 | comment += fmt.Sprintf(" // %#x", c.VMAddr) 53 | } 54 | if c.Class != nil && c.Class.IsSwift() { 55 | if len(comment) > 0 { 56 | comment += " (Swift)" 57 | } else { 58 | comment += " // (Swift)" 59 | } 60 | } 61 | cat = fmt.Sprintf("@interface %s(%s)%s%s", className, c.Name, protos, comment) 62 | } else { 63 | cat = fmt.Sprintf("@interface %s(%s)%s", className, c.Name, protos) 64 | } 65 | cat += "\n" 66 | 67 | if len(c.ClassMethods) > 0 { 68 | s := bytes.NewBufferString("/* class methods */\n") 69 | for _, meth := range c.ClassMethods { 70 | if !addrs && strings.HasPrefix(meth.Name, ".cxx_") { 71 | continue 72 | } 73 | if verbose { 74 | rtype, args := decodeMethodTypes(meth.Types) 75 | if addrs { 76 | s.WriteString(fmt.Sprintf("// %#x\n", meth.ImpVMAddr)) 77 | } 78 | s.WriteString(fmt.Sprintf("+ %s\n", getMethodWithArgs(meth.Name, rtype, args))) 79 | } else { 80 | s.WriteString(fmt.Sprintf("-[%s %s];\n", c.Name, meth.Name)) 81 | } 82 | } 83 | cMethods = s.String() 84 | if cMethods != "" { 85 | cMethods += "\n" 86 | } 87 | } 88 | if len(c.InstanceMethods) > 0 { 89 | s := bytes.NewBufferString("/* instance methods */\n") 90 | for _, meth := range c.InstanceMethods { 91 | if !addrs && strings.HasPrefix(meth.Name, ".cxx_") { 92 | continue 93 | } 94 | if verbose { 95 | rtype, args := decodeMethodTypes(meth.Types) 96 | if addrs { 97 | s.WriteString(fmt.Sprintf("// %#x\n", meth.ImpVMAddr)) 98 | } 99 | s.WriteString(fmt.Sprintf("- %s\n", getMethodWithArgs(meth.Name, rtype, args))) 100 | } else { 101 | s.WriteString(fmt.Sprintf("-[%s %s];\n", c.Name, meth.Name)) 102 | } 103 | } 104 | iMethods = s.String() 105 | if iMethods != "" { 106 | iMethods += "\n" 107 | } 108 | } 109 | 110 | return fmt.Sprintf( 111 | "%s\n"+ 112 | "%s"+ 113 | "%s"+ 114 | "@end\n", 115 | cat, 116 | cMethods, 117 | iMethods, 118 | ) 119 | } 120 | 121 | func (c *Category) String() string { 122 | return c.dump(false, false) 123 | } 124 | 125 | func (c *Category) Verbose() string { 126 | return c.dump(true, false) 127 | } 128 | 129 | func (c *Category) WithAddrs() string { 130 | return c.dump(true, true) 131 | } 132 | -------------------------------------------------------------------------------- /types/objc/class.go: -------------------------------------------------------------------------------- 1 | package objc 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | "text/tabwriter" 8 | ) 9 | 10 | type ObjcClassT struct { 11 | IsaVMAddr uint32 12 | SuperclassVMAddr uint32 13 | MethodCacheBuckets uint32 14 | MethodCacheProperties uint32 15 | DataVMAddrAndFastFlags uint32 16 | } 17 | 18 | type ObjcClass64 struct { 19 | IsaVMAddr uint64 20 | SuperclassVMAddr uint64 21 | MethodCacheBuckets uint64 22 | MethodCacheProperties uint64 23 | DataVMAddrAndFastFlags uint64 24 | } 25 | 26 | type SwiftClassMetadata struct { 27 | ObjcClassT 28 | SwiftClassFlags uint32 29 | } 30 | 31 | type SwiftClassMetadata64 struct { 32 | ObjcClass64 33 | SwiftClassFlags uint64 34 | } 35 | 36 | type ClassRoFlags uint32 37 | 38 | const ( 39 | // class is a metaclass 40 | RO_META ClassRoFlags = (1 << 0) 41 | // class is a root class 42 | RO_ROOT ClassRoFlags = (1 << 1) 43 | // class has .cxx_construct/destruct implementations 44 | RO_HAS_CXX_STRUCTORS ClassRoFlags = (1 << 2) 45 | // class has +load implementation 46 | RO_HAS_LOAD_METHOD ClassRoFlags = (1 << 3) 47 | // class has visibility=hidden set 48 | RO_HIDDEN ClassRoFlags = (1 << 4) 49 | // class has attributeClassRoFlags = (objc_exception): OBJC_EHTYPE_$_ThisClass is non-weak 50 | RO_EXCEPTION ClassRoFlags = (1 << 5) 51 | // class has ro field for Swift metadata initializer callback 52 | RO_HAS_SWIFT_INITIALIZER ClassRoFlags = (1 << 6) 53 | // class compiled with ARC 54 | RO_IS_ARC ClassRoFlags = (1 << 7) 55 | // class has .cxx_destruct but no .cxx_construct ClassRoFlags = (with RO_HAS_CXX_STRUCTORS) 56 | RO_HAS_CXX_DTOR_ONLY ClassRoFlags = (1 << 8) 57 | // class is not ARC but has ARC-style weak ivar layout 58 | RO_HAS_WEAK_WITHOUT_ARC ClassRoFlags = (1 << 9) 59 | // class does not allow associated objects on instances 60 | RO_FORBIDS_ASSOCIATED_OBJECTS ClassRoFlags = (1 << 10) 61 | 62 | // class is in an unloadable bundle - must never be set by compiler 63 | RO_FROM_BUNDLE ClassRoFlags = (1 << 29) 64 | // class is unrealized future class - must never be set by compiler 65 | RO_FUTURE ClassRoFlags = (1 << 30) 66 | // class is realized - must never be set by compiler 67 | RO_REALIZED ClassRoFlags = (1 << 31) 68 | ) 69 | 70 | func (f ClassRoFlags) IsMeta() bool { 71 | return (f & RO_META) != 0 72 | } 73 | func (f ClassRoFlags) IsRoot() bool { 74 | return (f & RO_ROOT) != 0 75 | } 76 | func (f ClassRoFlags) HasCxxStructors() bool { 77 | return (f & RO_HAS_CXX_STRUCTORS) != 0 78 | } 79 | func (f ClassRoFlags) HasFuture() bool { 80 | return (f & RO_FUTURE) != 0 81 | } 82 | func (f ClassRoFlags) String() string { 83 | var out []string 84 | if f.IsMeta() { 85 | out = append(out, "META") 86 | } 87 | if f.IsRoot() { 88 | out = append(out, "ROOT") 89 | } 90 | if f.HasCxxStructors() { 91 | out = append(out, "HAS_CXX_STRUCTORS") 92 | } 93 | if f.HasFuture() { 94 | out = append(out, "FUTURE") 95 | } 96 | return strings.Join(out, " | ") 97 | } 98 | 99 | type ClassRO struct { 100 | Flags ClassRoFlags 101 | InstanceStart uint32 102 | InstanceSize uint32 103 | _ uint32 104 | IvarLayoutVMAddr uint32 105 | NameVMAddr uint32 106 | BaseMethodsVMAddr uint32 107 | BaseProtocolsVMAddr uint32 108 | IvarsVMAddr uint32 109 | WeakIvarLayoutVMAddr uint32 110 | BasePropertiesVMAddr uint32 111 | } 112 | 113 | type ClassRO64 struct { 114 | Flags ClassRoFlags 115 | InstanceStart uint32 116 | InstanceSize uint64 117 | // _ uint32 118 | IvarLayoutVMAddr uint64 119 | NameVMAddr uint64 120 | BaseMethodsVMAddr uint64 121 | BaseProtocolsVMAddr uint64 122 | IvarsVMAddr uint64 123 | WeakIvarLayoutVMAddr uint64 124 | BasePropertiesVMAddr uint64 125 | } 126 | 127 | type Class struct { 128 | Name string 129 | SuperClass string 130 | Isa string 131 | InstanceMethods []Method 132 | ClassMethods []Method 133 | Ivars []Ivar 134 | Props []Property 135 | Protocols []Protocol 136 | ClassPtr uint64 137 | IsaVMAddr uint64 138 | SuperclassVMAddr uint64 139 | MethodCacheBuckets uint64 140 | MethodCacheProperties uint64 141 | DataVMAddr uint64 142 | IsSwiftLegacy bool 143 | IsSwiftStable bool 144 | ReadOnlyData ClassRO64 145 | } 146 | 147 | func (c *Class) dump(verbose, addrs bool) string { 148 | var iVars string 149 | var props string 150 | var cMethods string 151 | var iMethods string 152 | 153 | var subClass string 154 | if c.ReadOnlyData.Flags.IsRoot() { 155 | subClass = "" 156 | } else if len(c.SuperClass) > 0 { 157 | subClass = c.SuperClass 158 | } 159 | 160 | class := fmt.Sprintf("@interface %s : %s", c.Name, subClass) 161 | 162 | if len(c.Protocols) > 0 { 163 | var subProts []string 164 | for _, prot := range c.Protocols { 165 | subProts = append(subProts, prot.Name) 166 | } 167 | class += fmt.Sprintf(" <%s>", strings.Join(subProts, ", ")) 168 | } 169 | if len(c.Ivars) > 0 { 170 | class += fmt.Sprintf(" {") 171 | } 172 | if verbose { 173 | var comment string 174 | if addrs { 175 | comment += fmt.Sprintf(" // %#x", c.ClassPtr) 176 | } 177 | if c.IsSwift() { 178 | if len(comment) > 0 { 179 | comment += " (Swift)" 180 | } else { 181 | comment += " // (Swift)" 182 | } 183 | } 184 | class += comment 185 | } 186 | if len(c.Ivars) > 0 { 187 | s := bytes.NewBufferString("") 188 | w := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0) 189 | if addrs { 190 | fmt.Fprintf(w, "\n /* instance variables */\t// +size offset\n") 191 | } else { 192 | fmt.Fprintf(w, "\n /* instance variables */\n") 193 | } 194 | for _, ivar := range c.Ivars { 195 | if verbose { 196 | if addrs { 197 | fmt.Fprintf(w, " %s\n", ivar.WithAddrs()) 198 | } else { 199 | fmt.Fprintf(w, " %s\n", ivar.Verbose()) 200 | } 201 | } else { 202 | fmt.Fprintf(w, " %s\n", &ivar) 203 | } 204 | } 205 | w.Flush() 206 | s.WriteString("}") 207 | iVars = s.String() 208 | } 209 | if len(c.Props) > 0 { 210 | for _, prop := range c.Props { 211 | if verbose { 212 | attrs, _ := prop.Attributes() 213 | props += fmt.Sprintf("@property %s%s%s;\n", attrs, prop.Type(), prop.Name) 214 | } else { 215 | props += fmt.Sprintf("@property (%s) %s;\n", prop.EncodedAttributes, prop.Name) 216 | } 217 | } 218 | if props != "" { 219 | props += "\n" 220 | } 221 | } 222 | if len(c.ClassMethods) > 0 { 223 | s := bytes.NewBufferString("/* class methods */\n") 224 | w := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0) 225 | for _, meth := range c.ClassMethods { 226 | if !addrs && strings.HasPrefix(meth.Name, ".cxx_") { 227 | continue 228 | } 229 | if verbose { 230 | rtype, args := decodeMethodTypes(meth.Types) 231 | if addrs { 232 | s.WriteString(fmt.Sprintf("// %#x\n", meth.ImpVMAddr)) 233 | } 234 | s.WriteString(fmt.Sprintf("+ %s\n", getMethodWithArgs(meth.Name, rtype, args))) 235 | } else { 236 | s.WriteString(fmt.Sprintf("+[%s %s];\n", c.Name, meth.Name)) 237 | } 238 | } 239 | w.Flush() 240 | cMethods = s.String() 241 | if cMethods != "" { 242 | cMethods += "\n" 243 | } 244 | } 245 | if len(c.InstanceMethods) > 0 { 246 | s := bytes.NewBufferString("/* instance methods */\n") 247 | for _, meth := range c.InstanceMethods { 248 | if !addrs && strings.HasPrefix(meth.Name, ".cxx_") { 249 | continue 250 | } 251 | if verbose { 252 | rtype, args := decodeMethodTypes(meth.Types) 253 | if addrs { 254 | s.WriteString(fmt.Sprintf("// %#x\n", meth.ImpVMAddr)) 255 | } 256 | s.WriteString(fmt.Sprintf("- %s\n", getMethodWithArgs(meth.Name, rtype, args))) 257 | } else { 258 | s.WriteString(fmt.Sprintf("-[%s %s];\n", c.Name, meth.Name)) 259 | } 260 | } 261 | iMethods = s.String() 262 | if iMethods != "" { 263 | iMethods += "\n" 264 | } 265 | } 266 | 267 | return fmt.Sprintf( 268 | "%s"+ 269 | "%s\n\n"+ 270 | "%s"+ 271 | "%s"+ 272 | "%s"+ 273 | "@end\n", 274 | class, 275 | iVars, 276 | props, 277 | cMethods, 278 | iMethods, 279 | ) 280 | } 281 | 282 | // IsSwift returns true if the class is a Swift class. 283 | func (c *Class) IsSwift() bool { 284 | return c.IsSwiftLegacy || c.IsSwiftStable 285 | } 286 | func (c *Class) String() string { 287 | return c.dump(false, false) 288 | } 289 | func (c *Class) Verbose() string { 290 | return c.dump(true, false) 291 | } 292 | func (c *Class) WithAddrs() string { 293 | return c.dump(true, true) 294 | } 295 | -------------------------------------------------------------------------------- /types/objc/protocol.go: -------------------------------------------------------------------------------- 1 | package objc 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | const ( 9 | // Values for protocol_t->flags 10 | PROTOCOL_FIXED_UP_2 = (1 << 31) // must never be set by compiler 11 | PROTOCOL_FIXED_UP_1 = (1 << 30) // must never be set by compiler 12 | PROTOCOL_IS_CANONICAL = (1 << 29) // must never be set by compiler 13 | // Bits 0..15 are reserved for Swift's use. 14 | PROTOCOL_FIXED_UP_MASK = (PROTOCOL_FIXED_UP_1 | PROTOCOL_FIXED_UP_2) 15 | ) 16 | 17 | type ProtocolList struct { 18 | Count uint64 19 | Protocols []uint64 20 | } 21 | 22 | type ProtocolT struct { 23 | IsaVMAddr uint64 24 | NameVMAddr uint64 25 | ProtocolsVMAddr uint64 26 | InstanceMethodsVMAddr uint64 27 | ClassMethodsVMAddr uint64 28 | OptionalInstanceMethodsVMAddr uint64 29 | OptionalClassMethodsVMAddr uint64 30 | InstancePropertiesVMAddr uint64 31 | Size uint32 32 | Flags uint32 33 | // Fields below this point are not always present on disk. 34 | ExtendedMethodTypesVMAddr uint64 35 | DemangledNameVMAddr uint64 36 | ClassPropertiesVMAddr uint64 37 | } 38 | 39 | type Protocol struct { 40 | Name string 41 | Ptr uint64 42 | Isa *Class 43 | Prots []Protocol 44 | InstanceMethods []Method 45 | InstanceProperties []Property 46 | ClassMethods []Method 47 | OptionalInstanceMethods []Method 48 | OptionalClassMethods []Method 49 | ExtendedMethodTypes string 50 | DemangledName string 51 | ProtocolT 52 | } 53 | 54 | func (p *Protocol) dump(verbose, addrs bool) string { 55 | var props string 56 | var optProps string 57 | var cMethods string 58 | var iMethods string 59 | var optMethods string 60 | 61 | protocol := fmt.Sprintf("@protocol %s", p.Name) 62 | if len(p.Prots) > 0 { 63 | var subProts []string 64 | for _, prot := range p.Prots { 65 | subProts = append(subProts, prot.Name) 66 | } 67 | protocol += fmt.Sprintf(" <%s>", strings.Join(subProts, ", ")) 68 | } 69 | if addrs { 70 | protocol += fmt.Sprintf(" // %#x", p.Ptr) 71 | } 72 | if len(p.InstanceProperties) > 0 { 73 | for _, prop := range p.InstanceProperties { 74 | if verbose { 75 | if attrs, optional := prop.Attributes(); !optional { 76 | props += fmt.Sprintf("@property %s%s%s;\n", attrs, prop.Type(), prop.Name) 77 | } 78 | } else { 79 | props += fmt.Sprintf("@property (%s) %s;\n", prop.EncodedAttributes, prop.Name) 80 | } 81 | } 82 | if props != "" { 83 | props += "\n" 84 | } 85 | } 86 | if len(p.ClassMethods) > 0 { 87 | for _, meth := range p.ClassMethods { 88 | if verbose { 89 | rtype, args := decodeMethodTypes(meth.Types) 90 | cMethods += fmt.Sprintf("+ %s\n", getMethodWithArgs(meth.Name, rtype, args)) 91 | } else { 92 | cMethods += fmt.Sprintf("+[%s %s];\n", p.Name, meth.Name) 93 | } 94 | } 95 | if cMethods != "" { 96 | cMethods = "/* class methods */\n" + cMethods + "\n" 97 | } 98 | } 99 | if len(p.InstanceMethods) > 0 { 100 | for _, meth := range p.InstanceMethods { 101 | if verbose { 102 | rtype, args := decodeMethodTypes(meth.Types) 103 | iMethods += fmt.Sprintf("- %s\n", getMethodWithArgs(meth.Name, rtype, args)) 104 | } else { 105 | iMethods += fmt.Sprintf("-[%s %s];\n", p.Name, meth.Name) 106 | } 107 | } 108 | if iMethods != "" { 109 | iMethods = "/* required instance methods */\n" + iMethods + "\n" 110 | } 111 | } 112 | if len(p.InstanceProperties) > 0 { 113 | for _, prop := range p.InstanceProperties { 114 | if verbose { 115 | if attrs, optional := prop.Attributes(); optional { 116 | optProps += fmt.Sprintf("@property %s%s%s;\n", attrs, prop.Type(), prop.Name) 117 | } 118 | } else { 119 | // optProps += fmt.Sprintf("@property (%s) %s;\n", prop.EncodedAttributes, prop.Name) 120 | } 121 | } 122 | if optProps != "" { 123 | optProps += "\n" 124 | } 125 | } 126 | if len(p.OptionalInstanceMethods) > 0 { 127 | for _, meth := range p.OptionalInstanceMethods { 128 | if verbose { 129 | rtype, args := decodeMethodTypes(meth.Types) 130 | optMethods += fmt.Sprintf("- %s\n", getMethodWithArgs(meth.Name, rtype, args)) 131 | } else { 132 | optMethods += fmt.Sprintf("-[%s %s];\n", p.Name, meth.Name) 133 | } 134 | } 135 | if optMethods != "" { 136 | optMethods = "/* optional instance methods */\n" + optMethods + "\n" 137 | } 138 | } 139 | return fmt.Sprintf( 140 | "%s\n\n"+ 141 | "@required\n\n"+ 142 | "%s"+ 143 | "%s"+ 144 | "%s"+ 145 | "@optional\n\n"+ 146 | "%s"+ 147 | "%s"+ 148 | "@end\n", 149 | protocol, 150 | props, 151 | cMethods, 152 | iMethods, 153 | optProps, 154 | optMethods, 155 | ) 156 | } 157 | 158 | func (p *Protocol) String() string { 159 | return p.dump(false, false) 160 | } 161 | func (p *Protocol) Verbose() string { 162 | return p.dump(true, false) 163 | } 164 | func (p *Protocol) WithAddrs() string { 165 | return p.dump(true, true) 166 | } 167 | -------------------------------------------------------------------------------- /types/objc/type_encoding_test.go: -------------------------------------------------------------------------------- 1 | package objc 2 | 3 | import "testing" 4 | 5 | func Test_decodeType(t *testing.T) { 6 | type args struct { 7 | encType string 8 | } 9 | tests := []struct { 10 | name string 11 | args args 12 | want string 13 | }{ 14 | { 15 | name: "Test all", 16 | args: args{ 17 | encType: "^{OutterStruct=(InnerUnion=q{InnerStruct=ii})b1b2b10b1q[2^v]^![4,8c]AQ}", 18 | }, 19 | want: "struct OutterStruct { union InnerUnion { long long x0; struct InnerStruct { int x0; int x1; } x1; } x0; unsigned int x1:1; unsigned int x2:2; unsigned int x3:10; unsigned int x4:1; long long x5; void *x6[2]; signed char *x7 __attribute__((aligned(8), vector_size(4))); _Atomic unsigned long long x8; } *", 20 | }, 21 | { 22 | name: "Test array 0", 23 | args: args{ 24 | encType: "[2^v]", 25 | }, 26 | want: "void *x[2]", 27 | }, 28 | { 29 | name: "Test array 1", 30 | args: args{ 31 | encType: "[20{IDSGlobalLinkAttribute=\"type\"S\"len\"S\"value\"(?=\"ss\"{sockaddr_storage=\"ss_len\"C\"ss_family\"C\"__ss_pad1\"[6c]\"__ss_align\"q\"__ss_pad2\"[112c]}\"u16\"S\"u32\"I\"u64\"Q\"binaryData\"{IDSGLAttrBinaryData_=\"len\"i\"data\"[1024C]})}]", 32 | }, 33 | want: "struct IDSGlobalLinkAttribute { unsigned short type; unsigned short len; union { struct sockaddr_storage { unsigned char ss_len; unsigned char ss_family; signed char __ss_pad1[6]; long long __ss_align; signed char __ss_pad2[112]; } ss; unsigned short u16; unsigned int u32; unsigned long long u64; struct IDSGLAttrBinaryData_ { int len; unsigned char data[1024]; } binaryData; } value; } x[20]", 34 | }, 35 | { 36 | name: "Test bitfield", 37 | args: args{ 38 | encType: "b13", 39 | }, 40 | want: "unsigned int x:13", 41 | }, 42 | { 43 | name: "Test struct 0", 44 | args: args{ 45 | encType: "{test=@*i}", 46 | }, 47 | want: "struct test { id x0; char *x1; int x2; }", 48 | }, 49 | { 50 | name: "Test struct 1", 51 | args: args{ 52 | encType: "{?=i[3f]b3b2c}", 53 | }, 54 | want: "struct { int x0; float x1[3]; unsigned int x2:3; unsigned int x3:2; signed char x4; }", 55 | }, 56 | { 57 | name: "Test struct 3", 58 | args: args{ 59 | encType: "{__xar_t=}", 60 | }, 61 | want: "struct __xar_t", 62 | }, 63 | { 64 | name: "Test struct 2", 65 | args: args{ 66 | encType: "{?=\"val\"[8I]}", 67 | }, 68 | want: "struct { unsigned int val[8]; }", 69 | }, 70 | { 71 | name: "Test struct 3", 72 | args: args{ 73 | encType: "^{?}", 74 | }, 75 | want: "void * /* struct */", 76 | }, 77 | { 78 | name: "Test struct 4", 79 | args: args{ 80 | encType: "{__CFRuntimeBase=QAQ}", 81 | }, 82 | want: "struct __CFRuntimeBase { unsigned long long x0; _Atomic unsigned long long x1; }", 83 | }, 84 | { 85 | name: "Test struct 4", 86 | args: args{ 87 | encType: "{__cfobservers_t=\"slot\"@\"next\"^{__cfobservers_t}}", 88 | }, 89 | want: "struct __cfobservers_t { id slot; struct __cfobservers_t *next; }", 90 | }, 91 | { 92 | name: "Test struct 5", 93 | args: args{ 94 | encType: "{_UISmallVector=\"_vector\"\"_size\"Q}", 95 | }, 96 | want: "struct _UISmallVector { id _vector; unsigned long long _size; }", 97 | }, 98 | { 99 | name: "Test union 0", 100 | args: args{ 101 | encType: "(?=i)", 102 | }, 103 | want: "union { int x0; }", 104 | }, 105 | { 106 | name: "Test union 1", 107 | args: args{ 108 | encType: "(?=\"fat\"^S\"thin\"*)", 109 | }, 110 | want: "union { unsigned short *fat; char *thin; }", 111 | }, 112 | { 113 | name: "Test union 2", 114 | args: args{ 115 | encType: "^(?)", 116 | }, 117 | want: "void * /* union */", 118 | }, 119 | { 120 | name: "Test union 3", 121 | args: args{ 122 | encType: "(?=\"xpc\"@\"NSObject\"\"remote\"@\"OS_xpc_remote_connection\")", 123 | }, 124 | want: "union { NSObject *xpc; OS_xpc_remote_connection *remote; }", 125 | }, 126 | { 127 | name: "Test block", 128 | args: args{ 129 | encType: "@?", 130 | }, 131 | want: "id /* block */", 132 | }, 133 | { 134 | name: "Test vector 0", 135 | args: args{ 136 | encType: "![16,8i]", 137 | }, 138 | want: "int x __attribute__((aligned(8), vector_size(16)))", 139 | }, 140 | { 141 | name: "Test vector 1", 142 | args: args{ 143 | encType: "^![16,8c]", 144 | }, 145 | want: "signed char *x __attribute__((aligned(8), vector_size(16)))", 146 | }, 147 | } 148 | for _, tt := range tests { 149 | t.Run(tt.name, func(t *testing.T) { 150 | if got := decodeType(tt.args.encType); got != tt.want { 151 | t.Errorf("decodeType() = %v, want %v", got, tt.want) 152 | } 153 | }) 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /types/reloc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package types 6 | 7 | //go:generate stringer -type=RelocTypeGeneric,RelocTypeX86_64,RelocTypeARM,RelocTypeARM64 -output reloc_string.go 8 | 9 | type RelocTypeGeneric int 10 | 11 | const ( 12 | GENERIC_RELOC_VANILLA RelocTypeGeneric = 0 13 | GENERIC_RELOC_PAIR RelocTypeGeneric = 1 14 | GENERIC_RELOC_SECTDIFF RelocTypeGeneric = 2 15 | GENERIC_RELOC_PB_LA_PTR RelocTypeGeneric = 3 16 | GENERIC_RELOC_LOCAL_SECTDIFF RelocTypeGeneric = 4 17 | GENERIC_RELOC_TLV RelocTypeGeneric = 5 18 | ) 19 | 20 | func (r RelocTypeGeneric) GoString() string { return "macho." + r.String() } 21 | 22 | type RelocTypeX86_64 int 23 | 24 | const ( 25 | X86_64_RELOC_UNSIGNED RelocTypeX86_64 = 0 26 | X86_64_RELOC_SIGNED RelocTypeX86_64 = 1 27 | X86_64_RELOC_BRANCH RelocTypeX86_64 = 2 28 | X86_64_RELOC_GOT_LOAD RelocTypeX86_64 = 3 29 | X86_64_RELOC_GOT RelocTypeX86_64 = 4 30 | X86_64_RELOC_SUBTRACTOR RelocTypeX86_64 = 5 31 | X86_64_RELOC_SIGNED_1 RelocTypeX86_64 = 6 32 | X86_64_RELOC_SIGNED_2 RelocTypeX86_64 = 7 33 | X86_64_RELOC_SIGNED_4 RelocTypeX86_64 = 8 34 | X86_64_RELOC_TLV RelocTypeX86_64 = 9 35 | ) 36 | 37 | func (r RelocTypeX86_64) GoString() string { return "macho." + r.String() } 38 | 39 | type RelocTypeARM int 40 | 41 | const ( 42 | ARM_RELOC_VANILLA RelocTypeARM = 0 43 | ARM_RELOC_PAIR RelocTypeARM = 1 44 | ARM_RELOC_SECTDIFF RelocTypeARM = 2 45 | ARM_RELOC_LOCAL_SECTDIFF RelocTypeARM = 3 46 | ARM_RELOC_PB_LA_PTR RelocTypeARM = 4 47 | ARM_RELOC_BR24 RelocTypeARM = 5 48 | ARM_THUMB_RELOC_BR22 RelocTypeARM = 6 49 | ARM_THUMB_32BIT_BRANCH RelocTypeARM = 7 50 | ARM_RELOC_HALF RelocTypeARM = 8 51 | ARM_RELOC_HALF_SECTDIFF RelocTypeARM = 9 52 | ) 53 | 54 | func (r RelocTypeARM) GoString() string { return "macho." + r.String() } 55 | 56 | type RelocTypeARM64 int 57 | 58 | const ( 59 | ARM64_RELOC_UNSIGNED RelocTypeARM64 = 0 60 | ARM64_RELOC_SUBTRACTOR RelocTypeARM64 = 1 61 | ARM64_RELOC_BRANCH26 RelocTypeARM64 = 2 62 | ARM64_RELOC_PAGE21 RelocTypeARM64 = 3 63 | ARM64_RELOC_PAGEOFF12 RelocTypeARM64 = 4 64 | ARM64_RELOC_GOT_LOAD_PAGE21 RelocTypeARM64 = 5 65 | ARM64_RELOC_GOT_LOAD_PAGEOFF12 RelocTypeARM64 = 6 66 | ARM64_RELOC_POINTER_TO_GOT RelocTypeARM64 = 7 67 | ARM64_RELOC_TLVP_LOAD_PAGE21 RelocTypeARM64 = 8 68 | ARM64_RELOC_TLVP_LOAD_PAGEOFF12 RelocTypeARM64 = 9 69 | ARM64_RELOC_ADDEND RelocTypeARM64 = 10 70 | ) 71 | 72 | func (r RelocTypeARM64) GoString() string { return "macho." + r.String() } 73 | -------------------------------------------------------------------------------- /types/reloc_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=RelocTypeGeneric,RelocTypeX86_64,RelocTypeARM,RelocTypeARM64 -output reloc_string.go"; DO NOT EDIT. 2 | 3 | package types 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[GENERIC_RELOC_VANILLA-0] 12 | _ = x[GENERIC_RELOC_PAIR-1] 13 | _ = x[GENERIC_RELOC_SECTDIFF-2] 14 | _ = x[GENERIC_RELOC_PB_LA_PTR-3] 15 | _ = x[GENERIC_RELOC_LOCAL_SECTDIFF-4] 16 | _ = x[GENERIC_RELOC_TLV-5] 17 | } 18 | 19 | const _RelocTypeGeneric_name = "GENERIC_RELOC_VANILLAGENERIC_RELOC_PAIRGENERIC_RELOC_SECTDIFFGENERIC_RELOC_PB_LA_PTRGENERIC_RELOC_LOCAL_SECTDIFFGENERIC_RELOC_TLV" 20 | 21 | var _RelocTypeGeneric_index = [...]uint8{0, 21, 39, 61, 84, 112, 129} 22 | 23 | func (i RelocTypeGeneric) String() string { 24 | if i < 0 || i >= RelocTypeGeneric(len(_RelocTypeGeneric_index)-1) { 25 | return "RelocTypeGeneric(" + strconv.FormatInt(int64(i), 10) + ")" 26 | } 27 | return _RelocTypeGeneric_name[_RelocTypeGeneric_index[i]:_RelocTypeGeneric_index[i+1]] 28 | } 29 | func _() { 30 | // An "invalid array index" compiler error signifies that the constant values have changed. 31 | // Re-run the stringer command to generate them again. 32 | var x [1]struct{} 33 | _ = x[X86_64_RELOC_UNSIGNED-0] 34 | _ = x[X86_64_RELOC_SIGNED-1] 35 | _ = x[X86_64_RELOC_BRANCH-2] 36 | _ = x[X86_64_RELOC_GOT_LOAD-3] 37 | _ = x[X86_64_RELOC_GOT-4] 38 | _ = x[X86_64_RELOC_SUBTRACTOR-5] 39 | _ = x[X86_64_RELOC_SIGNED_1-6] 40 | _ = x[X86_64_RELOC_SIGNED_2-7] 41 | _ = x[X86_64_RELOC_SIGNED_4-8] 42 | _ = x[X86_64_RELOC_TLV-9] 43 | } 44 | 45 | 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" 46 | 47 | var _RelocTypeX86_64_index = [...]uint8{0, 21, 40, 59, 80, 96, 119, 140, 161, 182, 198} 48 | 49 | func (i RelocTypeX86_64) String() string { 50 | if i < 0 || i >= RelocTypeX86_64(len(_RelocTypeX86_64_index)-1) { 51 | return "RelocTypeX86_64(" + strconv.FormatInt(int64(i), 10) + ")" 52 | } 53 | return _RelocTypeX86_64_name[_RelocTypeX86_64_index[i]:_RelocTypeX86_64_index[i+1]] 54 | } 55 | func _() { 56 | // An "invalid array index" compiler error signifies that the constant values have changed. 57 | // Re-run the stringer command to generate them again. 58 | var x [1]struct{} 59 | _ = x[ARM_RELOC_VANILLA-0] 60 | _ = x[ARM_RELOC_PAIR-1] 61 | _ = x[ARM_RELOC_SECTDIFF-2] 62 | _ = x[ARM_RELOC_LOCAL_SECTDIFF-3] 63 | _ = x[ARM_RELOC_PB_LA_PTR-4] 64 | _ = x[ARM_RELOC_BR24-5] 65 | _ = x[ARM_THUMB_RELOC_BR22-6] 66 | _ = x[ARM_THUMB_32BIT_BRANCH-7] 67 | _ = x[ARM_RELOC_HALF-8] 68 | _ = x[ARM_RELOC_HALF_SECTDIFF-9] 69 | } 70 | 71 | 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" 72 | 73 | var _RelocTypeARM_index = [...]uint8{0, 17, 31, 49, 73, 92, 106, 126, 148, 162, 185} 74 | 75 | func (i RelocTypeARM) String() string { 76 | if i < 0 || i >= RelocTypeARM(len(_RelocTypeARM_index)-1) { 77 | return "RelocTypeARM(" + strconv.FormatInt(int64(i), 10) + ")" 78 | } 79 | return _RelocTypeARM_name[_RelocTypeARM_index[i]:_RelocTypeARM_index[i+1]] 80 | } 81 | func _() { 82 | // An "invalid array index" compiler error signifies that the constant values have changed. 83 | // Re-run the stringer command to generate them again. 84 | var x [1]struct{} 85 | _ = x[ARM64_RELOC_UNSIGNED-0] 86 | _ = x[ARM64_RELOC_SUBTRACTOR-1] 87 | _ = x[ARM64_RELOC_BRANCH26-2] 88 | _ = x[ARM64_RELOC_PAGE21-3] 89 | _ = x[ARM64_RELOC_PAGEOFF12-4] 90 | _ = x[ARM64_RELOC_GOT_LOAD_PAGE21-5] 91 | _ = x[ARM64_RELOC_GOT_LOAD_PAGEOFF12-6] 92 | _ = x[ARM64_RELOC_POINTER_TO_GOT-7] 93 | _ = x[ARM64_RELOC_TLVP_LOAD_PAGE21-8] 94 | _ = x[ARM64_RELOC_TLVP_LOAD_PAGEOFF12-9] 95 | _ = x[ARM64_RELOC_ADDEND-10] 96 | } 97 | 98 | 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" 99 | 100 | var _RelocTypeARM64_index = [...]uint16{0, 20, 42, 62, 80, 101, 128, 158, 184, 212, 243, 261} 101 | 102 | func (i RelocTypeARM64) String() string { 103 | if i < 0 || i >= RelocTypeARM64(len(_RelocTypeARM64_index)-1) { 104 | return "RelocTypeARM64(" + strconv.FormatInt(int64(i), 10) + ")" 105 | } 106 | return _RelocTypeARM64_name[_RelocTypeARM64_index[i]:_RelocTypeARM64_index[i+1]] 107 | } 108 | -------------------------------------------------------------------------------- /types/swift/README.md: -------------------------------------------------------------------------------- 1 | # swift 2 | 3 | ## TODO 4 | 5 | ### Sections 6 | 7 | - [x] `__swift5_entry` 8 | - [x] `__swift5_builtin` 9 | - [x] `__swift5_reflstr` 10 | - [x] `__swift5_fieldmd` 11 | - [x] `__swift5_assocty` 12 | - [x] `__swift5_proto` 13 | - [x] `__swift5_types` 14 | - [x] `__swift5_types2` // the section containing additional type references 15 | - [?] `__swift5_typeref` 16 | - [x] `__swift5_protos` 17 | - [x] `__swift5_capture` 18 | - [ ] `__swift5_replace` 19 | - [ ] `__swift5_replac2` 20 | - [x] `__swift5_acfuncs` 21 | - [ ] `__swift5_mpenum` ?? check Foundation 22 | - [x] `__constg_swiftt` 23 | - [ ] `__textg_swiftm` 24 | 25 | ### Protocol Conformances 26 | 27 | - [ ] parse witness tables *(I got the patterns, but there's data after the description ptr (looks like func ptrs))* 28 | 29 | ### Type *(Conformances)* 30 | 31 | - [ ] add type's protocol conformances to their output *(will require caching/looking up type names etc)* 32 | 33 | ### Protocols 34 | 35 | - [ ] properly represent signature requirements *(I believe if they are key_args they belong in PROT etc)* 36 | 37 | ### Metadata 38 | 39 | - [ ] parse all the different type's metatdata 40 | 41 | ### Demangle *(hard)* 42 | 43 | - [ ] pure Go Swift demangler 44 | - [ ] symbolic mangled type algorithm + demangler -------------------------------------------------------------------------------- /types/swift/accessible_funcs.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | // __swift5_acfuncs 9 | 10 | type AccessibleFunctionsSection struct { 11 | Begin uint64 // AccessibleFunctionRecord 12 | End uint64 // AccessibleFunctionRecord 13 | } 14 | 15 | type AccessibleFunctionFlags uint32 16 | 17 | const ( 18 | Distributed AccessibleFunctionFlags = 0 19 | ) 20 | 21 | type TargetAccessibleFunctionRecord struct { 22 | Name RelativeDirectPointer // char * 23 | GenericEnvironment RelativeDirectPointer // TargetGenericEnvironment 24 | FunctionType RelativeDirectPointer // mangled name 25 | Function RelativeDirectPointer // void * 26 | Flags AccessibleFunctionFlags 27 | } 28 | 29 | func (r TargetAccessibleFunctionRecord) Size() int64 { 30 | return int64( 31 | binary.Size(r.Name.RelOff) + 32 | binary.Size(r.GenericEnvironment.RelOff) + 33 | binary.Size(r.FunctionType.RelOff) + 34 | binary.Size(r.Function.RelOff) + 35 | binary.Size(r.Flags), 36 | ) 37 | } 38 | 39 | func (f *TargetAccessibleFunctionRecord) Read(r io.Reader, addr uint64) error { 40 | f.Name.Address = addr 41 | if err := binary.Read(r, binary.LittleEndian, &f.Name.RelOff); err != nil { 42 | return err 43 | } 44 | f.GenericEnvironment.Address = addr + uint64(binary.Size(f.Name.RelOff)) 45 | if err := binary.Read(r, binary.LittleEndian, &f.GenericEnvironment.RelOff); err != nil { 46 | return err 47 | } 48 | f.FunctionType.Address = addr + uint64(binary.Size(f.Name.RelOff)) + uint64(binary.Size(f.GenericEnvironment.RelOff)) 49 | if err := binary.Read(r, binary.LittleEndian, &f.FunctionType.RelOff); err != nil { 50 | return err 51 | } 52 | f.Function.Address = addr + uint64(binary.Size(f.Name.RelOff)) + uint64(binary.Size(f.GenericEnvironment.RelOff)) + uint64(binary.Size(f.FunctionType.RelOff)) 53 | if err := binary.Read(r, binary.LittleEndian, &f.Function.RelOff); err != nil { 54 | return err 55 | } 56 | return binary.Read(r, binary.LittleEndian, &f.Flags) 57 | } 58 | 59 | type AccessibleFunctionCacheEntry struct { 60 | Name string 61 | NameLen uint32 62 | R uint64 // AccessibleFunctionRecord 63 | 64 | } 65 | 66 | type AccessibleFunctionsState struct { 67 | Cache AccessibleFunctionCacheEntry 68 | SectionsToScan AccessibleFunctionsSection 69 | } 70 | -------------------------------------------------------------------------------- /types/swift/associated_type.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | "strings" 8 | ) 9 | 10 | // __TEXT.__swift5_assocty 11 | // This section contains an array of associated type descriptors. 12 | // An associated type descriptor contains a collection of associated type records for a conformance. 13 | // An associated type records describe the mapping from an associated type to the type witness of a conformance. 14 | 15 | type AssociatedType struct { 16 | AssociatedTypeDescriptor 17 | Address uint64 18 | ConformingTypeAddr uint64 19 | ConformingTypeName string 20 | ProtocolTypeName string 21 | TypeRecords []ATRecordType 22 | } 23 | 24 | func (a AssociatedType) String() string { 25 | return a.dump(false) 26 | } 27 | func (a AssociatedType) Verbose() string { 28 | return a.dump(true) 29 | } 30 | func (a AssociatedType) dump(verbose bool) string { 31 | var addr string 32 | var vars []string 33 | for _, v := range a.TypeRecords { 34 | if verbose { 35 | addr = fmt.Sprintf("/* %#x */ ", v.NameOffset.GetAddress()) 36 | } 37 | vars = append(vars, fmt.Sprintf(" %stypealias %s = %s", addr, v.Name, v.SubstitutedTypeName)) 38 | } 39 | if verbose { 40 | addr = fmt.Sprintf("// %#x\n", a.Address) 41 | } 42 | return fmt.Sprintf( 43 | "%s"+ 44 | "extension %s: %s {\n"+ 45 | "%s\n"+ 46 | "}", 47 | addr, 48 | a.ConformingTypeName, 49 | a.ProtocolTypeName, 50 | strings.Join(vars, "\n"), 51 | ) 52 | } 53 | 54 | // AssociatedTypeDescriptor an associated type descriptor contains a collection of associated type records for a conformance. 55 | // ref: include/swift/RemoteInspection/Records.h 56 | type AssociatedTypeDescriptor struct { 57 | ConformingTypeNameOffset RelativeDirectPointer 58 | ProtocolTypeNameOffset RelativeDirectPointer 59 | NumAssociatedTypes uint32 60 | AssociatedTypeRecordSize uint32 61 | } 62 | 63 | func (a AssociatedTypeDescriptor) Size() int64 { 64 | return int64( 65 | binary.Size(a.ConformingTypeNameOffset.RelOff) + 66 | binary.Size(a.ProtocolTypeNameOffset.RelOff) + 67 | binary.Size(a.NumAssociatedTypes) + 68 | binary.Size(a.AssociatedTypeRecordSize), 69 | ) 70 | } 71 | 72 | func (a *AssociatedTypeDescriptor) Read(r io.Reader, addr uint64) error { 73 | a.ConformingTypeNameOffset.Address = addr 74 | a.ProtocolTypeNameOffset.Address = addr + uint64(binary.Size(RelativeDirectPointer{}.RelOff)) 75 | if err := binary.Read(r, binary.LittleEndian, &a.ConformingTypeNameOffset.RelOff); err != nil { 76 | return err 77 | } 78 | if err := binary.Read(r, binary.LittleEndian, &a.ProtocolTypeNameOffset.RelOff); err != nil { 79 | return err 80 | } 81 | if err := binary.Read(r, binary.LittleEndian, &a.NumAssociatedTypes); err != nil { 82 | return err 83 | } 84 | if err := binary.Read(r, binary.LittleEndian, &a.AssociatedTypeRecordSize); err != nil { 85 | return err 86 | } 87 | return nil 88 | } 89 | 90 | type ATRecordType struct { 91 | AssociatedTypeRecord 92 | Name string 93 | SubstitutedTypeName string 94 | } 95 | 96 | // AssociatedTypeRecord type records describe the mapping from an associated type to the type witness of a conformance. 97 | // ref: include/swift/RemoteInspection/Records.h 98 | type AssociatedTypeRecord struct { 99 | NameOffset RelativeDirectPointer 100 | SubstitutedTypeNameOffset RelativeDirectPointer 101 | } 102 | 103 | func (a AssociatedTypeRecord) Size() int64 { 104 | return int64( 105 | binary.Size(a.NameOffset.RelOff) + 106 | binary.Size(a.SubstitutedTypeNameOffset.RelOff), 107 | ) 108 | } 109 | 110 | func (a *AssociatedTypeRecord) Read(r io.Reader, addr uint64) error { 111 | a.NameOffset.Address = addr 112 | a.SubstitutedTypeNameOffset.Address = addr + uint64(binary.Size(RelativeDirectPointer{}.RelOff)) 113 | if err := binary.Read(r, binary.LittleEndian, &a.NameOffset.RelOff); err != nil { 114 | return err 115 | } 116 | if err := binary.Read(r, binary.LittleEndian, &a.SubstitutedTypeNameOffset.RelOff); err != nil { 117 | return err 118 | } 119 | return nil 120 | } 121 | -------------------------------------------------------------------------------- /types/swift/builtin_type.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | // __TEXT.__swift5_builtin 10 | // This section contains an array of builtin type descriptors. 11 | // A builtin type descriptor describes the basic layout information about any builtin types referenced from other sections. 12 | 13 | const MaxNumExtraInhabitants = 0x7FFFFFFF 14 | 15 | // BuiltinType builtin swift type 16 | type BuiltinType struct { 17 | BuiltinTypeDescriptor 18 | Name string 19 | } 20 | 21 | func (b BuiltinType) String() string { 22 | return b.dump(false) 23 | } 24 | func (b BuiltinType) Verbose() string { 25 | return b.dump(true) 26 | } 27 | func (b BuiltinType) dump(verbose bool) string { 28 | var numExtraInhabitants string 29 | if b.NumExtraInhabitants == MaxNumExtraInhabitants { 30 | numExtraInhabitants = "max" 31 | } else { 32 | numExtraInhabitants = fmt.Sprintf("%d", b.NumExtraInhabitants) 33 | } 34 | var addr string 35 | if verbose { 36 | addr = fmt.Sprintf("// %#x\n", b.TypeName.GetAddress()) 37 | } 38 | return fmt.Sprintf( 39 | "%s"+ 40 | "%s /* (size: %d"+ 41 | ", align: %d"+ 42 | ", bitwise-takable: %t"+ 43 | ", stride: %d"+ 44 | ", extra-inhabitants: %s) */", 45 | addr, 46 | b.Name, 47 | b.Size, 48 | b.AlignmentAndFlags.Alignment(), 49 | b.AlignmentAndFlags.IsBitwiseTakable(), 50 | b.Stride, 51 | numExtraInhabitants, 52 | ) 53 | } 54 | 55 | // BuiltinTypeDescriptor type records describe basic layout information about any builtin types referenced from the other sections. 56 | // ref: include/swift/RemoteInspection/Records.h 57 | type BuiltinTypeDescriptor struct { 58 | TypeName RelativeDirectPointer 59 | Size uint32 60 | AlignmentAndFlags builtinTypeFlag 61 | Stride uint32 62 | NumExtraInhabitants uint32 63 | } 64 | 65 | func (b *BuiltinTypeDescriptor) Read(r io.Reader, addr uint64) error { 66 | b.TypeName.Address = addr 67 | if err := binary.Read(r, binary.LittleEndian, &b.TypeName.RelOff); err != nil { 68 | return err 69 | } 70 | if err := binary.Read(r, binary.LittleEndian, &b.Size); err != nil { 71 | return err 72 | } 73 | if err := binary.Read(r, binary.LittleEndian, &b.AlignmentAndFlags); err != nil { 74 | return err 75 | } 76 | if err := binary.Read(r, binary.LittleEndian, &b.Stride); err != nil { 77 | return err 78 | } 79 | return binary.Read(r, binary.LittleEndian, &b.NumExtraInhabitants) 80 | } 81 | 82 | type builtinTypeFlag uint32 83 | 84 | func (f builtinTypeFlag) IsBitwiseTakable() bool { 85 | return ((f >> 16) & 1) != 0 86 | } 87 | func (f builtinTypeFlag) Alignment() uint16 { 88 | return uint16(f & 0xffff) 89 | } 90 | -------------------------------------------------------------------------------- /types/swift/capture.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | //go:generate stringer -type NecessaryBindingsKind -output capture_string.go 10 | 11 | // __TEXT.__swift5_capture 12 | // Capture descriptors describe the layout of a closure context object. 13 | // Unlike nominal types, the generic substitutions for a closure context come from the object, and not the metadata. 14 | 15 | type Capture struct { 16 | CaptureDescriptor 17 | Address uint64 18 | CaptureTypes []CaptureType 19 | MetadataSources []MetadataSource 20 | Bindings []NecessaryBindings 21 | } 22 | 23 | func (c Capture) String() string { 24 | var captureTypes string 25 | if len(c.CaptureTypes) > 0 { 26 | captureTypes += " /* capture types */\n" 27 | for _, t := range c.CaptureTypes { 28 | captureTypes += fmt.Sprintf(" %s\n", t.TypeName) 29 | } 30 | } 31 | var metadataSources string 32 | if len(c.MetadataSources) > 0 { 33 | metadataSources += " /* metadata sources */\n" 34 | for _, m := range c.MetadataSources { 35 | metadataSources += fmt.Sprintf(" %s: %s\n", m.MangledType, m.MangledMetadataSource) 36 | } 37 | } 38 | var bindings string 39 | if len(c.Bindings) > 0 { 40 | bindings += " /* necessary bindings */\n" 41 | for _, b := range c.Bindings { 42 | bindings += fmt.Sprintf(" // Kind: %d, RequirementsSet: %d, RequirementsVector: %d, Conformances: %d\n", b.Kind, b.RequirementsSet, b.RequirementsVector, b.Conformances) 43 | } 44 | } 45 | return fmt.Sprintf( 46 | "block /* %#x */ {\n"+ 47 | "%s"+ 48 | "%s"+ 49 | "%s"+ 50 | "}", 51 | c.Address, 52 | captureTypes, 53 | metadataSources, 54 | bindings, 55 | ) 56 | } 57 | 58 | // CaptureDescriptor describe the layout of a closure context 59 | // object. Unlike nominal types, the generic substitutions for a 60 | // closure context come from the object, and not the metadata. 61 | // ref: include/swift/RemoteInspection/Records.h - CaptureDescriptor 62 | type CaptureDescriptor struct { 63 | NumCaptureTypes uint32 // The number of captures in the closure and the number of typerefs that immediately follow this struct. 64 | NumMetadataSources uint32 // The number of sources of metadata available in the MetadataSourceMap directly following the list of capture's typerefs. 65 | NumBindings uint32 // The number of items in the NecessaryBindings structure at the head of the closure. 66 | } 67 | 68 | type CaptureType struct { 69 | CaptureTypeRecord 70 | TypeName string 71 | } 72 | 73 | type CaptureTypeRecord struct { 74 | MangledTypeName RelativeDirectPointer 75 | } 76 | 77 | func (ctr CaptureTypeRecord) Size() int64 { 78 | return int64(binary.Size(ctr.MangledTypeName.RelOff)) 79 | } 80 | 81 | func (ctr *CaptureTypeRecord) Read(r io.Reader, addr uint64) error { 82 | ctr.MangledTypeName.Address = addr 83 | if err := binary.Read(r, binary.LittleEndian, &ctr.MangledTypeName.RelOff); err != nil { 84 | return err 85 | } 86 | return nil 87 | } 88 | 89 | type MetadataSourceRecord struct { 90 | MangledTypeNameOff RelativeDirectPointer 91 | MangledMetadataSourceOff RelativeDirectPointer 92 | } 93 | 94 | func (msr MetadataSourceRecord) Size() int64 { 95 | return int64(binary.Size(msr.MangledTypeNameOff.RelOff) + binary.Size(msr.MangledMetadataSourceOff.RelOff)) 96 | } 97 | 98 | func (msr *MetadataSourceRecord) Read(r io.Reader, addr uint64) error { 99 | msr.MangledTypeNameOff.Address = addr 100 | if err := binary.Read(r, binary.LittleEndian, &msr.MangledTypeNameOff.RelOff); err != nil { 101 | return err 102 | } 103 | addr += uint64(binary.Size(msr.MangledTypeNameOff.RelOff)) 104 | msr.MangledMetadataSourceOff.Address = addr 105 | if err := binary.Read(r, binary.LittleEndian, &msr.MangledMetadataSourceOff.RelOff); err != nil { 106 | return err 107 | } 108 | return nil 109 | } 110 | 111 | type MetadataSource struct { 112 | MetadataSourceRecord 113 | MangledType string 114 | MangledMetadataSource string 115 | } 116 | 117 | type NecessaryBindingsKind uint32 118 | 119 | const ( 120 | PartialApply NecessaryBindingsKind = iota 121 | AsyncFunction 122 | ) 123 | 124 | type NecessaryBindings struct { 125 | Kind NecessaryBindingsKind 126 | RequirementsSet RelativeDirectPointer 127 | RequirementsVector RelativeDirectPointer 128 | Conformances RelativeDirectPointer 129 | } 130 | 131 | func (nb NecessaryBindings) Size() int64 { 132 | return int64(binary.Size(nb.RequirementsSet.RelOff) + binary.Size(nb.RequirementsVector.RelOff) + binary.Size(nb.Conformances.RelOff)) 133 | } 134 | 135 | func (nb *NecessaryBindings) Read(r io.Reader, addr uint64) error { 136 | nb.RequirementsSet.Address = addr 137 | if err := binary.Read(r, binary.LittleEndian, &nb.RequirementsSet.RelOff); err != nil { 138 | return err 139 | } 140 | addr += uint64(binary.Size(nb.RequirementsSet.RelOff)) 141 | nb.RequirementsVector.Address = addr 142 | if err := binary.Read(r, binary.LittleEndian, &nb.RequirementsVector.RelOff); err != nil { 143 | return err 144 | } 145 | addr += uint64(binary.Size(nb.RequirementsVector.RelOff)) 146 | nb.Conformances.Address = addr 147 | if err := binary.Read(r, binary.LittleEndian, &nb.Conformances.RelOff); err != nil { 148 | return err 149 | } 150 | return nil 151 | } 152 | -------------------------------------------------------------------------------- /types/swift/capture_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type NecessaryBindingsKind -output capture_string.go"; DO NOT EDIT. 2 | 3 | package swift 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[PartialApply-0] 12 | _ = x[AsyncFunction-1] 13 | } 14 | 15 | const _NecessaryBindingsKind_name = "PartialApplyAsyncFunction" 16 | 17 | var _NecessaryBindingsKind_index = [...]uint8{0, 12, 25} 18 | 19 | func (i NecessaryBindingsKind) String() string { 20 | if i >= NecessaryBindingsKind(len(_NecessaryBindingsKind_index)-1) { 21 | return "NecessaryBindingsKind(" + strconv.FormatInt(int64(i), 10) + ")" 22 | } 23 | return _NecessaryBindingsKind_name[_NecessaryBindingsKind_index[i]:_NecessaryBindingsKind_index[i+1]] 24 | } 25 | -------------------------------------------------------------------------------- /types/swift/field.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | //go:generate stringer -type=FieldDescriptorKind -linecomment -output field_string.go 10 | 11 | // __TEXT.__swift5_fieldmd 12 | // This section contains an array of field descriptors. 13 | // A field descriptor contains a collection of field records for a single class, 14 | // struct or enum declaration. Each field descriptor can be a different length depending on how many field records the type contains. 15 | 16 | const SWIFT_REFLECTION_METADATA_VERSION = 3 // superclass field 17 | 18 | type Field struct { 19 | FieldDescriptor 20 | Address uint64 21 | Type string 22 | SuperClass string 23 | Records []FieldRecord 24 | } 25 | 26 | func (f Field) IsEnum() bool { 27 | return f.Kind == FDKindEnum || f.Kind == FDKindMultiPayloadEnum 28 | } 29 | func (f Field) IsClass() bool { 30 | return f.Kind == FDKindClass || f.Kind == FDKindObjCClass 31 | } 32 | func (f Field) IsProtocol() bool { 33 | return f.Kind == FDKindProtocol || f.Kind == FDKindClassProtocol || f.Kind == FDKindObjCProtocol 34 | } 35 | func (f Field) IsStruct() bool { 36 | return f.Kind == FDKindStruct 37 | } 38 | func (f Field) String() string { 39 | return f.dump(false) 40 | } 41 | func (f Field) Verbose() string { 42 | return f.dump(true) 43 | } 44 | func (f Field) dump(verbose bool) string { 45 | var recs string 46 | if len(f.Records) > 0 { 47 | recs = "\n" 48 | } 49 | for _, r := range f.Records { 50 | var flags string 51 | var hasType string 52 | if f.Kind == FDKindEnum || f.Kind == FDKindMultiPayloadEnum { 53 | flags = "case" 54 | } else { 55 | if r.Flags.String() == "IsVar" { 56 | flags = "var" 57 | } else { 58 | flags = "let" 59 | } 60 | } 61 | if len(r.MangledType) > 0 { 62 | hasType = ": " 63 | } 64 | recs += fmt.Sprintf(" %s %s%s%s\n", flags, r.Name, hasType, r.MangledType) 65 | } 66 | var addr string 67 | if verbose { 68 | addr = fmt.Sprintf("// %#x\n", f.Address) 69 | } 70 | if len(f.SuperClass) > 0 { 71 | return fmt.Sprintf("%s%s %s: %s {%s}\n", addr, f.Kind, f.Type, f.SuperClass, recs) 72 | } 73 | return fmt.Sprintf("%s%s %s {%s}\n", addr, f.Kind, f.Type, recs) 74 | } 75 | 76 | type FieldDescriptorKind uint16 77 | 78 | const ( 79 | // Swift nominal types. 80 | FDKindStruct FieldDescriptorKind = iota // struct 81 | FDKindClass // class 82 | FDKindEnum // enum 83 | 84 | // Fixed-size multi-payload enums have a special descriptor format that 85 | // encodes spare bits. 86 | // 87 | // FIXME: Actually implement this. For now, a descriptor with this kind 88 | // just means we also have a builtin descriptor from which we get the 89 | // size and alignment. 90 | FDKindMultiPayloadEnum // multi-payload enum 91 | 92 | // A Swift opaque protocol. There are no fields, just a record for the 93 | // type itself. 94 | FDKindProtocol // protocol 95 | 96 | // A Swift class-bound protocol. 97 | FDKindClassProtocol // class protocol 98 | 99 | // An Objective-C protocol, which may be imported or defined in Swift. 100 | FDKindObjCProtocol // objc protocol 101 | 102 | // An Objective-C class, which may be imported or defined in Swift. 103 | // In the former case, field type metadata is not emitted, and 104 | // must be obtained from the Objective-C runtime. 105 | FDKindObjCClass // objc class 106 | ) 107 | 108 | // FieldDescriptor contain a collection of field records for a single class, struct or enum declaration. 109 | // ref: swift/include/swift/Reflection/Records.h 110 | type FieldDescriptor struct { 111 | MangledTypeNameOffset RelativeDirectPointer 112 | SuperclassOffset RelativeDirectPointer 113 | Kind FieldDescriptorKind 114 | FieldRecordSize uint16 115 | NumFields uint32 116 | } 117 | 118 | func (fd FieldDescriptor) Size() uint64 { 119 | return uint64( 120 | binary.Size(fd.MangledTypeNameOffset.RelOff) + 121 | binary.Size(fd.SuperclassOffset.RelOff) + 122 | binary.Size(fd.Kind) + 123 | binary.Size(fd.FieldRecordSize) + 124 | binary.Size(fd.NumFields)) 125 | } 126 | 127 | func (fd *FieldDescriptor) Read(r io.Reader, addr uint64) error { 128 | fd.MangledTypeNameOffset.Address = addr 129 | fd.SuperclassOffset.Address = addr + uint64(binary.Size(RelativeDirectPointer{}.RelOff)) 130 | if err := binary.Read(r, binary.LittleEndian, &fd.MangledTypeNameOffset.RelOff); err != nil { 131 | return err 132 | } 133 | if err := binary.Read(r, binary.LittleEndian, &fd.SuperclassOffset.RelOff); err != nil { 134 | return err 135 | } 136 | if err := binary.Read(r, binary.LittleEndian, &fd.Kind); err != nil { 137 | return err 138 | } 139 | if err := binary.Read(r, binary.LittleEndian, &fd.FieldRecordSize); err != nil { 140 | return err 141 | } 142 | if err := binary.Read(r, binary.LittleEndian, &fd.NumFields); err != nil { 143 | return err 144 | } 145 | return nil 146 | } 147 | 148 | type FieldRecord struct { 149 | FieldRecordDescriptor 150 | Name string 151 | MangledType string 152 | } 153 | 154 | type FieldRecordDescriptor struct { 155 | Flags FieldRecordFlags 156 | MangledTypeNameOffset RelativeDirectPointer 157 | FieldNameOffset RelativeDirectPointer 158 | } 159 | 160 | func (fd FieldRecordDescriptor) Size() uint64 { 161 | return uint64( 162 | binary.Size(fd.Flags) + 163 | binary.Size(fd.MangledTypeNameOffset.RelOff) + 164 | binary.Size(fd.FieldNameOffset.RelOff)) 165 | } 166 | 167 | func (frd *FieldRecordDescriptor) Read(r io.Reader, addr uint64) error { 168 | frd.MangledTypeNameOffset.Address = addr + uint64(binary.Size(FieldRecordDescriptor{}.Flags)) 169 | frd.FieldNameOffset.Address = addr + 170 | uint64( 171 | binary.Size(FieldRecordDescriptor{}.Flags)+ 172 | binary.Size(RelativeDirectPointer{}.RelOff)) 173 | if err := binary.Read(r, binary.LittleEndian, &frd.Flags); err != nil { 174 | return err 175 | } 176 | if err := binary.Read(r, binary.LittleEndian, &frd.MangledTypeNameOffset.RelOff); err != nil { 177 | return err 178 | } 179 | if err := binary.Read(r, binary.LittleEndian, &frd.FieldNameOffset.RelOff); err != nil { 180 | return err 181 | } 182 | return nil 183 | } 184 | 185 | type FieldRecordFlags uint32 186 | 187 | const ( 188 | // IsIndirectCase is this an indirect enum case? 189 | IsIndirectCase FieldRecordFlags = 0x1 190 | // IsVar is this a mutable `var` property? 191 | IsVar FieldRecordFlags = 0x2 192 | // IsArtificial is this an artificial field? 193 | IsArtificial FieldRecordFlags = 0x4 194 | ) 195 | 196 | func (f FieldRecordFlags) IsIndirectCase() bool { 197 | return (f & IsIndirectCase) == IsIndirectCase 198 | } 199 | func (f FieldRecordFlags) IsVar() bool { 200 | return (f & IsVar) == IsVar 201 | } 202 | func (f FieldRecordFlags) IsArtificial() bool { 203 | return (f & IsArtificial) == IsArtificial 204 | } 205 | 206 | func (f FieldRecordFlags) String() string { // TODO: this is dumb (does ind or anon ever happen?) 207 | var out string 208 | if f.IsIndirectCase() { 209 | out = "indirect case" 210 | } 211 | if f.IsArtificial() { 212 | if len(out) > 0 { 213 | out += " | " 214 | } 215 | out += "artificial" 216 | } 217 | if f.IsVar() { 218 | out = "var" 219 | } else { 220 | out = "let" 221 | } 222 | return out 223 | } 224 | -------------------------------------------------------------------------------- /types/swift/field_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=FieldDescriptorKind -linecomment -output field_string.go"; DO NOT EDIT. 2 | 3 | package swift 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[FDKindStruct-0] 12 | _ = x[FDKindClass-1] 13 | _ = x[FDKindEnum-2] 14 | _ = x[FDKindMultiPayloadEnum-3] 15 | _ = x[FDKindProtocol-4] 16 | _ = x[FDKindClassProtocol-5] 17 | _ = x[FDKindObjCProtocol-6] 18 | _ = x[FDKindObjCClass-7] 19 | } 20 | 21 | const _FieldDescriptorKind_name = "structclassenummulti-payload enumprotocolclass protocolobjc protocolobjc class" 22 | 23 | var _FieldDescriptorKind_index = [...]uint8{0, 6, 11, 15, 33, 41, 55, 68, 78} 24 | 25 | func (i FieldDescriptorKind) String() string { 26 | if i >= FieldDescriptorKind(len(_FieldDescriptorKind_index)-1) { 27 | return "FieldDescriptorKind(" + strconv.FormatInt(int64(i), 10) + ")" 28 | } 29 | return _FieldDescriptorKind_name[_FieldDescriptorKind_index[i]:_FieldDescriptorKind_index[i+1]] 30 | } 31 | -------------------------------------------------------------------------------- /types/swift/mangling.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | var MangledKnownTypeKind = map[string]string{ 4 | "A": "Swift.AutoreleasingUnsafeMutablePointer", 5 | "a": "Swift.Array", 6 | "B": "Swift.BinaryFloatingPoint", 7 | "b": "Swift.Bool", 8 | "c": "MangledKnownTypeKind2", 9 | "D": "Swift.Dictionary", 10 | "d": "Swift.Float64", 11 | "E": "Swift.Encodable", 12 | "e": "Swift.Decodable", 13 | "F": "Swift.FloatingPoint", 14 | "f": "Swift.Float32", 15 | "G": "Swift.RandomNumberGenerator", 16 | "H": "Swift.Hashable", 17 | "h": "Swift.Set", 18 | "I": "Swift.DefaultIndices", 19 | "i": "Swift.Int", 20 | "J": "Swift.Character", 21 | "j": "Swift.Numeric", 22 | "K": "Swift.BidirectionalCollection", 23 | "k": "Swift.RandomAccessCollection", 24 | "L": "Swift.Comparable", 25 | "l": "Swift.Collection", 26 | "M": "Swift.MutableCollection", 27 | "m": "Swift.RangeReplaceableCollection", 28 | "N": "Swift.ClosedRange", 29 | "n": "Swift.Range", 30 | "O": "Swift.ObjectIdentifier", 31 | "P": "Swift.UnsafePointer", 32 | "p": "Swift.UnsafeMutablePointer", 33 | "Q": "Swift.Equatable", 34 | "q": "Swift.Optional", 35 | "R": "Swift.UnsafeBufferPointer", 36 | "r": "Swift.UnsafeMutableBufferPointer", 37 | "S": "Swift.String", 38 | "s": "Swift.Substring", 39 | "T": "Swift.Sequence", 40 | "t": "Swift.IteratorProtocol", 41 | "U": "Swift.UnsignedInteger", 42 | "u": "Swift.UInt", 43 | "V": "Swift.UnsafeRawPointer", 44 | "v": "Swift.UnsafeMutableRawPointer", 45 | "W": "Swift.UnsafeRawBufferPointer", 46 | "w": "Swift.UnsafeMutableRawBufferPointer", 47 | "X": "Swift.RangeExpression", 48 | "x": "Swift.Strideable", 49 | "Y": "Swift.RawRepresentable", 50 | "y": "Swift.StringProtocol", 51 | "Z": "Swift.SignedInteger", 52 | "z": "Swift.BinaryInteger", 53 | } 54 | 55 | var MangledKnownTypeKind2 = map[string]string{ 56 | "A": "Swift.Actor", 57 | "C": "Swift.CheckedContinuation", 58 | "c": "Swift.UnsafeContinuation", 59 | "E": "Swift.CancellationError", 60 | "e": "Swift.UnownedSerialExecutor", 61 | "F": "Swift.Executor", 62 | "f": "Swift.SerialExecutor", 63 | "G": "Swift.TaskGroup", 64 | "g": "Swift.ThrowingTaskGroup", 65 | "I": "Swift.AsyncIteratorProtocol", 66 | "i": "Swift.AsyncSequence", 67 | "J": "Swift.UnownedJob", 68 | "M": "Swift.MainActor", 69 | "P": "Swift.TaskPriority", 70 | "S": "Swift.AsyncStream", 71 | "s": "Swift.AsyncThrowingStream", 72 | "T": "Swift.Task", 73 | "t": "Swift.UnsafeCurrentTask", 74 | } 75 | 76 | // MangledType is a mangled type map 77 | var MangledType = map[string]string{ 78 | "Bb": "Builtin.BridgeObject", 79 | "BB": "Builtin.UnsafeValueBuffer", 80 | "Bc": "Builtin.RawUnsafeContinuation", 81 | "BD": "Builtin.DefaultActorStorage", 82 | "Be": "Builtin.Executor", 83 | "Bd": "Builtin.NonDefaultDistributedActorStorage", 84 | "Bf": "Builtin.Float", 85 | "Bi": "Builtin.Int", 86 | "BI": "Builtin.IntLiteral", 87 | "Bj": "Builtin.Job", 88 | "BP": "Builtin.PackIndex", 89 | "BO": "Builtin.UnknownObject", 90 | "Bo": "Builtin.NativeObject", 91 | "Bp": "Builtin.RawPointer", 92 | "Bt": "Builtin.SILToken", 93 | "Bv": "Builtin.Vecx", 94 | "Bw": "Builtin.Word", 95 | "c": "function type (escaping)", 96 | "X": "special function type", 97 | "Sg": "?", // shortcut for: type 'ySqG' 98 | "ySqG": "?", // optional type 99 | "GSg": "?", 100 | "_pSg": "?", 101 | "SgSg": "??", 102 | "ypG": "Any", 103 | "p": "Any", 104 | "SSG": "String", 105 | "SSGSg": "String?", 106 | "SSSgG": "String?", 107 | "SpySvSgGG": "UnsafeMutablePointer", 108 | "SiGSg": "Int?", 109 | "Xo": "@unowned type", 110 | "Xu": "@unowned(unsafe) type", 111 | "Xw": "@weak type", 112 | "XF": "function implementation type (currently unused)", 113 | "Xb": "SIL @box type (deprecated)", 114 | "Xx": "SIL box type", 115 | "XD": "dynamic self type", 116 | "m": "metatype without representation", 117 | "XM": "metatype with representation", 118 | "Xp": "existential metatype without representation", 119 | "Xm": "existential metatype with representation", 120 | "Xe": "(error)", 121 | "x": "A", // generic param, depth=0, idx=0 122 | "q_": "B", // dependent generic parameter 123 | "yxq_G": "", 124 | "xq_": "", 125 | "Sb": "Swift.Bool", 126 | "Qz": "==", 127 | "Qy_": "==", 128 | "Qy0_": "==", 129 | "SgXw": "?", 130 | } 131 | -------------------------------------------------------------------------------- /types/swift/metadata_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type MetadataKind -linecomment -output metadata_string.go"; DO NOT EDIT. 2 | 3 | package swift 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[ClassMetadataKind-0] 12 | _ = x[StructMetadataKind-512] 13 | _ = x[EnumMetadataKind-513] 14 | _ = x[OptionalMetadataKind-514] 15 | _ = x[ForeignClassMetadataKind-515] 16 | _ = x[ForeignReferenceTypeMetadataKind-516] 17 | _ = x[OpaqueMetadataKind-768] 18 | _ = x[TupleMetadataKind-769] 19 | _ = x[FunctionMetadataKind-770] 20 | _ = x[ExistentialMetadataKind-771] 21 | _ = x[MetatypeMetadataKind-772] 22 | _ = x[ObjCClassWrapperMetadataKind-773] 23 | _ = x[ExistentialMetatypeMetadataKind-774] 24 | _ = x[ExtendedExistentialMetadataKind-775] 25 | _ = x[HeapLocalVariableMetadataKind-1024] 26 | _ = x[HeapGenericLocalVariableMetadataKind-1280] 27 | _ = x[ErrorObjectMetadataKind-1281] 28 | _ = x[TaskMetadataKind-1282] 29 | _ = x[JobMetadataKind-1283] 30 | } 31 | 32 | const ( 33 | _MetadataKind_name_0 = "class" 34 | _MetadataKind_name_1 = "structenumoptionalforeign classforeign reference type" 35 | _MetadataKind_name_2 = "opaquetuplefunctionexistentialmetatypeobjc class wrapperexistential metatypeextended existential type" 36 | _MetadataKind_name_3 = "heap local variable" 37 | _MetadataKind_name_4 = "heap generic local variableerror objecttaskjob" 38 | ) 39 | 40 | var ( 41 | _MetadataKind_index_1 = [...]uint8{0, 6, 10, 18, 31, 53} 42 | _MetadataKind_index_2 = [...]uint8{0, 6, 11, 19, 30, 38, 56, 76, 101} 43 | _MetadataKind_index_4 = [...]uint8{0, 27, 39, 43, 46} 44 | ) 45 | 46 | func (i MetadataKind) String() string { 47 | switch { 48 | case i == 0: 49 | return _MetadataKind_name_0 50 | case 512 <= i && i <= 516: 51 | i -= 512 52 | return _MetadataKind_name_1[_MetadataKind_index_1[i]:_MetadataKind_index_1[i+1]] 53 | case 768 <= i && i <= 775: 54 | i -= 768 55 | return _MetadataKind_name_2[_MetadataKind_index_2[i]:_MetadataKind_index_2[i+1]] 56 | case i == 1024: 57 | return _MetadataKind_name_3 58 | case 1280 <= i && i <= 1283: 59 | i -= 1280 60 | return _MetadataKind_name_4[_MetadataKind_index_4[i]:_MetadataKind_index_4[i+1]] 61 | default: 62 | return "MetadataKind(" + strconv.FormatInt(int64(i), 10) + ")" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /types/swift/multi_payload_enum.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import "fmt" 4 | 5 | type MultiPayloadEnum struct { 6 | Address uint64 7 | Type string 8 | Contents []uint32 9 | } 10 | 11 | func (e MultiPayloadEnum) String() string { 12 | return fmt.Sprintf("// %#x (multi-payload)\nenum %s {}", e.Address, e.Type) 13 | } 14 | 15 | // ref: include/swift/RemoteInspection/Records.h 16 | type MultiPayloadEnumDescriptor struct { 17 | TypeName int32 18 | Contents []uint32 19 | } 20 | 21 | type MultiPayloadEnumSizeAndFlags uint32 22 | 23 | func (f MultiPayloadEnumSizeAndFlags) Size() uint16 { 24 | return uint16(f >> 16) 25 | } 26 | func (f MultiPayloadEnumSizeAndFlags) Flags() uint16 { 27 | return uint16(f & 0xffff) 28 | } 29 | func (f MultiPayloadEnumSizeAndFlags) UsesPayloadSpareBits() bool { 30 | return (f.Flags() & 1) != 0 31 | } 32 | func (f MultiPayloadEnumSizeAndFlags) String() string { 33 | return fmt.Sprintf("size: %d, flags: %d, uses_payload_spare_bits: %t", f.Size(), f.Flags(), f.UsesPayloadSpareBits()) 34 | } 35 | 36 | type MultiPayloadEnumPayloadSpareBitMaskByteCount uint32 37 | 38 | func (f MultiPayloadEnumPayloadSpareBitMaskByteCount) ByteOffset() uint16 { 39 | return uint16(f >> 16) 40 | } 41 | func (f MultiPayloadEnumPayloadSpareBitMaskByteCount) ByteCount() uint16 { 42 | return uint16(f & 0xffff) 43 | } 44 | func (f MultiPayloadEnumPayloadSpareBitMaskByteCount) String() string { 45 | return fmt.Sprintf("byte_offset: %d, byte_count: %d", f.ByteOffset(), f.ByteCount()) 46 | } 47 | -------------------------------------------------------------------------------- /types/swift/protocols_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type GenericRequirementKind,ProtocolRequirementKind,GenericPackKind,SpecialProtocol -linecomment -output protocols_string.go"; DO NOT EDIT. 2 | 3 | package swift 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[GRKindProtocol-0] 12 | _ = x[GRKindSameType-1] 13 | _ = x[GRKindBaseClass-2] 14 | _ = x[GRKindSameConformance-3] 15 | _ = x[GRKSameShape-4] 16 | _ = x[GRKindLayout-31] 17 | } 18 | 19 | const ( 20 | _GenericRequirementKind_name_0 = "protocolsame-typebase-classsame-conformancesame-shape" 21 | _GenericRequirementKind_name_1 = "layout" 22 | ) 23 | 24 | var ( 25 | _GenericRequirementKind_index_0 = [...]uint8{0, 8, 17, 27, 43, 53} 26 | ) 27 | 28 | func (i GenericRequirementKind) String() string { 29 | switch { 30 | case i <= 4: 31 | return _GenericRequirementKind_name_0[_GenericRequirementKind_index_0[i]:_GenericRequirementKind_index_0[i+1]] 32 | case i == 31: 33 | return _GenericRequirementKind_name_1 34 | default: 35 | return "GenericRequirementKind(" + strconv.FormatInt(int64(i), 10) + ")" 36 | } 37 | } 38 | func _() { 39 | // An "invalid array index" compiler error signifies that the constant values have changed. 40 | // Re-run the stringer command to generate them again. 41 | var x [1]struct{} 42 | _ = x[PRKindBaseProtocol-0] 43 | _ = x[PRKindMethod-1] 44 | _ = x[PRKindInit-2] 45 | _ = x[PRKindGetter-3] 46 | _ = x[PRKindSetter-4] 47 | _ = x[PRKindReadCoroutine-5] 48 | _ = x[PRKindModifyCoroutine-6] 49 | _ = x[PRKindAssociatedTypeAccessFunction-7] 50 | _ = x[PRKindAssociatedConformanceAccessFunction-8] 51 | } 52 | 53 | const _ProtocolRequirementKind_name = "base protocolmethodinitializergettersetterread coroutinemodify coroutineassociated type access functionassociated conformance access function" 54 | 55 | var _ProtocolRequirementKind_index = [...]uint8{0, 13, 19, 30, 36, 42, 56, 72, 103, 141} 56 | 57 | func (i ProtocolRequirementKind) String() string { 58 | if i >= ProtocolRequirementKind(len(_ProtocolRequirementKind_index)-1) { 59 | return "ProtocolRequirementKind(" + strconv.FormatInt(int64(i), 10) + ")" 60 | } 61 | return _ProtocolRequirementKind_name[_ProtocolRequirementKind_index[i]:_ProtocolRequirementKind_index[i+1]] 62 | } 63 | func _() { 64 | // An "invalid array index" compiler error signifies that the constant values have changed. 65 | // Re-run the stringer command to generate them again. 66 | var x [1]struct{} 67 | _ = x[GPKMetadata-0] 68 | _ = x[GPKWitnessTable-1] 69 | } 70 | 71 | const _GenericPackKind_name = "metadatawitness-table" 72 | 73 | var _GenericPackKind_index = [...]uint8{0, 8, 21} 74 | 75 | func (i GenericPackKind) String() string { 76 | if i >= GenericPackKind(len(_GenericPackKind_index)-1) { 77 | return "GenericPackKind(" + strconv.FormatInt(int64(i), 10) + ")" 78 | } 79 | return _GenericPackKind_name[_GenericPackKind_index[i]:_GenericPackKind_index[i+1]] 80 | } 81 | func _() { 82 | // An "invalid array index" compiler error signifies that the constant values have changed. 83 | // Re-run the stringer command to generate them again. 84 | var x [1]struct{} 85 | _ = x[None-0] 86 | _ = x[Error-1] 87 | } 88 | 89 | const _SpecialProtocol_name = "noneerror" 90 | 91 | var _SpecialProtocol_index = [...]uint8{0, 4, 9} 92 | 93 | func (i SpecialProtocol) String() string { 94 | if i >= SpecialProtocol(len(_SpecialProtocol_index)-1) { 95 | return "SpecialProtocol(" + strconv.FormatInt(int64(i), 10) + ")" 96 | } 97 | return _SpecialProtocol_name[_SpecialProtocol_index[i]:_SpecialProtocol_index[i+1]] 98 | } 99 | -------------------------------------------------------------------------------- /types/swift/relative_pointer.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | type RelativeString struct { 10 | RelativeDirectPointer 11 | Name string 12 | } 13 | 14 | type RelativeDirectPointer struct { 15 | Address uint64 16 | RelOff int32 17 | } 18 | 19 | func (r RelativeDirectPointer) GetAddress() uint64 { 20 | return uint64(int64(r.Address) + int64(r.RelOff)) 21 | } 22 | func (r RelativeDirectPointer) IsSet() bool { 23 | return r.RelOff != 0 24 | } 25 | func (p *RelativeDirectPointer) Read(r io.Reader, addr uint64) error { 26 | p.Address = addr 27 | return binary.Read(r, binary.LittleEndian, &p.RelOff) 28 | } 29 | 30 | type TargetRelativeDirectPointer struct { 31 | Address uint64 32 | RelOff int32 33 | } 34 | 35 | func (tr TargetRelativeDirectPointer) IsSet() bool { 36 | return tr.RelOff != 0 37 | } 38 | func (tr TargetRelativeDirectPointer) GetRelPtrAddress() uint64 { 39 | return uint64(int64(tr.Address) + int64(tr.RelOff)) 40 | } 41 | func (tr TargetRelativeDirectPointer) GetAddress(r io.Reader) (uint64, error) { 42 | var pointerRelOff int32 43 | if err := binary.Read(r, binary.LittleEndian, &pointerRelOff); err != nil { 44 | return 0, err 45 | } 46 | return uint64(int64(tr.Address) + int64(tr.RelOff) + int64(pointerRelOff)), nil 47 | } 48 | 49 | type RelativeIndirectablePointer struct { 50 | Address uint64 51 | RelOff int32 52 | } 53 | 54 | func (ri RelativeIndirectablePointer) IsSet() bool { 55 | return ri.RelOff != 0 56 | } 57 | func (ri RelativeIndirectablePointer) GetRelPtrAddress() uint64 { 58 | return uint64(int64(ri.Address) + int64(ri.RelOff)) 59 | } 60 | func (ri RelativeIndirectablePointer) GetAddress(readPtr func(uint64) (uint64, error)) (uint64, error) { 61 | addr := ri.GetRelPtrAddress() 62 | if (addr & 1) == 1 { 63 | addr = addr &^ 1 64 | return readPtr(addr) 65 | } else { 66 | return addr, nil 67 | } 68 | } 69 | 70 | type RelativeTargetProtocolDescriptorPointer struct { 71 | Address uint64 72 | RelOff int32 73 | } 74 | 75 | func (r RelativeTargetProtocolDescriptorPointer) IsSet() bool { 76 | return r.RelOff != 0 77 | } 78 | func (r RelativeTargetProtocolDescriptorPointer) mask() uint64 { 79 | return uint64(4-1) &^ 1 80 | } 81 | func (r RelativeTargetProtocolDescriptorPointer) IsObjC() bool { 82 | return uint64(int64(r.Address)+int64(r.RelOff))&r.mask()>>1 == 1 83 | } 84 | func (r RelativeTargetProtocolDescriptorPointer) GetRelPtrAddress() uint64 { 85 | return uint64(int64(r.Address)+int64(r.RelOff)) &^ r.mask() 86 | } 87 | func (r RelativeTargetProtocolDescriptorPointer) GetAddress(readPtr func(uint64) (uint64, error)) (uint64, error) { 88 | addr := r.GetRelPtrAddress() 89 | if (addr & 1) == 1 { 90 | addr = addr &^ 1 91 | return readPtr(addr) 92 | } else { 93 | return addr, nil 94 | } 95 | } 96 | func (r RelativeTargetProtocolDescriptorPointer) String() string { 97 | return fmt.Sprintf("addr: %#x, off: %d, mask: %#x, objc: %t -> %#x", r.Address, r.RelOff, r.mask(), r.IsObjC(), r.GetRelPtrAddress()) 98 | } 99 | -------------------------------------------------------------------------------- /types/swift/replacements.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | // __TEXT.__swift5_replace 4 | // This section contains dynamic replacement information. 5 | // This is essentially the Swift equivalent of Objective-C method swizzling. 6 | 7 | type AutomaticDynamicReplacements struct { 8 | Flags uint32 9 | NumScopes uint32 10 | AutomaticDynamicReplacementEntry 11 | } 12 | 13 | type AutomaticDynamicReplacementEntry struct { 14 | ReplacementScope int32 // DynamicReplacementScope 15 | Flags uint32 16 | } 17 | 18 | type DynamicReplacementKey struct { 19 | Root int32 20 | Flags uint32 21 | } 22 | 23 | func (d DynamicReplacementKey) ExtraDiscriminator() uint16 { 24 | return uint16(d.Flags & 0x0000FFFF) 25 | } 26 | func (d DynamicReplacementKey) IsAsync() bool { 27 | return ((d.Flags >> 16) & 0x1) != 0 28 | } 29 | 30 | type DynamicReplacementScope struct { 31 | Flags uint32 32 | NumReplacements uint32 // hard coded to 1 33 | DynamicReplacementDescriptor 34 | } 35 | 36 | const EnableChainingMask = 0x1 37 | 38 | type DynamicReplacementDescriptor struct { 39 | ReplacedFunctionKey int32 // DynamicReplacementKey 40 | ReplacementFunction int32 // UNION w/ ReplacementAsyncFunction - TargetCompactFunctionPointer|TargetRelativeDirectPointer 41 | ChainEntry int32 // DynamicReplacementChainEntry 42 | Flags uint32 43 | } 44 | 45 | func (d DynamicReplacementDescriptor) ShouldChain() bool { 46 | return (d.Flags & EnableChainingMask) != 0 47 | } 48 | 49 | type DynamicReplacementChainEntry struct { 50 | ImplementationFunction uint64 // void * 51 | Next uint64 // DynamicReplacementChainEntry * 52 | } 53 | 54 | // __TEXT.__swift5_replac2 55 | // This section contains dynamic replacement information for opaque types. 56 | 57 | type DynamicReplacementSomeDescriptor struct { 58 | OriginalOpaqueTypeDesc int32 // OpaqueTypeDescriptor -> TargetContextDescriptor 59 | ReplacementOpaqueTypeDesc int32 // OpaqueTypeDescriptor -> TargetContextDescriptor 60 | } 61 | 62 | type AutomaticDynamicReplacementsSome struct { 63 | Flags uint32 64 | NumReplacements uint32 65 | Replacements []DynamicReplacementSomeDescriptor 66 | } 67 | -------------------------------------------------------------------------------- /types/swift/swift_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type SpecialPointerAuthDiscriminators -trimprefix=Disc -output swift_string.go"; DO NOT EDIT. 2 | 3 | package swift 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[DiscHeapDestructor-48063] 12 | _ = x[DiscTypeDescriptor-44678] 13 | _ = x[DiscRuntimeFunctionEntry-25179] 14 | _ = x[DiscProtocolConformanceDescriptor-50923] 15 | _ = x[DiscValueWitnessTable-11839] 16 | _ = x[DiscExtendedExistentialTypeShape-23101] 17 | _ = x[DiscNonUniqueExtendedExistentialTypeShape-59288] 18 | _ = x[DiscInitializeBufferWithCopyOfBuffer-55882] 19 | _ = x[DiscDestroy-1272] 20 | _ = x[DiscInitializeWithCopy-58298] 21 | _ = x[DiscAssignWithCopy-34641] 22 | _ = x[DiscInitializeWithTake-18648] 23 | _ = x[DiscAssignWithTake-61402] 24 | _ = x[DiscDestroyArray-9112] 25 | _ = x[DiscInitializeArrayWithCopy-41052] 26 | _ = x[DiscInitializeArrayWithTakeFrontToBack-7230] 27 | _ = x[DiscInitializeArrayWithTakeBackToFront-36307] 28 | _ = x[DiscStoreExtraInhabitant-31173] 29 | _ = x[DiscGetExtraInhabitantIndex-11432] 30 | _ = x[DiscGetEnumTag-41909] 31 | _ = x[DiscDestructiveProjectEnumData-1053] 32 | _ = x[DiscDestructiveInjectEnumTag-45796] 33 | _ = x[DiscGetEnumTagSinglePayload-24816] 34 | _ = x[DiscStoreEnumTagSinglePayload-41169] 35 | _ = x[DiscKeyPathDestroy-28786] 36 | _ = x[DiscKeyPathCopy-28518] 37 | _ = x[DiscKeyPathEquals-30062] 38 | _ = x[DiscKeyPathHash-25460] 39 | _ = x[DiscKeyPathGetter-28530] 40 | _ = x[DiscKeyPathNonmutatingSetter-28528] 41 | _ = x[DiscKeyPathMutatingSetter-29801] 42 | _ = x[DiscKeyPathGetLayout-25459] 43 | _ = x[DiscKeyPathInitializer-25205] 44 | _ = x[DiscKeyPathMetadataAccessor-29812] 45 | _ = x[DiscObjectiveCTypeDiscriminator-12739] 46 | _ = x[DiscbridgeToObjectiveCDiscriminator-48288] 47 | _ = x[DiscforceBridgeFromObjectiveCDiscriminator-8955] 48 | _ = x[DiscconditionallyBridgeFromObjectiveCDiscriminator-39579] 49 | _ = x[DiscDynamicReplacementScope-18672] 50 | _ = x[DiscDynamicReplacementKey-11389] 51 | _ = x[DiscOpaqueReadResumeFunction-56769] 52 | _ = x[DiscOpaqueModifyResumeFunction-3909] 53 | _ = x[DiscObjCISA-27361] 54 | _ = x[DiscObjCSuperclass-46507] 55 | _ = x[DiscResilientClassStubInitCallback-50801] 56 | _ = x[DiscJobInvokeFunction-52324] 57 | _ = x[DiscTaskResumeFunction-11330] 58 | _ = x[DiscTaskResumeContext-30010] 59 | _ = x[DiscAsyncRunAndBlockFunction-3848] 60 | _ = x[DiscAsyncContextParent-48546] 61 | _ = x[DiscAsyncContextResume-55047] 62 | _ = x[DiscAsyncContextYield-57863] 63 | _ = x[DiscCancellationNotificationFunction-6451] 64 | _ = x[DiscEscalationNotificationFunction-23524] 65 | _ = x[DiscAsyncThinNullaryFunction-3848] 66 | _ = x[DiscAsyncFutureFunction-29199] 67 | _ = x[DiscSwiftAsyncContextExtendedFrameEntry-49946] 68 | _ = x[DiscClangTypeTaskContinuationFunction-10942] 69 | _ = x[DiscDispatchInvokeFunction-62611] 70 | _ = x[DiscAccessibleFunctionRecord-17292] 71 | } 72 | 73 | const _SpecialPointerAuthDiscriminators_name = "DestructiveProjectEnumDataDestroyAsyncRunAndBlockFunctionOpaqueModifyResumeFunctionCancellationNotificationFunctionInitializeArrayWithTakeFrontToBackforceBridgeFromObjectiveCDiscriminatorDestroyArrayClangTypeTaskContinuationFunctionTaskResumeFunctionDynamicReplacementKeyGetExtraInhabitantIndexValueWitnessTableObjectiveCTypeDiscriminatorAccessibleFunctionRecordInitializeWithTakeDynamicReplacementScopeExtendedExistentialTypeShapeEscalationNotificationFunctionGetEnumTagSinglePayloadRuntimeFunctionEntryKeyPathInitializerKeyPathGetLayoutKeyPathHashObjCISAKeyPathCopyKeyPathNonmutatingSetterKeyPathGetterKeyPathDestroyAsyncFutureFunctionKeyPathMutatingSetterKeyPathMetadataAccessorTaskResumeContextKeyPathEqualsStoreExtraInhabitantAssignWithCopyInitializeArrayWithTakeBackToFrontconditionallyBridgeFromObjectiveCDiscriminatorInitializeArrayWithCopyStoreEnumTagSinglePayloadGetEnumTagTypeDescriptorDestructiveInjectEnumTagObjCSuperclassHeapDestructorbridgeToObjectiveCDiscriminatorAsyncContextParentSwiftAsyncContextExtendedFrameEntryResilientClassStubInitCallbackProtocolConformanceDescriptorJobInvokeFunctionAsyncContextResumeInitializeBufferWithCopyOfBufferOpaqueReadResumeFunctionAsyncContextYieldInitializeWithCopyNonUniqueExtendedExistentialTypeShapeAssignWithTakeDispatchInvokeFunction" 74 | 75 | var _SpecialPointerAuthDiscriminators_map = map[SpecialPointerAuthDiscriminators]string{ 76 | 1053: _SpecialPointerAuthDiscriminators_name[0:26], 77 | 1272: _SpecialPointerAuthDiscriminators_name[26:33], 78 | 3848: _SpecialPointerAuthDiscriminators_name[33:57], 79 | 3909: _SpecialPointerAuthDiscriminators_name[57:83], 80 | 6451: _SpecialPointerAuthDiscriminators_name[83:115], 81 | 7230: _SpecialPointerAuthDiscriminators_name[115:149], 82 | 8955: _SpecialPointerAuthDiscriminators_name[149:187], 83 | 9112: _SpecialPointerAuthDiscriminators_name[187:199], 84 | 10942: _SpecialPointerAuthDiscriminators_name[199:232], 85 | 11330: _SpecialPointerAuthDiscriminators_name[232:250], 86 | 11389: _SpecialPointerAuthDiscriminators_name[250:271], 87 | 11432: _SpecialPointerAuthDiscriminators_name[271:294], 88 | 11839: _SpecialPointerAuthDiscriminators_name[294:311], 89 | 12739: _SpecialPointerAuthDiscriminators_name[311:338], 90 | 17292: _SpecialPointerAuthDiscriminators_name[338:362], 91 | 18648: _SpecialPointerAuthDiscriminators_name[362:380], 92 | 18672: _SpecialPointerAuthDiscriminators_name[380:403], 93 | 23101: _SpecialPointerAuthDiscriminators_name[403:431], 94 | 23524: _SpecialPointerAuthDiscriminators_name[431:461], 95 | 24816: _SpecialPointerAuthDiscriminators_name[461:484], 96 | 25179: _SpecialPointerAuthDiscriminators_name[484:504], 97 | 25205: _SpecialPointerAuthDiscriminators_name[504:522], 98 | 25459: _SpecialPointerAuthDiscriminators_name[522:538], 99 | 25460: _SpecialPointerAuthDiscriminators_name[538:549], 100 | 27361: _SpecialPointerAuthDiscriminators_name[549:556], 101 | 28518: _SpecialPointerAuthDiscriminators_name[556:567], 102 | 28528: _SpecialPointerAuthDiscriminators_name[567:591], 103 | 28530: _SpecialPointerAuthDiscriminators_name[591:604], 104 | 28786: _SpecialPointerAuthDiscriminators_name[604:618], 105 | 29199: _SpecialPointerAuthDiscriminators_name[618:637], 106 | 29801: _SpecialPointerAuthDiscriminators_name[637:658], 107 | 29812: _SpecialPointerAuthDiscriminators_name[658:681], 108 | 30010: _SpecialPointerAuthDiscriminators_name[681:698], 109 | 30062: _SpecialPointerAuthDiscriminators_name[698:711], 110 | 31173: _SpecialPointerAuthDiscriminators_name[711:731], 111 | 34641: _SpecialPointerAuthDiscriminators_name[731:745], 112 | 36307: _SpecialPointerAuthDiscriminators_name[745:779], 113 | 39579: _SpecialPointerAuthDiscriminators_name[779:825], 114 | 41052: _SpecialPointerAuthDiscriminators_name[825:848], 115 | 41169: _SpecialPointerAuthDiscriminators_name[848:873], 116 | 41909: _SpecialPointerAuthDiscriminators_name[873:883], 117 | 44678: _SpecialPointerAuthDiscriminators_name[883:897], 118 | 45796: _SpecialPointerAuthDiscriminators_name[897:921], 119 | 46507: _SpecialPointerAuthDiscriminators_name[921:935], 120 | 48063: _SpecialPointerAuthDiscriminators_name[935:949], 121 | 48288: _SpecialPointerAuthDiscriminators_name[949:980], 122 | 48546: _SpecialPointerAuthDiscriminators_name[980:998], 123 | 49946: _SpecialPointerAuthDiscriminators_name[998:1033], 124 | 50801: _SpecialPointerAuthDiscriminators_name[1033:1063], 125 | 50923: _SpecialPointerAuthDiscriminators_name[1063:1092], 126 | 52324: _SpecialPointerAuthDiscriminators_name[1092:1109], 127 | 55047: _SpecialPointerAuthDiscriminators_name[1109:1127], 128 | 55882: _SpecialPointerAuthDiscriminators_name[1127:1159], 129 | 56769: _SpecialPointerAuthDiscriminators_name[1159:1183], 130 | 57863: _SpecialPointerAuthDiscriminators_name[1183:1200], 131 | 58298: _SpecialPointerAuthDiscriminators_name[1200:1218], 132 | 59288: _SpecialPointerAuthDiscriminators_name[1218:1255], 133 | 61402: _SpecialPointerAuthDiscriminators_name[1255:1269], 134 | 62611: _SpecialPointerAuthDiscriminators_name[1269:1291], 135 | } 136 | 137 | func (i SpecialPointerAuthDiscriminators) String() string { 138 | if str, ok := _SpecialPointerAuthDiscriminators_map[i]; ok { 139 | return str 140 | } 141 | return "SpecialPointerAuthDiscriminators(" + strconv.FormatInt(int64(i), 10) + ")" 142 | } 143 | -------------------------------------------------------------------------------- /types/swift/type_anon.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "io" 5 | 6 | "github.com/blacktop/go-macho/types" 7 | ) 8 | 9 | // Flags for anonymous type context descriptors. These values are used as the 10 | // kindSpecificFlags of the ContextDescriptorFlags for the anonymous context. 11 | type AnonymousContextDescriptorFlags uint16 12 | 13 | const ( 14 | // Whether this anonymous context descriptor is followed by its 15 | // mangled name, which can be used to match the descriptor at runtime. 16 | HasMangledName = 0 17 | ) 18 | 19 | func (f AnonymousContextDescriptorFlags) HasMangledName() bool { 20 | return types.ExtractBits(uint64(f), HasMangledName, 1) != 0 21 | } 22 | 23 | type Anonymous struct { 24 | TargetAnonymousContextDescriptor 25 | GenericContext *GenericContext 26 | MangledContextName string 27 | } 28 | 29 | type TargetAnonymousContextDescriptor struct { 30 | TargetContextDescriptor 31 | } 32 | 33 | func (tacd TargetAnonymousContextDescriptor) HasMangledName() bool { 34 | return AnonymousContextDescriptorFlags(tacd.Flags.KindSpecific()).HasMangledName() 35 | } 36 | 37 | func (tacd TargetAnonymousContextDescriptor) Size() int64 { 38 | return tacd.TargetContextDescriptor.Size() 39 | } 40 | 41 | func (tacd *TargetAnonymousContextDescriptor) Read(r io.Reader, addr uint64) error { 42 | if err := tacd.TargetContextDescriptor.Read(r, addr); err != nil { 43 | return err 44 | } 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /types/swift/type_enum.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | type Enum struct { 10 | TargetEnumDescriptor 11 | GenericContext *TypeGenericContext 12 | ForeignMetadata *TargetForeignMetadataInitialization 13 | SingletonMetadata *TargetSingletonMetadataInitialization 14 | Metadatas []Metadata 15 | CachingOnceToken *TargetCanonicalSpecializedMetadatasCachingOnceToken 16 | } 17 | 18 | type TargetEnumDescriptor struct { 19 | TargetTypeContextDescriptor 20 | NumPayloadCasesAndPayloadSizeOffset uint32 21 | NumEmptyCases uint32 22 | } 23 | 24 | func (e TargetEnumDescriptor) Size() int64 { 25 | return int64( 26 | int(e.TargetTypeContextDescriptor.Size()) + 27 | binary.Size(e.NumPayloadCasesAndPayloadSizeOffset) + 28 | binary.Size(e.NumEmptyCases)) 29 | } 30 | 31 | func (e *TargetEnumDescriptor) Read(r io.Reader, addr uint64) error { 32 | if err := e.TargetTypeContextDescriptor.Read(r, addr); err != nil { 33 | return err 34 | } 35 | if err := binary.Read(r, binary.LittleEndian, &e.NumPayloadCasesAndPayloadSizeOffset); err != nil { 36 | return err 37 | } 38 | if err := binary.Read(r, binary.LittleEndian, &e.NumEmptyCases); err != nil { 39 | return err 40 | } 41 | return nil 42 | } 43 | 44 | func (e TargetEnumDescriptor) GetNumPayloadCases() uint32 { 45 | return e.NumPayloadCasesAndPayloadSizeOffset & 0x00FFFFFF 46 | } 47 | func (e TargetEnumDescriptor) GetNumCases() uint32 { 48 | return e.GetNumPayloadCases() + e.NumEmptyCases 49 | } 50 | func (e TargetEnumDescriptor) GetPayloadSizeOffset() uint32 { 51 | return (e.NumPayloadCasesAndPayloadSizeOffset & 0xFF000000) >> 24 52 | } 53 | func (e TargetEnumDescriptor) String() string { 54 | return fmt.Sprintf("num_payload_cases %d, num_cases %d, num_empty_cases %d, payload_size_offset %d", 55 | e.GetNumPayloadCases(), 56 | e.GetNumCases(), 57 | e.NumEmptyCases, 58 | e.GetPayloadSizeOffset()) 59 | } 60 | -------------------------------------------------------------------------------- /types/swift/type_ext.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | type Extension struct { 9 | TargetExtensionContextDescriptor 10 | GenericContext *GenericContext 11 | } 12 | 13 | type TargetExtensionContextDescriptor struct { 14 | TargetContextDescriptor 15 | // A mangling of the `Self` type context that the extension extends. 16 | // The mangled name represents the type in the generic context encoded by 17 | // this descriptor. For example, a nongeneric nominal type extension will 18 | // encode the nominal type name. A generic nominal type extension will encode 19 | // the instance of the type with any generic arguments bound. 20 | // 21 | // Note that the Parent of the extension will be the module context the 22 | // extension is declared inside. 23 | ExtendedContext RelativeDirectPointer 24 | } 25 | 26 | func (e TargetExtensionContextDescriptor) Size() int64 { 27 | return int64(int(e.TargetContextDescriptor.Size()) + binary.Size(e.ExtendedContext.RelOff)) 28 | } 29 | 30 | func (tmcd *TargetExtensionContextDescriptor) Read(r io.Reader, addr uint64) error { 31 | if err := tmcd.TargetContextDescriptor.Read(r, addr); err != nil { 32 | return err 33 | } 34 | addr += uint64(tmcd.TargetContextDescriptor.Size()) 35 | tmcd.ExtendedContext.Address = addr 36 | if err := binary.Read(r, binary.LittleEndian, &tmcd.ExtendedContext.RelOff); err != nil { 37 | return err 38 | } 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /types/swift/type_mod.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | type TargetModuleContext struct { 9 | TargetModuleContextDescriptor 10 | Name string 11 | Parent string 12 | } 13 | 14 | type TargetModuleContextDescriptor struct { 15 | TargetContextDescriptor 16 | NameOffset RelativeDirectPointer 17 | } 18 | 19 | func (tmc TargetModuleContextDescriptor) Size() int64 { 20 | return int64(int(tmc.TargetContextDescriptor.Size()) + binary.Size(tmc.NameOffset.RelOff)) 21 | } 22 | 23 | func (tmcd *TargetModuleContextDescriptor) Read(r io.Reader, addr uint64) error { 24 | if err := tmcd.TargetContextDescriptor.Read(r, addr); err != nil { 25 | return err 26 | } 27 | addr += uint64(tmcd.TargetContextDescriptor.Size()) 28 | tmcd.NameOffset.Address = addr 29 | if err := binary.Read(r, binary.LittleEndian, &tmcd.NameOffset.RelOff); err != nil { 30 | return err 31 | } 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /types/swift/type_struct.go: -------------------------------------------------------------------------------- 1 | package swift 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | type Struct struct { 9 | TargetStructDescriptor 10 | GenericContext *TypeGenericContext 11 | ForeignMetadata *TargetForeignMetadataInitialization 12 | SingletonMetadata *TargetSingletonMetadataInitialization 13 | Metadatas []Metadata 14 | CachingOnceToken *TargetCanonicalSpecializedMetadatasCachingOnceToken 15 | } 16 | 17 | type TargetStructDescriptor struct { 18 | TargetTypeContextDescriptor 19 | // The number of stored properties in the struct. 20 | // If there is a field offset vector, this is its length. 21 | NumFields uint32 22 | // The offset of the field offset vector for this struct's stored 23 | // properties in its metadata, if any. 0 means there is no field offset vector. 24 | FieldOffsetVectorOffset uint32 25 | } 26 | 27 | func (s TargetStructDescriptor) Size() int64 { 28 | return int64( 29 | int(s.TargetTypeContextDescriptor.Size()) + 30 | binary.Size(s.NumFields) + 31 | binary.Size(s.FieldOffsetVectorOffset)) 32 | } 33 | 34 | func (s *TargetStructDescriptor) Read(r io.Reader, addr uint64) error { 35 | if err := s.TargetTypeContextDescriptor.Read(r, addr); err != nil { 36 | return err 37 | } 38 | if err := binary.Read(r, binary.LittleEndian, &s.NumFields); err != nil { 39 | return err 40 | } 41 | if err := binary.Read(r, binary.LittleEndian, &s.FieldOffsetVectorOffset); err != nil { 42 | return err 43 | } 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /types/swift/types_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type ContextDescriptorKind,TypeReferenceKind,MetadataInitializationKind,SpecialKind,GenericParamKind,GenericRequirementLayoutKind -linecomment -output types_string.go"; DO NOT EDIT. 2 | 3 | package swift 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[CDKindModule-0] 12 | _ = x[CDKindExtension-1] 13 | _ = x[CDKindAnonymous-2] 14 | _ = x[CDKindProtocol-3] 15 | _ = x[CDKindOpaqueType-4] 16 | _ = x[CDKindClass-16] 17 | _ = x[CDKindStruct-17] 18 | _ = x[CDKindEnum-18] 19 | } 20 | 21 | const ( 22 | _ContextDescriptorKind_name_0 = "moduleextensionanonymousprotocolopaque_type" 23 | _ContextDescriptorKind_name_1 = "classstructenum" 24 | ) 25 | 26 | var ( 27 | _ContextDescriptorKind_index_0 = [...]uint8{0, 6, 15, 24, 32, 43} 28 | _ContextDescriptorKind_index_1 = [...]uint8{0, 5, 11, 15} 29 | ) 30 | 31 | func (i ContextDescriptorKind) String() string { 32 | switch { 33 | case i <= 4: 34 | return _ContextDescriptorKind_name_0[_ContextDescriptorKind_index_0[i]:_ContextDescriptorKind_index_0[i+1]] 35 | case 16 <= i && i <= 18: 36 | i -= 16 37 | return _ContextDescriptorKind_name_1[_ContextDescriptorKind_index_1[i]:_ContextDescriptorKind_index_1[i+1]] 38 | default: 39 | return "ContextDescriptorKind(" + strconv.FormatInt(int64(i), 10) + ")" 40 | } 41 | } 42 | func _() { 43 | // An "invalid array index" compiler error signifies that the constant values have changed. 44 | // Re-run the stringer command to generate them again. 45 | var x [1]struct{} 46 | _ = x[DirectTypeDescriptor-0] 47 | _ = x[IndirectTypeDescriptor-1] 48 | _ = x[DirectObjCClassName-2] 49 | _ = x[IndirectObjCClass-3] 50 | } 51 | 52 | const _TypeReferenceKind_name = "directindirectdirect_objc_classindirect_objc_class" 53 | 54 | var _TypeReferenceKind_index = [...]uint8{0, 6, 14, 31, 50} 55 | 56 | func (i TypeReferenceKind) String() string { 57 | if i >= TypeReferenceKind(len(_TypeReferenceKind_index)-1) { 58 | return "TypeReferenceKind(" + strconv.FormatInt(int64(i), 10) + ")" 59 | } 60 | return _TypeReferenceKind_name[_TypeReferenceKind_index[i]:_TypeReferenceKind_index[i+1]] 61 | } 62 | func _() { 63 | // An "invalid array index" compiler error signifies that the constant values have changed. 64 | // Re-run the stringer command to generate them again. 65 | var x [1]struct{} 66 | _ = x[MetadataInitNone-0] 67 | _ = x[MetadataInitSingleton-1] 68 | _ = x[MetadataInitForeign-2] 69 | } 70 | 71 | const _MetadataInitializationKind_name = "nonesingletonforeign" 72 | 73 | var _MetadataInitializationKind_index = [...]uint8{0, 4, 13, 20} 74 | 75 | func (i MetadataInitializationKind) String() string { 76 | if i >= MetadataInitializationKind(len(_MetadataInitializationKind_index)-1) { 77 | return "MetadataInitializationKind(" + strconv.FormatInt(int64(i), 10) + ")" 78 | } 79 | return _MetadataInitializationKind_name[_MetadataInitializationKind_index[i]:_MetadataInitializationKind_index[i+1]] 80 | } 81 | func _() { 82 | // An "invalid array index" compiler error signifies that the constant values have changed. 83 | // Re-run the stringer command to generate them again. 84 | var x [1]struct{} 85 | _ = x[SKNone-0] 86 | _ = x[SKClass-1] 87 | _ = x[SKMetatype-2] 88 | _ = x[SKExplicitLayout-3] 89 | } 90 | 91 | const _SpecialKind_name = "noneclassmetatypeexplicit layout" 92 | 93 | var _SpecialKind_index = [...]uint8{0, 4, 9, 17, 32} 94 | 95 | func (i SpecialKind) String() string { 96 | if i >= SpecialKind(len(_SpecialKind_index)-1) { 97 | return "SpecialKind(" + strconv.FormatInt(int64(i), 10) + ")" 98 | } 99 | return _SpecialKind_name[_SpecialKind_index[i]:_SpecialKind_index[i+1]] 100 | } 101 | func _() { 102 | // An "invalid array index" compiler error signifies that the constant values have changed. 103 | // Re-run the stringer command to generate them again. 104 | var x [1]struct{} 105 | _ = x[GPKType-0] 106 | _ = x[GPKTypePack-1] 107 | _ = x[GPKMax-63] 108 | } 109 | 110 | const ( 111 | _GenericParamKind_name_0 = "typetype_pack" 112 | _GenericParamKind_name_1 = "max" 113 | ) 114 | 115 | var ( 116 | _GenericParamKind_index_0 = [...]uint8{0, 4, 13} 117 | ) 118 | 119 | func (i GenericParamKind) String() string { 120 | switch { 121 | case i <= 1: 122 | return _GenericParamKind_name_0[_GenericParamKind_index_0[i]:_GenericParamKind_index_0[i+1]] 123 | case i == 63: 124 | return _GenericParamKind_name_1 125 | default: 126 | return "GenericParamKind(" + strconv.FormatInt(int64(i), 10) + ")" 127 | } 128 | } 129 | func _() { 130 | // An "invalid array index" compiler error signifies that the constant values have changed. 131 | // Re-run the stringer command to generate them again. 132 | var x [1]struct{} 133 | _ = x[GRLKClass-0] 134 | } 135 | 136 | const _GenericRequirementLayoutKind_name = "class" 137 | 138 | var _GenericRequirementLayoutKind_index = [...]uint8{0, 5} 139 | 140 | func (i GenericRequirementLayoutKind) String() string { 141 | if i >= GenericRequirementLayoutKind(len(_GenericRequirementLayoutKind_index)-1) { 142 | return "GenericRequirementLayoutKind(" + strconv.FormatInt(int64(i), 10) + ")" 143 | } 144 | return _GenericRequirementLayoutKind_name[_GenericRequirementLayoutKind_index[i]:_GenericRequirementLayoutKind_index[i+1]] 145 | } 146 | -------------------------------------------------------------------------------- /types/types_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Platform,Tool,DiceKind -trimprefix=Platform_ -output types_string.go"; DO NOT EDIT. 2 | 3 | package types 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[Platform_Unknown-0] 12 | _ = x[Platform_macOS-1] 13 | _ = x[Platform_iOS-2] 14 | _ = x[Platform_tvOS-3] 15 | _ = x[Platform_watchOS-4] 16 | _ = x[Platform_bridgeOS-5] 17 | _ = x[Platform_macCatalyst-6] 18 | _ = x[Platform_iOsSimulator-7] 19 | _ = x[Platform_tvOsSimulator-8] 20 | _ = x[Platform_watchOsSimulator-9] 21 | _ = x[Platform_Driverkit-10] 22 | _ = x[Platform_visionOS-11] 23 | _ = x[Platform_visionOsSimulator-12] 24 | _ = x[Platform_Firmware-13] 25 | _ = x[Platform_sepOS-14] 26 | _ = x[Platform_macOSExclaveCore-15] 27 | _ = x[Platform_macOSExclaveKit-16] 28 | _ = x[Platform_iOSExclaveCore-17] 29 | _ = x[Platform_iOSExclaveKit-18] 30 | _ = x[Platform_tvOsExclaveCore-19] 31 | _ = x[Platform_tvOsExclaveKit-20] 32 | _ = x[Platform_watchOsExclaveCore-21] 33 | _ = x[Platform_watchOsExclaveKit-22] 34 | _ = x[ANY-4294967295] 35 | } 36 | 37 | const ( 38 | _Platform_name_0 = "UnknownmacOSiOStvOSwatchOSbridgeOSmacCatalystiOsSimulatortvOsSimulatorwatchOsSimulatorDriverkitvisionOSvisionOsSimulatorFirmwaresepOSmacOSExclaveCoremacOSExclaveKitiOSExclaveCoreiOSExclaveKittvOsExclaveCoretvOsExclaveKitwatchOsExclaveCorewatchOsExclaveKit" 39 | _Platform_name_1 = "ANY" 40 | ) 41 | 42 | var ( 43 | _Platform_index_0 = [...]uint8{0, 7, 12, 15, 19, 26, 34, 45, 57, 70, 86, 95, 103, 120, 128, 133, 149, 164, 178, 191, 206, 220, 238, 255} 44 | ) 45 | 46 | func (i Platform) String() string { 47 | switch { 48 | case i <= 22: 49 | return _Platform_name_0[_Platform_index_0[i]:_Platform_index_0[i+1]] 50 | case i == 4294967295: 51 | return _Platform_name_1 52 | default: 53 | return "Platform(" + strconv.FormatInt(int64(i), 10) + ")" 54 | } 55 | } 56 | func _() { 57 | // An "invalid array index" compiler error signifies that the constant values have changed. 58 | // Re-run the stringer command to generate them again. 59 | var x [1]struct{} 60 | _ = x[none-0] 61 | _ = x[clang-1] 62 | _ = x[swift-2] 63 | _ = x[ld-3] 64 | _ = x[lld-4] 65 | _ = x[Metal-1024] 66 | _ = x[AirLld-1025] 67 | _ = x[AirNt-1026] 68 | _ = x[AirNtPlugin-1027] 69 | _ = x[AirPack-1028] 70 | _ = x[GpuArchiver-1031] 71 | _ = x[MetalFramework-1032] 72 | } 73 | 74 | const ( 75 | _Tool_name_0 = "noneclangswiftldlld" 76 | _Tool_name_1 = "MetalAirLldAirNtAirNtPluginAirPack" 77 | _Tool_name_2 = "GpuArchiverMetalFramework" 78 | ) 79 | 80 | var ( 81 | _Tool_index_0 = [...]uint8{0, 4, 9, 14, 16, 19} 82 | _Tool_index_1 = [...]uint8{0, 5, 11, 16, 27, 34} 83 | _Tool_index_2 = [...]uint8{0, 11, 25} 84 | ) 85 | 86 | func (i Tool) String() string { 87 | switch { 88 | case i <= 4: 89 | return _Tool_name_0[_Tool_index_0[i]:_Tool_index_0[i+1]] 90 | case 1024 <= i && i <= 1028: 91 | i -= 1024 92 | return _Tool_name_1[_Tool_index_1[i]:_Tool_index_1[i+1]] 93 | case 1031 <= i && i <= 1032: 94 | i -= 1031 95 | return _Tool_name_2[_Tool_index_2[i]:_Tool_index_2[i+1]] 96 | default: 97 | return "Tool(" + strconv.FormatInt(int64(i), 10) + ")" 98 | } 99 | } 100 | func _() { 101 | // An "invalid array index" compiler error signifies that the constant values have changed. 102 | // Re-run the stringer command to generate them again. 103 | var x [1]struct{} 104 | _ = x[KindData-1] 105 | _ = x[KindJumpTable8-2] 106 | _ = x[KindJumpTable16-3] 107 | _ = x[KindJumpTable32-4] 108 | _ = x[KindAbsJumpTable32-5] 109 | } 110 | 111 | const _DiceKind_name = "KindDataKindJumpTable8KindJumpTable16KindJumpTable32KindAbsJumpTable32" 112 | 113 | var _DiceKind_index = [...]uint8{0, 8, 22, 37, 52, 70} 114 | 115 | func (i DiceKind) String() string { 116 | i -= 1 117 | if i >= DiceKind(len(_DiceKind_index)-1) { 118 | return "DiceKind(" + strconv.FormatInt(int64(i+1), 10) + ")" 119 | } 120 | return _DiceKind_name[_DiceKind_index[i]:_DiceKind_index[i+1]] 121 | } 122 | --------------------------------------------------------------------------------