mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 01:22:28 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			233 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2019 The Go Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package goobj
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"github.com/twitchyliquid64/golang-asm/objabi"
 | |
| 	"encoding/binary"
 | |
| )
 | |
| 
 | |
| // CUFileIndex is used to index the filenames that are stored in the
 | |
| // per-package/per-CU FileList.
 | |
| type CUFileIndex uint32
 | |
| 
 | |
| // FuncInfo is serialized as a symbol (aux symbol). The symbol data is
 | |
| // the binary encoding of the struct below.
 | |
| //
 | |
| // TODO: make each pcdata a separate symbol?
 | |
| type FuncInfo struct {
 | |
| 	Args   uint32
 | |
| 	Locals uint32
 | |
| 	FuncID objabi.FuncID
 | |
| 
 | |
| 	Pcsp        uint32
 | |
| 	Pcfile      uint32
 | |
| 	Pcline      uint32
 | |
| 	Pcinline    uint32
 | |
| 	Pcdata      []uint32
 | |
| 	PcdataEnd   uint32
 | |
| 	Funcdataoff []uint32
 | |
| 	File        []CUFileIndex
 | |
| 
 | |
| 	InlTree []InlTreeNode
 | |
| }
 | |
| 
 | |
| func (a *FuncInfo) Write(w *bytes.Buffer) {
 | |
| 	var b [4]byte
 | |
| 	writeUint32 := func(x uint32) {
 | |
| 		binary.LittleEndian.PutUint32(b[:], x)
 | |
| 		w.Write(b[:])
 | |
| 	}
 | |
| 
 | |
| 	writeUint32(a.Args)
 | |
| 	writeUint32(a.Locals)
 | |
| 	writeUint32(uint32(a.FuncID))
 | |
| 
 | |
| 	writeUint32(a.Pcsp)
 | |
| 	writeUint32(a.Pcfile)
 | |
| 	writeUint32(a.Pcline)
 | |
| 	writeUint32(a.Pcinline)
 | |
| 	writeUint32(uint32(len(a.Pcdata)))
 | |
| 	for _, x := range a.Pcdata {
 | |
| 		writeUint32(x)
 | |
| 	}
 | |
| 	writeUint32(a.PcdataEnd)
 | |
| 	writeUint32(uint32(len(a.Funcdataoff)))
 | |
| 	for _, x := range a.Funcdataoff {
 | |
| 		writeUint32(x)
 | |
| 	}
 | |
| 	writeUint32(uint32(len(a.File)))
 | |
| 	for _, f := range a.File {
 | |
| 		writeUint32(uint32(f))
 | |
| 	}
 | |
| 	writeUint32(uint32(len(a.InlTree)))
 | |
| 	for i := range a.InlTree {
 | |
| 		a.InlTree[i].Write(w)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (a *FuncInfo) Read(b []byte) {
 | |
| 	readUint32 := func() uint32 {
 | |
| 		x := binary.LittleEndian.Uint32(b)
 | |
| 		b = b[4:]
 | |
| 		return x
 | |
| 	}
 | |
| 
 | |
| 	a.Args = readUint32()
 | |
| 	a.Locals = readUint32()
 | |
| 	a.FuncID = objabi.FuncID(readUint32())
 | |
| 
 | |
| 	a.Pcsp = readUint32()
 | |
| 	a.Pcfile = readUint32()
 | |
| 	a.Pcline = readUint32()
 | |
| 	a.Pcinline = readUint32()
 | |
| 	pcdatalen := readUint32()
 | |
| 	a.Pcdata = make([]uint32, pcdatalen)
 | |
| 	for i := range a.Pcdata {
 | |
| 		a.Pcdata[i] = readUint32()
 | |
| 	}
 | |
| 	a.PcdataEnd = readUint32()
 | |
| 	funcdataofflen := readUint32()
 | |
| 	a.Funcdataoff = make([]uint32, funcdataofflen)
 | |
| 	for i := range a.Funcdataoff {
 | |
| 		a.Funcdataoff[i] = readUint32()
 | |
| 	}
 | |
| 	filelen := readUint32()
 | |
| 	a.File = make([]CUFileIndex, filelen)
 | |
| 	for i := range a.File {
 | |
| 		a.File[i] = CUFileIndex(readUint32())
 | |
| 	}
 | |
| 	inltreelen := readUint32()
 | |
| 	a.InlTree = make([]InlTreeNode, inltreelen)
 | |
| 	for i := range a.InlTree {
 | |
| 		b = a.InlTree[i].Read(b)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // FuncInfoLengths is a cache containing a roadmap of offsets and
 | |
| // lengths for things within a serialized FuncInfo. Each length field
 | |
| // stores the number of items (e.g. files, inltree nodes, etc), and the
 | |
| // corresponding "off" field stores the byte offset of the start of
 | |
| // the items in question.
 | |
| type FuncInfoLengths struct {
 | |
| 	NumPcdata      uint32
 | |
| 	PcdataOff      uint32
 | |
| 	NumFuncdataoff uint32
 | |
| 	FuncdataoffOff uint32
 | |
| 	NumFile        uint32
 | |
| 	FileOff        uint32
 | |
| 	NumInlTree     uint32
 | |
| 	InlTreeOff     uint32
 | |
| 	Initialized    bool
 | |
| }
 | |
| 
 | |
| func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
 | |
| 	var result FuncInfoLengths
 | |
| 
 | |
| 	const numpcdataOff = 28
 | |
| 	result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
 | |
| 	result.PcdataOff = numpcdataOff + 4
 | |
| 
 | |
| 	numfuncdataoffOff := result.PcdataOff + 4*(result.NumPcdata+1)
 | |
| 	result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
 | |
| 	result.FuncdataoffOff = numfuncdataoffOff + 4
 | |
| 
 | |
| 	numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff
 | |
| 	result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:])
 | |
| 	result.FileOff = numfileOff + 4
 | |
| 
 | |
| 	numinltreeOff := result.FileOff + 4*result.NumFile
 | |
| 	result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:])
 | |
| 	result.InlTreeOff = numinltreeOff + 4
 | |
| 
 | |
| 	result.Initialized = true
 | |
| 
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
 | |
| 
 | |
| func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) }
 | |
| 
 | |
| func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) }
 | |
| 
 | |
| // return start and end offsets.
 | |
| func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) {
 | |
| 	return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])
 | |
| }
 | |
| 
 | |
| // return start and end offsets.
 | |
| func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) {
 | |
| 	return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:])
 | |
| }
 | |
| 
 | |
| // return start and end offsets.
 | |
| func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) {
 | |
| 	return binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])
 | |
| }
 | |
| 
 | |
| // return start and end offsets.
 | |
| func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) {
 | |
| 	return binary.LittleEndian.Uint32(b[24:]), binary.LittleEndian.Uint32(b[pcdataoffset:])
 | |
| }
 | |
| 
 | |
| // return start and end offsets.
 | |
| func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) {
 | |
| 	return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:])
 | |
| }
 | |
| 
 | |
| func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
 | |
| 	return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:]))
 | |
| }
 | |
| 
 | |
| func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex {
 | |
| 	return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:]))
 | |
| }
 | |
| 
 | |
| func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode {
 | |
| 	const inlTreeNodeSize = 4 * 6
 | |
| 	var result InlTreeNode
 | |
| 	result.Read(b[inltreeoff+k*inlTreeNodeSize:])
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| // InlTreeNode is the serialized form of FileInfo.InlTree.
 | |
| type InlTreeNode struct {
 | |
| 	Parent   int32
 | |
| 	File     CUFileIndex
 | |
| 	Line     int32
 | |
| 	Func     SymRef
 | |
| 	ParentPC int32
 | |
| }
 | |
| 
 | |
| func (inl *InlTreeNode) Write(w *bytes.Buffer) {
 | |
| 	var b [4]byte
 | |
| 	writeUint32 := func(x uint32) {
 | |
| 		binary.LittleEndian.PutUint32(b[:], x)
 | |
| 		w.Write(b[:])
 | |
| 	}
 | |
| 	writeUint32(uint32(inl.Parent))
 | |
| 	writeUint32(uint32(inl.File))
 | |
| 	writeUint32(uint32(inl.Line))
 | |
| 	writeUint32(inl.Func.PkgIdx)
 | |
| 	writeUint32(inl.Func.SymIdx)
 | |
| 	writeUint32(uint32(inl.ParentPC))
 | |
| }
 | |
| 
 | |
| // Read an InlTreeNode from b, return the remaining bytes.
 | |
| func (inl *InlTreeNode) Read(b []byte) []byte {
 | |
| 	readUint32 := func() uint32 {
 | |
| 		x := binary.LittleEndian.Uint32(b)
 | |
| 		b = b[4:]
 | |
| 		return x
 | |
| 	}
 | |
| 	inl.Parent = int32(readUint32())
 | |
| 	inl.File = CUFileIndex(readUint32())
 | |
| 	inl.Line = int32(readUint32())
 | |
| 	inl.Func = SymRef{readUint32(), readUint32()}
 | |
| 	inl.ParentPC = int32(readUint32())
 | |
| 	return b
 | |
| }
 |