* refs/heads/tmp-4b8fc9f UPSTREAM: locking: avoid passing around 'thread_info' in mutex debugging code ANDROID: arm64: fix undeclared 'init_thread_info' error UPSTREAM: kdb: use task_cpu() instead of task_thread_info()->cpu Linux 4.4.82 net: account for current skb length when deciding about UFO ipv4: Should use consistent conditional judgement for ip fragment in __ip_append_data and ip_finish_output mm/mempool: avoid KASAN marking mempool poison checks as use-after-free KVM: arm/arm64: Handle hva aging while destroying the vm sparc64: Prevent perf from running during super critical sections udp: consistently apply ufo or fragmentation revert "ipv4: Should use consistent conditional judgement for ip fragment in __ip_append_data and ip_finish_output" revert "net: account for current skb length when deciding about UFO" packet: fix tp_reserve race in packet_set_ring net: avoid skb_warn_bad_offload false positives on UFO tcp: fastopen: tcp_connect() must refresh the route net: sched: set xt_tgchk_param par.nft_compat as 0 in ipt_init_target bpf, s390: fix jit branch offset related to ldimm64 net: fix keepalive code vs TCP_FASTOPEN_CONNECT tcp: avoid setting cwnd to invalid ssthresh after cwnd reduction states ANDROID: keychord: Fix for a memory leak in keychord. ANDROID: keychord: Fix races in keychord_write. Use %zu to print resid (size_t). ANDROID: keychord: Fix a slab out-of-bounds read. Linux 4.4.81 workqueue: implicit ordered attribute should be overridable net: account for current skb length when deciding about UFO ipv4: Should use consistent conditional judgement for ip fragment in __ip_append_data and ip_finish_output mm: don't dereference struct page fields of invalid pages signal: protect SIGNAL_UNKILLABLE from unintentional clearing. lib/Kconfig.debug: fix frv build failure mm, slab: make sure that KMALLOC_MAX_SIZE will fit into MAX_ORDER ARM: 8632/1: ftrace: fix syscall name matching virtio_blk: fix panic in initialization error path drm/virtio: fix framebuffer sparse warning scsi: qla2xxx: Get mutex lock before checking optrom_state phy state machine: failsafe leave invalid RUNNING state x86/boot: Add missing declaration of string functions tg3: Fix race condition in tg3_get_stats64(). net: phy: dp83867: fix irq generation sh_eth: R8A7740 supports packet shecksumming wext: handle NULL extra data in iwe_stream_add_point better sparc64: Measure receiver forward progress to avoid send mondo timeout xen-netback: correctly schedule rate-limited queues net: phy: Fix PHY unbind crash net: phy: Correctly process PHY_HALTED in phy_stop_machine() net/mlx5: Fix command bad flow on command entry allocation failure sctp: fix the check for _sctp_walk_params and _sctp_walk_errors sctp: don't dereference ptr before leaving _sctp_walk_{params, errors}() dccp: fix a memleak for dccp_feat_init err process dccp: fix a memleak that dccp_ipv4 doesn't put reqsk properly dccp: fix a memleak that dccp_ipv6 doesn't put reqsk properly net: ethernet: nb8800: Handle all 4 RGMII modes identically ipv6: Don't increase IPSTATS_MIB_FRAGFAILS twice in ip6_fragment() packet: fix use-after-free in prb_retire_rx_blk_timer_expired() openvswitch: fix potential out of bound access in parse_ct mcs7780: Fix initialization when CONFIG_VMAP_STACK is enabled rtnetlink: allocate more memory for dev_set_mac_address() ipv4: initialize fib_trie prior to register_netdev_notifier call. ipv6: avoid overflow of offset in ip6_find_1stfragopt net: Zero terminate ifr_name in dev_ifname(). ipv4: ipv6: initialize treq->txhash in cookie_v[46]_check() saa7164: fix double fetch PCIe access condition drm: rcar-du: fix backport bug f2fs: sanity check checkpoint segno and blkoff media: lirc: LIRC_GET_REC_RESOLUTION should return microseconds mm, mprotect: flush TLB if potentially racing with a parallel reclaim leaving stale TLB entries iser-target: Avoid isert_conn->cm_id dereference in isert_login_recv_done iscsi-target: Fix delayed logout processing greater than SECONDS_FOR_LOGOUT_COMP iscsi-target: Fix initial login PDU asynchronous socket close OOPs iscsi-target: Fix early sk_data_ready LOGIN_FLAGS_READY race iscsi-target: Always wait for kthread_should_stop() before kthread exit target: Avoid mappedlun symlink creation during lun shutdown media: platform: davinci: return -EINVAL for VPFE_CMD_S_CCDC_RAW_PARAMS ioctl ARM: dts: armada-38x: Fix irq type for pca955 ext4: fix overflow caused by missing cast in ext4_resize_fs() ext4: fix SEEK_HOLE/SEEK_DATA for blocksize < pagesize mm/page_alloc: Remove kernel address exposure in free_reserved_area() KVM: async_pf: make rcu irq exit if not triggered from idle task ASoC: do not close shared backend dailink ALSA: hda - Fix speaker output from VAIO VPCL14M1R workqueue: restore WQ_UNBOUND/max_active==1 to be ordered libata: array underflow in ata_find_dev() ANDROID: binder: don't queue async transactions to thread. ANDROID: binder: don't enqueue death notifications to thread todo. ANDROID: binder: call poll_wait() unconditionally. android: configs: move quota-related configs to recommended BACKPORT: arm64: split thread_info from task stack UPSTREAM: arm64: assembler: introduce ldr_this_cpu UPSTREAM: arm64: make cpu number a percpu variable UPSTREAM: arm64: smp: prepare for smp_processor_id() rework BACKPORT: arm64: move sp_el0 and tpidr_el1 into cpu_suspend_ctx UPSTREAM: arm64: prep stack walkers for THREAD_INFO_IN_TASK UPSTREAM: arm64: unexport walk_stackframe UPSTREAM: arm64: traps: simplify die() and __die() UPSTREAM: arm64: factor out current_stack_pointer BACKPORT: arm64: asm-offsets: remove unused definitions UPSTREAM: arm64: thread_info remove stale items UPSTREAM: thread_info: include <current.h> for THREAD_INFO_IN_TASK UPSTREAM: thread_info: factor out restart_block UPSTREAM: kthread: Pin the stack via try_get_task_stack()/put_task_stack() in to_live_kthread() function UPSTREAM: sched/core: Add try_get_task_stack() and put_task_stack() UPSTREAM: sched/core: Allow putting thread_info into task_struct UPSTREAM: printk: when dumping regs, show the stack, not thread_info UPSTREAM: fix up initial thread stack pointer vs thread_info confusion UPSTREAM: Clarify naming of thread info/stack allocators ANDROID: sdcardfs: override credential for ioctl to lower fs Conflicts: android/configs/android-base.cfg arch/arm64/Kconfig arch/arm64/include/asm/suspend.h arch/arm64/kernel/head.S arch/arm64/kernel/smp.c arch/arm64/kernel/suspend.c arch/arm64/kernel/traps.c arch/arm64/mm/proc.S kernel/fork.c sound/soc/soc-pcm.c Change-Id: I273e216c94899a838bbd208391c6cbe20b2bf683 Signed-off-by: Blagovest Kolenichev <bkolenichev@codeaurora.org>
199 lines
5 KiB
C
199 lines
5 KiB
C
/*
|
|
* Stack tracing support
|
|
*
|
|
* Copyright (C) 2012 ARM Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <linux/kasan.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/export.h>
|
|
#include <linux/ftrace.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/stacktrace.h>
|
|
|
|
#include <asm/irq.h>
|
|
#include <asm/stack_pointer.h>
|
|
#include <asm/stacktrace.h>
|
|
|
|
/*
|
|
* AArch64 PCS assigns the frame pointer to x29.
|
|
*
|
|
* A simple function prologue looks like this:
|
|
* sub sp, sp, #0x10
|
|
* stp x29, x30, [sp]
|
|
* mov x29, sp
|
|
*
|
|
* A simple function epilogue looks like this:
|
|
* mov sp, x29
|
|
* ldp x29, x30, [sp]
|
|
* add sp, sp, #0x10
|
|
*/
|
|
int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
|
|
{
|
|
unsigned long high, low;
|
|
unsigned long fp = frame->fp;
|
|
unsigned long irq_stack_ptr;
|
|
|
|
/*
|
|
* Switching between stacks is valid when tracing current and in
|
|
* non-preemptible context.
|
|
*/
|
|
if (tsk == current && !preemptible())
|
|
irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
|
|
else
|
|
irq_stack_ptr = 0;
|
|
|
|
low = frame->sp;
|
|
/* irq stacks are not THREAD_SIZE aligned */
|
|
if (on_irq_stack(frame->sp, raw_smp_processor_id()))
|
|
high = irq_stack_ptr;
|
|
else
|
|
high = ALIGN(low, THREAD_SIZE) - 0x20;
|
|
|
|
if (fp < low || fp > high || fp & 0xf)
|
|
return -EINVAL;
|
|
|
|
kasan_disable_current();
|
|
|
|
frame->sp = fp + 0x10;
|
|
frame->fp = *(unsigned long *)(fp);
|
|
frame->pc = *(unsigned long *)(fp + 8);
|
|
|
|
kasan_enable_current();
|
|
|
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
|
if (tsk && tsk->ret_stack &&
|
|
(frame->pc == (unsigned long)return_to_handler)) {
|
|
/*
|
|
* This is a case where function graph tracer has
|
|
* modified a return address (LR) in a stack frame
|
|
* to hook a function return.
|
|
* So replace it to an original value.
|
|
*/
|
|
frame->pc = tsk->ret_stack[frame->graph--].ret;
|
|
}
|
|
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
|
|
|
/*
|
|
* Check whether we are going to walk through from interrupt stack
|
|
* to task stack.
|
|
* If we reach the end of the stack - and its an interrupt stack,
|
|
* unpack the dummy frame to find the original elr.
|
|
*
|
|
* Check the frame->fp we read from the bottom of the irq_stack,
|
|
* and the original task stack pointer are both in current->stack.
|
|
*/
|
|
if (frame->sp == irq_stack_ptr) {
|
|
struct pt_regs *irq_args;
|
|
unsigned long orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
|
|
|
|
if (object_is_on_stack((void *)orig_sp) &&
|
|
object_is_on_stack((void *)frame->fp)) {
|
|
frame->sp = orig_sp;
|
|
|
|
/* orig_sp is the saved pt_regs, find the elr */
|
|
irq_args = (struct pt_regs *)orig_sp;
|
|
frame->pc = irq_args->pc;
|
|
} else {
|
|
/*
|
|
* This frame has a non-standard format, and we
|
|
* didn't fix it, because the data looked wrong.
|
|
* Refuse to output this frame.
|
|
*/
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
|
|
int (*fn)(struct stackframe *, void *), void *data)
|
|
{
|
|
while (1) {
|
|
int ret;
|
|
|
|
if (fn(frame, data))
|
|
break;
|
|
ret = unwind_frame(tsk, frame);
|
|
if (ret < 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_STACKTRACE
|
|
struct stack_trace_data {
|
|
struct stack_trace *trace;
|
|
unsigned int no_sched_functions;
|
|
unsigned int skip;
|
|
};
|
|
|
|
static int save_trace(struct stackframe *frame, void *d)
|
|
{
|
|
struct stack_trace_data *data = d;
|
|
struct stack_trace *trace = data->trace;
|
|
unsigned long addr = frame->pc;
|
|
|
|
if (data->no_sched_functions && in_sched_functions(addr))
|
|
return 0;
|
|
if (data->skip) {
|
|
data->skip--;
|
|
return 0;
|
|
}
|
|
|
|
trace->entries[trace->nr_entries++] = addr;
|
|
|
|
return trace->nr_entries >= trace->max_entries;
|
|
}
|
|
|
|
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
|
{
|
|
struct stack_trace_data data;
|
|
struct stackframe frame;
|
|
|
|
if (!try_get_task_stack(tsk))
|
|
return;
|
|
|
|
data.trace = trace;
|
|
data.skip = trace->skip;
|
|
|
|
if (tsk != current) {
|
|
data.no_sched_functions = 1;
|
|
frame.fp = thread_saved_fp(tsk);
|
|
frame.sp = thread_saved_sp(tsk);
|
|
frame.pc = thread_saved_pc(tsk);
|
|
} else {
|
|
data.no_sched_functions = 0;
|
|
frame.fp = (unsigned long)__builtin_frame_address(0);
|
|
frame.sp = current_stack_pointer;
|
|
frame.pc = (unsigned long)save_stack_trace_tsk;
|
|
}
|
|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
|
frame.graph = tsk->curr_ret_stack;
|
|
#endif
|
|
|
|
walk_stackframe(tsk, &frame, save_trace, &data);
|
|
if (trace->nr_entries < trace->max_entries)
|
|
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
|
|
|
put_task_stack(tsk);
|
|
}
|
|
EXPORT_SYMBOL(save_stack_trace_tsk);
|
|
|
|
void save_stack_trace(struct stack_trace *trace)
|
|
{
|
|
save_stack_trace_tsk(current, trace);
|
|
}
|
|
EXPORT_SYMBOL_GPL(save_stack_trace);
|
|
#endif
|