l; charset=UTF-8 Last-Modified: Fri, 26 Jun 2026 17:48:33 GMT Expires: Mon, 23 Jun 2036 17:48:33 GMT litmus-rt-imx6.git - LITMUS^RT and MC^2 V1 support for the i.MX6 processor family.
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Richter <robert.richter@amd.com>2008-10-16 09:01:40 -0400
committerRobert Richter <robert.richter@amd.com>2008-10-16 09:01:40 -0400
commit6a18037d4165f691063b43816be3152e9006eb06 (patch)
tree61e5dab681cd0544f61b6d5ffad4c6a0c0c2b1a1
parent5a289395bf753f8a318d3a5fa335a757c16c0183 (diff)
oprofile: fixing whitespaces in drivers/oprofile/*
Signed-off-by: Robert Richter <robert.richter@amd.com>
-rw-r--r--drivers/oprofile/buffer_sync.h4
-rw-r--r--drivers/oprofile/cpu_buffer.c16
-rw-r--r--drivers/oprofile/cpu_buffer.h6
-rw-r--r--drivers/oprofile/event_buffer.c24
-rw-r--r--drivers/oprofile/event_buffer.h10
-rw-r--r--drivers/oprofile/oprof.c2
-rw-r--r--drivers/oprofile/oprof.h8
-rw-r--r--drivers/oprofile/oprofile_files.c20
-rw-r--r--drivers/oprofile/oprofile_stats.c14
-rw-r--r--drivers/oprofile/oprofile_stats.h8
-rw-r--r--drivers/oprofile/oprofilefs.c6
-rw-r--r--drivers/oprofile/timer_int.c2
12 files changed, 60 insertions, 60 deletions
diff --git a/drivers/oprofile/buffer_sync.h b/drivers/oprofile/buffer_sync.h
index 08866f6a96a3..3110732c1835 100644
--- a/drivers/oprofile/buffer_sync.h
+++ b/drivers/oprofile/buffer_sync.h
@@ -9,13 +9,13 @@
9 9
10#ifndef OPROFILE_BUFFER_SYNC_H 10#ifndef OPROFILE_BUFFER_SYNC_H
11#define OPROFILE_BUFFER_SYNC_H 11#define OPROFILE_BUFFER_SYNC_H
12 12
13/* add the necessary profiling hooks */ 13/* add the necessary profiling hooks */
14int sync_start(void); 14int sync_start(void);
15 15
16/* remove the hooks */ 16/* remove the hooks */
17void sync_stop(void); 17void sync_stop(void);
18 18
19/* sync the given CPU's buffer */ 19/* sync the given CPU's buffer */
20void sync_buffer(int cpu); 20void sync_buffer(int cpu);
21 21
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index b47ce038490f..5a178065cfa0 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -22,7 +22,7 @@
22#include <linux/oprofile.h> 22#include <linux/oprofile.h>
23#include <linux/vmalloc.h> 23#include <linux/vmalloc.h>
24#include <linux/errno.h> 24#include <linux/errno.h>
25 25
26#include "event_buffer.h" 26#include "event_buffer.h"
27#include "cpu_buffer.h" 27#include "cpu_buffer.h"
28#include "buffer_sync.h" 28#include "buffer_sync.h"
@@ -38,7 +38,7 @@ static int work_enabled;
38void free_cpu_buffers(void) 38void free_cpu_buffers(void)
39{ 39{
40 int i; 40 int i;
41 41
42 for_each_online_cpu(i) { 42 for_each_online_cpu(i) {
43 vfree(per_cpu(cpu_buffer, i).buffer); 43 vfree(per_cpu(cpu_buffer, i).buffer);
44 per_cpu(cpu_buffer, i).buffer = NULL; 44 per_cpu(cpu_buffer, i).buffer = NULL;
@@ -48,17 +48,17 @@ void free_cpu_buffers(void)
48int alloc_cpu_buffers(void) 48int alloc_cpu_buffers(void)
49{ 49{
50 int i; 50 int i;
51 51
52 unsigned long buffer_size = fs_cpu_buffer_size; 52 unsigned long buffer_size = fs_cpu_buffer_size;
53 53
54 for_each_online_cpu(i) { 54 for_each_online_cpu(i) {
55 struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i); 55 struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
56 56
57 b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size, 57 b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size,
58 cpu_to_node(i)); 58 cpu_to_node(i));
59 if (!b->buffer) 59 if (!b->buffer)
60 goto fail; 60 goto fail;
61 61
62 b->last_task = NULL; 62 b->last_task = NULL;
63 b->last_is_kernel = -1; 63 b->last_is_kernel = -1;
64 b->tracing = 0; 64 b->tracing = 0;
@@ -150,7 +150,7 @@ static void increment_head(struct oprofile_cpu_buffer *b)
150 150
151static inline void 151static inline void
152add_sample(struct oprofile_cpu_buffer *cpu_buf, 152add_sample(struct oprofile_cpu_buffer *cpu_buf,
153 unsigned long pc, unsigned long event) 153 unsigned long pc, unsigned long event)
154{ 154{
155 struct op_sample *entry = &cpu_buf->buffer[cpu_buf->head_pos]; 155 struct op_sample *entry = &cpu_buf->buffer[cpu_buf->head_pos];
156 entry->eip = pc; 156 entry->eip = pc;
@@ -205,7 +205,7 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
205 cpu_buf->last_task = task; 205 cpu_buf->last_task = task;
206 add_code(cpu_buf, (unsigned long)task); 206 add_code(cpu_buf, (unsigned long)task);
207 } 207 }
208 208
209 add_sample(cpu_buf, pc, event); 209 add_sample(cpu_buf, pc, event);
210 return 1; 210 return 1;
211} 211}
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index 9bc6bb20b6df..d3cc26264db5 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -15,9 +15,9 @@
15#include <linux/workqueue.h> 15#include <linux/workqueue.h>
16#include <linux/cache.h> 16#include <linux/cache.h>
17#include <linux/sched.h> 17#include <linux/sched.h>
18 18
19struct task_struct; 19struct task_struct;
20 20
21int alloc_cpu_buffers(void); 21int alloc_cpu_buffers(void);
22void free_cpu_buffers(void); 22void free_cpu_buffers(void);
23 23
@@ -31,7 +31,7 @@ struct op_sample {
31 unsigned long eip; 31 unsigned long eip;
32 unsigned long event; 32 unsigned long event;
33}; 33};
34 34
35struct oprofile_cpu_buffer { 35struct oprofile_cpu_buffer {
36 volatile unsigned long head_pos; 36 volatile unsigned long head_pos;
37 volatile unsigned long tail_pos; 37 volatile unsigned long tail_pos;
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index c9329f4e090f..d962ba0dd87a 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -19,13 +19,13 @@
19#include <linux/dcookies.h> 19#include <linux/dcookies.h>
20#include <linux/fs.h> 20#include <linux/fs.h>
21#include <asm/uaccess.h> 21#include <asm/uaccess.h>
22 22
23#include "oprof.h" 23#include "oprof.h"
24#include "event_buffer.h" 24#include "event_buffer.h"
25#include "oprofile_stats.h" 25#include "oprofile_stats.h"
26 26
27DEFINE_MUTEX(buffer_mutex); 27DEFINE_MUTEX(buffer_mutex);
28 28
29static unsigned long buffer_opened; 29static unsigned long buffer_opened;
30static DECLARE_WAIT_QUEUE_HEAD(buffer_wait); 30static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
31static unsigned long *event_buffer; 31static unsigned long *event_buffer;
@@ -66,7 +66,7 @@ void wake_up_buffer_waiter(void)
66 mutex_unlock(&buffer_mutex); 66 mutex_unlock(&buffer_mutex);
67} 67}
68 68
69 69
70int alloc_event_buffer(void) 70int alloc_event_buffer(void)
71{ 71{
72 int err = -ENOMEM; 72 int err = -ENOMEM;
@@ -76,13 +76,13 @@ int alloc_event_buffer(void)
76 buffer_size = fs_buffer_size; 76 buffer_size = fs_buffer_size;
77 buffer_watershed = fs_buffer_watershed; 77 buffer_watershed = fs_buffer_watershed;
78 spin_unlock_irqrestore(&oprofilefs_lock, flags); 78 spin_unlock_irqrestore(&oprofilefs_lock, flags);
79 79
80 if (buffer_watershed >= buffer_size) 80 if (buffer_watershed >= buffer_size)
81 return -EINVAL; 81 return -EINVAL;
82 82
83 event_buffer = vmalloc(sizeof(unsigned long) * buffer_size); 83 event_buffer = vmalloc(sizeof(unsigned long) * buffer_size);
84 if (!event_buffer) 84 if (!event_buffer)
85 goto out; 85 goto out;
86 86
87 err = 0; 87 err = 0;
88out: 88out:
@@ -97,7 +97,7 @@ void free_event_buffer(void)
97 event_buffer = NULL; 97 event_buffer = NULL;
98} 98}
99 99
100 100
101static int event_buffer_open(struct inode *inode, struct file *file) 101static int event_buffer_open(struct inode *inode, struct file *file)
102{ 102{
103 int err = -EPERM; 103 int err = -EPERM;
@@ -116,14 +116,14 @@ static int event_buffer_open(struct inode *inode, struct file *file)
116 file->private_data = dcookie_register(); 116 file->private_data = dcookie_register();
117 if (!file->private_data) 117 if (!file->private_data)
118 goto out; 118 goto out;
119 119
120 if ((err = oprofile_setup())) 120 if ((err = oprofile_setup()))
121 goto fail; 121 goto fail;
122 122
123 /* NB: the actual start happens from userspace 123 /* NB: the actual start happens from userspace
124 * echo 1 >/dev/oprofile/enable 124 * echo 1 >/dev/oprofile/enable
125 */ 125 */
126 126
127 return 0; 127 return 0;
128 128
129fail: 129fail:
@@ -172,18 +172,18 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
172 retval = -EFAULT; 172 retval = -EFAULT;
173 173
174 count = buffer_pos * sizeof(unsigned long); 174 count = buffer_pos * sizeof(unsigned long);
175 175
176 if (copy_to_user(buf, event_buffer, count)) 176 if (copy_to_user(buf, event_buffer, count))
177 goto out; 177 goto out;
178 178
179 retval = count; 179 retval = count;
180 buffer_pos = 0; 180 buffer_pos = 0;
181 181
182out: 182out:
183 mutex_unlock(&buffer_mutex); 183 mutex_unlock(&buffer_mutex);
184 return retval; 184 return retval;
185} 185}
186 186
187const struct file_operations event_buffer_fops = { 187const struct file_operations event_buffer_fops = {
188 .open = event_buffer_open, 188 .open = event_buffer_open,
189 .release = event_buffer_release, 189 .release = event_buffer_release,
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 5076ed1ebd8f..00db2e665708 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -10,13 +10,13 @@
10#ifndef EVENT_BUFFER_H 10#ifndef EVENT_BUFFER_H
11#define EVENT_BUFFER_H 11#define EVENT_BUFFER_H
12 12
13#include <linux/types.h> 13#include <linux/types.h>
14#include <asm/mutex.h> 14#include <asm/mutex.h>
15 15
16int alloc_event_buffer(void); 16int alloc_event_buffer(void);
17 17
18void free_event_buffer(void); 18void free_event_buffer(void);
19 19
20/* wake up the process sleeping on the event file */ 20/* wake up the process sleeping on the event file */
21void wake_up_buffer_waiter(void); 21void wake_up_buffer_waiter(void);
22 22
@@ -24,10 +24,10 @@ void wake_up_buffer_waiter(void);
24#define NO_COOKIE 0UL 24#define NO_COOKIE 0UL
25 25
26extern const struct file_operations event_buffer_fops; 26extern const struct file_operations event_buffer_fops;
27 27
28/* mutex between sync_cpu_buffers() and the 28/* mutex between sync_cpu_buffers() and the
29 * file reading code. 29 * file reading code.
30 */ 30 */
31extern struct mutex buffer_mutex; 31extern struct mutex buffer_mutex;
32 32
33#endif /* EVENT_BUFFER_H */ 33#endif /* EVENT_BUFFER_H */
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index 50062cea292c..cd375907f26f 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -94,7 +94,7 @@ int oprofile_start(void)
94 int err = -EINVAL; 94 int err = -EINVAL;
95 95
96 mutex_lock(&start_mutex); 96 mutex_lock(&start_mutex);
97 97
98 if (!is_setup) 98 if (!is_setup)
99 goto out; 99 goto out;
100 100
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
index 7a44ddba0beb..5df0c21a608f 100644
--- a/drivers/oprofile/oprof.h
+++ b/drivers/oprofile/oprof.h
@@ -11,7 +11,7 @@
11#define OPROF_H 11#define OPROF_H
12 12
13int oprofile_setup(void); 13int oprofile_setup(void);
14void oprofile_shutdown(void); 14void oprofile_shutdown(void);
15 15
16int oprofilefs_register(void); 16int oprofilefs_register(void);
17void oprofilefs_unregister(void); 17void oprofilefs_unregister(void);
@@ -20,14 +20,14 @@ int oprofile_start(void);
20void oprofile_stop(void); 20void oprofile_stop(void);
21 21
22struct oprofile_operations; 22struct oprofile_operations;
23 23
24extern unsigned long fs_buffer_size; 24extern unsigned long fs_buffer_size;
25extern unsigned long fs_cpu_buffer_size; 25extern unsigned long fs_cpu_buffer_size;
26extern unsigned long fs_buffer_watershed; 26extern unsigned long fs_buffer_watershed;
27extern struct oprofile_operations oprofile_ops; 27extern struct oprofile_operations oprofile_ops;
28extern unsigned long oprofile_started; 28extern unsigned long oprofile_started;
29extern unsigned long backtrace_depth; 29extern unsigned long backtrace_depth;
30 30
31struct super_block; 31struct super_block;
32struct dentry; 32struct dentry;
33 33
@@ -35,5 +35,5 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root);
35void oprofile_timer_init(struct oprofile_operations *ops); 35void oprofile_timer_init(struct oprofile_operations *ops);
36 36
37int oprofile_set_backtrace(unsigned long depth); 37int oprofile_set_backtrace(unsigned long depth);
38 38
39#endif /* OPROF_H */ 39#endif /* OPROF_H */
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
index 241804abbb5c..cc106d503ace 100644
--- a/drivers/oprofile/oprofile_files.c
+++ b/drivers/oprofile/oprofile_files.c
@@ -13,7 +13,7 @@
13#include "event_buffer.h" 13#include "event_buffer.h"
14#include "oprofile_stats.h" 14#include "oprofile_stats.h"
15#include "oprof.h" 15#include "oprof.h"
16 16
17unsigned long fs_buffer_size = 131072; 17unsigned long fs_buffer_size = 131072;
18unsigned long fs_cpu_buffer_size = 8192; 18unsigned long fs_cpu_buffer_size = 8192;
19unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */ 19unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
@@ -49,7 +49,7 @@ static const struct file_operations depth_fops = {
49 .write = depth_write 49 .write = depth_write
50}; 50};
51 51
52 52
53static ssize_t pointer_size_read(struct file *file, char __user *buf, size_t count, loff_t *offset) 53static ssize_t pointer_size_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
54{ 54{
55 return oprofilefs_ulong_to_user(sizeof(void *), buf, count, offset); 55 return oprofilefs_ulong_to_user(sizeof(void *), buf, count, offset);
@@ -65,13 +65,13 @@ static ssize_t cpu_type_read(struct file *file, char __user *buf, size_t count,
65{ 65{
66 return oprofilefs_str_to_user(oprofile_ops.cpu_type, buf, count, offset); 66 return oprofilefs_str_to_user(oprofile_ops.cpu_type, buf, count, offset);
67} 67}
68 68
69 69
70static const struct file_operations cpu_type_fops = { 70static const struct file_operations cpu_type_fops = {
71 .read = cpu_type_read, 71 .read = cpu_type_read,
72}; 72};
73 73
74 74
75static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset) 75static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
76{ 76{
77 return oprofilefs_ulong_to_user(oprofile_started, buf, count, offset); 77 return oprofilefs_ulong_to_user(oprofile_started, buf, count, offset);
@@ -89,7 +89,7 @@ static ssize_t enable_write(struct file *file, char const __user *buf, size_t co
89 retval = oprofilefs_ulong_from_user(&val, buf, count); 89 retval = oprofilefs_ulong_from_user(&val, buf, count);
90 if (retval) 90 if (retval)
91 return retval; 91 return retval;
92 92
93 if (val) 93 if (val)
94 retval = oprofile_start(); 94 retval = oprofile_start();
95 else 95 else
@@ -100,7 +100,7 @@ static ssize_t enable_write(struct file *file, char const __user *buf, size_t co
100 return count; 100 return count;
101} 101}
102 102
103 103
104static const struct file_operations enable_fops = { 104static const struct file_operations enable_fops = {
105 .read = enable_read, 105 .read = enable_read,
106 .write = enable_write, 106 .write = enable_write,
@@ -117,7 +117,7 @@ static ssize_t dump_write(struct file *file, char const __user *buf, size_t coun
117static const struct file_operations dump_fops = { 117static const struct file_operations dump_fops = {
118 .write = dump_write, 118 .write = dump_write,
119}; 119};
120 120
121void oprofile_create_files(struct super_block *sb, struct dentry *root) 121void oprofile_create_files(struct super_block *sb, struct dentry *root)
122{ 122{
123 oprofilefs_create_file(sb, root, "enable", &enable_fops); 123 oprofilefs_create_file(sb, root, "enable", &enable_fops);
@@ -126,7 +126,7 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root)
126 oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size); 126 oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
127 oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed); 127 oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
128 oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size); 128 oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size);
129 oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); 129 oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops);
130 oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); 130 oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops);
131 oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); 131 oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops);
132 oprofile_create_stats_files(sb, root); 132 oprofile_create_stats_files(sb, root);
diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c
index e0c45498d175..e1f6ce03705e 100644
--- a/drivers/oprofile/oprofile_stats.c
+++ b/drivers/oprofile/oprofile_stats.c
@@ -11,17 +11,17 @@
11#include <linux/smp.h> 11#include <linux/smp.h>
12#include <linux/cpumask.h> 12#include <linux/cpumask.h>
13#include <linux/threads.h> 13#include <linux/threads.h>
14 14
15#include "oprofile_stats.h" 15#include "oprofile_stats.h"
16#include "cpu_buffer.h" 16#include "cpu_buffer.h"
17 17
18struct oprofile_stat_struct oprofile_stats; 18struct oprofile_stat_struct oprofile_stats;
19 19
20void oprofile_reset_stats(void) 20void oprofile_reset_stats(void)
21{ 21{
22 struct oprofile_cpu_buffer *cpu_buf; 22 struct oprofile_cpu_buffer *cpu_buf;
23 int i; 23 int i;
24 24
25 for_each_possible_cpu(i) { 25 for_each_possible_cpu(i) {
26 cpu_buf = &per_cpu(cpu_buffer, i); 26 cpu_buf = &per_cpu(cpu_buffer, i);
27 cpu_buf->sample_received = 0; 27 cpu_buf->sample_received = 0;
@@ -29,7 +29,7 @@ void oprofile_reset_stats(void)
29 cpu_buf->backtrace_aborted = 0; 29 cpu_buf->backtrace_aborted = 0;
30 cpu_buf->sample_invalid_eip = 0; 30 cpu_buf->sample_invalid_eip = 0;
31 } 31 }
32 32
33 atomic_set(&oprofile_stats.sample_lost_no_mm, 0); 33 atomic_set(&oprofile_stats.sample_lost_no_mm, 0);
34 atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); 34 atomic_set(&oprofile_stats.sample_lost_no_mapping, 0);
35 atomic_set(&oprofile_stats.event_lost_overflow, 0); 35 atomic_set(&oprofile_stats.event_lost_overflow, 0);
@@ -52,7 +52,7 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root)
52 cpu_buf = &per_cpu(cpu_buffer, i); 52 cpu_buf = &per_cpu(cpu_buffer, i);
53 snprintf(buf, 10, "cpu%d", i); 53 snprintf(buf, 10, "cpu%d", i);
54 cpudir = oprofilefs_mkdir(sb, dir, buf); 54 cpudir = oprofilefs_mkdir(sb, dir, buf);
55 55
56 /* Strictly speaking access to these ulongs is racy, 56 /* Strictly speaking access to these ulongs is racy,
57 * but we can't simply lock them, and they are 57 * but we can't simply lock them, and they are
58 * informational only. 58 * informational only.
@@ -66,7 +66,7 @@ void oprofile_create_stats_files(struct super_block *sb, struct dentry *root)
66 oprofilefs_create_ro_ulong(sb, cpudir, "sample_invalid_eip", 66 oprofilefs_create_ro_ulong(sb, cpudir, "sample_invalid_eip",
67 &cpu_buf->sample_invalid_eip); 67 &cpu_buf->sample_invalid_eip);
68 } 68 }
69 69
70 oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mm", 70 oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mm",
71 &oprofile_stats.sample_lost_no_mm); 71 &oprofile_stats.sample_lost_no_mm);
72 oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mapping", 72 oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mapping",
diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h
index 54e59c29b439..3da0d08dc1f9 100644
--- a/drivers/oprofile/oprofile_stats.h
+++ b/drivers/oprofile/oprofile_stats.h
@@ -11,7 +11,7 @@
11#define OPROFILE_STATS_H 11#define OPROFILE_STATS_H
12 12
13#include <asm/atomic.h> 13#include <asm/atomic.h>
14 14
15struct oprofile_stat_struct { 15struct oprofile_stat_struct {
16 atomic_t sample_lost_no_mm; 16 atomic_t sample_lost_no_mm;
17 atomic_t sample_lost_no_mapping; 17 atomic_t sample_lost_no_mapping;
@@ -20,13 +20,13 @@ struct oprofile_stat_struct {
20}; 20};
21 21
22extern struct oprofile_stat_struct oprofile_stats; 22extern struct oprofile_stat_struct oprofile_stats;
23 23
24/* reset all stats to zero */ 24/* reset all stats to zero */
25void oprofile_reset_stats(void); 25void oprofile_reset_stats(void);
26 26
27struct super_block; 27struct super_block;
28struct dentry; 28struct dentry;
29 29
30/* create the stats/ dir */ 30/* create the stats/ dir */
31void oprofile_create_stats_files(struct super_block *sb, struct dentry *root); 31void oprofile_create_stats_files(struct super_block *sb, struct dentry *root);
32 32
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index a275a3aa5f0b..ddc4c59f02dc 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -181,13 +181,13 @@ static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t coun
181 atomic_t *val = file->private_data; 181 atomic_t *val = file->private_data;
182 return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset); 182 return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset);
183} 183}
184 184
185 185
186static const struct file_operations atomic_ro_fops = { 186static const struct file_operations atomic_ro_fops = {
187 .read = atomic_read_file, 187 .read = atomic_read_file,
188 .open = default_open, 188 .open = default_open,
189}; 189};
190 190
191 191
192int oprofilefs_create_ro_atomic(struct super_block *sb, struct dentry *root, 192int oprofilefs_create_ro_atomic(struct super_block *sb, struct dentry *root,
193 char const *name, atomic_t *val) 193 char const *name, atomic_t *val)
@@ -201,7 +201,7 @@ int oprofilefs_create_ro_atomic(struct super_block *sb, struct dentry *root,
201 return 0; 201 return 0;
202} 202}
203 203
204 204
205int oprofilefs_create_file(struct super_block *sb, struct dentry *root, 205int oprofilefs_create_file(struct super_block *sb, struct dentry *root,
206 char const *name, const struct file_operations *fops) 206 char const *name, const struct file_operations *fops)
207{ 207{
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c
index 7258b141a510..333f915568c7 100644
--- a/drivers/oprofile/timer_int.c
+++ b/drivers/oprofile/timer_int.c
@@ -19,7 +19,7 @@
19 19
20static int timer_notify(struct pt_regs *regs) 20static int timer_notify(struct pt_regs *regs)
21{ 21{
22 oprofile_add_sample(regs, 0); 22 oprofile_add_sample(regs, 0);
23 return 0; 23 return 0;
24} 24}
25 25
opt">); return -1; } insn = find_insn(file, rela->sym->sec, rela->addend); if (!insn) { WARN("can't find insn for unwind_hints[%d]", i); return -1; } cfa = &insn->state.cfa; if (hint->type == UNWIND_HINT_TYPE_SAVE) { insn->save = true; continue; } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) { insn->restore = true; insn->hint = true; continue; } insn->hint = true; switch (hint->sp_reg) { case ORC_REG_UNDEFINED: cfa->base = CFI_UNDEFINED; break; case ORC_REG_SP: cfa->base = CFI_SP; break; case ORC_REG_BP: cfa->base = CFI_BP; break; case ORC_REG_SP_INDIRECT: cfa->base = CFI_SP_INDIRECT; break; case ORC_REG_R10: cfa->base = CFI_R10; break; case ORC_REG_R13: cfa->base = CFI_R13; break; case ORC_REG_DI: cfa->base = CFI_DI; break; case ORC_REG_DX: cfa->base = CFI_DX; break; default: WARN_FUNC("unsupported unwind_hint sp base reg %d", insn->sec, insn->offset, hint->sp_reg); return -1; } cfa->offset = hint->sp_offset; insn->state.type = hint->type; } return 0; } static int decode_sections(struct objtool_file *file) { int ret; ret = decode_instructions(file); if (ret) return ret; ret = add_dead_ends(file); if (ret) return ret; add_ignores(file); ret = add_jump_destinations(file); if (ret) return ret; ret = add_call_destinations(file); if (ret) return ret; ret = add_special_section_alts(file); if (ret) return ret; ret = add_switch_table_alts(file); if (ret) return ret; ret = read_unwind_hints(file); if (ret) return ret; return 0; } static bool is_fentry_call(struct instruction *insn) { if (insn->type == INSN_CALL && insn->call_dest->type == STT_NOTYPE && !strcmp(insn->call_dest->name, "__fentry__")) return true; return false; } static bool has_modified_stack_frame(struct insn_state *state) { int i; if (state->cfa.base != initial_func_cfi.cfa.base || state->cfa.offset != initial_func_cfi.cfa.offset || state->stack_size != initial_func_cfi.cfa.offset || state->drap) return true; for (i = 0; i < CFI_NUM_REGS; i++) if (state->regs[i].base != initial_func_cfi.regs[i].base || state->regs[i].offset != initial_func_cfi.regs[i].offset) return true; return false; } static bool has_valid_stack_frame(struct insn_state *state) { if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA && state->regs[CFI_BP].offset == -16) return true; if (state->drap && state->regs[CFI_BP].base == CFI_BP) return true; return false; } static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) { struct cfi_reg *cfa = &state->cfa; struct stack_op *op = &insn->stack_op; if (cfa->base != CFI_SP) return 0; /* push */ if (op->dest.type == OP_DEST_PUSH) cfa->offset += 8; /* pop */ if (op->src.type == OP_SRC_POP) cfa->offset -= 8; /* add immediate to sp */ if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD && op->dest.reg == CFI_SP && op->src.reg == CFI_SP) cfa->offset -= op->src.offset; return 0; } static void save_reg(struct insn_state *state, unsigned char reg, int base, int offset) { if (arch_callee_saved_reg(reg) && state->regs[reg].base == CFI_UNDEFINED) { state->regs[reg].base = base; state->regs[reg].offset = offset; } } static void restore_reg(struct insn_state *state, unsigned char reg) { state->regs[reg].base = CFI_UNDEFINED; state->regs[reg].offset = 0; } /* * A note about DRAP stack alignment: * * GCC has the concept of a DRAP register, which is used to help keep track of * the stack pointer when aligning the stack. r10 or r13 is used as the DRAP * register. The typical DRAP pattern is: * * 4c 8d 54 24 08 lea 0x8(%rsp),%r10 * 48 83 e4 c0 and $0xffffffffffffffc0,%rsp * 41 ff 72 f8 pushq -0x8(%r10) * 55 push %rbp * 48 89 e5 mov %rsp,%rbp * (more pushes) * 41 52 push %r10 * ... * 41 5a pop %r10 * (more pops) * 5d pop %rbp * 49 8d 62 f8 lea -0x8(%r10),%rsp * c3 retq * * There are some variations in the epilogues, like: * * 5b pop %rbx * 41 5a pop %r10 * 41 5c pop %r12 * 41 5d pop %r13 * 41 5e pop %r14 * c9 leaveq * 49 8d 62 f8 lea -0x8(%r10),%rsp * c3 retq * * and: * * 4c 8b 55 e8 mov -0x18(%rbp),%r10 * 48 8b 5d e0 mov -0x20(%rbp),%rbx * 4c 8b 65 f0 mov -0x10(%rbp),%r12 * 4c 8b 6d f8 mov -0x8(%rbp),%r13 * c9 leaveq * 49 8d 62 f8 lea -0x8(%r10),%rsp * c3 retq * * Sometimes r13 is used as the DRAP register, in which case it's saved and * restored beforehand: * * 41 55 push %r13 * 4c 8d 6c 24 10 lea 0x10(%rsp),%r13 * 48 83 e4 f0 and $0xfffffffffffffff0,%rsp * ... * 49 8d 65 f0 lea -0x10(%r13),%rsp * 41 5d pop %r13 * c3 retq */ static int update_insn_state(struct instruction *insn, struct insn_state *state) { struct stack_op *op = &insn->stack_op; struct cfi_reg *cfa = &state->cfa; struct cfi_reg *regs = state->regs; /* stack operations don't make sense with an undefined CFA */ if (cfa->base == CFI_UNDEFINED) { if (insn->func) { WARN_FUNC("undefined stack state", insn->sec, insn->offset); return -1; } return 0; } if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) return update_insn_state_regs(insn, state); switch (op->dest.type) { case OP_DEST_REG: switch (op->src.type) { case OP_SRC_REG: if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP) { if (cfa->base == CFI_SP && regs[CFI_BP].base == CFI_CFA && regs[CFI_BP].offset == -cfa->offset) { /* mov %rsp, %rbp */ cfa->base = op->dest.reg; state->bp_scratch = false; } else if (state->drap) { /* drap: mov %rsp, %rbp */ regs[CFI_BP].base = CFI_BP; regs[CFI_BP].offset = -state->stack_size; state->bp_scratch = false; } } else if (op->dest.reg == cfa->base) { /* mov %reg, %rsp */ if (cfa->base == CFI_SP && state->vals[op->src.reg].base == CFI_CFA) { /* * This is needed for the rare case * where GCC does something dumb like: * * lea 0x8(%rsp), %rcx * ... * mov %rcx, %rsp */ cfa->offset = -state->vals[op->src.reg].offset; state->stack_size = cfa->offset; } else { cfa->base = CFI_UNDEFINED; cfa->offset = 0; } } break; case OP_SRC_ADD: if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) { /* add imm, %rsp */ state->stack_size -= op->src.offset; if (cfa->base == CFI_SP) cfa->offset -= op->src.offset; break; } if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { /* lea disp(%rbp), %rsp */ state->stack_size = -(op->src.offset + regs[CFI_BP].offset); break; } if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { /* drap: lea disp(%rsp), %drap */ state->drap_reg = op->dest.reg; /* * lea disp(%rsp), %reg * * This is needed for the rare case where GCC * does something dumb like: * * lea 0x8(%rsp), %rcx * ... * mov %rcx, %rsp */ state->vals[op->dest.reg].base = CFI_CFA; state->vals[op->dest.reg].offset = \ -state->stack_size + op->src.offset; break; } if (state->drap && op->dest.reg == CFI_SP && op->src.reg == state->drap_reg) { /* drap: lea disp(%drap), %rsp */ cfa->base = CFI_SP; cfa->offset = state->stack_size = -op->src.offset; state->drap_reg = CFI_UNDEFINED; state->drap = false; break; } if (op->dest.reg == state->cfa.base) { WARN_FUNC("unsupported stack register modification", insn->sec, insn->offset); return -1; } break; case OP_SRC_AND: if (op->dest.reg != CFI_SP || (state->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || (state->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { WARN_FUNC("unsupported stack pointer realignment", insn->sec, insn->offset); return -1; } if (state->drap_reg != CFI_UNDEFINED) { /* drap: and imm, %rsp */ cfa->base = state->drap_reg; cfa->offset = state->stack_size = 0; state->drap = true; } /* * Older versions of GCC (4.8ish) realign the stack * without DRAP, with a frame pointer. */ break; case OP_SRC_POP: if (!state->drap && op->dest.type == OP_DEST_REG && op->dest.reg == cfa->base) { /* pop %rbp */ cfa->base = CFI_SP; } if (state->drap && cfa->base == CFI_BP_INDIRECT && op->dest.type == OP_DEST_REG && op->dest.reg == state->drap_reg && state->drap_offset == -state->stack_size) { /* drap: pop %drap */ cfa->base = state->drap_reg; cfa->offset = 0; state->drap_offset = -1; } else if (regs[op->dest.reg].offset == -state->stack_size) { /* pop %reg */ restore_reg(state, op->dest.reg); } state->stack_size -= 8; if (cfa->base == CFI_SP) cfa->offset -= 8; break; case OP_SRC_REG_INDIRECT: if (state->drap && op->src.reg == CFI_BP && op->src.offset == state->drap_offset) { /* drap: mov disp(%rbp), %drap */ cfa->base = state->drap_reg; cfa->offset = 0; state->drap_offset = -1; } if (state->drap && op->src.reg == CFI_BP && op->src.offset == regs[op->dest.reg].offset) { /* drap: mov disp(%rbp), %reg */ restore_reg(state, op->dest.reg); } else if (op->src.reg == cfa->base && op->src.offset == regs[op->dest.reg].offset + cfa->offset) { /* mov disp(%rbp), %reg */ /* mov disp(%rsp), %reg */ restore_reg(state, op->dest.reg); } break; default: WARN_FUNC("unknown stack-related instruction", insn->sec, insn->offset); return -1; } break; case OP_DEST_PUSH: state->stack_size += 8; if (cfa->base == CFI_SP) cfa->offset += 8; if (op->src.type != OP_SRC_REG) break; if (state->drap) { if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { /* drap: push %drap */ cfa->base = CFI_BP_INDIRECT; cfa->offset = -state->stack_size; /* save drap so we know when to restore it */ state->drap_offset = -state->stack_size; } else if (op->src.reg == CFI_BP && cfa->base == state->drap_reg) { /* drap: push %rbp */ state->stack_size = 0; } else if (regs[op->src.reg].base == CFI_UNDEFINED) { /* drap: push %reg */ save_reg(state, op->src.reg, CFI_BP, -state->stack_size); } } else { /* push %reg */ save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); } /* detect when asm code uses rbp as a scratch register */ if (!no_fp && insn->func && op->src.reg == CFI_BP && cfa->base != CFI_BP) state->bp_scratch = true; break; case OP_DEST_REG_INDIRECT: if (state->drap) { if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { /* drap: mov %drap, disp(%rbp) */ cfa->base = CFI_BP_INDIRECT; cfa->offset = op->dest.offset; /* save drap offset so we know when to restore it */ state->drap_offset = op->dest.offset; } else if (regs[op->src.reg].base == CFI_UNDEFINED) { /* drap: mov reg, disp(%rbp) */ save_reg(state, op->src.reg, CFI_BP, op->dest.offset); } } else if (op->dest.reg == cfa->base) { /* mov reg, disp(%rbp) */ /* mov reg, disp(%rsp) */ save_reg(state, op->src.reg, CFI_CFA, op->dest.offset - state->cfa.offset); } break; case OP_DEST_LEAVE: if ((!state->drap && cfa->base != CFI_BP) || (state->drap && cfa->base != state->drap_reg)) { WARN_FUNC("leave instruction with modified stack frame", insn->sec, insn->offset); return -1; } /* leave (mov %rbp, %rsp; pop %rbp) */ state->stack_size = -state->regs[CFI_BP].offset - 8; restore_reg(state, CFI_BP); if (!state->drap) { cfa->base = CFI_SP; cfa->offset -= 8; } break; case OP_DEST_MEM: if (op->src.type != OP_SRC_POP) { WARN_FUNC("unknown stack-related memory operation", insn->sec, insn->offset); return -1; } /* pop mem */ state->stack_size -= 8; if (cfa->base == CFI_SP) cfa->offset -= 8; break; default: WARN_FUNC("unknown stack-related instruction", insn->sec, insn->offset); return -1; } return 0; } static bool insn_state_match(struct instruction *insn, struct insn_state *state) { struct insn_state *state1 = &insn->state, *state2 = state; int i; if (memcmp(&state1->cfa, &state2->cfa, sizeof(state1->cfa))) { WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d", insn->sec, insn->offset, state1->cfa.base, state1->cfa.offset, state2->cfa.base, state2->cfa.offset); } else if (memcmp(&state1->regs, &state2->regs, sizeof(state1->regs))) { for (i = 0; i < CFI_NUM_REGS; i++) { if (!memcmp(&state1->regs[i], &state2->regs[i], sizeof(struct cfi_reg))) continue; WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", insn->sec, insn->offset, i, state1->regs[i].base, state1->regs[i].offset, i, state2->regs[i].base, state2->regs[i].offset); break; } } else if (state1->type != state2->type) { WARN_FUNC("stack state mismatch: type1=%d type2=%d", insn->sec, insn->offset, state1->type, state2->type); } else if (state1->drap != state2->drap || (state1->drap && state1->drap_reg != state2->drap_reg) || (state1->drap && state1->drap_offset != state2->drap_offset)) { WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", insn->sec, insn->offset, state1->drap, state1->drap_reg, state1->drap_offset, state2->drap, state2->drap_reg, state2->drap_offset); } else return true; return false; } /* * Follow the branch starting at the given instruction, and recursively follow * any other branches (jumps). Meanwhile, track the frame pointer state at * each instruction and validate all the rules described in * tools/objtool/Documentation/stack-validation.txt. */ static int validate_branch(struct objtool_file *file, struct instruction *first, struct insn_state state) { struct alternative *alt; struct instruction *insn, *next_insn; struct section *sec; struct symbol *func = NULL; int ret; insn = first; sec = insn->sec; if (insn->alt_group && list_empty(&insn->alts)) { WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", sec, insn->offset); return 1; } while (1) { next_insn = next_insn_same_sec(file, insn); if (file->c_file && func && insn->func && func != insn->func) { WARN("%s() falls through to next function %s()", func->name, insn->func->name); return 1; } if (insn->func) func = insn->func; if (func && insn->ignore) { WARN_FUNC("BUG: why am I validating an ignored function?", sec, insn->offset); return 1; } if (insn->visited) { if (!insn->hint && !insn_state_match(insn, &state)) return 1; return 0; } if (insn->hint) { if (insn->restore) { struct instruction *save_insn, *i; i = insn; save_insn = NULL; func_for_each_insn_continue_reverse(file, func, i) { if (i->save) { save_insn = i; break; } } if (!save_insn) { WARN_FUNC("no corresponding CFI save for CFI restore", sec, insn->offset); return 1; } if (!save_insn->visited) { /* * Oops, no state to copy yet. * Hopefully we can reach this * instruction from another branch * after the save insn has been * visited. */ if (insn == first) return 0; WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo", sec, insn->offset); return 1; } insn->state = save_insn->state; } state = insn->state; } else insn->state = state; insn->visited = true; list_for_each_entry(alt, &insn->alts, list) { ret = validate_branch(file, alt->insn, state); if (ret) return 1; } switch (insn->type) { case INSN_RETURN: if (func && has_modified_stack_frame(&state)) { WARN_FUNC("return with modified stack frame", sec, insn->offset); return 1; } if (state.bp_scratch) { WARN("%s uses BP as a scratch register", insn->func->name); return 1; } return 0; case INSN_CALL: if (is_fentry_call(insn)) break; ret = dead_end_function(file, insn->call_dest); if (ret == 1) return 0; if (ret == -1) return 1; /* fallthrough */ case INSN_CALL_DYNAMIC: if (!no_fp && func && !has_valid_stack_frame(&state)) { WARN_FUNC("call without frame pointer save/setup", sec, insn->offset); return 1; } break; case INSN_JUMP_CONDITIONAL: case INSN_JUMP_UNCONDITIONAL: if (insn->jump_dest && (!func || !insn->jump_dest->func || func == insn->jump_dest->func)) { ret = validate_branch(file, insn->jump_dest, state); if (ret) return 1; } else if (func && has_modified_stack_frame(&state)) { WARN_FUNC("sibling call from callable instruction with modified stack frame", sec, insn->offset); return 1; } if (insn->type == INSN_JUMP_UNCONDITIONAL) return 0; break; case INSN_JUMP_DYNAMIC: if (func && list_empty(&insn->alts) && has_modified_stack_frame(&state)) { WARN_FUNC("sibling call from callable instruction with modified stack frame", sec, insn->offset); return 1; } return 0; case INSN_CONTEXT_SWITCH: if (func && (!next_insn || !next_insn->hint)) { WARN_FUNC("unsupported instruction in callable function", sec, insn->offset); return 1; } return 0; case INSN_STACK: if (update_insn_state(insn, &state)) return 1; break; default: break; } if (insn->dead_end) return 0; insn = next_insn; if (!insn) { WARN("%s: unexpected end of section", sec->name); return 1; } } return 0; } static int validate_unwind_hints(struct objtool_file *file) { struct instruction *insn; int ret, warnings = 0; struct insn_state state; if (!file->hints) return 0; clear_insn_state(&state); for_each_insn(file, insn) { if (insn->hint && !insn->visited) { ret = validate_branch(file, insn, state); warnings += ret; } } return warnings; } static bool is_kasan_insn(struct instruction *insn) { return (insn->type == INSN_CALL && !strcmp(insn->call_dest->name, "__asan_handle_no_return")); } static bool is_ubsan_insn(struct instruction *insn) { return (insn->type == INSN_CALL && !strcmp(insn->call_dest->name, "__ubsan_handle_builtin_unreachable")); } static bool ignore_unreachable_insn(struct instruction *insn) { int i; if (insn->ignore || insn->type == INSN_NOP) return true; /* * Ignore any unused exceptions. This can happen when a whitelisted * function has an exception table entry. * * Also ignore alternative replacement instructions. This can happen * when a whitelisted function uses one of the ALTERNATIVE macros. */ if (!strcmp(insn->sec->name, ".fixup") || !strcmp(insn->sec->name, ".altinstr_replacement") || !strcmp(insn->sec->name, ".altinstr_aux")) return true; /* * Check if this (or a subsequent) instruction is related to * CONFIG_UBSAN or CONFIG_KASAN. * * End the search at 5 instructions to avoid going into the weeds. */ if (!insn->func) return false; for (i = 0; i < 5; i++) { if (is_kasan_insn(insn) || is_ubsan_insn(insn)) return true; if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { insn = insn->jump_dest; continue; } if (insn->offset + insn->len >= insn->func->offset + insn->func->len) break; insn = list_next_entry(insn, list); } return false; } static int validate_functions(struct objtool_file *file) { struct section *sec; struct symbol *func; struct instruction *insn; struct insn_state state; int ret, warnings = 0; clear_insn_state(&state); state.cfa = initial_func_cfi.cfa; memcpy(&state.regs, &initial_func_cfi.regs, CFI_NUM_REGS * sizeof(struct cfi_reg)); state.stack_size = initial_func_cfi.cfa.offset; for_each_sec(file, sec) { list_for_each_entry(func, &sec->symbol_list, list) { if (func->type != STT_FUNC) continue; insn = find_insn(file, sec, func->offset); if (!insn || insn->ignore) continue; ret = validate_branch(file, insn, state); warnings += ret; } } return warnings; } static int validate_reachable_instructions(struct objtool_file *file) { struct instruction *insn; if (file->ignore_unreachables) return 0; for_each_insn(file, insn) { if (insn->visited || ignore_unreachable_insn(insn)) continue; WARN_FUNC("unreachable instruction", insn->sec, insn->offset); return 1; } return 0; } static void cleanup(struct objtool_file *file) { struct instruction *insn, *tmpinsn; struct alternative *alt, *tmpalt; list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { list_del(&alt->list); free(alt); } list_del(&insn->list); hash_del(&insn->hash); free(insn); } elf_close(file->elf); } int check(const char *_objname, bool _no_fp, bool no_unreachable, bool orc) { struct objtool_file file; int ret, warnings = 0; objname = _objname; no_fp = _no_fp; file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); if (!file.elf) return 1; INIT_LIST_HEAD(&file.insn_list); hash_init(file.insn_hash); file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); file.rodata = find_section_by_name(file.elf, ".rodata"); file.c_file = find_section_by_name(file.elf, ".comment"); file.ignore_unreachables = no_unreachable; file.hints = false; arch_initial_func_cfi_state(&initial_func_cfi); ret = decode_sections(&file); if (ret < 0) goto out; warnings += ret; if (list_empty(&file.insn_list)) goto out; ret = validate_functions(&file); if (ret < 0) goto out; warnings += ret; ret = validate_unwind_hints(&file); if (ret < 0) goto out; warnings += ret; if (!warnings) { ret = validate_reachable_instructions(&file); if (ret < 0) goto out; warnings += ret; } if (orc) { ret = create_orc(&file); if (ret < 0) goto out; ret = create_orc_sections(&file); if (ret < 0) goto out; ret = elf_write(file.elf); if (ret < 0) goto out; } out: cleanup(&file); /* ignore warnings for now until we get all the code cleaned up */ if (ret || warnings) return 0; return 0; }