map.c 18.8 KB
Newer Older
1
#include "symbol.h"
2
#include <errno.h>
3
#include <inttypes.h>
4
#include <limits.h>
5 6 7
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
8
#include <unistd.h>
9
#include "map.h"
10
#include "thread.h"
11
#include "strlist.h"
12
#include "vdso.h"
13
#include "build-id.h"
14
#include "util.h"
15
#include "debug.h"
16
#include "machine.h"
17
#include <linux/string.h>
18

19 20
static void __maps__insert(struct maps *maps, struct map *map);

21 22 23 24 25
const char *map_type__name[MAP__NR_TYPES] = {
	[MAP__FUNCTION] = "Functions",
	[MAP__VARIABLE] = "Variables",
};

26 27
static inline int is_anon_memory(const char *filename)
{
28
	return !strcmp(filename, "//anon") ||
29 30
	       !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
	       !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
31 32
}

33 34
static inline int is_no_dso_memory(const char *filename)
{
35
	return !strncmp(filename, "[stack", 6) ||
36
	       !strncmp(filename, "/SYSV",5)   ||
37 38 39
	       !strcmp(filename, "[heap]");
}

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
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;
}

127
void map__init(struct map *map, enum map_type type,
128
	       u64 start, u64 end, u64 pgoff, struct dso *dso)
129
{
130 131 132 133
	map->type     = type;
	map->start    = start;
	map->end      = end;
	map->pgoff    = pgoff;
134
	map->reloc    = 0;
135
	map->dso      = dso__get(dso);
136 137 138 139 140
	map->map_ip   = map__map_ip;
	map->unmap_ip = map__unmap_ip;
	RB_CLEAR_NODE(&map->rb_node);
	map->groups   = NULL;
	map->erange_warned = false;
141
	atomic_set(&map->refcnt, 1);
142 143
}

144
struct map *map__new(struct machine *machine, u64 start, u64 len,
145
		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
146
		     u64 ino_gen, u32 prot, u32 flags, char *filename,
147
		     enum map_type type, struct thread *thread)
148
{
149
	struct map *map = malloc(sizeof(*map));
150

151
	if (map != NULL) {
152
		char newfilename[PATH_MAX];
153
		struct dso *dso;
154
		int anon, no_dso, vdso, android;
155

156
		android = is_android_lib(filename);
157
		anon = is_anon_memory(filename);
158
		vdso = is_vdso_map(filename);
159
		no_dso = is_no_dso_memory(filename);
160

161 162 163 164
		map->maj = d_maj;
		map->min = d_min;
		map->ino = ino;
		map->ino_generation = ino_gen;
165 166
		map->prot = prot;
		map->flags = flags;
167

168
		if ((anon || no_dso) && type == MAP__FUNCTION) {
169
			snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
170 171 172
			filename = newfilename;
		}

173 174 175 176 177
		if (android) {
			if (replace_android_lib(filename, newfilename))
				filename = newfilename;
		}

178 179
		if (vdso) {
			pgoff = 0;
180
			dso = machine__findnew_vdso(machine, thread);
181
		} else
182
			dso = machine__findnew_dso(machine, filename);
183

184
		if (dso == NULL)
185 186
			goto out_delete;

187
		map__init(map, type, start, start + len, pgoff, dso);
188

189
		if (anon || no_dso) {
190
			map->map_ip = map->unmap_ip = identity__map_ip;
191 192 193 194 195 196

			/*
			 * Set memory without DSO as loaded. All map__find_*
			 * functions still return NULL, and we avoid the
			 * unnecessary map__load warning.
			 */
197
			if (type != MAP__FUNCTION)
198
				dso__set_loaded(dso, map->type);
199
		}
200
		dso__put(dso);
201
	}
202
	return map;
203
out_delete:
204
	free(map);
205 206 207
	return NULL;
}

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
/*
 * Constructor variant for modules (where we know from /proc/modules where
 * they are loaded) and for vmlinux, where only after we load all the
 * symbols we'll know where it starts and ends.
 */
struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
{
	struct map *map = calloc(1, (sizeof(*map) +
				     (dso->kernel ? sizeof(struct kmap) : 0)));
	if (map != NULL) {
		/*
		 * ->end will be filled after we load all the symbols
		 */
		map__init(map, type, start, 0, 0, dso);
	}

	return map;
}

227 228 229 230 231 232 233 234 235 236 237
/*
 * Use this and __map__is_kmodule() for map instances that are in
 * machine->kmaps, and thus have map->groups->machine all properly set, to
 * disambiguate between the kernel and modules.
 *
 * When the need arises, introduce map__is_{kernel,kmodule)() that
 * checks (map->groups != NULL && map->groups->machine != NULL &&
 * map->dso->kernel) before calling __map__is_{kernel,kmodule}())
 */
bool __map__is_kernel(const struct map *map)
{
238
	return __machine__kernel_map(map->groups->machine, map->type) == map;
239 240
}

241
static void map__exit(struct map *map)
242
{
243
	BUG_ON(!RB_EMPTY_NODE(&map->rb_node));
244 245 246 247 248 249
	dso__zput(map->dso);
}

void map__delete(struct map *map)
{
	map__exit(map);
250
	free(map);
251 252
}

253 254 255 256 257 258
void map__put(struct map *map)
{
	if (map && atomic_dec_and_test(&map->refcnt))
		map__delete(map);
}

259
void map__fixup_start(struct map *map)
260
{
261
	struct rb_root *symbols = &map->dso->symbols[map->type];
262
	struct rb_node *nd = rb_first(symbols);
263 264
	if (nd != NULL) {
		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
265
		map->start = sym->start;
266 267 268
	}
}

269
void map__fixup_end(struct map *map)
270
{
271
	struct rb_root *symbols = &map->dso->symbols[map->type];
272
	struct rb_node *nd = rb_last(symbols);
273 274
	if (nd != NULL) {
		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
275
		map->end = sym->end;
276 277 278
	}
}

279 280
#define DSO__DELETED "(deleted)"

281
int map__load(struct map *map, symbol_filter_t filter)
282
{
283
	const char *name = map->dso->long_name;
284
	int nr;
285

286
	if (dso__loaded(map->dso, map->type))
287 288
		return 0;

289
	nr = dso__load(map->dso, map, filter);
290
	if (nr < 0) {
291
		if (map->dso->has_build_id) {
292 293
			char sbuild_id[BUILD_ID_SIZE * 2 + 1];

294 295
			build_id__sprintf(map->dso->build_id,
					  sizeof(map->dso->build_id),
296 297 298 299 300 301 302 303 304
					  sbuild_id);
			pr_warning("%s with build id %s not found",
				   name, sbuild_id);
		} else
			pr_warning("Failed to open %s", name);

		pr_warning(", continuing without symbols\n");
		return -1;
	} else if (nr == 0) {
305
#ifdef HAVE_LIBELF_SUPPORT
306 307 308 309 310
		const size_t len = strlen(name);
		const size_t real_len = len - sizeof(DSO__DELETED);

		if (len > sizeof(DSO__DELETED) &&
		    strcmp(name + real_len + 1, DSO__DELETED) == 0) {
311 312
			pr_warning("%.*s was updated (is prelink enabled?). "
				"Restart the long running apps that use it!\n",
313 314 315 316
				   (int)real_len, name);
		} else {
			pr_warning("no symbols found in %s, maybe install "
				   "a debug package?\n", name);
317
		}
318
#endif
319
		return -1;
320 321
	}

322 323 324
	return 0;
}

325 326 327 328 329
int __weak arch__compare_symbol_names(const char *namea, const char *nameb)
{
	return strcmp(namea, nameb);
}

330
struct symbol *map__find_symbol(struct map *map, u64 addr,
331
				symbol_filter_t filter)
332
{
333
	if (map__load(map, filter) < 0)
334 335
		return NULL;

336
	return dso__find_symbol(map->dso, map->type, addr);
337 338
}

339
struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
340 341
					symbol_filter_t filter)
{
342
	if (map__load(map, filter) < 0)
343 344
		return NULL;

345 346
	if (!dso__sorted_by_name(map->dso, map->type))
		dso__sort_by_name(map->dso, map->type);
347

348
	return dso__find_symbol_by_name(map->dso, map->type, name);
349 350
}

351
struct map *map__clone(struct map *from)
352
{
353 354 355 356 357 358 359 360 361 362
	struct map *map = memdup(from, sizeof(*map));

	if (map != NULL) {
		atomic_set(&map->refcnt, 1);
		RB_CLEAR_NODE(&map->rb_node);
		dso__get(map->dso);
		map->groups = NULL;
	}

	return map;
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
}

int map__overlap(struct map *l, struct map *r)
{
	if (l->start > r->start) {
		struct map *t = l;
		l = r;
		r = t;
	}

	if (l->end > r->start)
		return 1;

	return 0;
}

379
size_t map__fprintf(struct map *map, FILE *fp)
380
{
381
	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
382
		       map->start, map->end, map->pgoff, map->dso->name);
383
}
384

385 386
size_t map__fprintf_dsoname(struct map *map, FILE *fp)
{
387
	const char *dsoname = "[unknown]";
388

389 390 391 392 393
	if (map && map->dso && (map->dso->name || map->dso->long_name)) {
		if (symbol_conf.show_kernel_path && map->dso->long_name)
			dsoname = map->dso->long_name;
		else if (map->dso->name)
			dsoname = map->dso->name;
394
	}
395 396 397 398

	return fprintf(fp, "%s", dsoname);
}

399 400 401 402 403 404 405 406
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,
407
				      map__rip_2objdump(map, addr), NULL, true);
408 409 410 411 412 413 414
		if (srcline != SRCLINE_UNKNOWN)
			ret = fprintf(fp, "%s%s", prefix, srcline);
		free_srcline(srcline);
	}
	return ret;
}

415 416 417 418 419
/**
 * map__rip_2objdump - convert symbol start address to objdump address.
 * @map: memory map
 * @rip: symbol start address
 *
420
 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
421 422
 * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
 * relative to section start.
423 424
 *
 * Return: Address suitable for passing to "objdump --start-address="
425 426 427
 */
u64 map__rip_2objdump(struct map *map, u64 rip)
{
428 429 430 431 432 433
	if (!map->dso->adjust_symbols)
		return rip;

	if (map->dso->rel)
		return rip - map->pgoff;

434
	return map->unmap_ip(map, rip) - map->reloc;
435
}
436

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
/**
 * map__objdump_2mem - convert objdump address to a memory address.
 * @map: memory map
 * @ip: objdump address
 *
 * Closely related to map__rip_2objdump(), this function takes an address from
 * objdump and converts it to a memory address.  Note this assumes that @map
 * contains the address.  To be sure the result is valid, check it forwards
 * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip
 *
 * Return: Memory address.
 */
u64 map__objdump_2mem(struct map *map, u64 ip)
{
	if (!map->dso->adjust_symbols)
		return map->unmap_ip(map, ip);

	if (map->dso->rel)
		return map->unmap_ip(map, ip + map->pgoff);

457
	return ip + map->reloc;
458 459
}

460 461 462
static void maps__init(struct maps *maps)
{
	maps->entries = RB_ROOT;
463
	pthread_rwlock_init(&maps->lock, NULL);
464 465
}

466
void map_groups__init(struct map_groups *mg, struct machine *machine)
467 468 469
{
	int i;
	for (i = 0; i < MAP__NR_TYPES; ++i) {
470
		maps__init(&mg->maps[i]);
471
	}
472
	mg->machine = machine;
473
	atomic_set(&mg->refcnt, 1);
474 475
}

476
static void __maps__purge(struct maps *maps)
477
{
478 479
	struct rb_root *root = &maps->entries;
	struct rb_node *next = rb_first(root);
480 481 482 483 484

	while (next) {
		struct map *pos = rb_entry(next, struct map, rb_node);

		next = rb_next(&pos->rb_node);
485
		rb_erase_init(&pos->rb_node, root);
486
		map__put(pos);
487 488 489
	}
}

490 491
static void maps__exit(struct maps *maps)
{
492 493 494
	pthread_rwlock_wrlock(&maps->lock);
	__maps__purge(maps);
	pthread_rwlock_unlock(&maps->lock);
495 496
}

497
void map_groups__exit(struct map_groups *mg)
498 499 500
{
	int i;

501 502
	for (i = 0; i < MAP__NR_TYPES; ++i)
		maps__exit(&mg->maps[i]);
503 504
}

505 506 507 508 509 510 511 512 513 514 515 516
bool map_groups__empty(struct map_groups *mg)
{
	int i;

	for (i = 0; i < MAP__NR_TYPES; ++i) {
		if (maps__first(&mg->maps[i]))
			return false;
	}

	return true;
}

517
struct map_groups *map_groups__new(struct machine *machine)
518 519 520 521
{
	struct map_groups *mg = malloc(sizeof(*mg));

	if (mg != NULL)
522
		map_groups__init(mg, machine);
523 524 525 526 527 528 529 530 531 532

	return mg;
}

void map_groups__delete(struct map_groups *mg)
{
	map_groups__exit(mg);
	free(mg);
}

533 534
void map_groups__put(struct map_groups *mg)
{
535
	if (mg && atomic_dec_and_test(&mg->refcnt))
536 537 538
		map_groups__delete(mg);
}

539
struct symbol *map_groups__find_symbol(struct map_groups *mg,
540
				       enum map_type type, u64 addr,
541
				       struct map **mapp,
542 543
				       symbol_filter_t filter)
{
544
	struct map *map = map_groups__find(mg, type, addr);
545

546 547
	/* Ensure map is loaded before using map->map_ip */
	if (map != NULL && map__load(map, filter) >= 0) {
548 549
		if (mapp != NULL)
			*mapp = map;
550
		return map__find_symbol(map, map->map_ip(map, addr), filter);
551 552 553 554 555
	}

	return NULL;
}

556 557
struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
					 struct map **mapp, symbol_filter_t filter)
558
{
559
	struct symbol *sym;
560 561
	struct rb_node *nd;

562 563 564
	pthread_rwlock_rdlock(&maps->lock);

	for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
565
		struct map *pos = rb_entry(nd, struct map, rb_node);
566 567

		sym = map__find_symbol_by_name(pos, name, filter);
568 569 570 571 572

		if (sym == NULL)
			continue;
		if (mapp != NULL)
			*mapp = pos;
573
		goto out;
574
	}
575

576 577 578 579
	sym = NULL;
out:
	pthread_rwlock_unlock(&maps->lock);
	return sym;
580 581
}

582 583 584 585 586 587 588 589 590 591 592
struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
					       enum map_type type,
					       const char *name,
					       struct map **mapp,
					       symbol_filter_t filter)
{
	struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp, filter);

	return sym;
}

593 594
int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
{
595
	if (ams->addr < ams->map->start || ams->addr >= ams->map->end) {
596 597 598 599 600 601 602 603 604 605 606 607 608 609
		if (ams->map->groups == NULL)
			return -1;
		ams->map = map_groups__find(ams->map->groups, ams->map->type,
					    ams->addr);
		if (ams->map == NULL)
			return -1;
	}

	ams->al_addr = ams->map->map_ip(ams->map, ams->addr);
	ams->sym = map__find_symbol(ams->map, ams->al_addr, filter);

	return ams->sym ? 0 : -1;
}

610
static size_t maps__fprintf(struct maps *maps, FILE *fp)
611
{
612
	size_t printed = 0;
613 614
	struct rb_node *nd;

615 616 617
	pthread_rwlock_rdlock(&maps->lock);

	for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
618 619 620 621
		struct map *pos = rb_entry(nd, struct map, rb_node);
		printed += fprintf(fp, "Map:");
		printed += map__fprintf(pos, fp);
		if (verbose > 2) {
622
			printed += dso__fprintf(pos->dso, pos->type, fp);
623 624 625 626
			printed += fprintf(fp, "--\n");
		}
	}

627 628
	pthread_rwlock_unlock(&maps->lock);

629 630 631
	return printed;
}

632 633 634 635 636 637 638
size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
				  FILE *fp)
{
	size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
	return printed += maps__fprintf(&mg->maps[type], fp);
}

639
size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
640 641 642
{
	size_t printed = 0, i;
	for (i = 0; i < MAP__NR_TYPES; ++i)
643
		printed += __map_groups__fprintf_maps(mg, i, fp);
644 645 646
	return printed;
}

647 648 649 650 651 652
static void __map_groups__insert(struct map_groups *mg, struct map *map)
{
	__maps__insert(&mg->maps[map->type], map);
	map->groups = mg;
}

653
static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
654
{
655 656
	struct rb_root *root;
	struct rb_node *next;
657
	int err = 0;
658

659 660 661 662 663
	pthread_rwlock_wrlock(&maps->lock);

	root = &maps->entries;
	next = rb_first(root);

664 665 666 667 668 669 670 671 672 673 674 675 676
	while (next) {
		struct map *pos = rb_entry(next, struct map, rb_node);
		next = rb_next(&pos->rb_node);

		if (!map__overlap(pos, map))
			continue;

		if (verbose >= 2) {
			fputs("overlapping maps:\n", fp);
			map__fprintf(map, fp);
			map__fprintf(pos, fp);
		}

677
		rb_erase_init(&pos->rb_node, root);
678 679 680 681 682 683 684
		/*
		 * Now check if we need to create new maps for areas not
		 * overlapped by the new map:
		 */
		if (map->start > pos->start) {
			struct map *before = map__clone(pos);

685 686
			if (before == NULL) {
				err = -ENOMEM;
687
				goto put_map;
688
			}
689

690
			before->end = map->start;
691
			__map_groups__insert(pos->groups, before);
692 693 694 695 696 697 698
			if (verbose >= 2)
				map__fprintf(before, fp);
		}

		if (map->end < pos->end) {
			struct map *after = map__clone(pos);

699 700
			if (after == NULL) {
				err = -ENOMEM;
701
				goto put_map;
702
			}
703

704
			after->start = map->end;
705
			__map_groups__insert(pos->groups, after);
706 707 708
			if (verbose >= 2)
				map__fprintf(after, fp);
		}
709
put_map:
710
		map__put(pos);
711 712

		if (err)
713
			goto out;
714 715
	}

716 717 718 719 720 721 722 723 724 725
	err = 0;
out:
	pthread_rwlock_unlock(&maps->lock);
	return err;
}

int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
				   FILE *fp)
{
	return maps__fixup_overlappings(&mg->maps[map->type], map, fp);
726 727 728 729 730
}

/*
 * XXX This should not really _copy_ te maps, but refcount them.
 */
731
int map_groups__clone(struct map_groups *mg,
732 733
		      struct map_groups *parent, enum map_type type)
{
734
	int err = -ENOMEM;
735
	struct map *map;
736
	struct maps *maps = &parent->maps[type];
737

738 739
	pthread_rwlock_rdlock(&maps->lock);

740
	for (map = maps__first(maps); map; map = map__next(map)) {
741 742
		struct map *new = map__clone(map);
		if (new == NULL)
743
			goto out_unlock;
744
		map_groups__insert(mg, new);
745
	}
746 747 748 749 750

	err = 0;
out_unlock:
	pthread_rwlock_unlock(&maps->lock);
	return err;
751 752
}

753
static void __maps__insert(struct maps *maps, struct map *map)
754
{
755
	struct rb_node **p = &maps->entries.rb_node;
756 757 758 759 760 761 762 763 764 765 766 767 768 769
	struct rb_node *parent = NULL;
	const u64 ip = map->start;
	struct map *m;

	while (*p != NULL) {
		parent = *p;
		m = rb_entry(parent, struct map, rb_node);
		if (ip < m->start)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&map->rb_node, parent, p);
770
	rb_insert_color(&map->rb_node, &maps->entries);
771
	map__get(map);
772 773
}

774 775 776 777 778 779 780 781
void maps__insert(struct maps *maps, struct map *map)
{
	pthread_rwlock_wrlock(&maps->lock);
	__maps__insert(maps, map);
	pthread_rwlock_unlock(&maps->lock);
}

static void __maps__remove(struct maps *maps, struct map *map)
782
{
783
	rb_erase_init(&map->rb_node, &maps->entries);
784
	map__put(map);
785 786
}

787 788 789 790 791 792 793
void maps__remove(struct maps *maps, struct map *map)
{
	pthread_rwlock_wrlock(&maps->lock);
	__maps__remove(maps, map);
	pthread_rwlock_unlock(&maps->lock);
}

794
struct map *maps__find(struct maps *maps, u64 ip)
795
{
796
	struct rb_node **p, *parent = NULL;
797 798
	struct map *m;

799 800 801
	pthread_rwlock_rdlock(&maps->lock);

	p = &maps->entries.rb_node;
802 803 804 805 806
	while (*p != NULL) {
		parent = *p;
		m = rb_entry(parent, struct map, rb_node);
		if (ip < m->start)
			p = &(*p)->rb_left;
807
		else if (ip >= m->end)
808 809
			p = &(*p)->rb_right;
		else
810
			goto out;
811 812
	}

813 814 815 816
	m = NULL;
out:
	pthread_rwlock_unlock(&maps->lock);
	return m;
817
}
818

819
struct map *maps__first(struct maps *maps)
820
{
821
	struct rb_node *first = rb_first(&maps->entries);
822 823 824 825 826 827

	if (first)
		return rb_entry(first, struct map, rb_node);
	return NULL;
}

828
struct map *map__next(struct map *map)
829 830 831 832 833 834 835
{
	struct rb_node *next = rb_next(&map->rb_node);

	if (next)
		return rb_entry(next, struct map, rb_node);
	return NULL;
}
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855

struct kmap *map__kmap(struct map *map)
{
	if (!map->dso || !map->dso->kernel) {
		pr_err("Internal error: map__kmap with a non-kernel map\n");
		return NULL;
	}
	return (struct kmap *)(map + 1);
}

struct map_groups *map__kmaps(struct map *map)
{
	struct kmap *kmap = map__kmap(map);

	if (!kmap || !kmap->kmaps) {
		pr_err("Internal error: map__kmaps with a non-kernel map\n");
		return NULL;
	}
	return kmap->kmaps;
}