linux/arch/arm/kernel/return_address.c
<<
>>
Prefs
   1/*
   2 * arch/arm/kernel/return_address.c
   3 *
   4 * Copyright (C) 2009 Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
   5 * for Pengutronix
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License version 2 as published by
   9 * the Free Software Foundation.
  10 */
  11#include <linux/export.h>
  12#include <linux/ftrace.h>
  13
  14#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
  15#include <linux/sched.h>
  16
  17#include <asm/stacktrace.h>
  18
  19struct return_address_data {
  20        unsigned int level;
  21        void *addr;
  22};
  23
  24static int save_return_addr(struct stackframe *frame, void *d)
  25{
  26        struct return_address_data *data = d;
  27
  28        if (!data->level) {
  29                data->addr = (void *)frame->lr;
  30
  31                return 1;
  32        } else {
  33                --data->level;
  34                return 0;
  35        }
  36}
  37
  38void *return_address(unsigned int level)
  39{
  40        struct return_address_data data;
  41        struct stackframe frame;
  42        register unsigned long current_sp asm ("sp");
  43
  44        data.level = level + 1;
  45
  46        frame.fp = (unsigned long)__builtin_frame_address(0);
  47        frame.sp = current_sp;
  48        frame.lr = (unsigned long)__builtin_return_address(0);
  49        frame.pc = (unsigned long)return_address;
  50
  51        walk_stackframe(&frame, save_return_addr, &data);
  52
  53        if (!data.level)
  54                return data.addr;
  55        else
  56                return NULL;
  57}
  58
  59#else /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */
  60
  61#if defined(CONFIG_ARM_UNWIND)
  62#warning "TODO: return_address should use unwind tables"
  63#endif
  64
  65void *return_address(unsigned int level)
  66{
  67        return NULL;
  68}
  69
  70#endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) / else */
  71
  72EXPORT_SYMBOL_GPL(return_address);
  73