diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 4a9fe228be2aa8e4b7b1d71bf857a7a8c7b6732c..a02fc4146017b94f65da3bf92683c00e2d9c45a5 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -318,7 +318,7 @@ static void show_details(struct sym_entry *syme)
 }
 
 /*
- * Symbols will be added here in record_ip and will get out
+ * Symbols will be added here in event__process_sample and will get out
  * after decayed.
  */
 static LIST_HEAD(active_symbols);
@@ -459,18 +459,18 @@ static void print_sym_table(void)
 	}
 
 	if (nr_counters == 1)
-		printf("             samples    pcnt");
+		printf("             samples  pcnt");
 	else
-		printf("   weight    samples    pcnt");
+		printf("   weight    samples  pcnt");
 
 	if (verbose)
 		printf("         RIP       ");
-	printf("   kernel function\n");
-	printf("   %s    _______   _____",
+	printf(" function                                 DSO\n");
+	printf("   %s    _______ _____",
 	       nr_counters == 1 ? "      " : "______");
 	if (verbose)
-		printf("   ________________");
-	printf("   _______________\n\n");
+		printf(" ________________");
+	printf(" ________________________________ ________________\n\n");
 
 	for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
 		struct symbol *sym;
@@ -486,16 +486,15 @@ static void print_sym_table(void)
 					 sum_ksamples));
 
 		if (nr_counters == 1 || !display_weighted)
-			printf("%20.2f - ", syme->weight);
+			printf("%20.2f ", syme->weight);
 		else
-			printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
+			printf("%9.1f %10ld ", syme->weight, syme->snap_count);
 
 		percent_color_fprintf(stdout, "%4.1f%%", pcnt);
 		if (verbose)
-			printf(" - %016llx", sym->start);
-		printf(" : %s", sym->name);
-		if (syme->map->dso->name[0] == '[')
-			printf(" \t%s", syme->map->dso->name);
+			printf(" %016llx", sym->start);
+		printf(" %-32s", sym->name);
+		printf(" %s", syme->map->dso->short_name);
 		printf("\n");
 	}
 }
@@ -818,41 +817,97 @@ static int parse_symbols(void)
 	return 0;
 }
 
-/*
- * Binary search in the histogram table and record the hit:
- */
-static void record_ip(u64 ip, int counter)
+static void event__process_sample(const event_t *self, int counter)
 {
+	u64 ip = self->ip.ip;
 	struct map *map;
-	struct symbol *sym = kernel_maps__find_symbol(ip, &map);
-
-	if (sym != NULL) {
-		struct sym_entry *syme = dso__sym_priv(map->dso, sym);
-
-		if (!syme->skip) {
-			syme->count[counter]++;
-			record_precise_ip(syme, counter, ip);
-			pthread_mutex_lock(&active_symbols_lock);
-			if (list_empty(&syme->node) || !syme->node.next)
-				__list_insert_active_sym(syme);
-			pthread_mutex_unlock(&active_symbols_lock);
+	struct sym_entry *syme;
+	struct symbol *sym;
+
+	switch (self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) {
+	case PERF_RECORD_MISC_USER: {
+		struct thread *thread = threads__findnew(self->ip.pid);
+
+		if (thread == NULL)
 			return;
+
+		map = thread__find_map(thread, ip);
+		if (map != NULL) {
+			ip = map->map_ip(map, ip);
+			sym = map->dso->find_symbol(map->dso, ip);
+			if (sym == NULL)
+				return;
+			userspace_samples++;
+			break;
 		}
 	}
+		/*
+		 * If this is outside of all known maps,
+		 * and is a negative address, try to look it
+		 * up in the kernel dso, as it might be a
+		 * vsyscall or vdso (which executes in user-mode).
+		 */
+		if ((long long)ip >= 0)
+			return;
+		/* Fall thru */
+	case PERF_RECORD_MISC_KERNEL:
+		sym = kernel_maps__find_symbol(ip, &map);
+		if (sym == NULL)
+			return;
+		break;
+	default:
+		return;
+	}
+
+	syme = dso__sym_priv(map->dso, sym);
 
-	samples--;
+	if (!syme->skip) {
+		syme->count[counter]++;
+		record_precise_ip(syme, counter, ip);
+		pthread_mutex_lock(&active_symbols_lock);
+		if (list_empty(&syme->node) || !syme->node.next)
+			__list_insert_active_sym(syme);
+		pthread_mutex_unlock(&active_symbols_lock);
+		++samples;
+		return;
+	}
 }
 
-static void process_event(u64 ip, int counter, int user)
+static void event__process_mmap(event_t *self)
 {
-	samples++;
+	struct thread *thread = threads__findnew(self->mmap.pid);
+
+	if (thread != NULL) {
+		struct map *map = map__new(&self->mmap, NULL, 0,
+					   sizeof(struct sym_entry),
+					   symbol_filter);
+		if (map != NULL)
+			thread__insert_map(thread, map);
+	}
+}
 
-	if (user) {
-		userspace_samples++;
-		return;
+static void event__process_comm(event_t *self)
+{
+	struct thread *thread = threads__findnew(self->comm.pid);
+
+	if (thread != NULL)
+		thread__set_comm(thread, self->comm.comm);
+}
+
+static int event__process(event_t *event)
+{
+	switch (event->header.type) {
+	case PERF_RECORD_COMM:
+		event__process_comm(event);
+		break;
+	case PERF_RECORD_MMAP:
+		event__process_mmap(event);
+		break;
+	default:
+		break;
 	}
 
-	record_ip(ip, counter);
+	return 0;
 }
 
 struct mmap_data {
@@ -925,13 +980,11 @@ static void mmap_read_counter(struct mmap_data *md)
 			event = &event_copy;
 		}
 
+		if (event->header.type == PERF_RECORD_SAMPLE)
+			event__process_sample(event, md->counter);
+		else
+			event__process(event);
 		old += size;
-
-		if (event->header.type == PERF_RECORD_SAMPLE) {
-			int user =
-	(event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
-			process_event(event->ip.ip, md->counter, user);
-		}
 	}
 
 	md->prev = old;
@@ -973,6 +1026,7 @@ static void start_counter(int i, int counter)
 	}
 
 	attr->inherit		= (cpu < 0) && inherit;
+	attr->mmap		= 1;
 
 try_again:
 	fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -1031,6 +1085,11 @@ static int __cmd_top(void)
 	int i, counter;
 	int ret;
 
+	if (target_pid != -1)
+		event__synthesize_thread(target_pid, event__process);
+	else
+		event__synthesize_threads(event__process);
+
 	for (i = 0; i < nr_cpus; i++) {
 		group_fd = -1;
 		for (counter = 0; counter < nr_counters; counter++)