cb513bfa7a808e59505c8cdd79494116d308f3b6
[linux-2.6.git] / drivers / misc / tegra-profiler / mmap.c
1 /*
2  * drivers/misc/tegra-profiler/mmap.c
3  *
4  * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  */
16
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19 #include <linux/mm.h>
20 #include <linux/fs.h>
21 #include <linux/slab.h>
22 #include <linux/err.h>
23 #include <linux/sched.h>
24
25 #include <linux/tegra_profiler.h>
26
27 #include "mmap.h"
28 #include "comm.h"
29 #include "hrt.h"
30
31 static void
32 put_mmap_sample(struct quadd_mmap_data *s, char *filename,
33                 size_t length, unsigned long pgoff)
34 {
35         struct quadd_record_data r;
36         struct quadd_iovec vec[2];
37         u64 pgoff_val = pgoff << PAGE_SHIFT;
38
39         r.magic = QUADD_RECORD_MAGIC;
40         r.record_type = QUADD_RECORD_TYPE_MMAP;
41
42         memcpy(&r.mmap, s, sizeof(*s));
43         r.mmap.filename_length = length;
44
45         vec[0].base = &pgoff_val;
46         vec[0].len = sizeof(pgoff_val);
47
48         vec[1].base = filename;
49         vec[1].len = length;
50
51         pr_debug("MMAP: pid: %u, file_name: '%s', addr: %#llx - %#llx, len: %llx, pgoff: %#lx\n",
52                  s->pid, filename, s->addr, s->addr + s->len, s->len, pgoff);
53
54         quadd_put_sample(&r, vec, ARRAY_SIZE(vec));
55 }
56
57 void quadd_process_mmap(struct vm_area_struct *vma, pid_t pid)
58 {
59         struct file *vm_file;
60         struct path *path;
61         char *file_name, *tmp_buf;
62         struct quadd_mmap_data sample;
63         size_t length, length_aligned;
64
65         if (!vma)
66                 return;
67
68         if (!(vma->vm_flags & VM_EXEC))
69                 return;
70
71         vm_file = vma->vm_file;
72         if (!vm_file)
73                 return;
74
75         path = &vm_file->f_path;
76
77         tmp_buf = kzalloc(PATH_MAX + sizeof(u64), GFP_KERNEL);
78         if (!tmp_buf)
79                 return;
80
81         file_name = d_path(path, tmp_buf, PATH_MAX);
82         if (IS_ERR(file_name))
83                 goto out;
84
85         if (strstr(file_name, " (deleted)"))
86                 goto out;
87
88         sample.pid = pid;
89         sample.user_mode = 1;
90
91         sample.addr = vma->vm_start;
92         sample.len = vma->vm_end - vma->vm_start;
93
94         length = strlen(file_name) + 1;
95         length_aligned = ALIGN(length, sizeof(u64));
96
97         put_mmap_sample(&sample, file_name, length_aligned, vma->vm_pgoff);
98
99 out:
100         kfree(tmp_buf);
101 }
102
103 int quadd_get_current_mmap(pid_t pid)
104 {
105         struct vm_area_struct *vma;
106         struct file *vm_file;
107         struct path *path;
108         char *file_name;
109         struct task_struct *task;
110         struct mm_struct *mm;
111         struct quadd_mmap_data sample;
112         size_t length, length_aligned;
113         char *tmp_buf;
114
115         rcu_read_lock();
116         task = pid_task(find_vpid(pid), PIDTYPE_PID);
117         rcu_read_unlock();
118         if (!task) {
119                 pr_err("Process not found: %d\n", pid);
120                 return -ESRCH;
121         }
122
123         mm = task->mm;
124         if (!mm) {
125                 pr_warn("mm is not existed for task: %d\n", pid);
126                 return 0;
127         }
128
129         pr_info("Get mapped memory objects\n");
130
131         tmp_buf = kzalloc(PATH_MAX + sizeof(u64), GFP_KERNEL);
132         if (!tmp_buf)
133                 return -ENOMEM;
134
135         for (vma = mm->mmap; vma; vma = vma->vm_next) {
136                 if (!(vma->vm_flags & VM_EXEC))
137                         continue;
138
139                 vm_file = vma->vm_file;
140                 if (!vm_file)
141                         continue;
142
143                 path = &vm_file->f_path;
144
145                 file_name = d_path(path, tmp_buf, PATH_MAX);
146                 if (IS_ERR(file_name))
147                         continue;
148
149                 if (strstr(file_name, " (deleted)"))
150                         continue;
151
152                 length = strlen(file_name) + 1;
153                 length_aligned = ALIGN(length, sizeof(u64));
154
155                 sample.pid = pid;
156                 sample.user_mode = 1;
157
158                 sample.addr = vma->vm_start;
159                 sample.len = vma->vm_end - vma->vm_start;
160
161                 put_mmap_sample(&sample, file_name, length_aligned,
162                                 vma->vm_pgoff);
163         }
164         kfree(tmp_buf);
165
166         return 0;
167 }