Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

memparse: add search functionality to memparse #141

Merged
merged 4 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions cmd/memparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,30 @@ func MemParse() *cobra.Command {
"Specify the output file to be written to",
)

flags.StringVarP(
searchPattern,
"search",
"s",
"",
"Search for a string pattern in memory pages",
)

flags.StringVarP(
searchRegexPattern,
"search-regex",
"r",
"",
"Search for a regex pattern in memory pages",
)

flags.IntVarP(
searchContext,
"context",
"c",
0,
"Print the specified number of bytes surrounding each match",
)
rst0git marked this conversation as resolved.
Show resolved Hide resolved

return cmd
}

Expand Down Expand Up @@ -79,6 +103,10 @@ func memparse(cmd *cobra.Command, args []string) error {
}
defer internal.CleanupTasks(tasks)

if *searchPattern != "" || *searchRegexPattern != "" {
return printMemorySearchResultForPID(tasks[0])
}

if *pID != 0 {
return printProcessMemoryPages(tasks[0])
}
Expand Down Expand Up @@ -273,3 +301,68 @@ func generateHexAndAscii(data []byte) (string, string) {

return hex, ascii
}

// Searches for a pattern in the memory of a given PID and prints the results.
func printMemorySearchResultForPID(task internal.Task) error {
c := crit.New(nil, nil, filepath.Join(task.OutputDir, metadata.CheckpointDirectory), false, false)
psTree, err := c.ExplorePs()
if err != nil {
return fmt.Errorf("failed to get process tree: %w", err)
}

// Check if PID exist within the checkpoint
ps := psTree.FindPs(*pID)
if ps == nil {
return fmt.Errorf("no process with PID %d (use `inspect --ps-tree` to view all PIDs)", *pID)
}

memReader, err := crit.NewMemoryReader(
filepath.Join(task.OutputDir, metadata.CheckpointDirectory),
*pID, pageSize,
)
if err != nil {
return fmt.Errorf("failed to create memory reader: %w", err)
}

if err := internal.UntarFiles(
task.CheckpointFilePath, task.OutputDir,
[]string{filepath.Join(metadata.CheckpointDirectory, fmt.Sprintf("pages-%d.img", memReader.GetPagesID()))},
); err != nil {
return fmt.Errorf("failed to extract pages file: %w", err)
}

pattern := *searchPattern
escapeRegExpCharacters := true
if pattern == "" {
pattern = *searchRegexPattern
escapeRegExpCharacters = false
}

results, err := memReader.SearchPattern(pattern, escapeRegExpCharacters, *searchContext, 0)
if err != nil {
return fmt.Errorf("failed to search pattern in memory: %w", err)
}

if len(results) == 0 {
fmt.Printf("No matches for pattern \"%s\" in the memory of PID %d\n", pattern, *pID)
return nil
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Address", "Match", "Instance"})
table.SetAutoMergeCells(false)
table.SetRowLine(true)

for i, result := range results {
table.Append([]string{
fmt.Sprintf(
"%016x", result.Vaddr),
result.Match,
fmt.Sprintf("%d", i+1),
})
}

table.Render()

return nil
}
25 changes: 14 additions & 11 deletions cmd/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ package cmd
import "github.com/checkpoint-restore/checkpointctl/internal"

var (
format *string = &internal.Format
stats *bool = &internal.Stats
mounts *bool = &internal.Mounts
outputFilePath *string = &internal.OutputFilePath
pID *uint32 = &internal.PID
psTree *bool = &internal.PsTree
psTreeCmd *bool = &internal.PsTreeCmd
psTreeEnv *bool = &internal.PsTreeEnv
files *bool = &internal.Files
sockets *bool = &internal.Sockets
showAll *bool = &internal.ShowAll
format *string = &internal.Format
stats *bool = &internal.Stats
mounts *bool = &internal.Mounts
outputFilePath *string = &internal.OutputFilePath
pID *uint32 = &internal.PID
psTree *bool = &internal.PsTree
psTreeCmd *bool = &internal.PsTreeCmd
psTreeEnv *bool = &internal.PsTreeEnv
files *bool = &internal.Files
sockets *bool = &internal.Sockets
showAll *bool = &internal.ShowAll
searchPattern *string = &internal.SearchPattern
searchRegexPattern *string = &internal.SearchRegexPattern
searchContext *int = &internal.SearchContext
)
25 changes: 14 additions & 11 deletions internal/options.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package internal

var (
Format string
Stats bool
Mounts bool
OutputFilePath string
PID uint32
PsTree bool
PsTreeCmd bool
PsTreeEnv bool
Files bool
Sockets bool
ShowAll bool
Format string
Stats bool
Mounts bool
OutputFilePath string
PID uint32
PsTree bool
PsTreeCmd bool
PsTreeEnv bool
Files bool
Sockets bool
ShowAll bool
SearchPattern string
SearchRegexPattern string
SearchContext int
)