 7dbf4dcfe2
			
		
	
	
	7dbf4dcfe2
	
	
	
		
			
			Storing data for VDSO shared object, because we need it for the post
unwind processing.
The VDSO shared object is same for all process on a running system, so
it makes no difference when we store it inside the tracer - perf.
When [vdso] map memory is hit, we retrieve [vdso] DSO image and store it
into temporary file.
During the build-id processing phase, the [vdso] DSO image is stored in
build-id db, and build-id reference is made inside perf.data. The
build-id vdso file object is called '[vdso]'. We don't use temporary
file name which gets removed when record is finished.
During report phase the vdso build-id object is treated as any other
build-id DSO object.
Adding following API for vdso object:
  bool is_vdso_map(const char *filename)
    - returns true if the filename matches vdso map name
  struct dso *vdso__dso_findnew(struct list_head *head)
    - find/create proper vdso DSO object
  vdso__exit(void)
    - removes temporary VDSO image if there's any
This change makes backtrace dwarf post unwind possible from [vdso] maps.
Following output is current report of [vdso] sample dwarf backtrace:
  # Overhead  Command      Shared Object                         Symbol
  # ........  .......  .................  .............................
  #
      99.52%       ex  [vdso]             [.] 0x00007fff3ace89af
                   |
                   --- 0x7fff3ace89af
Following output is new report of [vdso] sample dwarf backtrace:
  # Overhead  Command      Shared Object                         Symbol
  # ........  .......  .................  .............................
  #
      99.52%       ex  [vdso]             [.] 0x00000000000009af
                   |
                   --- 0x7fff3ace89af
                       main
                       __libc_start_main
                       _start
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1347295819-23177-5-git-send-email-jolsa@redhat.com
[ committer note: s/ALIGN/PERF_ALIGN/g to cope with the android build changes ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
		
	
			
		
			
				
	
	
		
			111 lines
		
	
	
	
		
			1.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
	
		
			1.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| #include <unistd.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <stdlib.h>
 | |
| #include <linux/kernel.h>
 | |
| 
 | |
| #include "vdso.h"
 | |
| #include "util.h"
 | |
| #include "symbol.h"
 | |
| #include "linux/string.h"
 | |
| 
 | |
| static bool vdso_found;
 | |
| static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
 | |
| 
 | |
| static int find_vdso_map(void **start, void **end)
 | |
| {
 | |
| 	FILE *maps;
 | |
| 	char line[128];
 | |
| 	int found = 0;
 | |
| 
 | |
| 	maps = fopen("/proc/self/maps", "r");
 | |
| 	if (!maps) {
 | |
| 		pr_err("vdso: cannot open maps\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	while (!found && fgets(line, sizeof(line), maps)) {
 | |
| 		int m = -1;
 | |
| 
 | |
| 		/* We care only about private r-x mappings. */
 | |
| 		if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
 | |
| 				start, end, &m))
 | |
| 			continue;
 | |
| 		if (m < 0)
 | |
| 			continue;
 | |
| 
 | |
| 		if (!strncmp(&line[m], VDSO__MAP_NAME,
 | |
| 			     sizeof(VDSO__MAP_NAME) - 1))
 | |
| 			found = 1;
 | |
| 	}
 | |
| 
 | |
| 	fclose(maps);
 | |
| 	return !found;
 | |
| }
 | |
| 
 | |
| static char *get_file(void)
 | |
| {
 | |
| 	char *vdso = NULL;
 | |
| 	char *buf = NULL;
 | |
| 	void *start, *end;
 | |
| 	size_t size;
 | |
| 	int fd;
 | |
| 
 | |
| 	if (vdso_found)
 | |
| 		return vdso_file;
 | |
| 
 | |
| 	if (find_vdso_map(&start, &end))
 | |
| 		return NULL;
 | |
| 
 | |
| 	size = end - start;
 | |
| 
 | |
| 	buf = memdup(start, size);
 | |
| 	if (!buf)
 | |
| 		return NULL;
 | |
| 
 | |
| 	fd = mkstemp(vdso_file);
 | |
| 	if (fd < 0)
 | |
| 		goto out;
 | |
| 
 | |
| 	if (size == (size_t) write(fd, buf, size))
 | |
| 		vdso = vdso_file;
 | |
| 
 | |
| 	close(fd);
 | |
| 
 | |
|  out:
 | |
| 	free(buf);
 | |
| 
 | |
| 	vdso_found = (vdso != NULL);
 | |
| 	return vdso;
 | |
| }
 | |
| 
 | |
| void vdso__exit(void)
 | |
| {
 | |
| 	if (vdso_found)
 | |
| 		unlink(vdso_file);
 | |
| }
 | |
| 
 | |
| struct dso *vdso__dso_findnew(struct list_head *head)
 | |
| {
 | |
| 	struct dso *dso = dsos__find(head, VDSO__MAP_NAME);
 | |
| 
 | |
| 	if (!dso) {
 | |
| 		char *file;
 | |
| 
 | |
| 		file = get_file();
 | |
| 		if (!file)
 | |
| 			return NULL;
 | |
| 
 | |
| 		dso = dso__new(VDSO__MAP_NAME);
 | |
| 		if (dso != NULL) {
 | |
| 			dsos__add(head, dso);
 | |
| 			dso__set_long_name(dso, file);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return dso;
 | |
| }
 |