Repository: gojue/ecapture
File: user/config/config_gotls.go (Go)

Code before:
	}
	lineTable := gosym.NewLineTable(tableData, addr)
	symTable, err := gosym.NewTable([]byte{}, lineTable)
	if err != nil {
		return nil, ErrorSymbolNotFoundFromTable
	}
	return symTable, nil
}

func (gc *GoTLSConfig) findRetOffsetsPie(lfunc string) ([]int, error) {
	var offsets []int
	var address uint64
	var err error
	address, err = gc.findPieSymbolAddr(lfunc)
	if err != nil {
		return offsets, err
	}
	f := gc.goSymTab.LookupFunc(lfunc)
	funcLen := f.End - f.Entry
	for _, prog := range gc.goElf.Progs {
		if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
			continue
		}
		data := make([]byte, funcLen)
		_, err = prog.ReadAt(data, int64(address-prog.Vaddr))
		if err != nil {
			return offsets, fmt.Errorf("finding function return: %w", err)
		}
		offsets, err = gc.decodeInstruction(data)
		if err != nil {
			return offsets, fmt.Errorf("finding function return: %w", err)
		}
		for i, offset := range offsets {
			offsets[i] = int(address) + offset
		}
		return offsets, nil
	}
	return offsets, errors.New("cant found gotls symbol offsets.")
}

func (gc *GoTLSConfig) findPieSymbolAddr(lfunc string) (uint64, error) {
	f := gc.goSymTab.LookupFunc(lfunc)
	if f == nil {
		return 0, errors.New("Cant found symbol address on pie model.")
	}
	var err error
	for _, prog := range gc.goElf.Progs {
		if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
			continue
		}
		// For more info on this calculation: stackoverflow.com/a/40249502

Review comment (bug):
In [this code](https://github.com/golang/go/blob/bdd27c4debfb51fe42df0c0532c1c747777b7a32/src/cmd/internal/objfile/elf.go#L175):
```
addr = s(type: *elf.Symbol).Value 
prog.ReadAt(data, addr- prog.Vaddr )
```
However, in our code:
```
address, err = gc.findPieSymbolAddr(lfunc)
    (address = f(type: *gosym.Function).Value - prog.Vaddr + prog.Off)
_, err = prog.ReadAt(data, int64(address-prog.Vaddr))
```
We know that the virtual address from the symbol is the same as the virtual address from gosym.Function. Therefore, I believe there is an error, we should use `f.Value` instead.
I check this in my armLinux, use `f.Value` is correct, and `address` is wrong.

However, I don't understand why it runs properly in your test, LOL.

Code after:
	}
	lineTable := gosym.NewLineTable(tableData, addr)
	symTable, err := gosym.NewTable([]byte{}, lineTable)
	if err != nil {
		return nil, ErrorSymbolNotFoundFromTable
	}
	return symTable, nil
}

func (gc *GoTLSConfig) findRetOffsetsPie(lfunc string) ([]int, error) {
	var offsets []int
	var address uint64
	var err error
	address, err = gc.findPieSymbolAddr(lfunc)
	if err != nil {
		return offsets, err
	}
	f := gc.goSymTab.LookupFunc(lfunc)
	funcLen := f.End - f.Entry
	for _, prog := range gc.goElf.Progs {
		if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
			continue
		}
		// via https://github.com/golang/go/blob/a65a2bbd8e58cd77dbff8a751dbd6079424beb05/src/cmd/internal/objfile/elf.go#L174
		data := make([]byte, funcLen)
		_, err = prog.ReadAt(data, int64(address-prog.Vaddr))
		if err != nil {
			return offsets, fmt.Errorf("finding function return: %w", err)
		}
		offsets, err = gc.decodeInstruction(data)
		if err != nil {
			return offsets, fmt.Errorf("finding function return: %w", err)
		}
		for i, offset := range offsets {
			offsets[i] = int(address) + offset
		}
		return offsets, nil
	}
	return offsets, errors.New("cant found gotls symbol offsets.")
}

func (gc *GoTLSConfig) findPieSymbolAddr(lfunc string) (uint64, error) {
	f := gc.goSymTab.LookupFunc(lfunc)
	if f == nil {
		return 0, ErrorNoFuncFoundFromSymTabFun
	}
	return f.Value, nil
}