mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-09-26 23:19:11 +08:00
test(ptracer): add helper func to find readable memory
This commit is contained in:
parent
9df6a51947
commit
25c32240cf
@ -66,61 +66,66 @@ func createTestProcess(t *testing.T) (int, func()) {
|
|||||||
return cmd.Process.Pid, cleanup
|
return cmd.Process.Pid, cleanup
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestVmRead tests the vmRead function
|
// findReadableMemoryRegion finds a readable memory region in the process's address space
|
||||||
func TestVmRead(t *testing.T) {
|
func findReadableMemoryRegion(t *testing.T, pid int, minSize int) uintptr {
|
||||||
pid, cleanup := createTestProcess(t)
|
|
||||||
defer cleanup()
|
|
||||||
|
|
||||||
// create test data
|
|
||||||
testData := []byte("Hello, World!")
|
|
||||||
buff := make([]byte, len(testData))
|
|
||||||
|
|
||||||
// get process memory maps
|
|
||||||
maps, err := os.ReadFile(fmt.Sprintf("/proc/%d/maps", pid))
|
maps, err := os.ReadFile(fmt.Sprintf("/proc/%d/maps", pid))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to read process maps: %v", err)
|
t.Fatalf("Failed to read process maps: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse memory maps to find a readable address
|
|
||||||
var addr uintptr
|
|
||||||
for _, line := range bytes.Split(maps, []byte{'\n'}) {
|
for _, line := range bytes.Split(maps, []byte{'\n'}) {
|
||||||
if len(line) == 0 {
|
if len(line) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if bytes.Contains(line, []byte("r-x")) { // find a readable segment
|
if bytes.Contains(line, []byte("r-x")) {
|
||||||
var start uint64
|
// Parse address range: start-end
|
||||||
fmt.Sscanf(string(line), "%x-", &start)
|
var start, end uint64
|
||||||
addr = uintptr(start)
|
_, err := fmt.Sscanf(string(line), "%x-%x", &start, &end)
|
||||||
break
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate region size
|
||||||
|
size := end - start
|
||||||
|
if size >= uint64(minSize) {
|
||||||
|
return uintptr(start)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if addr == 0 {
|
t.Fatalf("Failed to find readable memory region with minimum size %d", minSize)
|
||||||
t.Fatal("Failed to find readable memory region")
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// test reading
|
// TestVmRead tests the vmRead function
|
||||||
n, err := vmRead(pid, addr, buff)
|
func TestVmRead(t *testing.T) {
|
||||||
|
pid, cleanup := createTestProcess(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
buff := make([]byte, 100)
|
||||||
|
// Ensure the found memory region is large enough
|
||||||
|
baseAddr := findReadableMemoryRegion(t, pid, len(buff))
|
||||||
|
|
||||||
|
n, err := vmRead(pid, baseAddr, buff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("vmRead failed: %v", err)
|
t.Errorf("vmRead() error = %v", err)
|
||||||
}
|
}
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
t.Error("vmRead returned 0 bytes")
|
t.Error("vmRead returned 0 bytes")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestVmReadStr tests the vmReadStr function
|
// vmReadStrTestCase defines a test case for vmReadStr
|
||||||
func TestVmReadStr(t *testing.T) {
|
type vmReadStrTestCase struct {
|
||||||
pid, cleanup := createTestProcess(t)
|
name string
|
||||||
defer cleanup()
|
buffSize int
|
||||||
|
addrAlign uintptr // address alignment, used to test different alignment scenarios
|
||||||
|
wantErr bool
|
||||||
|
}
|
||||||
|
|
||||||
// test cases
|
// getVmReadStrTestCases returns test cases for vmReadStr testing
|
||||||
testCases := []struct {
|
func getVmReadStrTestCases() []vmReadStrTestCase {
|
||||||
name string
|
return []vmReadStrTestCase{
|
||||||
buffSize int
|
|
||||||
addrAlign uintptr // address alignment, used to test different alignment scenarios
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
{
|
||||||
name: "small_buffer_aligned",
|
name: "small_buffer_aligned",
|
||||||
buffSize: 10,
|
buffSize: 10,
|
||||||
@ -158,53 +163,42 @@ func TestVmReadStr(t *testing.T) {
|
|||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVmReadStr tests the vmReadStr function
|
||||||
|
func TestVmReadStr(t *testing.T) {
|
||||||
|
pid, cleanup := createTestProcess(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
testCases := getVmReadStrTestCases()
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
buff := make([]byte, tc.buffSize)
|
buff := make([]byte, tc.buffSize)
|
||||||
|
|
||||||
// get a readable memory address
|
// Ensure the found memory region is large enough
|
||||||
maps, err := os.ReadFile(fmt.Sprintf("/proc/%d/maps", pid))
|
baseAddr := findReadableMemoryRegion(t, pid, tc.buffSize)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to read process maps: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var baseAddr uintptr
|
// Use test case specified alignment offset
|
||||||
for _, line := range bytes.Split(maps, []byte{'\n'}) {
|
|
||||||
if len(line) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if bytes.Contains(line, []byte("r-x")) {
|
|
||||||
var start uint64
|
|
||||||
fmt.Sscanf(string(line), "%x-", &start)
|
|
||||||
baseAddr = uintptr(start)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if baseAddr == 0 {
|
|
||||||
t.Fatal("Failed to find readable memory region")
|
|
||||||
}
|
|
||||||
|
|
||||||
// use test case specified alignment offset
|
|
||||||
testAddr := baseAddr + tc.addrAlign
|
testAddr := baseAddr + tc.addrAlign
|
||||||
|
|
||||||
// record buffer content before reading
|
// Record buffer content before reading
|
||||||
originalBuff := make([]byte, len(buff))
|
originalBuff := make([]byte, len(buff))
|
||||||
copy(originalBuff, buff)
|
copy(originalBuff, buff)
|
||||||
|
|
||||||
err = vmReadStr(pid, testAddr, buff)
|
err := vmReadStr(pid, testAddr, buff)
|
||||||
if (err != nil) != tc.wantErr {
|
if (err != nil) != tc.wantErr {
|
||||||
t.Errorf("vmReadStr() error = %v, wantErr %v", err, tc.wantErr)
|
t.Errorf("vmReadStr() error = %v, wantErr %v", err, tc.wantErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify if actual reading occurred
|
// Verify reading results
|
||||||
if !bytes.Equal(buff, originalBuff) {
|
if !bytes.Equal(buff, originalBuff) {
|
||||||
// at least some data was read
|
// For vmReadStr, we only care that some data was read
|
||||||
|
// and that the function completed without error
|
||||||
t.Logf("Data was read successfully for case: %s", tc.name)
|
t.Logf("Data was read successfully for case: %s", tc.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// special case: check buffer size smaller than distance to boundary
|
// Special case: check buffer size smaller than distance to boundary
|
||||||
if tc.name == "buffer_smaller_than_to_boundary" {
|
if tc.name == "buffer_smaller_than_to_boundary" {
|
||||||
distToBoundary := pageSize - int(testAddr%uintptr(pageSize))
|
distToBoundary := pageSize - int(testAddr%uintptr(pageSize))
|
||||||
if distToBoundary > len(buff) {
|
if distToBoundary > len(buff) {
|
||||||
|
Loading…
Reference in New Issue
Block a user