github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/report/linux.go (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package report
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"path/filepath"
    10  	"regexp"
    11  	"strconv"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/google/syzkaller/pkg/cover/backend"
    16  	"github.com/google/syzkaller/pkg/osutil"
    17  	"github.com/google/syzkaller/pkg/report/crash"
    18  	"github.com/google/syzkaller/pkg/symbolizer"
    19  	"github.com/google/syzkaller/pkg/vcs"
    20  	"github.com/google/syzkaller/sys/targets"
    21  	"github.com/ianlancetaylor/demangle"
    22  )
    23  
    24  type linux struct {
    25  	*config
    26  	vmlinux               string
    27  	symbols               map[string]map[string][]symbolizer.Symbol
    28  	consoleOutputRe       *regexp.Regexp
    29  	taskContext           *regexp.Regexp
    30  	cpuContext            *regexp.Regexp
    31  	questionableFrame     *regexp.Regexp
    32  	guiltyFileIgnores     []*regexp.Regexp
    33  	guiltyLineIgnore      *regexp.Regexp
    34  	reportStartIgnores    []*regexp.Regexp
    35  	infoMessagesWithStack [][]byte
    36  	eoi                   []byte
    37  	symbolizerCache       symbolizer.Cache
    38  }
    39  
    40  func ctorLinux(cfg *config) (reporterImpl, []string, error) {
    41  	symbols := make(map[string]map[string][]symbolizer.Symbol)
    42  	vmlinux := ""
    43  	if cfg.kernelDirs.Obj != "" {
    44  		vmlinux = filepath.Join(cfg.kernelDirs.Obj, cfg.target.KernelObject)
    45  		var err error
    46  		symbols[""], err = symbolizer.ReadTextSymbols(vmlinux)
    47  		if err != nil {
    48  			return nil, nil, err
    49  		}
    50  		for _, mod := range cfg.kernelModules {
    51  			if mod.Name == "" {
    52  				continue
    53  			}
    54  			ss, err := symbolizer.ReadTextSymbols(mod.Path)
    55  			if err != nil {
    56  				continue
    57  			}
    58  			symbols[mod.Name] = ss
    59  		}
    60  	}
    61  	ctx := &linux{
    62  		config:  cfg,
    63  		vmlinux: vmlinux,
    64  		symbols: symbols,
    65  	}
    66  	// nolint: lll
    67  	ctx.consoleOutputRe = regexp.MustCompile(`^(?:\*\* [0-9]+ printk messages dropped \*\* )?(?:.* login: )?(?:\<[0-9]+\>)?\[ *[0-9]+\.[0-9]+\](\[ *(?:C|T)[0-9]+\])? `)
    68  	ctx.taskContext = regexp.MustCompile(`\[ *T[0-9]+\]`)
    69  	ctx.cpuContext = regexp.MustCompile(`\[ *C[0-9]+\]`)
    70  	ctx.questionableFrame = regexp.MustCompile(`(\[\<[0-9a-f]+\>\])? \? `)
    71  	ctx.eoi = []byte("<EOI>")
    72  	ctx.guiltyFileIgnores = []*regexp.Regexp{
    73  		regexp.MustCompile(`.*\.h`),
    74  		regexp.MustCompile(`^lib/.*`),
    75  		regexp.MustCompile(`^virt/lib/.*`),
    76  		regexp.MustCompile(`^mm/kasan/.*`),
    77  		regexp.MustCompile(`^mm/kmsan/.*`),
    78  		regexp.MustCompile(`^kernel/kcov.c`),
    79  		regexp.MustCompile(`^mm/sl.b.c`),
    80  		regexp.MustCompile(`^mm/filemap.c`),
    81  		regexp.MustCompile(`^mm/folio-compat.c`),
    82  		regexp.MustCompile(`^mm/truncate.c`),
    83  		regexp.MustCompile(`^mm/memory.c`),
    84  		regexp.MustCompile(`^mm/percpu.*`),
    85  		regexp.MustCompile(`^mm/vmalloc.c`),
    86  		regexp.MustCompile(`^mm/page_alloc.c`),
    87  		regexp.MustCompile(`^mm/mempool.c`),
    88  		regexp.MustCompile(`^mm/util.c`),
    89  		regexp.MustCompile(`^kernel/rcu/.*`),
    90  		regexp.MustCompile(`^arch/.*/kernel/traps.c`),
    91  		regexp.MustCompile(`^arch/.*/kernel/unwind.*.c`),
    92  		regexp.MustCompile(`^arch/.*/mm/fault.c`),
    93  		regexp.MustCompile(`^arch/.*/mm/physaddr.c`),
    94  		regexp.MustCompile(`^arch/.*/kernel/stacktrace.c`),
    95  		regexp.MustCompile(`^arch/.*/kernel/apic/apic.c`),
    96  		regexp.MustCompile(`^arch/arm64/kernel/entry.*.c`),
    97  		regexp.MustCompile(`^arch/arm64/kernel/process\.c`),
    98  		regexp.MustCompile(`^kernel/locking/.*`),
    99  		regexp.MustCompile(`^kernel/panic.c`),
   100  		regexp.MustCompile(`^kernel/printk/printk.*.c`),
   101  		regexp.MustCompile(`^kernel/softirq.c`),
   102  		regexp.MustCompile(`^kernel/kthread.c`),
   103  		regexp.MustCompile(`^kernel/sched/.*.c`),
   104  		regexp.MustCompile(`^kernel/stacktrace.c`),
   105  		regexp.MustCompile(`^kernel/time/timer.c`),
   106  		regexp.MustCompile(`^kernel/workqueue.c`),
   107  		regexp.MustCompile(`^net/core/dev.c`),
   108  		regexp.MustCompile(`^net/core/sock.c`),
   109  		regexp.MustCompile(`^net/core/skbuff.c`),
   110  		regexp.MustCompile(`^fs/proc/generic.c`),
   111  		regexp.MustCompile(`^trusty/`),                // Trusty sources are not in linux kernel tree.
   112  		regexp.MustCompile(`^drivers/usb/core/urb.c`), // WARNING in urb.c usually means a bug in a driver
   113  		// Crashes in these files are almost always caused by the calling code.
   114  		regexp.MustCompile(`^arch/.*/lib/crc.*`),
   115  	}
   116  	ctx.guiltyLineIgnore = regexp.MustCompile(`(hardirqs|softirqs)\s+last\s+(enabled|disabled)|^Register r\d+ information`)
   117  	// These pattern do _not_ start a new report, i.e. can be in a middle of another report.
   118  	ctx.reportStartIgnores = []*regexp.Regexp{
   119  		compile(`invalid opcode: 0000`),
   120  		compile(`Kernel panic - not syncing`),
   121  		compile(`unregister_netdevice: waiting for`),
   122  		// Double fault can happen during handling of paging faults
   123  		// if memory is badly corrupted. Also it usually happens
   124  		// synchronously, which means that maybe the report is not corrupted.
   125  		// But of course it can come from another CPU as well.
   126  		compile(`PANIC: double fault`),
   127  		compile(`Internal error:`),
   128  	}
   129  	// These pattern math kernel reports which are not bugs in itself but contain stack traces.
   130  	// If we see them in the middle of another report, we know that the report is potentially corrupted.
   131  	ctx.infoMessagesWithStack = [][]byte{
   132  		[]byte("vmalloc: allocation failure:"),
   133  		[]byte("FAULT_INJECTION: forcing a failure"),
   134  		[]byte("FAULT_FLAG_ALLOW_RETRY missing"),
   135  	}
   136  	suppressions := []string{
   137  		"panic: failed to start executor binary",
   138  		"panic: executor failed: pthread_create failed",
   139  		"panic: failed to create temp dir",
   140  		"fatal error: unexpected signal during runtime execution", // presubmably OOM turned into SIGBUS
   141  		"signal SIGBUS: bus error",                                // presubmably OOM turned into SIGBUS
   142  		"SYZFAIL: SIGBUS",
   143  		"Out of memory: Kill process .* \\(syz-executor\\)",
   144  		"Out of memory: Kill process .* \\(sshd\\)",
   145  		"Killed process .* \\(syz-executor\\)",
   146  		"Killed process .* \\(sshd\\)",
   147  		"lowmemorykiller: Killing 'syz-executor'",
   148  		"lowmemorykiller: Killing 'sshd'",
   149  		"INIT: PANIC: segmentation violation!",
   150  		"\\*\\*\\* stack smashing detected \\*\\*\\*: terminated",
   151  	}
   152  	return ctx, suppressions, nil
   153  }
   154  
   155  const contextConsole = "console"
   156  
   157  func (ctx *linux) ContainsCrash(output []byte) bool {
   158  	return containsCrash(output, linuxOopses, ctx.ignores)
   159  }
   160  
   161  func (ctx *linux) Parse(output []byte) *Report {
   162  	oops, startPos, context := ctx.findFirstOops(output)
   163  	if oops == nil {
   164  		return nil
   165  	}
   166  	for questionable := false; ; questionable = true {
   167  		rep := &Report{
   168  			Output:   output,
   169  			StartPos: startPos,
   170  		}
   171  		endPos, reportEnd, report, prefix := ctx.findReport(output, oops, startPos, context, questionable)
   172  		rep.EndPos = endPos
   173  		title, corrupted, altTitles, format := extractDescription(report[:reportEnd], oops, linuxStackParams)
   174  		if title == "" {
   175  			prefix = nil
   176  			report = output[rep.StartPos:rep.EndPos]
   177  			title, corrupted, altTitles, format = extractDescription(report, oops, linuxStackParams)
   178  			if title == "" {
   179  				panic(fmt.Sprintf("non matching oops for %q context=%q in:\n%s\n",
   180  					oops.header, context, report))
   181  			}
   182  		}
   183  		rep.Title = title
   184  		rep.AltTitles = altTitles
   185  		rep.Corrupted = corrupted != ""
   186  		rep.CorruptedReason = corrupted
   187  		for _, line := range prefix {
   188  			rep.Report = append(rep.Report, line...)
   189  			rep.Report = append(rep.Report, '\n')
   190  		}
   191  		rep.reportPrefixLen = len(rep.Report)
   192  		rep.Report = append(rep.Report, report...)
   193  		rep.Type = TitleToCrashType(rep.Title)
   194  		setExecutorInfo(rep)
   195  		if !rep.Corrupted {
   196  			rep.Corrupted, rep.CorruptedReason = isCorrupted(title, report, format)
   197  		}
   198  		if rep.CorruptedReason == corruptedNoFrames && context != contextConsole && !questionable {
   199  			// We used to look at questionable frame with the following incentive:
   200  			// """
   201  			// Some crash reports have all frames questionable.
   202  			// So if we get a corrupted report because there are no frames,
   203  			// try again now looking at questionable frames.
   204  			// Only do this if we have a real context (CONFIG_PRINTK_CALLER=y),
   205  			// to be on the safer side. Without context it's too easy to use
   206  			// a stray frame from a wrong context.
   207  			// """
   208  			// Most likely reports without proper stack traces were caused by a bug
   209  			// in the unwinder and are now fixed in 187b96db5ca7 "x86/unwind/orc:
   210  			// Fix unwind_get_return_address_ptr() for inactive tasks".
   211  			// Disable trying to use questionable frames for now.
   212  			useQuestionableFrames := false
   213  			if useQuestionableFrames {
   214  				continue
   215  			}
   216  		}
   217  		return rep
   218  	}
   219  }
   220  
   221  func (ctx *linux) findFirstOops(output []byte) (oops *oops, startPos int, context string) {
   222  	for pos, next := 0, 0; pos < len(output); pos = next + 1 {
   223  		next = bytes.IndexByte(output[pos:], '\n')
   224  		if next != -1 {
   225  			next += pos
   226  		} else {
   227  			next = len(output)
   228  		}
   229  		line := output[pos:next]
   230  		for _, oops1 := range linuxOopses {
   231  			if matchOops(line, oops1, ctx.ignores) {
   232  				oops = oops1
   233  				startPos = pos
   234  				context = ctx.extractContext(line)
   235  				return
   236  			}
   237  		}
   238  	}
   239  	return
   240  }
   241  
   242  // This method decides if the report prefix is already long enough to be cut on "Kernel panic - not
   243  // syncing: panic_on_kmsan set ...".
   244  func (ctx *linux) reportMinLines(oopsLine []byte) int {
   245  	if bytes.Contains(oopsLine, []byte("BUG: KMSAN:")) {
   246  		// KMSAN reports do not have the "Call trace" and some of the other lines which are
   247  		// present e.g. in KASAN reports. So we use a lower threshold for them.
   248  		return 16
   249  	}
   250  	return 22
   251  }
   252  
   253  // Yes, it is complex, but all state and logic are tightly coupled. It's unclear how to simplify it.
   254  // nolint: gocyclo, gocognit
   255  func (ctx *linux) findReport(output []byte, oops *oops, startPos int, context string, useQuestionable bool) (
   256  	endPos, reportEnd int, report []byte, prefix [][]byte) {
   257  	// Prepend 5 lines preceding start of the report,
   258  	// they can contain additional info related to the report.
   259  	maxPrefix := 5
   260  	if ctx.taskContext.MatchString(context) {
   261  		// If we have CONFIG_PRINTK_CALLER, we collect more b/c it comes from the same task.
   262  		maxPrefix = 50
   263  	}
   264  	secondReportPos := 0
   265  	textLines := 0
   266  	skipText, cpuTraceback := false, false
   267  	oopsLine := []byte{}
   268  	for pos, next := 0, 0; pos < len(output); pos = next + 1 {
   269  		next = bytes.IndexByte(output[pos:], '\n')
   270  		if next != -1 {
   271  			next += pos
   272  		} else {
   273  			next = len(output)
   274  		}
   275  		line := output[pos:next]
   276  		context1 := ctx.extractContext(line)
   277  		stripped, questionable := ctx.stripLinePrefix(line, context1, useQuestionable)
   278  		if pos < startPos {
   279  			if context1 == context && len(stripped) != 0 && !questionable {
   280  				prefix = append(prefix, append([]byte{}, stripped...))
   281  				if len(prefix) > maxPrefix {
   282  					prefix = prefix[1:]
   283  				}
   284  			}
   285  			continue
   286  		}
   287  		isOopsLine := pos == startPos
   288  		if isOopsLine {
   289  			oopsLine = line
   290  		}
   291  
   292  		for _, oops1 := range linuxOopses {
   293  			if !matchOops(line, oops1, ctx.ignores) {
   294  				if !isOopsLine && secondReportPos == 0 {
   295  					for _, pattern := range ctx.infoMessagesWithStack {
   296  						if bytes.Contains(line, pattern) {
   297  							secondReportPos = pos
   298  							break
   299  						}
   300  					}
   301  				}
   302  				continue
   303  			}
   304  			endPos = next
   305  			if !isOopsLine && secondReportPos == 0 {
   306  				if !matchesAny(line, ctx.reportStartIgnores) {
   307  					secondReportPos = pos
   308  				}
   309  			}
   310  		}
   311  		if !isOopsLine && (questionable ||
   312  			context1 != context && (!cpuTraceback || !ctx.cpuContext.MatchString(context1))) {
   313  			continue
   314  		}
   315  		textLines++
   316  		skipLine := skipText
   317  		if bytes.Contains(line, []byte("Disabling lock debugging due to kernel taint")) {
   318  			skipLine = true
   319  		} else if bytes.Contains(line, []byte("Sending NMI from CPU")) {
   320  			// If we are doing traceback of all CPUs, then we also need to preserve output
   321  			// from other CPUs regardless of what is the current context.
   322  			// Otherwise we will throw traceback away because it does not match the oops context.
   323  			cpuTraceback = true
   324  		} else if (bytes.Contains(line, []byte("Kernel panic - not syncing")) ||
   325  			bytes.Contains(line, []byte("WARNING: possible circular locking dependency detected"))) &&
   326  			textLines > ctx.reportMinLines(oopsLine) {
   327  			// If panic_on_warn set, then we frequently have 2 stacks:
   328  			// one for the actual report (or maybe even more than one),
   329  			// and then one for panic caused by panic_on_warn. This makes
   330  			// reports unnecessary long and the panic (current) stack
   331  			// is always present in the actual report. So we strip the
   332  			// panic message. However, we check that we have enough lines
   333  			// before the panic, because sometimes we have, for example,
   334  			// a single WARNING line without a stack and then the panic
   335  			// with the stack.
   336  			// Oops messages frequently induce possible deadlock reports
   337  			// because oops reporting introduces unexpected locking chains.
   338  			// So if we have enough of the actual oops, strip the deadlock message.
   339  			skipText = true
   340  			skipLine = true
   341  		}
   342  		if !isOopsLine && skipLine {
   343  			continue
   344  		}
   345  		report = append(report, stripped...)
   346  		report = append(report, '\n')
   347  		if secondReportPos == 0 || context != "" && context != contextConsole {
   348  			reportEnd = len(report)
   349  		}
   350  	}
   351  	return
   352  }
   353  
   354  func (ctx *linux) stripLinePrefix(line []byte, context string, useQuestionable bool) ([]byte, bool) {
   355  	if context == "" {
   356  		return line, false
   357  	}
   358  	start := bytes.Index(line, []byte("] "))
   359  	line = line[start+2:]
   360  	if !bytes.Contains(line, ctx.eoi) {
   361  		// x86_64 prefix.
   362  		if ctx.questionableFrame.Match(line) {
   363  			pos := bytes.Index(line, []byte(" ? "))
   364  			return line[pos+2:], !useQuestionable
   365  		}
   366  		// PowerPC suffix.
   367  		if bytes.HasSuffix(line, []byte(" (unreliable)")) {
   368  			return line[:len(line)-13], !useQuestionable
   369  		}
   370  	}
   371  	return line, false
   372  }
   373  
   374  func (ctx *linux) extractContext(line []byte) string {
   375  	match := ctx.consoleOutputRe.FindSubmatchIndex(line)
   376  	if match == nil {
   377  		return ""
   378  	}
   379  	if match[2] == -1 {
   380  		return contextConsole
   381  	}
   382  	return string(line[match[2]:match[3]])
   383  }
   384  
   385  func (ctx *linux) Symbolize(rep *Report) error {
   386  	var symbFunc symbFuncCb
   387  	if ctx.vmlinux != "" {
   388  		symb := symbolizer.Make(ctx.config.target)
   389  		defer symb.Close()
   390  		symbFunc = func(bin string, pc uint64) ([]symbolizer.Frame, error) {
   391  			return ctx.symbolizerCache.Symbolize(symb.Symbolize, bin, pc)
   392  		}
   393  	}
   394  	if err := ctx.symbolize(rep, symbFunc); err != nil {
   395  		return err
   396  	}
   397  	rep.Report = ctx.decompileOpcodes(rep.Report, rep)
   398  
   399  	// Skip getting maintainers for Android fuzzing since the kernel source
   400  	// directory structure is different.
   401  	if ctx.config.vmType == "cuttlefish" || ctx.config.vmType == "proxyapp" {
   402  		return nil
   403  	}
   404  
   405  	// We still do this even if we did not symbolize,
   406  	// because tests pass in already symbolized input.
   407  	rep.GuiltyFile = ctx.extractGuiltyFile(rep)
   408  	if rep.GuiltyFile != "" {
   409  		maintainers, err := ctx.getMaintainers(rep.GuiltyFile)
   410  		if err != nil {
   411  			return err
   412  		}
   413  		rep.Recipients = maintainers
   414  	}
   415  	return nil
   416  }
   417  
   418  type symbFuncCb = func(string, uint64) ([]symbolizer.Frame, error)
   419  
   420  func (ctx *linux) symbolize(rep *Report, symbFunc symbFuncCb) error {
   421  	var symbolized []byte
   422  	prefix := rep.reportPrefixLen
   423  	for _, line := range bytes.SplitAfter(rep.Report, []byte("\n")) {
   424  		var newLine []byte
   425  		parsed, ok := parseLinuxBacktraceLine(line)
   426  		if ok {
   427  			lines := []linuxBacktraceLine{parsed}
   428  			if symbFunc != nil {
   429  				lines = symbolizeLine(symbFunc, ctx, parsed)
   430  			}
   431  			for _, line := range lines {
   432  				line.Name = demangle.Filter(line.Name, demangle.NoParams)
   433  				newLine = append(newLine, line.Assemble()...)
   434  			}
   435  		} else {
   436  			newLine = line
   437  		}
   438  		if prefix > len(symbolized) {
   439  			prefix += len(newLine) - len(line)
   440  		}
   441  		symbolized = append(symbolized, newLine...)
   442  	}
   443  	oldReport := rep.Report
   444  	rep.Report = symbolized
   445  	oldPrefixLen := rep.reportPrefixLen
   446  	rep.reportPrefixLen = prefix
   447  
   448  	if len(rep.Report) > 0 && rep.reportPrefixLen > len(rep.Report) {
   449  		panic(fmt.Sprintf("invalid reportPrefixLen after symbolize: prefix %d -> %d,"+
   450  			"report len: %d -> %d, old report: %q",
   451  			oldPrefixLen, rep.reportPrefixLen, len(oldReport), len(rep.Report), oldReport,
   452  		))
   453  	}
   454  	return nil
   455  }
   456  
   457  type linuxBacktraceLine struct {
   458  	// Fields and corresponding indices in the indices array.
   459  	Name   string // 2:3
   460  	Offset uint64 // 4:5
   461  	Size   uint64 // 6:7
   462  	// ... 8:9 is a ModName + its enclosing parentheses.
   463  	ModName    string // 10:11
   464  	BuildID    string // 12:13
   465  	IsRipFrame bool
   466  	// These fields are to be set externally.
   467  	Inline   bool
   468  	FileLine string
   469  	// These fields are not to be modified outside of the type's methods.
   470  	raw     []byte
   471  	indices []int
   472  }
   473  
   474  func parseLinuxBacktraceLine(line []byte) (info linuxBacktraceLine, ok bool) {
   475  	match := linuxSymbolizeRe.FindSubmatchIndex(line)
   476  	if match == nil {
   477  		return
   478  	}
   479  	info.raw = line
   480  	info.indices = match
   481  	info.Name = string(line[match[2]:match[3]])
   482  	var err error
   483  	info.Offset, err = strconv.ParseUint(string(line[match[4]:match[5]]), 16, 64)
   484  	if err != nil {
   485  		return
   486  	}
   487  	info.Size, err = strconv.ParseUint(string(line[match[6]:match[7]]), 16, 64)
   488  	if err != nil {
   489  		return
   490  	}
   491  	if match[10] != -1 && match[11] != -1 {
   492  		info.ModName = string(line[match[10]:match[11]])
   493  	}
   494  	if match[12] != -1 && match[13] != -1 {
   495  		info.BuildID = string(line[match[12]:match[13]])
   496  	}
   497  	info.IsRipFrame = linuxRipFrame.Match(line)
   498  	return info, true
   499  }
   500  
   501  // Note that Assemble() ignores changes to Offset and Size (no reason as these are not updated anywhere).
   502  func (line linuxBacktraceLine) Assemble() []byte {
   503  	match := line.indices
   504  	modified := append([]byte{}, line.raw...)
   505  	if line.BuildID != "" {
   506  		modified = replace(modified, match[8], match[9], []byte(" ["+line.ModName+"]"))
   507  	}
   508  	if line.FileLine != "" {
   509  		modified = replace(modified, match[7], match[7], []byte(line.FileLine))
   510  	}
   511  	if line.Inline {
   512  		end := match[7] + len(line.FileLine)
   513  		modified = replace(modified, end, end, []byte(" [inline]"))
   514  		modified = replace(modified, match[2], match[7], []byte(line.Name))
   515  	} else {
   516  		modified = replace(modified, match[2], match[3], []byte(line.Name))
   517  	}
   518  	return modified
   519  }
   520  
   521  func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error), ctx *linux,
   522  	parsed linuxBacktraceLine) []linuxBacktraceLine {
   523  	symb := ctx.symbols[parsed.ModName][parsed.Name]
   524  	if len(symb) == 0 {
   525  		return []linuxBacktraceLine{parsed}
   526  	}
   527  	var funcStart uint64
   528  	for _, s := range symb {
   529  		if funcStart == 0 || int(parsed.Size) == s.Size {
   530  			funcStart = s.Addr
   531  		}
   532  	}
   533  	pc := funcStart + parsed.Offset
   534  	if !parsed.IsRipFrame {
   535  		// Usually we have return PCs, so we need to look at the previous instruction.
   536  		// But RIP lines contain the exact faulting PC.
   537  		pc--
   538  	}
   539  	var bin string
   540  	for _, mod := range ctx.config.kernelModules {
   541  		if mod.Name == parsed.ModName {
   542  			bin = mod.Path
   543  			break
   544  		}
   545  	}
   546  	frames, err := symbFunc(bin, pc)
   547  	if err != nil || len(frames) == 0 {
   548  		return []linuxBacktraceLine{parsed}
   549  	}
   550  	var ret []linuxBacktraceLine
   551  	for _, frame := range frames {
   552  		path, _ := backend.CleanPath(frame.File, &ctx.kernelDirs, nil)
   553  		copy := parsed
   554  		copy.FileLine = fmt.Sprintf(" %v:%v", path, frame.Line)
   555  		if frame.Inline {
   556  			copy.Inline = true
   557  			copy.Name = frame.Func
   558  		}
   559  		ret = append(ret, copy)
   560  	}
   561  	return ret
   562  }
   563  
   564  type parsedOpcodes struct {
   565  	rawBytes       []byte
   566  	decompileFlags DecompilerFlagMask
   567  	offset         int
   568  }
   569  
   570  type decompiledOpcodes struct {
   571  	opcodes           []DecompiledOpcode
   572  	trappingOpcodeIdx int
   573  	leftBytesCut      int
   574  }
   575  
   576  // processOpcodes converts a string representation of opcodes used by the Linux kernel into
   577  // a sequence of the machine instructions, that surround the one that crashed the kernel.
   578  // If the input does not start on a boundary of an instruction, it is attempted to adjust the
   579  // strting position.
   580  // The method returns an error if it did not manage to correctly decompile the opcodes or
   581  // of the decompiled code is not of interest to the reader (e.g. it is a user-space code).
   582  func (ctx *linux) processOpcodes(codeSlice string) (*decompiledOpcodes, error) {
   583  	parsed, err := ctx.parseOpcodes(codeSlice)
   584  	if err != nil {
   585  		return nil, err
   586  	}
   587  
   588  	decompiled, err := ctx.decompileWithOffset(parsed)
   589  	if err != nil {
   590  		return nil, err
   591  	}
   592  
   593  	if linuxSkipTrapInstrRe.MatchString(decompiled.opcodes[decompiled.trappingOpcodeIdx].Instruction) {
   594  		// For some reports (like WARNINGs) the trapping instruction is an intentionally
   595  		// invalid instruction. Decompilation of such code only allows to see the
   596  		// mechanism, through which the kernel implements such assertions and does not
   597  		// aid in finding the real issue.
   598  		return nil, fmt.Errorf("these opcodes are not of interest")
   599  	}
   600  
   601  	return decompiled, nil
   602  }
   603  
   604  func (ctx *linux) decompileWithOffset(parsed parsedOpcodes) (*decompiledOpcodes, error) {
   605  	// It is not guaranteed that the fragment of opcodes starts exactly at the boundary
   606  	// of a machine instruction. In order to simplify debugging process, we are trying
   607  	// to find the right starting position.
   608  	//
   609  	// We iterate over a fixed number of left boundaries. The exact number of iterations
   610  	// should strike a balance between the potential usefulness and the extra time needed
   611  	// to invoke the decompiler.
   612  	const opcodeAdjustmentLimit = 8
   613  
   614  	var bestResult *decompiledOpcodes
   615  
   616  	for leftCut := 0; leftCut <= parsed.offset && leftCut < opcodeAdjustmentLimit; leftCut++ {
   617  		newBytes := parsed.rawBytes[leftCut:]
   618  		newOffset := parsed.offset - leftCut
   619  		instructions, err := DecompileOpcodes(newBytes, parsed.decompileFlags, ctx.target)
   620  		if err != nil {
   621  			return nil, err
   622  		}
   623  
   624  		// We only want to return the response, where there exists a decoded instruction that
   625  		// perfectly aligns with the trapping instruction offset.
   626  		// At the same time, we'll do out best to find a code listing that does not contain
   627  		// unrecognized (bad) instuctions - this serves as an indicator of a valid result.
   628  
   629  		hasBad := false
   630  		trappingIdx := -1
   631  		for idx, instruction := range instructions {
   632  			if instruction.Offset == newOffset {
   633  				trappingIdx = idx
   634  			}
   635  			if instruction.Offset >= newOffset {
   636  				// Do not take into account instructions after the target offset. Once
   637  				// decompiler begins to find the right boundary, we cannot improve them.
   638  				break
   639  			}
   640  			hasBad = hasBad || instruction.IsBad
   641  		}
   642  
   643  		if trappingIdx < 0 {
   644  			continue
   645  		}
   646  
   647  		if !hasBad || bestResult == nil {
   648  			bestResult = &decompiledOpcodes{
   649  				opcodes:           instructions,
   650  				trappingOpcodeIdx: trappingIdx,
   651  				leftBytesCut:      leftCut,
   652  			}
   653  			if !hasBad {
   654  				// The best offset is already found.
   655  				break
   656  			}
   657  		}
   658  	}
   659  	if bestResult == nil {
   660  		return nil, fmt.Errorf("unable to align decompiled code and the trapping instruction offset")
   661  	}
   662  	return bestResult, nil
   663  }
   664  
   665  func (ctx *linux) parseOpcodes(codeSlice string) (parsedOpcodes, error) {
   666  	width := 0
   667  	bytes := []byte{}
   668  	trapOffset := -1
   669  	for _, part := range strings.Split(strings.TrimSpace(codeSlice), " ") {
   670  		if part == "" || len(part)%2 != 0 {
   671  			return parsedOpcodes{}, fmt.Errorf("invalid opcodes string %#v", part)
   672  		}
   673  
   674  		// Check if this is a marker of a trapping instruction.
   675  		if part[0] == '(' || part[0] == '<' {
   676  			if trapOffset >= 0 {
   677  				return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: multiple trap intructions")
   678  			}
   679  			trapOffset = len(bytes)
   680  
   681  			if len(part) < 3 {
   682  				return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: invalid trap opcode")
   683  			}
   684  			part = part[1 : len(part)-1]
   685  		}
   686  
   687  		if width == 0 {
   688  			width = len(part) / 2
   689  		}
   690  
   691  		number, err := strconv.ParseUint(part, 16, 64)
   692  		if err != nil {
   693  			return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: failed to parse %#v", part)
   694  		}
   695  
   696  		extraBytes := make([]byte, width)
   697  		switch len(extraBytes) {
   698  		case 1:
   699  			extraBytes[0] = byte(number)
   700  		case 2:
   701  			ctx.target.HostEndian.PutUint16(extraBytes, uint16(number))
   702  		case 4:
   703  			ctx.target.HostEndian.PutUint32(extraBytes, uint32(number))
   704  		case 8:
   705  			ctx.target.HostEndian.PutUint64(extraBytes, number)
   706  		default:
   707  			return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: invalid width %v", width)
   708  		}
   709  		bytes = append(bytes, extraBytes...)
   710  	}
   711  
   712  	if trapOffset < 0 {
   713  		return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: no trapping instructions")
   714  	}
   715  
   716  	var flags DecompilerFlagMask
   717  	if ctx.target.Arch == targets.ARM && width == 2 {
   718  		flags |= FlagForceArmThumbMode
   719  	}
   720  	return parsedOpcodes{
   721  		rawBytes:       bytes,
   722  		decompileFlags: flags,
   723  		offset:         trapOffset,
   724  	}, nil
   725  }
   726  
   727  // decompileOpcodes detects the most meaningful "Code: " lines from the report, decompiles
   728  // them and appends a human-readable listing to the end of the report.
   729  func (ctx *linux) decompileOpcodes(text []byte, report *Report) []byte {
   730  	if report.Type == crash.Hang {
   731  		// Even though Hang reports do contain the Code: section, there's no point in
   732  		// decompiling that. So just return the text.
   733  		return text
   734  	}
   735  	// Iterate over all "Code: " lines and pick the first that could be decompiled
   736  	// that might be of interest to the user.
   737  	var decompiled *decompiledOpcodes
   738  	lines := lines(text)
   739  	for i, line := range lines {
   740  		var prevLine []byte
   741  		if i > 0 {
   742  			prevLine = lines[i-1]
   743  		}
   744  		// We want to avoid decompiling code from user-space as it is not of big interest during
   745  		// debugging kernel problems.
   746  		// For now this check only works for x86/amd64, but Linux on other architectures supported
   747  		// by syzkaller does not seem to include user-space code in its oops messages.
   748  		if linuxUserSegmentRe.Match(prevLine) {
   749  			continue
   750  		}
   751  		match := linuxCodeRe.FindSubmatch(line)
   752  		if match == nil {
   753  			continue
   754  		}
   755  		decompiledLine, err := ctx.processOpcodes(string(match[1]))
   756  		if err != nil {
   757  			continue
   758  		}
   759  		decompiled = decompiledLine
   760  		break
   761  	}
   762  
   763  	if decompiled == nil {
   764  		return text
   765  	}
   766  
   767  	skipInfo := ""
   768  	if decompiled.leftBytesCut > 0 {
   769  		skipInfo = fmt.Sprintf(", %v bytes skipped", decompiled.leftBytesCut)
   770  	}
   771  
   772  	// The decompiled instructions are intentionally put to the bottom of the report instead
   773  	// being inlined below the corresponding "Code:" line. The intent is to continue to keep
   774  	// the most important information at the top of the report, so that it is visible from
   775  	// the syzbot dashboard without scrolling.
   776  	headLine := fmt.Sprintf("----------------\nCode disassembly (best guess)%v:\n", skipInfo)
   777  	text = append(text, headLine...)
   778  
   779  	for idx, opcode := range decompiled.opcodes {
   780  		line := opcode.FullDescription
   781  		if idx == decompiled.trappingOpcodeIdx {
   782  			line = fmt.Sprintf("*%s <-- trapping instruction\n", line[1:])
   783  		} else {
   784  			line += "\n"
   785  		}
   786  		text = append(text, line...)
   787  	}
   788  	return text
   789  }
   790  
   791  func (ctx *linux) extractGuiltyFile(rep *Report) string {
   792  	return ctx.extractGuiltyFileRaw(rep.Title, rep.Report[rep.reportPrefixLen:])
   793  }
   794  
   795  func (ctx *linux) extractGuiltyFileRaw(title string, report []byte) string {
   796  	if strings.HasPrefix(title, "INFO: rcu detected stall") {
   797  		// Special case for rcu stalls.
   798  		// There are too many frames that we want to skip before actual guilty frames,
   799  		// we would need to ignore too many files and that would be fragile.
   800  		// So instead we try to extract guilty file starting from the known
   801  		// interrupt entry point first.
   802  		for _, interruptEnd := range []string{"apic_timer_interrupt+0x",
   803  			"el1h_64_irq+0x", "Exception stack"} {
   804  			if pos := bytes.Index(report, []byte(interruptEnd)); pos != -1 {
   805  				if file := ctx.extractGuiltyFileImpl(report[pos:]); file != "" {
   806  					return file
   807  				}
   808  			}
   809  		}
   810  	}
   811  	return ctx.extractGuiltyFileImpl(report)
   812  }
   813  
   814  func (ctx *linux) extractGuiltyFileImpl(report []byte) string {
   815  	// Extract the first possible guilty file.
   816  	guilty := ""
   817  	var line []byte
   818  	lines := lines(report)
   819  	for len(lines) > 0 {
   820  		line, lines = lines[0], lines[1:]
   821  		match := filenameRe.FindSubmatch(line)
   822  		if match == nil {
   823  			continue
   824  		}
   825  		file := match[1]
   826  		if guilty == "" {
   827  			// Avoid producing no guilty file at all, otherwise we mail the report to nobody.
   828  			// It's unclear if it's better to return the first one or the last one.
   829  			// So far the only test we have has only one file anyway.
   830  			guilty = string(file)
   831  		}
   832  
   833  		if matchesAny(file, ctx.guiltyFileIgnores) || ctx.guiltyLineIgnore.Match(line) {
   834  			continue
   835  		}
   836  		guilty = filepath.Clean(string(file))
   837  		break
   838  	}
   839  
   840  	// Search for deeper filepaths in the stack trace below the first possible guilty file.
   841  	deepestPath := filepath.Dir(guilty)
   842  	for len(lines) > 0 {
   843  		line, lines = lines[0], lines[1:]
   844  		match := filenameRe.FindSubmatch(line)
   845  		if match == nil {
   846  			continue
   847  		}
   848  		file := match[1]
   849  		if matchesAny(file, ctx.guiltyFileIgnores) || ctx.guiltyLineIgnore.Match(line) {
   850  			continue
   851  		}
   852  		clean := filepath.Clean(string(file))
   853  
   854  		// Check if the new path has *both* the same directory prefix *and* a deeper suffix.
   855  		if strings.HasPrefix(clean, deepestPath) {
   856  			suffix := strings.TrimPrefix(clean, deepestPath)
   857  			if deeperPathRe.Match([]byte(suffix)) {
   858  				guilty = clean
   859  				deepestPath = filepath.Dir(guilty)
   860  			}
   861  		}
   862  	}
   863  
   864  	return guilty
   865  }
   866  
   867  func (ctx *linux) getMaintainers(file string) (vcs.Recipients, error) {
   868  	if ctx.kernelDirs.Src == "" {
   869  		return nil, nil
   870  	}
   871  	return GetLinuxMaintainers(ctx.kernelDirs.Src, file)
   872  }
   873  
   874  func GetLinuxMaintainers(kernelSrc, file string) (vcs.Recipients, error) {
   875  	mtrs, err := getMaintainersImpl(kernelSrc, file, false)
   876  	if err != nil {
   877  		return nil, err
   878  	}
   879  	if len(mtrs) <= 1 {
   880  		mtrs, err = getMaintainersImpl(kernelSrc, file, true)
   881  		if err != nil {
   882  			return nil, err
   883  		}
   884  	}
   885  	return mtrs, nil
   886  }
   887  
   888  func getMaintainersImpl(kernelSrc, file string, blame bool) (vcs.Recipients, error) {
   889  	// See #1441 re --git-min-percent.
   890  	args := []string{"--git-min-percent=15"}
   891  	if blame {
   892  		args = append(args, "--git-blame")
   893  	}
   894  	args = append(args, "-f", file)
   895  	script := filepath.FromSlash("scripts/get_maintainer.pl")
   896  	output, err := osutil.RunCmd(time.Minute, kernelSrc, script, args...)
   897  	if err != nil {
   898  		return nil, err
   899  	}
   900  	return vcs.ParseMaintainersLinux(output), nil
   901  }
   902  
   903  func isCorrupted(title string, report []byte, format oopsFormat) (bool, string) {
   904  	// Check for common title corruptions.
   905  	for _, re := range linuxCorruptedTitles {
   906  		if re.MatchString(title) {
   907  			return true, "title matches corrupted regexp"
   908  		}
   909  	}
   910  	// If the report hasn't matched any of the oops titles, don't mark it as corrupted.
   911  	if format.title == nil {
   912  		return false, ""
   913  	}
   914  	if format.noStackTrace {
   915  		return false, ""
   916  	}
   917  	// When a report contains 'Call Trace', 'backtrace', 'Allocated' or 'Freed' keywords,
   918  	// it must also contain at least a single stack frame after each of them.
   919  	hasStackTrace := false
   920  	for _, key := range linuxStackParams.stackStartRes {
   921  		match := key.FindSubmatchIndex(report)
   922  		if match == nil {
   923  			continue
   924  		}
   925  		frames := lines(report[match[0]:])
   926  		if len(frames) < 4 {
   927  			return true, "call trace is missed"
   928  		}
   929  		corrupted := true
   930  		frames = frames[1:]
   931  		// Check that at least one of the next few lines contains a frame.
   932  	outer:
   933  		for i := 0; i < 15 && i < len(frames); i++ {
   934  			for _, key1 := range linuxStackParams.stackStartRes {
   935  				// Next stack trace starts.
   936  				if key1.Match(frames[i]) {
   937  					break outer
   938  				}
   939  			}
   940  			if bytes.Contains(frames[i], []byte("(stack is not available)")) ||
   941  				matchesAny(frames[i], linuxStackParams.frameRes) {
   942  				hasStackTrace = true
   943  				corrupted = false
   944  				break
   945  			}
   946  		}
   947  		if corrupted {
   948  			return true, "no frames in a stack trace"
   949  		}
   950  	}
   951  	if !hasStackTrace {
   952  		return true, "no stack trace in report"
   953  	}
   954  	return false, ""
   955  }
   956  
   957  var syzLinuxCommRe = regexp.MustCompile(` Comm: syz\.(\d+)\.(\d+) `)
   958  
   959  func setExecutorInfo(rep *Report) {
   960  	match := syzLinuxCommRe.FindSubmatch(rep.Report)
   961  	if match == nil {
   962  		return
   963  	}
   964  	info := &ExecutorInfo{}
   965  	var err error
   966  	info.ProcID, err = strconv.Atoi(string(match[1]))
   967  	if err != nil {
   968  		return
   969  	}
   970  	info.ExecID, err = strconv.Atoi(string(match[2]))
   971  	if err != nil {
   972  		return
   973  	}
   974  	rep.Executor = info
   975  }
   976  
   977  func linuxStallFrameExtractor(frames []string) (string, int) {
   978  	// During rcu stalls and cpu lockups kernel loops in some part of code,
   979  	// usually across several functions. When the stall is detected, traceback
   980  	// points to a random stack within the looping code. We generally take
   981  	// the top function in the stack (with few exceptions) as the bug identity.
   982  	// As the result stalls with the same root would produce multiple reports
   983  	// in different functions, which is bad.
   984  	// Instead we identify a representative function deeper in the stack.
   985  	// For most syscalls it can be the syscall entry function (e.g. SyS_timer_create).
   986  	// However, for highly discriminated functions syscalls like ioctl/read/write/connect
   987  	// we take the previous function (e.g. for connect the one that points to exact
   988  	// protocol, or for ioctl the one that is related to the device).
   989  	prev, prevIdx := frames[0], 0
   990  	for i, frame := range frames {
   991  		if matchesAny([]byte(frame), linuxStallAnchorFrames) {
   992  			if strings.Contains(frame, "smp_call_function") {
   993  				// In this case we want this function rather than the previous one
   994  				// (there can be several variations on the next one).
   995  				prev = "smp_call_function"
   996  				prevIdx = i
   997  			}
   998  			return prev, prevIdx
   999  		}
  1000  		prev, prevIdx = frame, i
  1001  	}
  1002  	return "", -1
  1003  }
  1004  
  1005  func linuxHangTaskFrameExtractor(frames []string) (string, int) {
  1006  	// The problem with task hung reports is that they manifest at random victim stacks,
  1007  	// rather at the root cause stack. E.g. if there is something wrong with RCU subsystem,
  1008  	// we are getting hangs all over the kernel on all synchronize_* calls.
  1009  	// So before resotring to the common logic of skipping some common frames,
  1010  	// we look for 2 common buckets: hangs on synchronize_rcu and hangs on rtnl_lock
  1011  	// and group these together.
  1012  	const synchronizeRCU = "synchronize_rcu"
  1013  	anchorFrames := map[string]string{
  1014  		"rtnl_lock":         "",
  1015  		"synchronize_rcu":   synchronizeRCU,
  1016  		"synchronize_srcu":  synchronizeRCU,
  1017  		"synchronize_net":   synchronizeRCU,
  1018  		"synchronize_sched": synchronizeRCU,
  1019  	}
  1020  	for i, frame := range frames {
  1021  		for anchor, replacement := range anchorFrames {
  1022  			if strings.Contains(frame, anchor) {
  1023  				if replacement != "" {
  1024  					frame = replacement
  1025  				}
  1026  				return frame, i
  1027  			}
  1028  		}
  1029  	}
  1030  	skip := []string{"sched", "_lock", "_slowlock", "down", "rwsem", "completion", "kthread",
  1031  		"wait", "synchronize", "context_switch", "__switch_to", "cancel_delayed_work",
  1032  		"rcu_barrier"}
  1033  nextFrame:
  1034  	for i, frame := range frames {
  1035  		for _, ignore := range skip {
  1036  			if strings.Contains(frame, ignore) {
  1037  				continue nextFrame
  1038  			}
  1039  		}
  1040  		return frame, i
  1041  	}
  1042  	return "", -1
  1043  }
  1044  
  1045  var linuxStallAnchorFrames = []*regexp.Regexp{
  1046  	// Various generic functions that dispatch work.
  1047  	// We also include some of their callers, so that if some names change
  1048  	// we don't skip whole stacks and proceed parsing the next one.
  1049  	compile("process_one_work"),  // workqueue callback
  1050  	compile("do_syscall_"),       // syscall entry
  1051  	compile("do_fast_syscall_"),  // syscall entry
  1052  	compile("sysenter_dispatch"), // syscall entry
  1053  	compile("tracesys_phase2"),   // syscall entry
  1054  	compile("el0_svc_handler"),   // syscall entry
  1055  	compile("invoke_syscall"),    // syscall entry
  1056  	compile("ret_fast_syscall"),  // arm syscall entry
  1057  	compile("netif_receive_skb"), // net receive entry point
  1058  	compile("do_softirq"),
  1059  	compile("call_timer_fn"),
  1060  	compile("_run_timers"),
  1061  	compile("run_timer_softirq"),
  1062  	compile("hrtimer_run"),
  1063  	compile("run_ksoftirqd"),
  1064  	compile("smpboot_thread_fn"),
  1065  	compile("^kthread$"),
  1066  	compile("start_secondary"),
  1067  	compile("cpu_startup_entry"),
  1068  	compile("ret_from_fork"),
  1069  	// Important discriminated syscalls (file_operations callbacks, etc):
  1070  	compile("vfs_write"),
  1071  	compile("vfs_read"),
  1072  	compile("vfs_iter_read"),
  1073  	compile("vfs_iter_write"),
  1074  	compile("do_iter_read"),
  1075  	compile("do_iter_write"),
  1076  	compile("call_read_iter"),
  1077  	compile("call_write_iter"),
  1078  	compile("new_sync_read"),
  1079  	compile("new_sync_write"),
  1080  	compile("vfs_ioctl"),
  1081  	compile("ksys_ioctl"), // vfs_ioctl may be inlined
  1082  	compile("compat_ioctl"),
  1083  	compile("compat_sys_ioctl"),
  1084  	compile("blkdev_driver_ioctl"),
  1085  	compile("blkdev_ioctl"),
  1086  	compile("^call_read_iter"),
  1087  	compile("^call_write_iter"),
  1088  	compile("do_iter_readv_writev"),
  1089  	compile("^call_mmap"),
  1090  	compile("mmap_region"),
  1091  	compile("do_mmap"),
  1092  	compile("do_dentry_open"),
  1093  	compile("vfs_open"),
  1094  	// Socket operations:
  1095  	compile("^sock_sendmsg"),
  1096  	compile("^sock_recvmsg"),
  1097  	compile("^sock_release"),
  1098  	compile("^__sock_release"),
  1099  	compile("^setsockopt$"),
  1100  	compile("kernel_setsockopt"),
  1101  	compile("sock_common_setsockopt"),
  1102  	compile("^listen$"),
  1103  	compile("kernel_listen"),
  1104  	compile("sk_common_release"),
  1105  	compile("^sock_mmap"),
  1106  	compile("^accept$"),
  1107  	compile("kernel_accept"),
  1108  	compile("^sock_do_ioctl"),
  1109  	compile("^sock_ioctl"),
  1110  	compile("^compat_sock_ioctl"),
  1111  	compile("^nfnetlink_rcv_msg"),
  1112  	compile("^rtnetlink_rcv_msg"),
  1113  	compile("^netlink_dump"),
  1114  	compile("^(sys_)?(socketpair|connect|ioctl)"),
  1115  	// Page fault entry points:
  1116  	compile("__do_fault"),
  1117  	compile("do_page_fault"),
  1118  	compile("^page_fault$"),
  1119  	// exit_to_usermode_loop callbacks:
  1120  	compile("__fput"),
  1121  	compile("task_work_run"),
  1122  	compile("exit_to_usermode"),
  1123  	compile("smp_call_function"),
  1124  	compile("tasklet_action"),
  1125  	compile("tasklet_hi_action"),
  1126  }
  1127  
  1128  // nolint: lll
  1129  var (
  1130  	linuxSymbolizeRe     = regexp.MustCompile(`(?:\[\<(?:(?:0x)?[0-9a-f]+)\>\])?[ \t]+\(?(?:[0-9]+:)?([a-zA-Z0-9_.]+)\+0x([0-9a-f]+)/0x([0-9a-f]+)( ?\[([a-zA-Z0-9_.]+)( .*)?\])?\)?`)
  1131  	linuxRipFrame        = compile(`(?:IP|NIP|pc |PC is at):? (?:(?:[0-9]+:)?(?:{{PC}} +){0,2}{{FUNC}}|(?:[0-9]+:)?0x[0-9a-f]+|(?:[0-9]+:)?{{PC}} +\[< *\(null\)>\] +\(null\)|[0-9]+: +\(null\))`)
  1132  	linuxCallTrace       = compile(`(?:Call (?:T|t)race:)|(?:Backtrace:)`)
  1133  	linuxCodeRe          = regexp.MustCompile(`(?m)^\s*Code\:\s+((?:[A-Fa-f0-9\(\)\<\>]{2,8}\s*)*)\s*$`)
  1134  	linuxSkipTrapInstrRe = regexp.MustCompile(`^ud2|brk\s+#0x800$`)
  1135  	linuxUserSegmentRe   = regexp.MustCompile(`^RIP:\s+0033:`)
  1136  )
  1137  
  1138  var linuxCorruptedTitles = []*regexp.Regexp{
  1139  	// Sometimes timestamps get merged into the middle of report description.
  1140  	regexp.MustCompile(`\[ *[0-9]+\.[0-9]+\]`),
  1141  }
  1142  
  1143  var linuxStackParams = &stackParams{
  1144  	stackStartRes: []*regexp.Regexp{
  1145  		regexp.MustCompile(`Call (?:T|t)race`),
  1146  		regexp.MustCompile(`Allocated:`),
  1147  		regexp.MustCompile(`Allocated by task [0-9]+:`),
  1148  		regexp.MustCompile(`Freed:`),
  1149  		regexp.MustCompile(`Freed by task [0-9]+:`),
  1150  		// Match 'backtrace:', but exclude 'stack backtrace:'
  1151  		// Also match optional crc hash for KMEMLEAK reports.
  1152  		regexp.MustCompile(`[^k] backtrace(?: \(crc [[:xdigit:]]*\))?:`),
  1153  		regexp.MustCompile(`Backtrace:`),
  1154  		regexp.MustCompile(`Uninit was stored to memory at`),
  1155  	},
  1156  	frameRes: []*regexp.Regexp{
  1157  		compile("^ *(?:{{PC}} ){0,2}{{FUNC}}"),
  1158  		// Arm is totally different.
  1159  		// Extract both current and next frames. This is needed for the top
  1160  		// frame which is present only in LR register which we don't parse.
  1161  		compile(`^ *{{PC}} \(([a-zA-Z0-9_.]+)\) from {{PC}} \({{FUNC}}`),
  1162  	},
  1163  	skipPatterns: []string{
  1164  		"__sanitizer",
  1165  		"__asan",
  1166  		"kasan",
  1167  		"hwasan",
  1168  		"__msan",
  1169  		"kmsan",
  1170  		"kcsan_setup_watchpoint",
  1171  		"check_memory_region",
  1172  		"check_heap_object",
  1173  		"check_object",
  1174  		"read_word_at_a_time",
  1175  		"(read|write)_once_.*nocheck",
  1176  		"print_address_description",
  1177  		"panic",
  1178  		"invalid_op",
  1179  		"report_bug",
  1180  		"fixup_bug",
  1181  		"print_report",
  1182  		"print_usage_bug",
  1183  		"do_error",
  1184  		"invalid_op",
  1185  		`_trap$|do_trap`,
  1186  		"show_stack",
  1187  		"dump_stack",
  1188  		"walk_stack",
  1189  		"dump_backtrace",
  1190  		"warn_slowpath",
  1191  		"warn_alloc",
  1192  		"warn_bogus",
  1193  		"__warn",
  1194  		"alloc_page",
  1195  		"k?v?(?:m|z|c)alloc",
  1196  		"krealloc",
  1197  		"kmem_cache",
  1198  		"allocate_slab",
  1199  		"__alloc_frozen_pages_noprof",
  1200  		"folio_(?:alloc|unlock)",
  1201  		"filemap_alloc_folio",
  1202  		"__filemap_get_folio",
  1203  		"find_or_create_page",
  1204  		"do_read_cache_folio",
  1205  		"read_cache_page",
  1206  		"pagecache_get_page",
  1207  		"grab_cache_page_write_begin",
  1208  		"slab_",
  1209  		"debug_object",
  1210  		"timer_is_static_object",
  1211  		"work_is_static_object",
  1212  		"__might_fault",
  1213  		"print_unlock",
  1214  		"imbalance_bug",
  1215  		"lockdep",
  1216  		"bh_enable",
  1217  		"bh_disable",
  1218  		"perf_trace",
  1219  		"lock_acquire",
  1220  		"lock_release",
  1221  		"lock_class",
  1222  		"mark_lock",
  1223  		"(reacquire|mark)_held_locks",
  1224  		"raw_spin_rq",
  1225  		"spin_lock",
  1226  		"spin_trylock",
  1227  		"spin_unlock",
  1228  		"read_lock",
  1229  		"read_trylock",
  1230  		"write_lock",
  1231  		"write_trylock",
  1232  		"read_unlock",
  1233  		"write_unlock",
  1234  		"^down$",
  1235  		"down_read",
  1236  		"down_write",
  1237  		"down_read_trylock",
  1238  		"down_write_trylock",
  1239  		"down_trylock",
  1240  		"up_read",
  1241  		"up_write",
  1242  		"^mutex_",
  1243  		"^__mutex_",
  1244  		"^rt_mutex_",
  1245  		"owner_on_cpu",
  1246  		"osq_lock",
  1247  		"osq_unlock",
  1248  		"atomic(64)?_(dec|inc|read|set|or|xor|and|add|sub|fetch|xchg|cmpxchg|try)",
  1249  		"(set|clear|change|test)_bit",
  1250  		"__wake_up",
  1251  		"^refcount_",
  1252  		"^kref_",
  1253  		"ref_tracker",
  1254  		"seqprop_assert",
  1255  		"memcpy",
  1256  		"memcmp",
  1257  		"memset",
  1258  		"memchr",
  1259  		"memmove",
  1260  		"memdup",
  1261  		"strcmp",
  1262  		"strncmp",
  1263  		"strcpy",
  1264  		"strlcpy",
  1265  		"strncpy",
  1266  		"strscpy",
  1267  		"strlen",
  1268  		"strstr",
  1269  		"strnstr",
  1270  		"strnlen",
  1271  		"strchr",
  1272  		"strdup",
  1273  		"strndup",
  1274  		"copy_to_user",
  1275  		"copy_from_user",
  1276  		"copy_to_iter",
  1277  		"copy_from_iter",
  1278  		"copy_page_to_iter",
  1279  		"copy_page_from_iter",
  1280  		"copy_folio_to_iter",
  1281  		"^copyin$",
  1282  		"^copyout$",
  1283  		"put_user",
  1284  		"get_user",
  1285  		"might_fault",
  1286  		"might_sleep",
  1287  		"list_add",
  1288  		"list_del",
  1289  		"list_replace",
  1290  		"list_move",
  1291  		"list_splice",
  1292  		"^rb_",
  1293  		"^__rb_",
  1294  		"_indirect_thunk_", // retpolines
  1295  		"string",
  1296  		"pointer",
  1297  		"snprintf",
  1298  		"scnprintf",
  1299  		"kasprintf",
  1300  		"kvasprintf",
  1301  		"printk",
  1302  		"va_format",
  1303  		"dev_info",
  1304  		"dev_notice",
  1305  		"dev_warn",
  1306  		"dev_err",
  1307  		"dev_alert",
  1308  		"dev_crit",
  1309  		"dev_emerg",
  1310  		"program_check_exception",
  1311  		"program_check_common",
  1312  		"del_timer",
  1313  		"flush_work",
  1314  		"__cancel_work_timer",
  1315  		"cancel_work_sync",
  1316  		"try_to_grab_pending",
  1317  		"flush_workqueue",
  1318  		"drain_workqueue",
  1319  		"destroy_workqueue",
  1320  		"queue_work",
  1321  		"finish_wait",
  1322  		"kthread_stop",
  1323  		"kobject_",
  1324  		"add_uevent_var",
  1325  		"get_device_parent",
  1326  		"device_add",
  1327  		"device_del",
  1328  		"device_unregister",
  1329  		"device_destroy",
  1330  		"device_release",
  1331  		"devres_release_all",
  1332  		"hwrng_unregister",
  1333  		"i2c_del_adapter",
  1334  		"__unregister_client",
  1335  		"device_for_each_child",
  1336  		"rollback_registered",
  1337  		"unregister_netdev",
  1338  		"sysfs_remove",
  1339  		"device_remove_file",
  1340  		"tty_unregister_device",
  1341  		"dummy_urb_enqueue",
  1342  		"usb_kill_urb",
  1343  		"usb_kill_anchored_urbs",
  1344  		"usb_control_msg",
  1345  		"usb_hcd_submit_urb",
  1346  		"usb_submit_urb",
  1347  		"^complete$",
  1348  		"wait_for_completion",
  1349  		"^kv?free$",
  1350  		"kfree_skb",
  1351  		"readb$",
  1352  		"readw$",
  1353  		"readl$",
  1354  		"readq$",
  1355  		"writeb$",
  1356  		"writew$",
  1357  		"writel$",
  1358  		"writeq$",
  1359  		"logic_in",
  1360  		"logic_out",
  1361  		"^crc\\d+",
  1362  		"crc_itu_t",
  1363  		"__might_resched",
  1364  		"assertfail",
  1365  		"^iput$",
  1366  		"^iput_final$",
  1367  		"^ihold$",
  1368  		"hex_dump_to_buffer",
  1369  		"print_hex_dump",
  1370  		"^klist_",
  1371  		"(trace|lockdep)_(hard|soft)irq",
  1372  		"^(un)?lock_page",
  1373  		"stack_trace_consume_entry",
  1374  		"arch_stack_walk",
  1375  		"stack_trace_save",
  1376  		"insert_work",
  1377  		"__queue_delayed_work",
  1378  		"queue_delayed_work_on",
  1379  		"ida_free",
  1380  		// arm64 translation exception handling path.
  1381  		"do_(kernel|translation)_fault",
  1382  		"do_mem_abort",
  1383  		"el1_abort",
  1384  		"el1h_64_sync(?:_handler)?",
  1385  		"print_tainted",
  1386  		"xas_(?:start|load|find)",
  1387  		"find_lock_entries",
  1388  		"truncate_inode_pages_range",
  1389  		"__phys_addr",
  1390  		"__fortify_report",
  1391  		"cleanup_srcu_struct",
  1392  		"rhashtable_lookup",
  1393  		"extract_(user|iter)_to_sg",
  1394  		"drop_nlink",
  1395  		"^get_taint$",
  1396  		"^put_device$",
  1397  		"lock_timer_base",
  1398  		"__timer_delete_sync",
  1399  		"sk_stop_timer_sync",
  1400  		"__mod_timer",
  1401  		"fast_dput",
  1402  		"dput",
  1403  	},
  1404  	corruptedLines: []*regexp.Regexp{
  1405  		// Fault injection stacks are frequently intermixed with crash reports.
  1406  		// Note: the actual symbol can have all kinds of weird suffixes like ".isra.7", ".cold" or ".isra.56.cold.74".
  1407  		compile(`^( \[\<?(?:0x)?[0-9a-f]+\>?\])? should_fail(slab)?(\.[a-z0-9.]+)?\+0x`),
  1408  	},
  1409  	stripFramePrefixes: []string{
  1410  		"SYSC_",
  1411  		"SyS_",
  1412  		"sys_",
  1413  		"__x64_",
  1414  		"__ia32_",
  1415  		"__arm64_",
  1416  		"____sys_",
  1417  		"___sys_",
  1418  		"__sys_",
  1419  		"__se_",
  1420  		"__se_sys_",
  1421  		"__do_sys_",
  1422  		"compat_SYSC_",
  1423  		"compat_SyS_",
  1424  		"ksys_",
  1425  	},
  1426  }
  1427  
  1428  func warningStackFmt(skip ...string) *stackFmt {
  1429  	return &stackFmt{
  1430  		// In newer kernels WARNING traps and actual stack starts after invalid_op frame,
  1431  		// older kernels just print stack.
  1432  		parts: []*regexp.Regexp{
  1433  			// x86_64 warning stack starts with "RIP:" line,
  1434  			// while powerpc64 starts with "--- interrupt:".
  1435  			compile("(?:" + linuxRipFrame.String() + "|--- interrupt: [0-9]+ at {{FUNC}})"),
  1436  			parseStackTrace,
  1437  		},
  1438  		parts2: []*regexp.Regexp{
  1439  			linuxCallTrace,
  1440  			parseStackTrace,
  1441  		},
  1442  		skip: skip,
  1443  	}
  1444  }
  1445  
  1446  // nolint: lll
  1447  var linuxOopses = append([]*oops{
  1448  	{
  1449  		[]byte("BUG:"),
  1450  		[]oopsFormat{
  1451  			{
  1452  				title:  compile("BUG: KASAN:"),
  1453  				report: compile("BUG: KASAN: ([a-z\\-]+) in {{FUNC}}(?:.*\\n)+?.*(Read|Write) (?:of size|at addr) (?:[0-9a-f]+)"),
  1454  				fmt:    "KASAN: %[1]v %[3]v in %[4]v",
  1455  				alt:    []string{"bad-access in %[4]v"},
  1456  				stack: &stackFmt{
  1457  					parts: []*regexp.Regexp{
  1458  						compile("BUG: KASAN: (?:[a-z\\-]+) in {{FUNC}}"),
  1459  						linuxCallTrace,
  1460  						parseStackTrace,
  1461  					},
  1462  					// These frames are present in KASAN_HW_TAGS reports.
  1463  					skip: []string{"kernel_fault", "tag_check", "mem_abort", "^el1_", "^el1h_"},
  1464  				},
  1465  			},
  1466  			{
  1467  				title:  compile("BUG: KASAN:"),
  1468  				report: compile("BUG: KASAN: (?:double-free or invalid-free|double-free|invalid-free) in {{FUNC}}"),
  1469  				fmt:    "KASAN: invalid-free in %[2]v",
  1470  				alt:    []string{"invalid-free in %[2]v"},
  1471  				stack: &stackFmt{
  1472  					parts: []*regexp.Regexp{
  1473  						compile("BUG: KASAN: (?:double-free or invalid-free|double-free|invalid-free) in {{FUNC}}"),
  1474  						linuxCallTrace,
  1475  						parseStackTrace,
  1476  					},
  1477  					skip: []string{"slab_", "kfree", "vunmap", "vfree"},
  1478  				},
  1479  			},
  1480  			{
  1481  				title: compile("BUG: KASAN: ([a-z\\-]+) on address(?:.*\\n)+?.*(Read|Write) of size ([0-9]+)"),
  1482  				fmt:   "KASAN: %[1]v %[2]v",
  1483  			},
  1484  			{
  1485  				title:     compile("BUG: KASAN: (.*)"),
  1486  				fmt:       "KASAN: %[1]v",
  1487  				corrupted: true,
  1488  			},
  1489  			{
  1490  				title:  compile("BUG: KMSAN: kernel-usb-infoleak"),
  1491  				report: compile("BUG: KMSAN: kernel-usb-infoleak in {{FUNC}}"),
  1492  				fmt:    "KMSAN: kernel-usb-infoleak in %[2]v",
  1493  				alt:    []string{"KMSAN origin in %[3]v"},
  1494  				stack: &stackFmt{
  1495  					parts: []*regexp.Regexp{
  1496  						parseStackTrace,
  1497  						compile("(Local variable .* created at:|Uninit was created at:)"),
  1498  						parseStackTrace,
  1499  					},
  1500  					skip: []string{"alloc_skb", "usb_submit_urb", "usb_start_wait_urb", "usb_bulk_msg", "usb_interrupt_msg", "usb_control_msg"},
  1501  				},
  1502  				noStackTrace: true,
  1503  			},
  1504  			{
  1505  				title:  compile("BUG: KMSAN:"),
  1506  				report: compile("BUG: KMSAN: ([a-z\\-]+) in {{FUNC}}"),
  1507  				fmt:    "KMSAN: %[1]v in %[3]v",
  1508  				alt: []string{
  1509  					"bad-access in %[3]v",
  1510  				},
  1511  				stack: &stackFmt{
  1512  					parts: []*regexp.Regexp{
  1513  						parseStackTrace,
  1514  						compile("(Local variable .* created at:|Uninit was created at:)"),
  1515  						parseStackTrace,
  1516  					},
  1517  					skip: []string{
  1518  						"alloc_skb", "netlink_ack", "netlink_rcv_skb",
  1519  						// Encryption routines are the place where we hit the bug, but
  1520  						// the generic code is a bad candidate for bug titles.
  1521  						"_encrypt$", "^(?:crypto|cipher|drbg|rng)_"},
  1522  				},
  1523  				noStackTrace: true,
  1524  			},
  1525  			{
  1526  				title:        compile("BUG: KCSAN: data-race"),
  1527  				report:       compile("BUG: KCSAN: (.*)"),
  1528  				fmt:          "KCSAN: %[1]v",
  1529  				noStackTrace: true,
  1530  			},
  1531  			{
  1532  				title:        compile("BUG: KCSAN:"),
  1533  				report:       compile("BUG: KCSAN: (.*)"),
  1534  				fmt:          "KCSAN: %[1]v",
  1535  				noStackTrace: true,
  1536  			},
  1537  			{
  1538  				title: compile("BUG: KFENCE: (use-after-free|out-of-bounds) (read|write) in {{FUNC}}"),
  1539  				fmt:   "KFENCE: %[1]v %[2]v in %[4]v",
  1540  				alt:   []string{"bad-access in %[4]v"},
  1541  				stack: &stackFmt{
  1542  					parts: []*regexp.Regexp{
  1543  						compile("BUG: KFENCE: (?:[a-z\\- ]+) in {{FUNC}}"),
  1544  						parseStackTrace,
  1545  					},
  1546  				},
  1547  			},
  1548  			{
  1549  				title:        compile("BUG: KFENCE: invalid free in {{FUNC}}"),
  1550  				fmt:          "KFENCE: invalid free in %[2]v",
  1551  				alt:          []string{"invalid-free in %[2]v"},
  1552  				noStackTrace: true,
  1553  				stack: &stackFmt{
  1554  					parts: []*regexp.Regexp{
  1555  						compile("BUG: KFENCE: (?:[a-z\\- ]+) in {{FUNC}}"),
  1556  						parseStackTrace,
  1557  					},
  1558  				},
  1559  			},
  1560  			{
  1561  				title: compile("BUG: KFENCE: invalid (read|write) in {{FUNC}}"),
  1562  				fmt:   "KFENCE: invalid %[1]v in %[3]v",
  1563  				alt:   []string{"bad-access in %[3]v"},
  1564  				stack: &stackFmt{
  1565  					parts: []*regexp.Regexp{
  1566  						compile("BUG: KFENCE: (?:[a-z\\- ]+) in {{FUNC}}"),
  1567  						parseStackTrace,
  1568  					},
  1569  				},
  1570  			},
  1571  			{
  1572  				title:        compile("BUG: KFENCE: memory corruption in {{FUNC}}"),
  1573  				fmt:          "KFENCE: memory corruption in %[2]v",
  1574  				noStackTrace: true,
  1575  				stack: &stackFmt{
  1576  					parts: []*regexp.Regexp{
  1577  						compile("BUG: KFENCE: (?:[a-z\\- ]+) in {{FUNC}}"),
  1578  						parseStackTrace,
  1579  					},
  1580  				},
  1581  			},
  1582  			{
  1583  				title: compile("BUG: (?:unable to handle kernel paging request|unable to handle page fault for address|Unable to handle kernel data access)"),
  1584  				fmt:   "BUG: unable to handle kernel paging request in %[1]v",
  1585  				alt:   []string{"bad-access in %[1]v"},
  1586  				stack: &stackFmt{
  1587  					parts: []*regexp.Regexp{
  1588  						linuxRipFrame,
  1589  						linuxCallTrace,
  1590  						parseStackTrace,
  1591  					},
  1592  				},
  1593  			},
  1594  			{
  1595  				title: compile("BUG: (?:unable to handle kernel NULL pointer dereference|kernel NULL pointer dereference|Kernel NULL pointer dereference)"),
  1596  				fmt:   "BUG: unable to handle kernel NULL pointer dereference in %[1]v",
  1597  				alt:   []string{"bad-access in %[1]v"},
  1598  				stack: &stackFmt{
  1599  					parts: []*regexp.Regexp{
  1600  						linuxRipFrame,
  1601  						linuxCallTrace,
  1602  						parseStackTrace,
  1603  					},
  1604  				},
  1605  			},
  1606  			{
  1607  				// Sometimes with such BUG failures, the second part of the header doesn't get printed
  1608  				// or gets corrupted, because kernel prints it as two separate printk() calls.
  1609  				title:     compile("BUG: (?:unable to handle kernel|Unable to handle kernel)"),
  1610  				fmt:       "BUG: unable to handle kernel",
  1611  				corrupted: true,
  1612  			},
  1613  			{
  1614  				title: compile("BUG: (spinlock|rwlock) (lockup suspected|already unlocked|recursion" +
  1615  					"|cpu recursion|bad magic|wrong owner|wrong CPU|trylock failure on UP)"),
  1616  				fmt: "BUG: %[1]v %[2]v in %[3]v",
  1617  				stack: &stackFmt{
  1618  					parts: []*regexp.Regexp{
  1619  						linuxCallTrace,
  1620  						parseStackTrace,
  1621  					},
  1622  					skip: []string{"spin_", "_lock", "_unlock"},
  1623  				},
  1624  			},
  1625  			{
  1626  				title: compile("BUG: soft lockup"),
  1627  				fmt:   "BUG: soft lockup in %[1]v",
  1628  				alt:   []string{"stall in %[1]v"},
  1629  				stack: &stackFmt{
  1630  					parts: []*regexp.Regexp{
  1631  						linuxRipFrame,
  1632  						linuxCallTrace,
  1633  						parseStackTrace,
  1634  					},
  1635  					extractor: linuxStallFrameExtractor,
  1636  				},
  1637  			},
  1638  			{
  1639  				title:  compile("BUG: .*still has locks held!"),
  1640  				report: compile("BUG: .*still has locks held!(?:.*\\n)+?.*{{PC}} +{{FUNC}}"),
  1641  				fmt:    "BUG: still has locks held in %[1]v",
  1642  			},
  1643  			{
  1644  				title: compile("BUG: scheduling while atomic"),
  1645  				fmt:   "BUG: scheduling while atomic in %[1]v",
  1646  				stack: &stackFmt{
  1647  					parts: []*regexp.Regexp{
  1648  						linuxCallTrace,
  1649  						parseStackTrace,
  1650  					},
  1651  					skip: []string{"schedule"},
  1652  				},
  1653  			},
  1654  			{
  1655  				title:        compile("BUG: lock held when returning to user space"),
  1656  				report:       compile("BUG: lock held when returning to user space(?:.*\\n)+?.*leaving the kernel with locks still held(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"),
  1657  				fmt:          "BUG: lock held when returning to user space in %[1]v",
  1658  				noStackTrace: true,
  1659  			},
  1660  			{
  1661  				title: compile("BUG: bad unlock balance detected!"),
  1662  				fmt:   "BUG: bad unlock balance in %[1]v",
  1663  				stack: &stackFmt{
  1664  					parts: []*regexp.Regexp{
  1665  						compile("{{PC}} +{{FUNC}}"),
  1666  						linuxCallTrace,
  1667  						parseStackTrace,
  1668  					},
  1669  				},
  1670  			},
  1671  			{
  1672  				title:  compile("BUG: held lock freed!"),
  1673  				report: compile("BUG: held lock freed!(?:.*\\n)+?.*{{PC}} +{{FUNC}}"),
  1674  				fmt:    "BUG: held lock freed in %[1]v",
  1675  			},
  1676  			{
  1677  				title:        compile("BUG: Bad rss-counter state"),
  1678  				fmt:          "BUG: Bad rss-counter state",
  1679  				noStackTrace: true,
  1680  			},
  1681  			{
  1682  				title:        compile("BUG: non-zero nr_ptes on freeing mm"),
  1683  				fmt:          "BUG: non-zero nr_ptes on freeing mm",
  1684  				noStackTrace: true,
  1685  			},
  1686  			{
  1687  				title:        compile("BUG: non-zero nr_pmds on freeing mm"),
  1688  				fmt:          "BUG: non-zero nr_pmds on freeing mm",
  1689  				noStackTrace: true,
  1690  			},
  1691  			{
  1692  				// Kernel includes filesystem type and block device name into the message.
  1693  				// We used to include them, but block devices are plain harmful (loop0/1/2),
  1694  				// and filesystem type also leads to duplicates. So now we exclude them.
  1695  				title:  compile("BUG: Dentry .* still in use"),
  1696  				report: compile("BUG: Dentry .* still in use \\([0-9]+\\) \\[(unmount) of ([^\\]]+)\\]"),
  1697  				fmt:    "BUG: Dentry still in use in %[1]v",
  1698  				alt:    []string{"BUG: Dentry still in use [%[1]v of %[2]v]"},
  1699  			},
  1700  			{
  1701  				title: compile("BUG: Bad page (state|cache)"),
  1702  				fmt:   "BUG: Bad page %[1]v in %[2]v",
  1703  				stack: &stackFmt{
  1704  					// TODO: on arm64, for some reason we don't see the page origin backtrace.
  1705  					// We see the stack trace where the bug was detected, but we consider it to be
  1706  					// not sufficient to reliably group crashes.
  1707  					// So Bad page reports on arm64 for now will end up marked as corrupted.
  1708  					parts: []*regexp.Regexp{
  1709  						compile(`page last allocated`),
  1710  						parseStackTrace,
  1711  					},
  1712  					skip: []string{"(free|put|get|update|release)_page",
  1713  						"free_unref", "^_*folio", "truncate_inode_pages",
  1714  						"page_frag_free", "alloc", "vmap", "page_owner"},
  1715  				},
  1716  			},
  1717  			{
  1718  				title: compile("BUG: Bad page map"),
  1719  				fmt:   "BUG: Bad page map",
  1720  			},
  1721  			{
  1722  				title:        compile("BUG: workqueue lockup"),
  1723  				fmt:          "BUG: workqueue lockup",
  1724  				noStackTrace: true,
  1725  			},
  1726  			{
  1727  				title: compile("BUG: sleeping function called from invalid context at (.*)"),
  1728  				fmt:   "BUG: sleeping function called from invalid context in %[2]v",
  1729  				stack: &stackFmt{
  1730  					parts: []*regexp.Regexp{
  1731  						linuxCallTrace,
  1732  						parseStackTrace,
  1733  					},
  1734  				},
  1735  			},
  1736  			{
  1737  				title: compile("BUG: using ([a-z_]+)\\(\\) in preemptible"),
  1738  				fmt:   "BUG: using %[1]v() in preemptible code in %[2]v",
  1739  				stack: &stackFmt{
  1740  					parts: []*regexp.Regexp{
  1741  						linuxCallTrace,
  1742  						parseStackTrace,
  1743  					},
  1744  					skip: []string{"dump_stack", "preemption", "preempt", "debug_",
  1745  						"processor_id", "this_cpu"},
  1746  				},
  1747  			},
  1748  			{
  1749  				title: compile("BUG: workqueue leaked lock or atomic"),
  1750  				report: compile("BUG: workqueue leaked lock or atomic(?:.*\\n)+?" +
  1751  					".*last function: ([a-zA-Z0-9_]+)\\n"),
  1752  				fmt:          "BUG: workqueue leaked lock or atomic in %[1]v",
  1753  				noStackTrace: true,
  1754  			},
  1755  			{
  1756  				title: compile("BUG: memory leak"),
  1757  				fmt:   "memory leak in %[1]v",
  1758  				stack: &stackFmt{
  1759  					parts: []*regexp.Regexp{
  1760  						compile("backtrace(?: \\(crc [[:xdigit:]]*\\))?:"),
  1761  						parseStackTrace,
  1762  					},
  1763  					skip: []string{"kmemleak", "mmap", "kmem", "slab", "alloc", "create_object",
  1764  						"idr_get", "list_lru_init", "kasprintf", "kvasprintf",
  1765  						"pcpu_create", "strdup", "strndup", "memdup"},
  1766  				},
  1767  			},
  1768  			{
  1769  				title: compile("BUG: .*stack guard page was hit at"),
  1770  				fmt:   "BUG: stack guard page was hit in %[1]v",
  1771  				alt:   []string{"stack-overflow in %[1]v"},
  1772  				stack: &stackFmt{
  1773  					parts: []*regexp.Regexp{
  1774  						linuxRipFrame,
  1775  						linuxCallTrace,
  1776  						parseStackTrace,
  1777  					},
  1778  					extractor: linuxStallFrameExtractor,
  1779  				},
  1780  			},
  1781  			{
  1782  				title: compile("BUG: Invalid wait context"),
  1783  				// Somehow amd64 and arm/arm64 report this bug completely differently.
  1784  				// This is arm/arm64 format, but we match amd64 title to not duplicate bug reports.
  1785  				fmt: "WARNING: locking bug in %[1]v",
  1786  				stack: &stackFmt{
  1787  					parts: []*regexp.Regexp{
  1788  						linuxCallTrace,
  1789  						parseStackTrace,
  1790  					},
  1791  					skip: []string{"lock_sock", "release_sock"},
  1792  				},
  1793  			},
  1794  			{
  1795  				title:     compile(`BUG:[[:space:]]*(?:\n|$)`),
  1796  				fmt:       "BUG: corrupted",
  1797  				corrupted: true,
  1798  			},
  1799  		},
  1800  		[]*regexp.Regexp{
  1801  			// CONFIG_DEBUG_OBJECTS output.
  1802  			compile("ODEBUG:"),
  1803  			// Android prints this sometimes during boot.
  1804  			compile("Boot_DEBUG:"),
  1805  			compile("xlog_status:"),
  1806  			// Android ART debug output.
  1807  			compile("DEBUG:"),
  1808  			// pkg/host output in debug mode.
  1809  			compile("BUG: no syscalls can create resource"),
  1810  		},
  1811  	},
  1812  	{
  1813  		[]byte("WARNING:"),
  1814  		[]oopsFormat{
  1815  			{
  1816  				title: compile("WARNING: .*lib/debugobjects\\.c.* (?:debug_print|debug_check|at)"),
  1817  				fmt:   "WARNING: ODEBUG bug in %[1]v",
  1818  				// Skip all users of ODEBUG as well.
  1819  				stack: warningStackFmt("debug_", "rcu", "hrtimer_", "timer_",
  1820  					"work_", "percpu_", "vunmap",
  1821  					"vfree", "__free_", "debug_check", "kobject_"),
  1822  			},
  1823  			{
  1824  				title: compile("WARNING: .*mm/usercopy\\.c.* (?:usercopy_warn|at)"),
  1825  				fmt:   "WARNING: bad usercopy in %[1]v",
  1826  				stack: warningStackFmt("usercopy", "__check"),
  1827  			},
  1828  			{
  1829  				title: compile("WARNING: .*lib/kobject\\.c.* (?:kobject_|at)"),
  1830  				fmt:   "WARNING: kobject bug in %[1]v",
  1831  				stack: warningStackFmt("kobject_"),
  1832  			},
  1833  			{
  1834  				title: compile("WARNING: .*fs/proc/generic\\.c.* (?:proc_register|at)"),
  1835  				fmt:   "WARNING: proc registration bug in %[1]v",
  1836  				stack: warningStackFmt("proc_"),
  1837  			},
  1838  			{
  1839  				title: compile("WARNING: .*lib/refcount\\.c.* (?:refcount_|at)"),
  1840  				fmt:   "WARNING: refcount bug in %[1]v",
  1841  				stack: warningStackFmt("refcount", "kobject_"),
  1842  			},
  1843  			{
  1844  				title: compile("WARNING: .*kernel/locking/lockdep\\.c.*lock_"),
  1845  				fmt:   "WARNING: locking bug in %[1]v",
  1846  				stack: warningStackFmt("lock_sock", "release_sock"),
  1847  			},
  1848  			{
  1849  				title:  compile("WARNING: .*still has locks held!"),
  1850  				report: compile("WARNING: .*still has locks held!(?:.*\\n)+?.*at: {{FUNC}}"),
  1851  				fmt:    "WARNING: still has locks held in %[1]v",
  1852  			},
  1853  			{
  1854  				title: compile("WARNING: Nested lock was not taken"),
  1855  				fmt:   "WARNING: nested lock was not taken in %[1]v",
  1856  				stack: warningStackFmt(),
  1857  			},
  1858  			{
  1859  				title:        compile("WARNING: lock held when returning to user space"),
  1860  				report:       compile("WARNING: lock held when returning to user space(?:.*\\n)+?.*leaving the kernel with locks still held(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"),
  1861  				fmt:          "WARNING: lock held when returning to user space in %[1]v",
  1862  				noStackTrace: true,
  1863  			},
  1864  			{
  1865  				title: compile("WARNING: .*mm/.*\\.c.* k?.?malloc"),
  1866  				fmt:   "WARNING: kmalloc bug in %[1]v",
  1867  				stack: warningStackFmt("kmalloc", "krealloc", "slab", "kmem"),
  1868  			},
  1869  			{
  1870  				title: compile("WARNING: .*mm/vmalloc.c.*__vmalloc_node"),
  1871  				fmt:   "WARNING: zero-size vmalloc in %[1]v",
  1872  				stack: warningStackFmt(),
  1873  			},
  1874  			{
  1875  				title: compile("WARNING: .* usb_submit_urb"),
  1876  				fmt:   "WARNING in %[1]v/usb_submit_urb",
  1877  				stack: warningStackFmt("usb_submit_urb", "usb_start_wait_urb", "usb_bulk_msg", "usb_interrupt_msg", "usb_control_msg"),
  1878  			},
  1879  			{
  1880  				// Format introduced in https://lore.kernel.org/all/20251110114633.202485143@infradead.org/.
  1881  				title: compile(`WARNING: {{SRC}} at 0x\d+, CPU#\d+`),
  1882  				fmt:   "WARNING in %[2]v",
  1883  				stack: warningStackFmt(),
  1884  			},
  1885  			{
  1886  				title: compile("WARNING: .* at {{SRC}} {{FUNC}}"),
  1887  				fmt:   "WARNING in %[3]v",
  1888  				stack: warningStackFmt(),
  1889  			},
  1890  			{
  1891  				title: compile("WARNING: {{SRC}} at {{FUNC}}"),
  1892  				fmt:   "WARNING in %[3]v",
  1893  				stack: warningStackFmt(),
  1894  			},
  1895  			{
  1896  				title:  compile("WARNING: possible circular locking dependency detected"),
  1897  				report: compile("WARNING: possible circular locking dependency detected(?:.*\\n)+?.*is trying to acquire lock"),
  1898  				fmt:    "possible deadlock in %[1]v",
  1899  				stack: &stackFmt{
  1900  					parts: []*regexp.Regexp{
  1901  						compile("at: (?:{{PC}} +)?{{FUNC}}"),
  1902  						compile("at: (?:{{PC}} +)?{{FUNC}}"),
  1903  						parseStackTrace,
  1904  					},
  1905  					// These workqueue functions take locks associated with work items.
  1906  					// All deadlocks observed in these functions are
  1907  					// work-item-subsystem-related.
  1908  					skip: []string{"process_one_work", "flush_workqueue",
  1909  						"drain_workqueue", "destroy_workqueue"},
  1910  				},
  1911  			},
  1912  			{
  1913  				title:  compile("WARNING: possible irq lock inversion dependency detected"),
  1914  				report: compile("WARNING: possible irq lock inversion dependency detected(?:.*\\n)+?.*just changed the state of lock(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"),
  1915  				fmt:    "possible deadlock in %[1]v",
  1916  			},
  1917  			{
  1918  				title: compile("WARNING: .*-safe -> .*-unsafe lock order detected"),
  1919  				fmt:   "possible deadlock in %[1]v",
  1920  				stack: &stackFmt{
  1921  					parts: []*regexp.Regexp{
  1922  						compile("which became (?:.*) at:"),
  1923  						parseStackTrace,
  1924  					},
  1925  				},
  1926  			},
  1927  			{
  1928  				title:  compile("WARNING: possible recursive locking detected"),
  1929  				report: compile("WARNING: possible recursive locking detected(?:.*\\n)+?.*is trying to acquire lock(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"),
  1930  				fmt:    "possible deadlock in %[1]v",
  1931  			},
  1932  			{
  1933  				title:  compile("WARNING: inconsistent lock state"),
  1934  				report: compile("WARNING: inconsistent lock state(?:.*\\n)+?.*takes(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"),
  1935  				fmt:    "inconsistent lock state in %[2]v",
  1936  				stack: &stackFmt{
  1937  					parts: []*regexp.Regexp{
  1938  						linuxCallTrace,
  1939  						parseStackTrace,
  1940  					},
  1941  				},
  1942  			},
  1943  			{
  1944  				title:  compile("WARNING: suspicious RCU usage"),
  1945  				report: compile("WARNING: suspicious RCU usage(?:.*\n)+?.*?{{SRC}}"),
  1946  				fmt:    "WARNING: suspicious RCU usage in %[2]v",
  1947  				stack: &stackFmt{
  1948  					parts: []*regexp.Regexp{
  1949  						linuxCallTrace,
  1950  						parseStackTrace,
  1951  					},
  1952  					skip: []string{"rcu", "kmem", "slab"},
  1953  				},
  1954  			},
  1955  			{
  1956  				title:        compile("WARNING: kernel stack regs at [0-9a-f]+ in [^ ]* has bad '([^']+)' value"),
  1957  				fmt:          "WARNING: kernel stack regs has bad '%[1]v' value",
  1958  				noStackTrace: true,
  1959  			},
  1960  			{
  1961  				title:        compile("WARNING: kernel stack frame pointer at [0-9a-f]+ in [^ ]* has bad value"),
  1962  				fmt:          "WARNING: kernel stack frame pointer has bad value",
  1963  				noStackTrace: true,
  1964  			},
  1965  			{
  1966  				title: compile("WARNING: bad unlock balance detected!"),
  1967  				fmt:   "WARNING: bad unlock balance in %[1]v",
  1968  				stack: &stackFmt{
  1969  					parts: []*regexp.Regexp{
  1970  						compile("{{PC}} +{{FUNC}}"),
  1971  						linuxCallTrace,
  1972  						parseStackTrace,
  1973  					},
  1974  				},
  1975  			},
  1976  			{
  1977  				title:  compile("WARNING: held lock freed!"),
  1978  				report: compile("WARNING: held lock freed!(?:.*\\n)+?.*at:(?: {{PC}})? +{{FUNC}}"),
  1979  				fmt:    "WARNING: held lock freed in %[1]v",
  1980  			},
  1981  			{
  1982  				title:        compile("WARNING: kernel stack regs .* has bad 'bp' value"),
  1983  				fmt:          "WARNING: kernel stack regs has bad value",
  1984  				noStackTrace: true,
  1985  			},
  1986  			{
  1987  				title:        compile("WARNING: kernel stack frame pointer .* has bad value"),
  1988  				fmt:          "WARNING: kernel stack regs has bad value",
  1989  				noStackTrace: true,
  1990  			},
  1991  			{
  1992  				title:     compile(`WARNING:[[:space:]]*(?:\n|$)`),
  1993  				fmt:       "WARNING: corrupted",
  1994  				corrupted: true,
  1995  			},
  1996  		},
  1997  		[]*regexp.Regexp{
  1998  			compile("WARNING: /etc/ssh/moduli does not exist, using fixed modulus"), // printed by sshd
  1999  			compile("WARNING: workqueue cpumask: online intersect > possible intersect"),
  2000  			compile("WARNING: [Tt]he mand mount option"),
  2001  			compile("WARNING: Unsupported flag value\\(s\\) of 0x%x in DT_FLAGS_1"), // printed when glibc is dumped
  2002  			compile("WARNING: Unprivileged eBPF is enabled with eIBRS"),
  2003  			compile(`WARNING: fbcon: Driver '(.*)' missed to adjust virtual screen size (\((?:\d+)x(?:\d+) vs\. (?:\d+)x(?:\d+)\))`),
  2004  			compile(`WARNING: See https.* for mitigation options.`),
  2005  			compile(`WARNING: kernel not compiled with CPU_SRSO`),
  2006  			compile(`EXT4-[Ff][Ss](?: \(.*\))?:`), // printed in __ext4_msg
  2007  			compile(`(?i)warning: .* uses (deprecated v2 capabilities|wireless extensions)`),
  2008  			compile(`XFS \(\w+\): WARNING`),
  2009  		},
  2010  	},
  2011  	{
  2012  		[]byte("INFO:"),
  2013  		[]oopsFormat{
  2014  			{
  2015  				title:  compile("INFO: possible circular locking dependency detected"),
  2016  				report: compile("INFO: possible circular locking dependency detected \\](?:.*\\n)+?.*is trying to acquire lock(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"),
  2017  				fmt:    "possible deadlock in %[1]v",
  2018  			},
  2019  			{
  2020  				title:  compile("INFO: possible irq lock inversion dependency detected"),
  2021  				report: compile("INFO: possible irq lock inversion dependency detected \\](?:.*\\n)+?.*just changed the state of lock(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"),
  2022  				fmt:    "possible deadlock in %[1]v",
  2023  			},
  2024  			{
  2025  				title:  compile("INFO: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected"),
  2026  				report: compile("INFO: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected \\](?:.*\\n)+?.*is trying to acquire(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"),
  2027  				fmt:    "possible deadlock in %[1]v",
  2028  			},
  2029  			{
  2030  				title:  compile("INFO: possible recursive locking detected"),
  2031  				report: compile("INFO: possible recursive locking detected \\](?:.*\\n)+?.*is trying to acquire lock(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"),
  2032  				fmt:    "possible deadlock in %[1]v",
  2033  			},
  2034  			{
  2035  				title:  compile("INFO: inconsistent lock state"),
  2036  				report: compile("INFO: inconsistent lock state \\](?:.*\\n)+?.*takes(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"),
  2037  				fmt:    "inconsistent lock state in %[1]v",
  2038  			},
  2039  			{
  2040  				title: compile("INFO: rcu_(?:preempt|sched|bh) (?:self-)?detected(?: expedited)? stall"),
  2041  				fmt:   "INFO: rcu detected stall in %[1]v",
  2042  				alt:   []string{"stall in %[1]v"},
  2043  				stack: &stackFmt{
  2044  					parts: []*regexp.Regexp{
  2045  						compile("apic_timer_interrupt"),
  2046  						linuxRipFrame,
  2047  						parseStackTrace,
  2048  					},
  2049  					parts2: []*regexp.Regexp{
  2050  						compile("(?:apic_timer_interrupt|Exception stack|el1h_64_irq)"),
  2051  						parseStackTrace,
  2052  					},
  2053  					skip:      []string{"apic_timer_interrupt", "rcu"},
  2054  					extractor: linuxStallFrameExtractor,
  2055  				},
  2056  			},
  2057  			{
  2058  				title: compile("INFO: trying to register non-static key"),
  2059  				fmt:   "INFO: trying to register non-static key in %[1]v",
  2060  				stack: &stackFmt{
  2061  					parts: []*regexp.Regexp{
  2062  						linuxCallTrace,
  2063  						parseStackTrace,
  2064  					},
  2065  					skip: []string{"stack", "lock", "IRQ"},
  2066  				},
  2067  			},
  2068  			{
  2069  				title:  compile("INFO: suspicious RCU usage"),
  2070  				report: compile("INFO: suspicious RCU usage(?:.*\n)+?.*?{{SRC}}"),
  2071  				fmt:    "INFO: suspicious RCU usage in %[2]v",
  2072  				stack: &stackFmt{
  2073  					parts: []*regexp.Regexp{
  2074  						linuxCallTrace,
  2075  						parseStackTrace,
  2076  					},
  2077  					skip: []string{"rcu", "kmem", "slab"},
  2078  				},
  2079  			},
  2080  			{
  2081  				title: compile("INFO: task .* blocked for more than [0-9]+ seconds"),
  2082  				fmt:   "INFO: task hung in %[1]v",
  2083  				alt:   []string{"hang in %[1]v"},
  2084  				stack: &stackFmt{
  2085  					parts: []*regexp.Regexp{
  2086  						linuxCallTrace,
  2087  						parseStackTrace,
  2088  					},
  2089  					extractor: linuxHangTaskFrameExtractor,
  2090  				},
  2091  			},
  2092  			{
  2093  				title: compile("INFO: task .* can't die for more than .* seconds"),
  2094  				fmt:   "INFO: task can't die in %[1]v",
  2095  				alt:   []string{"hang in %[1]v"},
  2096  				stack: &stackFmt{
  2097  					parts: []*regexp.Regexp{
  2098  						linuxCallTrace,
  2099  						parseStackTrace,
  2100  					},
  2101  					skip: []string{"schedule"},
  2102  				},
  2103  			},
  2104  			{
  2105  				// This gets captured for corrupted old-style KASAN reports.
  2106  				title:     compile("INFO: (Freed|Allocated) in (.*)"),
  2107  				fmt:       "INFO: %[1]v in %[2]v",
  2108  				corrupted: true,
  2109  			},
  2110  			{
  2111  				title:     compile(`INFO:[[:space:]]*(?:\n|$)`),
  2112  				fmt:       "INFO: corrupted",
  2113  				corrupted: true,
  2114  			},
  2115  		},
  2116  		[]*regexp.Regexp{
  2117  			compile("INFO: lockdep is turned off"),
  2118  			compile("INFO: Stall ended before state dump start"),
  2119  			compile("INFO: NMI handler"),
  2120  			compile("INFO: recovery required on readonly filesystem"),
  2121  			compile("(handler|interrupt).*took too long"),
  2122  			compile("INFO: sys_.* is not present in /proc/kallsyms"), // pkg/host output in debug mode
  2123  			compile("INFO: no syscalls can create resource"),         // pkg/host output in debug mode
  2124  			compile("rmt_storage:INFO:"),                             // Android prints this.
  2125  			compile("_INFO:"),                                        // To filter out "INVALID BTF_INFO:NUM".
  2126  		},
  2127  	},
  2128  	{
  2129  		[]byte("Unable to handle kernel"),
  2130  		[]oopsFormat{
  2131  			{
  2132  				title: compile("Unable to handle kernel (paging request|NULL pointer dereference|access to user memory)"),
  2133  				fmt:   "BUG: unable to handle kernel %[1]v in %[2]v",
  2134  				alt:   []string{"bad-access in %[2]v"},
  2135  				stack: &stackFmt{
  2136  					parts: []*regexp.Regexp{
  2137  						linuxRipFrame,
  2138  						linuxCallTrace,
  2139  						parseStackTrace,
  2140  					},
  2141  				},
  2142  			},
  2143  		},
  2144  		[]*regexp.Regexp{},
  2145  	},
  2146  	{
  2147  		[]byte("general protection fault"),
  2148  		[]oopsFormat{
  2149  			{
  2150  				title: compile("general protection fault.*:"),
  2151  				fmt:   "general protection fault in %[1]v",
  2152  				alt:   []string{"bad-access in %[1]v"},
  2153  				stack: &stackFmt{
  2154  					parts: []*regexp.Regexp{
  2155  						linuxRipFrame,
  2156  						linuxCallTrace,
  2157  						parseStackTrace,
  2158  					},
  2159  				},
  2160  			},
  2161  		},
  2162  		[]*regexp.Regexp{
  2163  			compile(`general protection fault .* error:\d+ in `),
  2164  		},
  2165  	},
  2166  	{
  2167  		[]byte("stack segment: "),
  2168  		[]oopsFormat{
  2169  			{
  2170  				title: compile("stack segment: "),
  2171  				fmt:   "stack segment fault in %[1]v",
  2172  				stack: &stackFmt{
  2173  					parts: []*regexp.Regexp{
  2174  						linuxRipFrame,
  2175  						linuxCallTrace,
  2176  						parseStackTrace,
  2177  					},
  2178  				},
  2179  			},
  2180  		},
  2181  		[]*regexp.Regexp{},
  2182  	},
  2183  	{
  2184  		[]byte("Kernel panic"),
  2185  		[]oopsFormat{
  2186  			// Note: for stack corruption reports kernel may fail
  2187  			// to print function symbol name and/or unwind stack.
  2188  			{
  2189  				title:        compile("Kernel panic - not syncing: stack-protector:"),
  2190  				report:       compile("Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: {{FUNC}}"),
  2191  				fmt:          "kernel panic: stack is corrupted in %[1]v",
  2192  				noStackTrace: true,
  2193  			},
  2194  			{
  2195  				title:  compile("Kernel panic - not syncing: stack-protector:"),
  2196  				report: compile("Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: [a-f0-9]+"),
  2197  				fmt:    "kernel panic: stack is corrupted in %[1]v",
  2198  				stack: &stackFmt{
  2199  					parts: []*regexp.Regexp{
  2200  						linuxCallTrace,
  2201  						parseStackTrace,
  2202  					},
  2203  					skip: []string{"stack_chk"},
  2204  				},
  2205  			},
  2206  			{
  2207  				title:  compile("Kernel panic - not syncing: corrupted stack end"),
  2208  				report: compile("Kernel panic - not syncing: corrupted stack end detected inside scheduler"),
  2209  				fmt:    "kernel panic: corrupted stack end in %[1]v",
  2210  				alt:    []string{"stack-overflow in %[1]v"},
  2211  				stack: &stackFmt{
  2212  					parts: []*regexp.Regexp{
  2213  						linuxCallTrace,
  2214  						parseStackTrace,
  2215  					},
  2216  					skip:      []string{"schedule", "retint_kernel"},
  2217  					extractor: linuxStallFrameExtractor,
  2218  				},
  2219  			},
  2220  			{
  2221  				title: compile("Kernel panic - not syncing: kernel stack overflow"),
  2222  				fmt:   "kernel stack overflow in %[1]v",
  2223  				alt:   []string{"stack-overflow in %[1]v"},
  2224  				stack: &stackFmt{
  2225  					parts: []*regexp.Regexp{
  2226  						linuxCallTrace,
  2227  						parseStackTrace,
  2228  					},
  2229  					skip:      []string{"bad_stack"},
  2230  					extractor: linuxStallFrameExtractor,
  2231  				},
  2232  			},
  2233  			{
  2234  				title: compile("Kernel panic - not syncing: Attempted to kill init!"),
  2235  				fmt:   "kernel panic: Attempted to kill init!",
  2236  			},
  2237  			{
  2238  				title: compile("Kernel panic - not syncing: Couldn't open N_TTY ldisc for [^ ]+ --- error -[0-9]+"),
  2239  				fmt:   "kernel panic: Couldn't open N_TTY ldisc",
  2240  			},
  2241  			{
  2242  				// 'kernel panic: Fatal exception' is usually printed after BUG,
  2243  				// so if we captured it as a report description, that means the
  2244  				// report got truncated and we missed the actual BUG header.
  2245  				title:     compile("Kernel panic - not syncing: Fatal exception"),
  2246  				fmt:       "kernel panic: Fatal exception",
  2247  				corrupted: true,
  2248  			},
  2249  			{
  2250  				// Same, but for WARNINGs and KASAN reports.
  2251  				title:     compile("Kernel panic - not syncing: panic_on_warn set"),
  2252  				fmt:       "kernel panic: panic_on_warn set",
  2253  				corrupted: true,
  2254  			},
  2255  			{
  2256  				// Same, but for task hung reports.
  2257  				title:     compile("Kernel panic - not syncing: hung_task: blocked tasks"),
  2258  				fmt:       "kernel panic: hung_task: blocked tasks",
  2259  				corrupted: true,
  2260  			},
  2261  			{
  2262  				title: compile("Kernel panic - not syncing: (.*)"),
  2263  				fmt:   "kernel panic: %[1]v",
  2264  			},
  2265  		},
  2266  		[]*regexp.Regexp{},
  2267  	},
  2268  	{
  2269  		[]byte("PANIC: double fault"),
  2270  		[]oopsFormat{
  2271  			{
  2272  				title: compile("PANIC: double fault"),
  2273  				fmt:   "PANIC: double fault in %[1]v",
  2274  				stack: &stackFmt{
  2275  					parts: []*regexp.Regexp{
  2276  						linuxRipFrame,
  2277  					},
  2278  				},
  2279  			},
  2280  		},
  2281  		[]*regexp.Regexp{},
  2282  	},
  2283  	{
  2284  		[]byte("rust_kernel: panicked"),
  2285  		[]oopsFormat{
  2286  			{
  2287  				title:  compile("rust_kernel: panicked"),
  2288  				report: compile("rust_kernel: panicked at [^\n]*?\n(.+?)\n"),
  2289  				fmt:    "%[1]v in %[2]v",
  2290  				stack: &stackFmt{
  2291  					parts: []*regexp.Regexp{
  2292  						linuxCallTrace,
  2293  						parseStackTrace,
  2294  					},
  2295  					skip: []string{
  2296  						regexp.QuoteMeta(`__rustc::rust_begin_unwind`),
  2297  					},
  2298  				},
  2299  			},
  2300  		},
  2301  		[]*regexp.Regexp{},
  2302  	},
  2303  	{
  2304  		[]byte("kernel BUG"),
  2305  		[]oopsFormat{
  2306  			{
  2307  				title: compile("kernel BUG at mm/usercopy.c"),
  2308  				fmt:   "BUG: bad usercopy in %[1]v",
  2309  				stack: &stackFmt{
  2310  					parts: []*regexp.Regexp{
  2311  						linuxCallTrace,
  2312  						parseStackTrace,
  2313  					},
  2314  					skip: []string{"usercopy", "__check"},
  2315  				},
  2316  			},
  2317  			{
  2318  				title: compile("kernel BUG at lib/list_debug.c"),
  2319  				fmt:   "BUG: corrupted list in %[1]v",
  2320  				alt:   []string{"bad-access in %[1]v"}, // also sometimes due to memory corruption/race
  2321  				stack: &stackFmt{
  2322  					parts: []*regexp.Regexp{
  2323  						linuxCallTrace,
  2324  						parseStackTrace,
  2325  					},
  2326  				},
  2327  			},
  2328  			{
  2329  				title: compile("kernel BUG at (.*)"),
  2330  				fmt:   "kernel BUG in %[2]v",
  2331  				stack: &stackFmt{
  2332  					parts: []*regexp.Regexp{
  2333  						linuxRipFrame,
  2334  						linuxCallTrace,
  2335  						parseStackTrace,
  2336  					},
  2337  					// Lots of skb wrappers contain BUG_ON, but the bug is almost always in the caller.
  2338  					skip: []string{"^skb_"},
  2339  				},
  2340  			},
  2341  		},
  2342  		[]*regexp.Regexp{},
  2343  	},
  2344  	{
  2345  		[]byte("Kernel BUG"),
  2346  		[]oopsFormat{
  2347  			{
  2348  				title: compile("Kernel BUG (.*)"),
  2349  				fmt:   "kernel BUG %[1]v",
  2350  			},
  2351  		},
  2352  		[]*regexp.Regexp{},
  2353  	},
  2354  	{
  2355  		[]byte("BUG kmalloc-"),
  2356  		[]oopsFormat{
  2357  			{
  2358  				title: compile("BUG kmalloc-.*: Object already free"),
  2359  				fmt:   "BUG: Object already free",
  2360  			},
  2361  		},
  2362  		[]*regexp.Regexp{},
  2363  	},
  2364  	{
  2365  		[]byte("divide error:"),
  2366  		[]oopsFormat{
  2367  			{
  2368  				title: compile("divide error: "),
  2369  				fmt:   "divide error in %[1]v",
  2370  				stack: &stackFmt{
  2371  					parts: []*regexp.Regexp{
  2372  						linuxRipFrame,
  2373  					},
  2374  				},
  2375  			},
  2376  		},
  2377  		[]*regexp.Regexp{},
  2378  	},
  2379  	{
  2380  		// A misspelling of the above introduced in 9d06c4027f21 ("x86/entry: Convert Divide Error to IDTENTRY").
  2381  		[]byte("divide_error:"),
  2382  		[]oopsFormat{
  2383  			{
  2384  				title: compile("divide_error: "),
  2385  				fmt:   "divide error in %[1]v",
  2386  				stack: &stackFmt{
  2387  					parts: []*regexp.Regexp{
  2388  						linuxRipFrame,
  2389  					},
  2390  				},
  2391  			},
  2392  		},
  2393  		[]*regexp.Regexp{},
  2394  	},
  2395  	{
  2396  		[]byte("invalid opcode:"),
  2397  		[]oopsFormat{
  2398  			{
  2399  				title: compile("invalid opcode: "),
  2400  				fmt:   "invalid opcode in %[1]v",
  2401  				stack: &stackFmt{
  2402  					parts: []*regexp.Regexp{
  2403  						linuxRipFrame,
  2404  					},
  2405  				},
  2406  			},
  2407  		},
  2408  		[]*regexp.Regexp{},
  2409  	},
  2410  	{
  2411  		[]byte("UBSAN:"),
  2412  		[]oopsFormat{
  2413  			{
  2414  				title:  compile("UBSAN:"),
  2415  				report: compile("UBSAN: Undefined behaviour in"),
  2416  				fmt:    "UBSAN: undefined-behaviour in %[1]v",
  2417  				stack: &stackFmt{
  2418  					parts: []*regexp.Regexp{
  2419  						linuxCallTrace,
  2420  						parseStackTrace,
  2421  					},
  2422  					skip: []string{"ubsan", "overflow"},
  2423  				},
  2424  			},
  2425  			{
  2426  				title: compile("UBSAN: array-index-out-of-bounds in"),
  2427  				fmt:   "UBSAN: array-index-out-of-bounds in %[1]v",
  2428  				alt:   []string{"bad-access in %[1]v"},
  2429  				stack: &stackFmt{
  2430  					parts: []*regexp.Regexp{
  2431  						linuxCallTrace,
  2432  						parseStackTrace,
  2433  					},
  2434  					skip: []string{"ubsan", "overflow"},
  2435  				},
  2436  			},
  2437  			{
  2438  				title:  compile("UBSAN:"),
  2439  				report: compile("UBSAN: (.*?) in"),
  2440  				fmt:    "UBSAN: %[1]v in %[2]v",
  2441  				stack: &stackFmt{
  2442  					parts: []*regexp.Regexp{
  2443  						linuxCallTrace,
  2444  						parseStackTrace,
  2445  					},
  2446  					skip: []string{"ubsan", "overflow"},
  2447  				},
  2448  			},
  2449  		},
  2450  		[]*regexp.Regexp{},
  2451  	},
  2452  	{
  2453  		[]byte("Booting the kernel."),
  2454  		[]oopsFormat{
  2455  			{
  2456  				title:        compile("^Booting the kernel"),
  2457  				fmt:          "unexpected kernel reboot",
  2458  				noStackTrace: true,
  2459  			},
  2460  		},
  2461  		[]*regexp.Regexp{
  2462  			// These may appear on the same line when the fuzzer reads from the console the existing
  2463  			// boot message and then pass it as mount option, kernel then prints it back
  2464  			// as an invalid mount option and we detect false reboot.
  2465  			compile("Parsing ELF|Decompressing Linux|Unknown parameter '"),
  2466  		},
  2467  	},
  2468  	{
  2469  		[]byte("unregister_netdevice: waiting for"),
  2470  		[]oopsFormat{
  2471  			{
  2472  				title:        compile("unregister_netdevice: waiting for (?:.*) to become free"),
  2473  				fmt:          "unregister_netdevice: waiting for DEV to become free",
  2474  				noStackTrace: true,
  2475  			},
  2476  		},
  2477  		[]*regexp.Regexp{},
  2478  	},
  2479  	{
  2480  		// Custom vfs error printed by older versions of the kernel, see #3621.
  2481  		[]byte("VFS: Close: file count is 0"),
  2482  		[]oopsFormat{
  2483  			{
  2484  				title:        compile("VFS: Close: file count is 0"),
  2485  				fmt:          "VFS: Close: file count is zero (use-after-free)",
  2486  				noStackTrace: true,
  2487  			},
  2488  		},
  2489  		[]*regexp.Regexp{},
  2490  	},
  2491  	{
  2492  		// Custom vfs error printed by older versions of the kernel, see #3621.
  2493  		[]byte("VFS: Busy inodes after unmount"),
  2494  		[]oopsFormat{
  2495  			{
  2496  				title:        compile("VFS: Busy inodes after unmount"),
  2497  				fmt:          "VFS: Busy inodes after unmount (use-after-free)",
  2498  				noStackTrace: true,
  2499  			},
  2500  		},
  2501  		[]*regexp.Regexp{},
  2502  	},
  2503  	{
  2504  		[]byte("Internal error:"),
  2505  		[]oopsFormat{
  2506  			{
  2507  				title: compile("Internal error:"),
  2508  				fmt:   "Internal error in %[1]v",
  2509  				// arm64 shows some crashes as "Internal error: synchronous external abort",
  2510  				// while arm shows the same crash as "Unable to handle kernel paging request",
  2511  				// so we need to merge them.
  2512  				alt: []string{"bad-access in %[1]v"},
  2513  				stack: &stackFmt{
  2514  					parts: []*regexp.Regexp{
  2515  						linuxRipFrame,
  2516  						linuxCallTrace,
  2517  						parseStackTrace,
  2518  					},
  2519  				},
  2520  			},
  2521  		},
  2522  		[]*regexp.Regexp{},
  2523  	},
  2524  	{
  2525  		[]byte("Unhandled fault:"),
  2526  		[]oopsFormat{
  2527  			{
  2528  				title: compile("Unhandled fault:"),
  2529  				fmt:   "Unhandled fault in %[1]v",
  2530  				// x86_64 shows NULL derefs as "general protection fault",
  2531  				// while arm shows the same crash as "Unhandled fault: page domain fault".
  2532  				alt: []string{"bad-access in %[1]v"},
  2533  				stack: &stackFmt{
  2534  					parts: []*regexp.Regexp{
  2535  						linuxRipFrame,
  2536  						linuxCallTrace,
  2537  						parseStackTrace,
  2538  					},
  2539  				},
  2540  			},
  2541  		},
  2542  		[]*regexp.Regexp{},
  2543  	},
  2544  	{
  2545  		[]byte("Alignment trap:"),
  2546  		[]oopsFormat{
  2547  			{
  2548  				title: compile("Alignment trap:"),
  2549  				fmt:   "Alignment trap in %[1]v",
  2550  				stack: &stackFmt{
  2551  					parts: []*regexp.Regexp{
  2552  						linuxRipFrame,
  2553  						linuxCallTrace,
  2554  						parseStackTrace,
  2555  					},
  2556  				},
  2557  			},
  2558  		},
  2559  		[]*regexp.Regexp{},
  2560  	},
  2561  	{
  2562  		[]byte("trusty: panic"),
  2563  		[]oopsFormat{
  2564  			{
  2565  				title:        compile("trusty: panic.* ASSERT FAILED"),
  2566  				report:       compile("trusty: panic \\(.*?\\):(?: DEBUG)? ASSERT FAILED at \\(.*?\\): (.+)"),
  2567  				fmt:          "trusty: ASSERT FAILED: %[1]v",
  2568  				noStackTrace: true,
  2569  			},
  2570  			{
  2571  				title:     compile("trusty: panic.* ASSERT FAILED.*: *(.*)"),
  2572  				fmt:       "trusty: ASSERT FAILED: %[1]v",
  2573  				corrupted: true,
  2574  			},
  2575  			{
  2576  				title:        compile("trusty: panic"),
  2577  				report:       compile("trusty: panic \\(.*?\\): (.+)"),
  2578  				fmt:          "trusty: panic: %[1]v",
  2579  				noStackTrace: true,
  2580  			},
  2581  		},
  2582  		[]*regexp.Regexp{},
  2583  	},
  2584  	&groupGoRuntimeErrors,
  2585  }, commonOopses...)