github.com/lsg2020/gort@v0.0.0-20220515072951-7a7794baa036/gort_plugin.go (about)

     1  package gort
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"io"
     8  	"strings"
     9  
    10  	"github.com/go-delve/delve/pkg/proc"
    11  )
    12  
    13  func (d *DwarfRT) SearchPluginByName(name string) (string, uint64, error) {
    14  	libs, addr, err := d.SearchPlugins()
    15  	if err != nil {
    16  		return "", 0, err
    17  	}
    18  	for i := 0; i < len(libs); i++ {
    19  		if strings.LastIndex(libs[i], name) >= 0 {
    20  			return libs[i], addr[i], nil
    21  		}
    22  	}
    23  	return "", 0, ErrNotFound
    24  }
    25  
    26  func (d *DwarfRT) SearchPlugins() ([]string, []uint64, error) {
    27  	if err := d.check(); err != nil {
    28  		return nil, nil, err
    29  	}
    30  	bi := d.bi
    31  
    32  	if bi.ElfDynamicSection.Addr == 0 {
    33  		// no dynamic section, therefore nothing to do here
    34  		return nil, nil, nil
    35  	}
    36  	debugAddr, err := dynamicSearchDebug(bi)
    37  	if err != nil {
    38  		return nil, nil, err
    39  	}
    40  	if debugAddr == 0 {
    41  		// no DT_DEBUG entry
    42  		return nil, nil, nil
    43  	}
    44  
    45  	// Offsets of the fields of the r_debug and link_map structs,
    46  	// see /usr/include/elf/link.h for a full description of those structs.
    47  	debugMapOffset := uint64(bi.Arch.PtrSize())
    48  
    49  	r_map, err := readPtr(bi, debugAddr+debugMapOffset)
    50  	if err != nil {
    51  		return nil, nil, err
    52  	}
    53  
    54  	var libs []string
    55  	var addr []uint64
    56  
    57  	for {
    58  		if r_map == 0 {
    59  			break
    60  		}
    61  		if len(libs) > maxNumLibraries {
    62  			return nil, nil, ErrTooManyLibraries
    63  		}
    64  		lm, err := readLinkMapNode(bi, r_map)
    65  		if err != nil {
    66  			return nil, nil, err
    67  		}
    68  
    69  		libs = append(libs, lm.name)
    70  		addr = append(addr, lm.addr)
    71  		r_map = lm.next
    72  	}
    73  
    74  	return libs, addr, nil
    75  }
    76  
    77  const (
    78  	maxNumLibraries      = 1000000 // maximum number of loaded libraries, to avoid loading forever on corrupted memory
    79  	maxLibraryPathLength = 1000000 // maximum length for the path of a library, to avoid loading forever on corrupted memory
    80  )
    81  
    82  const (
    83  	_DT_NULL  = 0  // DT_NULL as defined by SysV ABI specification
    84  	_DT_DEBUG = 21 // DT_DEBUG as defined by SysV ABI specification
    85  )
    86  
    87  func readPtr(bi *proc.BinaryInfo, addr uint64) (uint64, error) {
    88  	ptrbuf := entryAddress(uintptr(addr), bi.Arch.PtrSize())
    89  	return readUintRaw(bytes.NewReader(ptrbuf), binary.LittleEndian, bi.Arch.PtrSize())
    90  }
    91  
    92  // readUintRaw reads an integer of ptrSize bytes, with the specified byte order, from reader.
    93  func readUintRaw(reader io.Reader, order binary.ByteOrder, ptrSize int) (uint64, error) {
    94  	switch ptrSize {
    95  	case 4:
    96  		var n uint32
    97  		if err := binary.Read(reader, order, &n); err != nil {
    98  			return 0, err
    99  		}
   100  		return uint64(n), nil
   101  	case 8:
   102  		var n uint64
   103  		if err := binary.Read(reader, order, &n); err != nil {
   104  			return 0, err
   105  		}
   106  		return n, nil
   107  	}
   108  	return 0, fmt.Errorf("not supprted ptr size %d", ptrSize)
   109  }
   110  
   111  // dynamicSearchDebug searches for the DT_DEBUG entry in the .dynamic section
   112  func dynamicSearchDebug(bi *proc.BinaryInfo) (uint64, error) {
   113  	dynbuf := entryAddress(uintptr(bi.ElfDynamicSection.Addr), int(bi.ElfDynamicSection.Size))
   114  	rd := bytes.NewReader(dynbuf)
   115  
   116  	for {
   117  		var tag, val uint64
   118  		var err error
   119  		if tag, err = readUintRaw(rd, binary.LittleEndian, bi.Arch.PtrSize()); err != nil {
   120  			return 0, err
   121  		}
   122  		if val, err = readUintRaw(rd, binary.LittleEndian, bi.Arch.PtrSize()); err != nil {
   123  			return 0, err
   124  		}
   125  		switch tag {
   126  		case _DT_NULL:
   127  			return 0, nil
   128  		case _DT_DEBUG:
   129  			return val, nil
   130  		}
   131  	}
   132  }
   133  
   134  type linkMap struct {
   135  	addr       uint64
   136  	name       string
   137  	ld         uint64
   138  	next, prev uint64
   139  }
   140  
   141  func readLinkMapNode(bi *proc.BinaryInfo, r_map uint64) (*linkMap, error) {
   142  	var lm linkMap
   143  	var ptrs [5]uint64
   144  	for i := range ptrs {
   145  		var err error
   146  		ptrs[i], err = readPtr(bi, r_map+uint64(bi.Arch.PtrSize()*i))
   147  		if err != nil {
   148  			return nil, err
   149  		}
   150  	}
   151  	lm.addr = ptrs[0]
   152  	var err error
   153  	lm.name, err = readCString(ptrs[1])
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  	lm.ld = ptrs[2]
   158  	lm.next = ptrs[3]
   159  	lm.prev = ptrs[4]
   160  	return &lm, nil
   161  }
   162  
   163  func readCString(addr uint64) (string, error) {
   164  	if addr == 0 {
   165  		return "", nil
   166  	}
   167  	r := []byte{}
   168  	for {
   169  		if len(r) > maxLibraryPathLength {
   170  			return "", fmt.Errorf("error reading libraries: string too long (%d)", len(r))
   171  		}
   172  		buf := entryAddress(uintptr(addr), 1)
   173  		if buf[0] == 0 {
   174  			break
   175  		}
   176  		r = append(r, buf[0])
   177  		addr++
   178  	}
   179  	return string(r), nil
   180  }