Skip to content

Commit

Permalink
coredump: no need for full dump with bundled files (#213)
Browse files Browse the repository at this point in the history
  • Loading branch information
fabled authored Dec 6, 2024
1 parent af113af commit 84cce0a
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 27 deletions.
13 changes: 10 additions & 3 deletions tools/coredump/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,18 @@ with existing test cases.
In this variant we essentially make the kernel think that the target application
crashed, causing the kernel to save a coredump for us.

#### Setting the coredump filter
#### Setting the coredump filter (optional)

Coredumps normally contain only the anonymous and modified pages to save disk
space. For our test cases, we want a full process memory dump that also contains
the pages mapped into the process from the ELF files.
space. This is sufficient if the mapped in ELF files are available to the
`coredump` utility to be bundled. This is the case if you run
`./coredump new -core core` on the same machine where the core was generated,
or if you supply `-sysroot` as a prefix to find the correct files.

If the above is not possible, the testing infrastructure has limited support
to allow reading the ELF file data directly from the coredump. In this case
a full process memory dump that also contains the pages mapped into the process
from the ELF files is needed.

To get a full process memory dump one has to set the [`coredump_filter`][filter]
in advance by running:
Expand Down
54 changes: 30 additions & 24 deletions tools/coredump/new.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type newCmd struct {

// User-specified command line arguments.
coredumpPath string
sysroot string
pid uint64
name string
importThreadInfo string
Expand Down Expand Up @@ -110,6 +111,7 @@ func newNewCmd(store *modulestore.Store) *ffcli.Command {

set := flag.NewFlagSet("new", flag.ExitOnError)
set.StringVar(&args.coredumpPath, "core", "", "Path of the coredump to import")
set.StringVar(&args.sysroot, "sysroot", "", "Path for the coredump associated ELF files")
set.Uint64Var(&args.pid, "pid", 0, "PID to create a fresh coredump for")
set.StringVar(&args.name, "name", "", "Name for the test case [required]")
set.StringVar(&args.importThreadInfo, "import-thread-info", "", "If this flag is specified, "+
Expand Down Expand Up @@ -139,17 +141,19 @@ func (cmd *newCmd) exec(context.Context, []string) (err error) {
}

var corePath string
prefix := ""
prefix := cmd.sysroot
if cmd.coredumpPath != "" {
corePath = cmd.coredumpPath
} else {
// No path provided: create a new dump.
corePath, err = dumpCore(cmd.pid)
corePath, err = dumpCore(cmd.pid, cmd.noModuleBundling)
if err != nil {
return fmt.Errorf("failed to create coredump: %w", err)
}
defer os.Remove(corePath)
prefix = fmt.Sprintf("/proc/%d/root/", cmd.pid)
if prefix == "" {
prefix = fmt.Sprintf("/proc/%d/root/", cmd.pid)
}
}

core, err := newTrackedCoredump(corePath, prefix)
Expand Down Expand Up @@ -195,32 +199,34 @@ func (cmd *newCmd) exec(context.Context, []string) (err error) {
return nil
}

func dumpCore(pid uint64) (string, error) {
// Backup current coredump filter mask.
// https://man7.org/linux/man-pages/man5/core.5.html
coredumpFilterPath := fmt.Sprintf("/proc/%d/coredump_filter", pid)
prevMask, err := os.ReadFile(coredumpFilterPath)
if err != nil {
return "", fmt.Errorf("failed to read coredump filter: %w", err)
}
// Adjust coredump filter mask.
//nolint:gosec
err = os.WriteFile(coredumpFilterPath, []byte("0x3f"), 0o644)
if err != nil {
return "", fmt.Errorf("failed to write coredump filter: %w", err)
}
// Restore coredump filter mask upon leaving the function.
defer func() {
func dumpCore(pid uint64, noModuleBundling bool) (string, error) {
if noModuleBundling {
// Backup current coredump filter mask.
// https://man7.org/linux/man-pages/man5/core.5.html
coredumpFilterPath := fmt.Sprintf("/proc/%d/coredump_filter", pid)
prevMask, err := os.ReadFile(coredumpFilterPath)
if err != nil {
return "", fmt.Errorf("failed to read coredump filter: %w", err)
}
// Adjust coredump filter mask.
//nolint:gosec
err2 := os.WriteFile(coredumpFilterPath, prevMask, 0o644)
if err2 != nil {
log.Warnf("Failed to restore previous coredump filter: %v", err2)
err = os.WriteFile(coredumpFilterPath, []byte("0x3f"), 0o644)
if err != nil {
return "", fmt.Errorf("failed to write coredump filter: %w", err)
}
}()
// Restore coredump filter mask upon leaving the function.
defer func() {
//nolint:gosec
err2 := os.WriteFile(coredumpFilterPath, append([]byte("0x"), prevMask...), 0o644)
if err2 != nil {
log.Warnf("Failed to restore previous coredump filter: %v", err2)
}
}()
}

// `gcore` only accepts a path-prefix, not an exact path.
//nolint:gosec
err = exec.Command("gcore", "-o", gcorePathPrefix, strconv.FormatUint(pid, 10)).Run()
err := exec.Command("gcore", "-o", gcorePathPrefix, strconv.FormatUint(pid, 10)).Run()
if err != nil {
return "", fmt.Errorf("gcore failed: %w", err)
}
Expand Down

0 comments on commit 84cce0a

Please sign in to comment.