1/*
2 * stack_profile.c
3 *
4 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 *  * Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *  * Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *  * Neither the name Texas Instruments nor the names of its
18 *    contributors may be used to endorse or promote products derived
19 *    from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * src/stack_profile.c
36 *
37 */
38
39#include <linux/stddef.h>
40#include <linux/kernel.h>
41#include <linux/sched.h>
42
43#define STACK_MASK		(THREAD_SIZE-1)
44#define MAX_STACK_FRAME		2
45
46typedef struct STACK_FRAME {
47	unsigned long stack_buf[THREAD_SIZE/sizeof(unsigned long)];
48	unsigned long *stack_start;
49	unsigned long stack_size;
50} stack_frame_t;
51
52static stack_frame_t sf_array[MAX_STACK_FRAME];
53
54static unsigned long check_stack(unsigned long *base)
55{
56	register unsigned long sp asm ("sp");
57	unsigned long retval = sp;
58
59	*base = ((sp & ~STACK_MASK) + sizeof(struct task_struct) + 4);
60	return retval;
61}
62
63unsigned long check_stack_start(unsigned long *base, unsigned long real_sp,
64				int id)
65{
66	unsigned long i;
67	unsigned long from, to;
68
69	to = check_stack(&from);
70	*base = from;
71
72	/* save used stack context */
73	if (id < MAX_STACK_FRAME) {
74		stack_frame_t *sfp = &sf_array[id];
75
76		if (!real_sp)
77			real_sp = to;
78		sfp->stack_size = THREAD_SIZE - (real_sp & STACK_MASK);
79		sfp->stack_start = (unsigned long *)real_sp;
80		memcpy(sfp->stack_buf, sfp->stack_start, sfp->stack_size);
81	}
82	/* run from the stack pointer down to the base */
83	for(i=from;(i < to);i+=4) {
84		/* fill up the pattern */
85		*(unsigned long *)i = 0xdeadbeef;
86	}
87	/*printk("check_stack_start: from=%x to=%x data=%x\n",from,to,*(long *)(from+4));*/
88	return to;
89}
90
91unsigned long check_stack_stop(unsigned long *base, int id)
92{
93	unsigned long i;
94	unsigned long from, to;
95
96	to = check_stack(&from);
97	*base = from;
98
99	/* check used stack context */
100	if (id < MAX_STACK_FRAME) {
101		stack_frame_t *sfp = &sf_array[id];
102
103		if (memcmp(sfp->stack_buf, sfp->stack_start, sfp->stack_size)) {
104			printk("%s: %p - Error\n", __func__, sfp->stack_start);
105			for(i=0;(i < sfp->stack_size/sizeof(unsigned long));i++) {
106				if (sfp->stack_start[i] != sfp->stack_buf[i])
107					printk("%p: 0x%08lx != 0x%08lx\n", &sfp->stack_start[i], sfp->stack_start[i], sfp->stack_buf[i]);
108			}
109		}
110	}
111
112	/* run from the stack pointer down to the base */
113	for(i=from;(i < to);i+=4) {
114		/* check up the pattern */
115		if ((*(unsigned long *)i) != 0xdeadbeef)
116			break;
117	}
118
119	/*printk("check_stack_stop: from=%x to=%x data=%x data=%x i=0x%x\n",from,to,*(long *)from,*(long *)(from+4),i);*/
120	/* return the first time when the pattern doesn't match */
121	return i;
122}
123
124void print_stack(int id)
125{
126	stack_frame_t *sfp = &sf_array[id];
127	unsigned long i;
128
129	printk("%s: %d\n", __func__, id);
130	for(i=0;(i < sfp->stack_size/sizeof(unsigned long));i++) {
131		printk("%p: 0x%08lx\n", &sfp->stack_start[i], sfp->stack_start[i]);
132	}
133}
134
135struct task_struct *get_task_struct_ptr_by_name(char *name)
136{
137	struct task_struct *g, *p;
138
139	read_lock(&tasklist_lock);
140	do_each_thread(g, p) {
141		/*
142		 * reset the NMI-timeout, listing all files on a slow
143		 * console might take alot of time:
144		 */
145		/* touch_nmi_watchdog(); */
146		if (!strcmp(name, p->comm)) {
147			read_unlock(&tasklist_lock);
148			return p;
149		}
150	} while_each_thread(g, p);
151	read_unlock(&tasklist_lock);
152	return NULL;
153}
154
155unsigned long save_stack_context(char *name, int id)
156{
157/*	register unsigned long sp asm ("sp");
158	unsigned long sp_local = sp;
159*/
160	struct task_struct *p;
161	stack_frame_t *sfp;
162
163	if (id >= MAX_STACK_FRAME)
164		return 0L;
165	sfp = &sf_array[id];
166	p = get_task_struct_ptr_by_name(name);
167	if (p) {
168		printk("%s: %s found\n", __func__, p->comm); /* sched_show_task(t);*/
169		sfp->stack_start = (unsigned long *)((unsigned long)end_of_stack(p) & ~STACK_MASK);
170		sfp->stack_size = THREAD_SIZE;
171		memcpy(sfp->stack_buf, sfp->stack_start, sfp->stack_size);
172	}
173	return sfp->stack_size;
174}
175