152 lines
2.9 KiB
Go
152 lines
2.9 KiB
Go
![]() |
package proc
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"io/ioutil"
|
||
|
"os/exec"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
|
||
|
"fmt"
|
||
|
|
||
|
"path"
|
||
|
|
||
|
"github.com/derekparker/delve/pkg/proc/test"
|
||
|
)
|
||
|
|
||
|
func TestSplicedReader(t *testing.T) {
|
||
|
data := []byte{}
|
||
|
data2 := []byte{}
|
||
|
for i := 0; i < 100; i++ {
|
||
|
data = append(data, byte(i))
|
||
|
data2 = append(data2, byte(i+100))
|
||
|
}
|
||
|
|
||
|
type region struct {
|
||
|
data []byte
|
||
|
off uintptr
|
||
|
length uintptr
|
||
|
}
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
regions []region
|
||
|
readAddr uintptr
|
||
|
readLen int
|
||
|
want []byte
|
||
|
}{
|
||
|
{
|
||
|
"Insert after",
|
||
|
[]region{
|
||
|
{data, 0, 1},
|
||
|
{data2, 1, 1},
|
||
|
},
|
||
|
0,
|
||
|
2,
|
||
|
[]byte{0, 101},
|
||
|
},
|
||
|
{
|
||
|
"Insert before",
|
||
|
[]region{
|
||
|
{data, 1, 1},
|
||
|
{data2, 0, 1},
|
||
|
},
|
||
|
0,
|
||
|
2,
|
||
|
[]byte{100, 1},
|
||
|
},
|
||
|
{
|
||
|
"Completely overwrite",
|
||
|
[]region{
|
||
|
{data, 1, 1},
|
||
|
{data2, 0, 3},
|
||
|
},
|
||
|
0,
|
||
|
3,
|
||
|
[]byte{100, 101, 102},
|
||
|
},
|
||
|
{
|
||
|
"Overwrite end",
|
||
|
[]region{
|
||
|
{data, 0, 2},
|
||
|
{data2, 1, 2},
|
||
|
},
|
||
|
0,
|
||
|
3,
|
||
|
[]byte{0, 101, 102},
|
||
|
},
|
||
|
{
|
||
|
"Overwrite start",
|
||
|
[]region{
|
||
|
{data, 0, 3},
|
||
|
{data2, 0, 2},
|
||
|
},
|
||
|
0,
|
||
|
3,
|
||
|
[]byte{100, 101, 2},
|
||
|
},
|
||
|
{
|
||
|
"Punch hole",
|
||
|
[]region{
|
||
|
{data, 0, 5},
|
||
|
{data2, 1, 3},
|
||
|
},
|
||
|
0,
|
||
|
5,
|
||
|
[]byte{0, 101, 102, 103, 4},
|
||
|
},
|
||
|
{
|
||
|
"Overlap two",
|
||
|
[]region{
|
||
|
{data, 10, 4},
|
||
|
{data, 14, 4},
|
||
|
{data2, 12, 4},
|
||
|
},
|
||
|
10,
|
||
|
8,
|
||
|
[]byte{10, 11, 112, 113, 114, 115, 16, 17},
|
||
|
},
|
||
|
}
|
||
|
for _, test := range tests {
|
||
|
t.Run(test.name, func(t *testing.T) {
|
||
|
mem := &SplicedMemory{}
|
||
|
for _, region := range test.regions {
|
||
|
r := bytes.NewReader(region.data)
|
||
|
mem.Add(&OffsetReaderAt{r, 0}, region.off, region.length)
|
||
|
}
|
||
|
got := make([]byte, test.readLen)
|
||
|
n, err := mem.ReadMemory(got, test.readAddr)
|
||
|
if n != test.readLen || err != nil || !reflect.DeepEqual(got, test.want) {
|
||
|
t.Errorf("ReadAt = %v, %v, %v, want %v, %v, %v", n, err, got, test.readLen, nil, test.want)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestReadCore(t *testing.T) {
|
||
|
// This is all very fragile and won't work on hosts with non-default core patterns.
|
||
|
// Might be better to check in the core?
|
||
|
tempDir, err := ioutil.TempDir("", "")
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
fix := test.BuildFixture("panic")
|
||
|
bashCmd := fmt.Sprintf("cd %v && ulimit -c unlimited && GOTRACEBACK=crash %v", tempDir, fix.Path)
|
||
|
exec.Command("bash", "-c", bashCmd).Run()
|
||
|
corePath := path.Join(tempDir, "core")
|
||
|
|
||
|
core, err := readCore(corePath, fix.Path)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if len(core.Threads) == 0 {
|
||
|
t.Error("expected at least one thread")
|
||
|
}
|
||
|
// Punch through the abstraction to verify that we got some mappings.
|
||
|
spliced := core.MemoryReader.(*SplicedMemory)
|
||
|
// There should be at least an RO section, RW section, RX section, the heap, and a thread stack.
|
||
|
if len(spliced.readers) < 5 {
|
||
|
t.Errorf("expected at least 5 memory regions, got only %v", len(spliced.readers))
|
||
|
}
|
||
|
// Would be good to test more stuff but not sure what without reading debug information, etc.
|
||
|
}
|