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
46 typedef 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
52 static stack_frame_t sf_array[MAX_STACK_FRAME];
53
check_stack(unsigned long * base)54 static 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
check_stack_start(unsigned long * base,unsigned long real_sp,int id)63 unsigned 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
check_stack_stop(unsigned long * base,int id)91 unsigned 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
print_stack(int id)124 void 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
get_task_struct_ptr_by_name(char * name)135 struct 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
save_stack_context(char * name,int id)155 unsigned 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