diff options
| author | Grigory Bazilevich <g.bazilevich@ispras.ru> | 2025-10-27 18:35:41 +0300 |
|---|---|---|
| committer | Grigory Bazilevich <g.bazilevich@ispras.ru> | 2026-03-12 11:30:09 +0300 |
| commit | 12aee2a11f4d9f364ce06451b87e3076bf0bf0b7 (patch) | |
| tree | addae0fb2605be19ad5f2ec5a9ef9e50777cafb1 /pkg/report/linux.go | |
| parent | 3e8f9cea1b2feb873fbad88a55ae8091e0c09e84 (diff) | |
pkg/report: ignore timer-related and mark_buffer_dirty frames
Fix corresponding test, remove incorrect tests
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: Denis Efremov <efremov@ispras.ru>
Diffstat (limited to 'pkg/report/linux.go')
| -rw-r--r-- | pkg/report/linux.go | 628 |
1 files changed, 326 insertions, 302 deletions
diff --git a/pkg/report/linux.go b/pkg/report/linux.go index 69e674836..ab555f3b3 100644 --- a/pkg/report/linux.go +++ b/pkg/report/linux.go @@ -257,7 +257,8 @@ func (ctx *linux) reportMinLines(oopsLine []byte) int { // Yes, it is complex, but all state and logic are tightly coupled. It's unclear how to simplify it. // nolint: gocyclo func (ctx *linux) findReport(output []byte, oops *oops, startPos int, context string, useQuestionable bool) ( - endPos, reportEnd int, report []byte, prefix [][]byte) { + endPos, reportEnd int, report []byte, prefix [][]byte, +) { // Prepend 5 lines preceding start of the report, // they can contain additional info related to the report. maxPrefix := 5 @@ -523,7 +524,8 @@ func (line linuxBacktraceLine) Assemble() []byte { } func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error), ctx *linux, - parsed linuxBacktraceLine) []linuxBacktraceLine { + parsed linuxBacktraceLine, +) []linuxBacktraceLine { symb := ctx.symbols[parsed.ModName][parsed.Name] if len(symb) == 0 { return []linuxBacktraceLine{parsed} @@ -803,8 +805,10 @@ func (ctx *linux) extractGuiltyFileRaw(title string, report []byte) string { // we would need to ignore too many files and that would be fragile. // So instead we try to extract guilty file starting from the known // interrupt entry point first. - for _, interruptEnd := range []string{"apic_timer_interrupt+0x", - "el1h_64_irq+0x", "Exception stack"} { + for _, interruptEnd := range []string{ + "apic_timer_interrupt+0x", + "el1h_64_irq+0x", "Exception stack", + } { if pos := bytes.Index(report, []byte(interruptEnd)); pos != -1 { if file := ctx.extractGuiltyFileImpl(report[pos:]); file != "" { return file @@ -1031,9 +1035,11 @@ func linuxHangTaskFrameExtractor(frames []string) (string, int) { } } } - skip := []string{"sched", "_lock", "_slowlock", "down", "rwsem", "completion", "kthread", + skip := []string{ + "sched", "_lock", "_slowlock", "down", "rwsem", "completion", "kthread", "wait", "synchronize", "context_switch", "__switch_to", "cancel_delayed_work", - "rcu_barrier"} + "rcu_barrier", + } nextFrame: for i, frame := range frames { for _, ignore := range skip { @@ -1147,293 +1153,302 @@ var linuxCorruptedTitles = []*regexp.Regexp{ // In riscv, if show_regs() is called from kernel space, the stack is dumped without a proper indicator. However a // missing stack trace does not necessarily mean the log is corrupted. Match the last line printed by show_regs(), // before the stack dump. -var riscvSpecialStackStart = regexp.MustCompile(`status: [0-9a-f]{16} badaddr: [0-9a-f]{16} cause: [0-9a-f]{16}`) -var linuxStackParams = &stackParams{ - stackStartRes: []*regexp.Regexp{ - regexp.MustCompile(`Call (?:T|t)race`), - regexp.MustCompile(`Allocated:`), - regexp.MustCompile(`Allocated by task [0-9]+:`), - regexp.MustCompile(`Freed:`), - regexp.MustCompile(`Freed by task [0-9]+:`), - // Match 'backtrace:', but exclude 'stack backtrace:' - // Also match optional crc hash for KMEMLEAK reports. - regexp.MustCompile(`[^k] backtrace(?: \(crc [[:xdigit:]]*\))?:`), - regexp.MustCompile(`Backtrace:`), - regexp.MustCompile(`Uninit was stored to memory at`), - // A special stack trace for RISC-V is handled separately. - riscvSpecialStackStart, - }, - frameRes: []*regexp.Regexp{ - compile("^ *(?:{{PC}} ){0,2}{{FUNC}}"), - // Arm is totally different. - // Extract both current and next frames. This is needed for the top - // frame which is present only in LR register which we don't parse. - compile(`^ *{{PC}} \(([a-zA-Z0-9_.]+)\) from {{PC}} \({{FUNC}}`), - }, - skipPatterns: []string{ - "__sanitizer", - "__asan", - "kasan", - "hwasan", - "__msan", - "kmsan", - "kcsan_setup_watchpoint", - "check_memory_region", - "check_heap_object", - "check_object", - "read_word_at_a_time", - "(read|write)_once_.*nocheck", - "print_address_description", - "panic", - "invalid_op", - "report_bug", - "fixup_bug", - "print_report", - "print_usage_bug", - "do_error", - "invalid_op", - `_trap$|do_trap`, - "show_stack", - "dump_stack", - "walk_stack", - "dump_backtrace", - "warn_slowpath", - "warn_alloc", - "warn_bogus", - "__warn", - "alloc_page", - "k?v?(?:m|z|c)alloc", - "krealloc", - "kmem_cache", - "allocate_slab", - "__alloc_frozen_pages_noprof", - "folio_(?:alloc|unlock)", - "filemap_alloc_folio", - "__filemap_get_folio", - "find_or_create_page", - "do_read_cache_folio", - "read_cache_page", - "pagecache_get_page", - "grab_cache_page_write_begin", - "slab_", - "debug_object", - "timer_is_static_object", - "work_is_static_object", - "__might_fault", - "print_unlock", - "imbalance_bug", - "lockdep", - "bh_enable", - "bh_disable", - "perf_trace", - "lock_acquire", - "lock_release", - "lock_class", - "mark_lock", - "(reacquire|mark)_held_locks", - "raw_spin_rq", - "spin_lock", - "spin_trylock", - "spin_unlock", - "read_lock", - "read_trylock", - "write_lock", - "write_trylock", - "read_unlock", - "write_unlock", - "^down$", - "down_read", - "down_write", - "down_read_trylock", - "down_write_trylock", - "down_trylock", - "up_read", - "up_write", - "^mutex_", - "^__mutex_", - "^rt_mutex_", - "owner_on_cpu", - "osq_lock", - "osq_unlock", - "atomic(64)?_(dec|inc|read|set|or|xor|and|add|sub|fetch|xchg|cmpxchg|try)", - "(set|clear|change|test)_bit", - "__wake_up", - "^refcount_", - "^kref_", - "ref_tracker", - "seqprop_assert", - "memcpy", - "memcmp", - "memset", - "memchr", - "memmove", - "memdup", - "strcmp", - "strncmp", - "strcpy", - "strlcpy", - "strncpy", - "strscpy", - "strlen", - "strstr", - "strnstr", - "strnlen", - "strchr", - "strdup", - "strndup", - "copy_to_user", - "copy_from_user", - "copy_to_iter", - "copy_from_iter", - "copy_page_to_iter", - "copy_page_from_iter", - "copy_folio_to_iter", - "^copyin$", - "^copyout$", - "put_user", - "get_user", - "might_fault", - "might_sleep", - "list_add", - "list_del", - "list_replace", - "list_move", - "list_splice", - "^rb_", - "^__rb_", - "_indirect_thunk_", // retpolines - "string", - "pointer", - "snprintf", - "scnprintf", - "kasprintf", - "kvasprintf", - "printk", - "va_format", - "dev_info", - "dev_notice", - "dev_warn", - "dev_err", - "dev_alert", - "dev_crit", - "dev_emerg", - "program_check_exception", - "program_check_common", - "del_timer", - "flush_work", - "__cancel_work_timer", - "cancel_work_sync", - "try_to_grab_pending", - "flush_workqueue", - "drain_workqueue", - "destroy_workqueue", - "queue_work", - "finish_wait", - "kthread_stop", - "kobject_", - "add_uevent_var", - "get_device_parent", - "device_add", - "device_del", - "device_unregister", - "device_destroy", - "device_release", - "devres_release_all", - "hwrng_unregister", - "i2c_del_adapter", - "__unregister_client", - "device_for_each_child", - "rollback_registered", - "unregister_netdev", - "sysfs_remove", - "device_remove_file", - "tty_unregister_device", - "dummy_urb_enqueue", - "usb_kill_urb", - "usb_kill_anchored_urbs", - "usb_control_msg", - "usb_hcd_submit_urb", - "usb_submit_urb", - "^complete$", - "wait_for_completion", - "^kv?free$", - "kfree_skb", - "readb$", - "readw$", - "readl$", - "readq$", - "writeb$", - "writew$", - "writel$", - "writeq$", - "logic_in", - "logic_out", - "^crc\\d+", - "crc_itu_t", - "__might_resched", - "assertfail", - "^iput$", - "^iput_final$", - "^ihold$", - "hex_dump_to_buffer", - "print_hex_dump", - "^klist_", - "(trace|lockdep)_(hard|soft)irq", - "^(un)?lock_page", - "stack_trace_consume_entry", - "arch_stack_walk", - "stack_trace_save", - "insert_work", - "__queue_delayed_work", - "queue_delayed_work_on", - "ida_free", - // arm64 translation exception handling path. - "do_(kernel|translation)_fault", - "do_mem_abort", - "el1_abort", - "el1h_64_sync(?:_handler)?", - "print_tainted", - "xas_(?:start|load|find)", - "find_lock_entries", - "truncate_inode_pages_range", - "__phys_addr", - "__fortify_report", - "cleanup_srcu_struct", - "rhashtable_lookup", - "extract_(user|iter)_to_sg", - "drop_nlink", - "^get_taint$", - "^put_device$", - "lock_timer_base", - "__timer_delete_sync", - "sk_stop_timer_sync", - "__mod_timer", - "fast_dput", - "dput", - }, - corruptedLines: []*regexp.Regexp{ - // Fault injection stacks are frequently intermixed with crash reports. - // Note: the actual symbol can have all kinds of weird suffixes like ".isra.7", ".cold" or ".isra.56.cold.74". - compile(`^( \[\<?(?:0x)?[0-9a-f]+\>?\])? should_fail(slab)?(\.[a-z0-9.]+)?\+0x`), - }, - stripFramePrefixes: []string{ - "SYSC_", - "SyS_", - "sys_", - "__x64_", - "__ia32_", - "__arm64_", - "____sys_", - "___sys_", - "__sys_", - "__se_", - "__se_sys_", - "__do_sys_", - "compat_SYSC_", - "compat_SyS_", - "ksys_", - }, -} +var ( + riscvSpecialStackStart = regexp.MustCompile(`status: [0-9a-f]{16} badaddr: [0-9a-f]{16} cause: [0-9a-f]{16}`) + linuxStackParams = &stackParams{ + stackStartRes: []*regexp.Regexp{ + regexp.MustCompile(`Call (?:T|t)race`), + regexp.MustCompile(`Allocated:`), + regexp.MustCompile(`Allocated by task [0-9]+:`), + regexp.MustCompile(`Freed:`), + regexp.MustCompile(`Freed by task [0-9]+:`), + // Match 'backtrace:', but exclude 'stack backtrace:' + // Also match optional crc hash for KMEMLEAK reports. + regexp.MustCompile(`[^k] backtrace(?: \(crc [[:xdigit:]]*\))?:`), + regexp.MustCompile(`Backtrace:`), + regexp.MustCompile(`Uninit was stored to memory at`), + // A special stack trace for RISC-V is handled separately. + riscvSpecialStackStart, + }, + frameRes: []*regexp.Regexp{ + compile("^ *(?:{{PC}} ){0,2}{{FUNC}}"), + // Arm is totally different. + // Extract both current and next frames. This is needed for the top + // frame which is present only in LR register which we don't parse. + compile(`^ *{{PC}} \(([a-zA-Z0-9_.]+)\) from {{PC}} \({{FUNC}}`), + }, + skipPatterns: []string{ + "__sanitizer", + "__asan", + "kasan", + "hwasan", + "__msan", + "kmsan", + "kcsan_setup_watchpoint", + "check_memory_region", + "check_heap_object", + "check_object", + "read_word_at_a_time", + "(read|write)_once_.*nocheck", + "print_address_description", + "panic", + "invalid_op", + "report_bug", + "fixup_bug", + "print_report", + "print_usage_bug", + "do_error", + "invalid_op", + `_trap$|do_trap`, + "show_stack", + "dump_stack", + "walk_stack", + "dump_backtrace", + "warn_slowpath", + "warn_alloc", + "warn_bogus", + "__warn", + "alloc_page", + "k?v?(?:m|z|c)alloc", + "krealloc", + "kmem_cache", + "allocate_slab", + "__alloc_frozen_pages_noprof", + "folio_(?:alloc|unlock)", + "filemap_alloc_folio", + "__filemap_get_folio", + "find_or_create_page", + "do_read_cache_folio", + "read_cache_page", + "pagecache_get_page", + "grab_cache_page_write_begin", + "slab_", + "debug_object", + "timer_is_static_object", + "work_is_static_object", + "__might_fault", + "print_unlock", + "imbalance_bug", + "lockdep", + "bh_enable", + "bh_disable", + "perf_trace", + "lock_acquire", + "lock_release", + "lock_class", + "mark_lock", + "(reacquire|mark)_held_locks", + "raw_spin_rq", + "spin_lock", + "spin_trylock", + "spin_unlock", + "read_lock", + "read_trylock", + "write_lock", + "write_trylock", + "read_unlock", + "write_unlock", + "^down$", + "down_read", + "down_write", + "down_read_trylock", + "down_write_trylock", + "down_trylock", + "up_read", + "up_write", + "^mutex_", + "^__mutex_", + "^rt_mutex_", + "owner_on_cpu", + "osq_lock", + "osq_unlock", + "atomic(64)?_(dec|inc|read|set|or|xor|and|add|sub|fetch|xchg|cmpxchg|try)", + "(set|clear|change|test)_bit", + "__wake_up", + "^refcount_", + "^kref_", + "ref_tracker", + "seqprop_assert", + "memcpy", + "memcmp", + "memset", + "memchr", + "memmove", + "memdup", + "strcmp", + "strncmp", + "strcpy", + "strlcpy", + "strncpy", + "strscpy", + "strlen", + "strstr", + "strnstr", + "strnlen", + "strchr", + "strdup", + "strndup", + "copy_to_user", + "copy_from_user", + "copy_to_iter", + "copy_from_iter", + "copy_page_to_iter", + "copy_page_from_iter", + "copy_folio_to_iter", + "^copyin$", + "^copyout$", + "put_user", + "get_user", + "might_fault", + "might_sleep", + "list_add", + "list_del", + "list_replace", + "list_move", + "list_splice", + "^rb_", + "^__rb_", + "_indirect_thunk_", // retpolines + "string", + "pointer", + "snprintf", + "scnprintf", + "kasprintf", + "kvasprintf", + "printk", + "va_format", + "dev_info", + "dev_notice", + "dev_warn", + "dev_err", + "dev_alert", + "dev_crit", + "dev_emerg", + "program_check_exception", + "program_check_common", + "del_timer", + "flush_work", + "cancel_work_sync", + "try_to_grab_pending", + "flush_workqueue", + "drain_workqueue", + "destroy_workqueue", + "queue_work", + "finish_wait", + "kthread_stop", + "kobject_", + "add_uevent_var", + "get_device_parent", + "device_add", + "device_del", + "device_unregister", + "device_destroy", + "device_release", + "devres_release_all", + "hwrng_unregister", + "i2c_del_adapter", + "__unregister_client", + "device_for_each_child", + "rollback_registered", + "unregister_netdev", + "sysfs_remove", + "device_remove_file", + "tty_unregister_device", + "dummy_urb_enqueue", + "usb_kill_urb", + "usb_kill_anchored_urbs", + "usb_control_msg", + "usb_hcd_submit_urb", + "usb_submit_urb", + "^complete$", + "wait_for_completion", + "^kv?free$", + "kfree_skb", + "readb$", + "readw$", + "readl$", + "readq$", + "writeb$", + "writew$", + "writel$", + "writeq$", + "logic_in", + "logic_out", + "^crc\\d+", + "crc_itu_t", + "__might_resched", + "assertfail", + "^iput$", + "^iput_final$", + "^ihold$", + "hex_dump_to_buffer", + "print_hex_dump", + "^klist_", + "(trace|lockdep)_(hard|soft)irq", + "^(un)?lock_page", + "stack_trace_consume_entry", + "arch_stack_walk", + "stack_trace_save", + "insert_work", + "__queue_delayed_work", + "queue_delayed_work_on", + "ida_free", + // arm64 translation exception handling path. + "do_(kernel|translation)_fault", + "do_mem_abort", + "el1_abort", + "el1h_64_sync(?:_handler)?", + "print_tainted", + "xas_(?:start|load|find)", + "find_lock_entries", + "truncate_inode_pages_range", + "__phys_addr", + "__fortify_report", + "cleanup_srcu_struct", + "rhashtable_lookup", + "extract_(user|iter)_to_sg", + "drop_nlink", + "^get_taint$", + "^put_device$", + "lock_timer_base", + "__timer_delete_sync", + "sk_stop_timer_sync", + "enqueue_timer", + "internal_add_timer", + "__mod_timer", + "fast_dput", + "dput", + "mod_timer", + "queue_delayed_work", + "detach_timer", + "detach_if_pending", + "__cancel_work_timer", + "mark_buffer_dirty", + }, + corruptedLines: []*regexp.Regexp{ + // Fault injection stacks are frequently intermixed with crash reports. + // Note: the actual symbol can have all kinds of weird suffixes like ".isra.7", ".cold" or ".isra.56.cold.74". + compile(`^( \[\<?(?:0x)?[0-9a-f]+\>?\])? should_fail(slab)?(\.[a-z0-9.]+)?\+0x`), + }, + stripFramePrefixes: []string{ + "SYSC_", + "SyS_", + "sys_", + "__x64_", + "__ia32_", + "__arm64_", + "____sys_", + "___sys_", + "__sys_", + "__se_", + "__se_sys_", + "__do_sys_", + "compat_SYSC_", + "compat_SyS_", + "ksys_", + }, + } +) func warningStackFmt(skip ...string) *stackFmt { return &stackFmt{ @@ -1528,7 +1543,8 @@ var linuxOopses = append([]*oops{ "alloc_skb", "netlink_ack", "netlink_rcv_skb", // Encryption routines are the place where we hit the bug, but // the generic code is a bad candidate for bug titles. - "_encrypt$", "^(?:crypto|cipher|drbg|rng)_"}, + "_encrypt$", "^(?:crypto|cipher|drbg|rng)_", + }, }, noStackTrace: true, }, @@ -1719,9 +1735,11 @@ var linuxOopses = append([]*oops{ compile(`page last allocated`), parseStackTrace, }, - skip: []string{"(free|put|get|update|release)_page", + skip: []string{ + "(free|put|get|update|release)_page", "free_unref", "^_*folio", "truncate_inode_pages", - "page_frag_free", "alloc", "vmap", "page_owner"}, + "page_frag_free", "alloc", "vmap", "page_owner", + }, }, }, { @@ -1751,8 +1769,10 @@ var linuxOopses = append([]*oops{ linuxCallTrace, parseStackTrace, }, - skip: []string{"dump_stack", "preemption", "preempt", "debug_", - "processor_id", "this_cpu"}, + skip: []string{ + "dump_stack", "preemption", "preempt", "debug_", + "processor_id", "this_cpu", + }, }, }, { @@ -1770,9 +1790,11 @@ var linuxOopses = append([]*oops{ compile("backtrace(?: \\(crc [[:xdigit:]]*\\))?:"), parseStackTrace, }, - skip: []string{"kmemleak", "mmap", "kmem", "slab", "alloc", "create_object", + skip: []string{ + "kmemleak", "mmap", "kmem", "slab", "alloc", "create_object", "idr_get", "list_lru_init", "kasprintf", "kvasprintf", - "pcpu_create", "strdup", "strndup", "memdup"}, + "pcpu_create", "strdup", "strndup", "memdup", + }, }, }, { @@ -1920,8 +1942,10 @@ var linuxOopses = append([]*oops{ // These workqueue functions take locks associated with work items. // All deadlocks observed in these functions are // work-item-subsystem-related. - skip: []string{"process_one_work", "flush_workqueue", - "drain_workqueue", "destroy_workqueue"}, + skip: []string{ + "process_one_work", "flush_workqueue", + "drain_workqueue", "destroy_workqueue", + }, }, }, { |
