#include <asm/stack_pointer.h>
 #include <asm/stacktrace.h>
 
+enum kunwind_source {
+       KUNWIND_SOURCE_UNKNOWN,
+       KUNWIND_SOURCE_FRAME,
+       KUNWIND_SOURCE_CALLER,
+       KUNWIND_SOURCE_TASK,
+       KUNWIND_SOURCE_REGS_PC,
+};
+
 /*
  * Kernel unwind state
  *
 #ifdef CONFIG_KRETPROBES
        struct llist_node *kr_cur;
 #endif
+       enum kunwind_source source;
 };
 
 static __always_inline void
 {
        unwind_init_common(&state->common);
        state->task = task;
+       state->source = KUNWIND_SOURCE_UNKNOWN;
 }
 
 /*
 
        state->common.fp = regs->regs[29];
        state->common.pc = regs->pc;
+       state->source = KUNWIND_SOURCE_REGS_PC;
 }
 
 /*
 
        state->common.fp = (unsigned long)__builtin_frame_address(1);
        state->common.pc = (unsigned long)__builtin_return_address(0);
+       state->source = KUNWIND_SOURCE_CALLER;
 }
 
 /*
 
        state->common.fp = thread_saved_fp(task);
        state->common.pc = thread_saved_pc(task);
+       state->source = KUNWIND_SOURCE_TASK;
 }
 
 static __always_inline int
        if (fp == (unsigned long)&task_pt_regs(tsk)->stackframe)
                return -ENOENT;
 
-       err = unwind_next_frame_record(&state->common);
-       if (err)
-               return err;
+       switch (state->source) {
+       case KUNWIND_SOURCE_FRAME:
+       case KUNWIND_SOURCE_CALLER:
+       case KUNWIND_SOURCE_TASK:
+       case KUNWIND_SOURCE_REGS_PC:
+               err = unwind_next_frame_record(&state->common);
+               if (err)
+                       return err;
+               state->source = KUNWIND_SOURCE_FRAME;
+               break;
+       default:
+               return -EINVAL;
+       }
 
        state->common.pc = ptrauth_strip_kernel_insn_pac(state->common.pc);
 
        kunwind_stack_walk(arch_bpf_unwind_consume_entry, &data, current, NULL);
 }
 
+static const char *state_source_string(const struct kunwind_state *state)
+{
+       switch (state->source) {
+       case KUNWIND_SOURCE_FRAME:      return NULL;
+       case KUNWIND_SOURCE_CALLER:     return "C";
+       case KUNWIND_SOURCE_TASK:       return "T";
+       case KUNWIND_SOURCE_REGS_PC:    return "P";
+       default:                        return "U";
+       }
+}
+
 static bool dump_backtrace_entry(const struct kunwind_state *state, void *arg)
 {
+       const char *source = state_source_string(state);
        char *loglvl = arg;
-       printk("%s %pSb\n", loglvl, (void *)state->common.pc);
+       printk("%s %pSb%s%s%s\n", loglvl,
+               (void *)state->common.pc,
+               source ? " (" : "",
+               source ? source : "",
+               source ? ")" : "");
        return true;
 }