aboutsummaryrefslogtreecommitdiff
path: root/tools/perf/util/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/map.c')
-rw-r--r--tools/perf/util/map.c151
1 files changed, 144 insertions, 7 deletions
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index ef5bc913ca7..25c571f4cba 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -11,6 +11,7 @@
#include "strlist.h"
#include "vdso.h"
#include "build-id.h"
+#include "util.h"
#include <linux/string.h>
const char *map_type__name[MAP__NR_TYPES] = {
@@ -31,6 +32,93 @@ static inline int is_no_dso_memory(const char *filename)
!strcmp(filename, "[heap]");
}
+static inline int is_android_lib(const char *filename)
+{
+ return !strncmp(filename, "/data/app-lib", 13) ||
+ !strncmp(filename, "/system/lib", 11);
+}
+
+static inline bool replace_android_lib(const char *filename, char *newfilename)
+{
+ const char *libname;
+ char *app_abi;
+ size_t app_abi_length, new_length;
+ size_t lib_length = 0;
+
+ libname = strrchr(filename, '/');
+ if (libname)
+ lib_length = strlen(libname);
+
+ app_abi = getenv("APP_ABI");
+ if (!app_abi)
+ return false;
+
+ app_abi_length = strlen(app_abi);
+
+ if (!strncmp(filename, "/data/app-lib", 13)) {
+ char *apk_path;
+
+ if (!app_abi_length)
+ return false;
+
+ new_length = 7 + app_abi_length + lib_length;
+
+ apk_path = getenv("APK_PATH");
+ if (apk_path) {
+ new_length += strlen(apk_path) + 1;
+ if (new_length > PATH_MAX)
+ return false;
+ snprintf(newfilename, new_length,
+ "%s/libs/%s/%s", apk_path, app_abi, libname);
+ } else {
+ if (new_length > PATH_MAX)
+ return false;
+ snprintf(newfilename, new_length,
+ "libs/%s/%s", app_abi, libname);
+ }
+ return true;
+ }
+
+ if (!strncmp(filename, "/system/lib/", 11)) {
+ char *ndk, *app;
+ const char *arch;
+ size_t ndk_length;
+ size_t app_length;
+
+ ndk = getenv("NDK_ROOT");
+ app = getenv("APP_PLATFORM");
+
+ if (!(ndk && app))
+ return false;
+
+ ndk_length = strlen(ndk);
+ app_length = strlen(app);
+
+ if (!(ndk_length && app_length && app_abi_length))
+ return false;
+
+ arch = !strncmp(app_abi, "arm", 3) ? "arm" :
+ !strncmp(app_abi, "mips", 4) ? "mips" :
+ !strncmp(app_abi, "x86", 3) ? "x86" : NULL;
+
+ if (!arch)
+ return false;
+
+ new_length = 27 + ndk_length +
+ app_length + lib_length
+ + strlen(arch);
+
+ if (new_length > PATH_MAX)
+ return false;
+ snprintf(newfilename, new_length,
+ "%s/platforms/%s/arch-%s/usr/lib/%s",
+ ndk, app, arch, libname);
+
+ return true;
+ }
+ return false;
+}
+
void map__init(struct map *map, enum map_type type,
u64 start, u64 end, u64 pgoff, struct dso *dso)
{
@@ -38,6 +126,7 @@ void map__init(struct map *map, enum map_type type,
map->start = start;
map->end = end;
map->pgoff = pgoff;
+ map->reloc = 0;
map->dso = dso;
map->map_ip = map__map_ip;
map->unmap_ip = map__unmap_ip;
@@ -49,7 +138,7 @@ void map__init(struct map *map, enum map_type type,
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
- u64 ino_gen, char *filename,
+ u64 ino_gen, u32 prot, u32 flags, char *filename,
enum map_type type)
{
struct map *map = malloc(sizeof(*map));
@@ -57,8 +146,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
if (map != NULL) {
char newfilename[PATH_MAX];
struct dso *dso;
- int anon, no_dso, vdso;
+ int anon, no_dso, vdso, android;
+ android = is_android_lib(filename);
anon = is_anon_memory(filename);
vdso = is_vdso_map(filename);
no_dso = is_no_dso_memory(filename);
@@ -67,12 +157,19 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
map->min = d_min;
map->ino = ino;
map->ino_generation = ino_gen;
+ map->prot = prot;
+ map->flags = flags;
- if (anon) {
+ if ((anon || no_dso) && type == MAP__FUNCTION) {
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
filename = newfilename;
}
+ if (android) {
+ if (replace_android_lib(filename, newfilename))
+ filename = newfilename;
+ }
+
if (vdso) {
pgoff = 0;
dso = vdso__dso_findnew(dsos__list);
@@ -92,7 +189,7 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
* functions still return NULL, and we avoid the
* unnecessary map__load warning.
*/
- if (no_dso)
+ if (type != MAP__FUNCTION)
dso__set_loaded(dso, map->type);
}
}
@@ -252,6 +349,22 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
return fprintf(fp, "%s", dsoname);
}
+int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
+ FILE *fp)
+{
+ char *srcline;
+ int ret = 0;
+
+ if (map && map->dso) {
+ srcline = get_srcline(map->dso,
+ map__rip_2objdump(map, addr));
+ if (srcline != SRCLINE_UNKNOWN)
+ ret = fprintf(fp, "%s%s", prefix, srcline);
+ free_srcline(srcline);
+ }
+ return ret;
+}
+
/**
* map__rip_2objdump - convert symbol start address to objdump address.
* @map: memory map
@@ -271,7 +384,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip)
if (map->dso->rel)
return rip - map->pgoff;
- return map->unmap_ip(map, rip);
+ return map->unmap_ip(map, rip) - map->reloc;
}
/**
@@ -294,7 +407,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
if (map->dso->rel)
return map->unmap_ip(map, ip + map->pgoff);
- return ip;
+ return ip + map->reloc;
}
void map_groups__init(struct map_groups *mg)
@@ -305,6 +418,7 @@ void map_groups__init(struct map_groups *mg)
INIT_LIST_HEAD(&mg->removed_maps[i]);
}
mg->machine = NULL;
+ mg->refcnt = 1;
}
static void maps__delete(struct rb_root *maps)
@@ -340,6 +454,28 @@ void map_groups__exit(struct map_groups *mg)
}
}
+struct map_groups *map_groups__new(void)
+{
+ struct map_groups *mg = malloc(sizeof(*mg));
+
+ if (mg != NULL)
+ map_groups__init(mg);
+
+ return mg;
+}
+
+void map_groups__delete(struct map_groups *mg)
+{
+ map_groups__exit(mg);
+ free(mg);
+}
+
+void map_groups__put(struct map_groups *mg)
+{
+ if (--mg->refcnt == 0)
+ map_groups__delete(mg);
+}
+
void map_groups__flush(struct map_groups *mg)
{
int type;
@@ -369,7 +505,8 @@ struct symbol *map_groups__find_symbol(struct map_groups *mg,
{
struct map *map = map_groups__find(mg, type, addr);
- if (map != NULL) {
+ /* Ensure map is loaded before using map->map_ip */
+ if (map != NULL && map__load(map, filter) >= 0) {
if (mapp != NULL)
*mapp = map;
return map__find_symbol(map, map->map_ip(map, addr), filter);