perf annotate: Defer allocating sym_priv->hist array
[pandora-kernel.git] / tools / perf / util / map.c
1 #include "event.h"
2 #include "symbol.h"
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include "debug.h"
7
8 const char *map_type__name[MAP__NR_TYPES] = {
9         [MAP__FUNCTION] = "Functions",
10         [MAP__VARIABLE] = "Variables",
11 };
12
13 static inline int is_anon_memory(const char *filename)
14 {
15         return strcmp(filename, "//anon") == 0;
16 }
17
18 static int strcommon(const char *pathname, char *cwd, int cwdlen)
19 {
20         int n = 0;
21
22         while (n < cwdlen && pathname[n] == cwd[n])
23                 ++n;
24
25         return n;
26 }
27
28 void map__init(struct map *self, enum map_type type,
29                u64 start, u64 end, u64 pgoff, struct dso *dso)
30 {
31         self->type     = type;
32         self->start    = start;
33         self->end      = end;
34         self->pgoff    = pgoff;
35         self->dso      = dso;
36         self->map_ip   = map__map_ip;
37         self->unmap_ip = map__unmap_ip;
38         RB_CLEAR_NODE(&self->rb_node);
39 }
40
41 struct map *map__new(struct mmap_event *event, enum map_type type,
42                      char *cwd, int cwdlen)
43 {
44         struct map *self = malloc(sizeof(*self));
45
46         if (self != NULL) {
47                 const char *filename = event->filename;
48                 char newfilename[PATH_MAX];
49                 struct dso *dso;
50                 int anon;
51
52                 if (cwd) {
53                         int n = strcommon(filename, cwd, cwdlen);
54
55                         if (n == cwdlen) {
56                                 snprintf(newfilename, sizeof(newfilename),
57                                          ".%s", filename + n);
58                                 filename = newfilename;
59                         }
60                 }
61
62                 anon = is_anon_memory(filename);
63
64                 if (anon) {
65                         snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
66                         filename = newfilename;
67                 }
68
69                 dso = dsos__findnew(filename);
70                 if (dso == NULL)
71                         goto out_delete;
72
73                 map__init(self, type, event->start, event->start + event->len,
74                           event->pgoff, dso);
75
76                 if (anon) {
77 set_identity:
78                         self->map_ip = self->unmap_ip = identity__map_ip;
79                 } else if (strcmp(filename, "[vdso]") == 0) {
80                         dso__set_loaded(dso, self->type);
81                         goto set_identity;
82                 }
83         }
84         return self;
85 out_delete:
86         free(self);
87         return NULL;
88 }
89
90 void map__delete(struct map *self)
91 {
92         free(self);
93 }
94
95 void map__fixup_start(struct map *self)
96 {
97         struct rb_root *symbols = &self->dso->symbols[self->type];
98         struct rb_node *nd = rb_first(symbols);
99         if (nd != NULL) {
100                 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
101                 self->start = sym->start;
102         }
103 }
104
105 void map__fixup_end(struct map *self)
106 {
107         struct rb_root *symbols = &self->dso->symbols[self->type];
108         struct rb_node *nd = rb_last(symbols);
109         if (nd != NULL) {
110                 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
111                 self->end = sym->end;
112         }
113 }
114
115 #define DSO__DELETED "(deleted)"
116
117 int map__load(struct map *self, symbol_filter_t filter)
118 {
119         const char *name = self->dso->long_name;
120         int nr;
121
122         if (dso__loaded(self->dso, self->type))
123                 return 0;
124
125         nr = dso__load(self->dso, self, filter);
126         if (nr < 0) {
127                 if (self->dso->has_build_id) {
128                         char sbuild_id[BUILD_ID_SIZE * 2 + 1];
129
130                         build_id__sprintf(self->dso->build_id,
131                                           sizeof(self->dso->build_id),
132                                           sbuild_id);
133                         pr_warning("%s with build id %s not found",
134                                    name, sbuild_id);
135                 } else
136                         pr_warning("Failed to open %s", name);
137
138                 pr_warning(", continuing without symbols\n");
139                 return -1;
140         } else if (nr == 0) {
141                 const size_t len = strlen(name);
142                 const size_t real_len = len - sizeof(DSO__DELETED);
143
144                 if (len > sizeof(DSO__DELETED) &&
145                     strcmp(name + real_len + 1, DSO__DELETED) == 0) {
146                         pr_warning("%.*s was updated, restart the long "
147                                    "running apps that use it!\n",
148                                    (int)real_len, name);
149                 } else {
150                         pr_warning("no symbols found in %s, maybe install "
151                                    "a debug package?\n", name);
152                 }
153
154                 return -1;
155         }
156         /*
157          * Only applies to the kernel, as its symtabs aren't relative like the
158          * module ones.
159          */
160         if (self->dso->kernel)
161                 map__reloc_vmlinux(self);
162
163         return 0;
164 }
165
166 struct symbol *map__find_symbol(struct map *self, u64 addr,
167                                 symbol_filter_t filter)
168 {
169         if (map__load(self, filter) < 0)
170                 return NULL;
171
172         return dso__find_symbol(self->dso, self->type, addr);
173 }
174
175 struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
176                                         symbol_filter_t filter)
177 {
178         if (map__load(self, filter) < 0)
179                 return NULL;
180
181         if (!dso__sorted_by_name(self->dso, self->type))
182                 dso__sort_by_name(self->dso, self->type);
183
184         return dso__find_symbol_by_name(self->dso, self->type, name);
185 }
186
187 struct map *map__clone(struct map *self)
188 {
189         struct map *map = malloc(sizeof(*self));
190
191         if (!map)
192                 return NULL;
193
194         memcpy(map, self, sizeof(*self));
195
196         return map;
197 }
198
199 int map__overlap(struct map *l, struct map *r)
200 {
201         if (l->start > r->start) {
202                 struct map *t = l;
203                 l = r;
204                 r = t;
205         }
206
207         if (l->end > r->start)
208                 return 1;
209
210         return 0;
211 }
212
213 size_t map__fprintf(struct map *self, FILE *fp)
214 {
215         return fprintf(fp, " %Lx-%Lx %Lx %s\n",
216                        self->start, self->end, self->pgoff, self->dso->name);
217 }
218
219 /*
220  * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
221  * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
222  */
223 u64 map__rip_2objdump(struct map *map, u64 rip)
224 {
225         u64 addr = map->dso->adjust_symbols ?
226                         map->unmap_ip(map, rip) :       /* RIP -> IP */
227                         rip;
228         return addr;
229 }
230
231 u64 map__objdump_2ip(struct map *map, u64 addr)
232 {
233         u64 ip = map->dso->adjust_symbols ?
234                         addr :
235                         map->unmap_ip(map, addr);       /* RIP -> IP */
236         return ip;
237 }