<commit_before>#define _GNU_SOURCE
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include "symbol.h"
#include "strlist.h"

#include <libelf.h>
#include <gelf.h>
#include <elf.h>
#include <limits.h>
#include <sys/utsname.h>

#ifndef NT_GNU_BUILD_ID
#define NT_GNU_BUILD_ID 3
#endif

static void dsos__add(struct list_head *head, struct dso *dso);
static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static int dso__load_kernel_sym(struct dso *self, struct map *map,
				symbol_filter_t filter);
static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
			symbol_filter_t filter);
static int vmlinux_path__nr_entries;
static char **vmlinux_path;

struct symbol_conf symbol_conf = {
	.exclude_other	  = true,
	.use_modules	  = true,
	.try_vmlinux_path = true,
};

bool dso__loaded(const struct dso *self, enum map_type type)
{
	return self->loaded & (1 << type);
}

bool dso__sorted_by_name(const struct dso *self, enum map_type type)
{
	return self->sorted_by_name & (1 << type);
}

static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
{
	self->sorted_by_name |= (1 << type);
}

bool symbol_type__is_a(char symbol_type, enum map_type map_type)
{
	switch (map_type) {
	case MAP__FUNCTION:
		return symbol_type == 'T' || symbol_type == 'W';
	case MAP__VARIABLE:
		return symbol_type == 'D' || symbol_type == 'd';
	default:
		return false;
	}
}

static void symbols__fixup_end(struct rb_root *self)
{
	struct rb_node *nd, *prevnd = rb_first(self);
	struct symbol *curr, *prev;

	if (prevnd == NULL)
		return;

	curr = rb_entry(prevnd, struct symbol, rb_node);

	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
		prev = curr;
		curr = rb_entry(nd, struct symbol, rb_node);

		if (prev->end == prev->start)
			prev->end = curr->start - 1;
	}

	/* Last entry */
	if (curr->end == curr->start)
		curr->end = roundup(curr->start, 4096);
}

static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
{
	struct map *prev, *curr;
	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);

	if (prevnd == NULL)
		return;

	curr = rb_entry(prevnd, struct map, rb_node);

	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
		prev = curr;
		curr = rb_entry(nd, struct map, rb_node);
		prev->end = curr->start - 1;
	}

	/*
	 * We still haven't the actual symbols, so guess the
	 * last map final address.
	 */
	curr->end = ~0UL;
}

static void map_groups__fixup_end(struct map_groups *self)
{
	int i;
	for (i = 0; i < MAP__NR_TYPES; ++i)
		__map_groups__fixup_end(self, i);
}

static struct symbol *symbol__new(u64 start, u64 len, const char *name)
{
	size_t namelen = strlen(name) + 1;
	struct symbol *self = calloc(1, (symbol_conf.priv_size +
					 sizeof(*self) + namelen));
	if (self == NULL)
		return NULL;

	if (symbol_conf.priv_size)
		self = ((void *)self) + symbol_conf.priv_size;

	self->start   = start;
	self->end     = len ? start + len - 1 : start;
	self->namelen = namelen - 1;

	pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);

	memcpy(self->name, name, namelen);

	return self;
}

void symbol__delete(struct symbol *self)
{
	free(((void *)self) - symbol_conf.priv_size);
}

static size_t symbol__fprintf(struct symbol *self, FILE *fp)
{
	return fprintf(fp, " %llx-%llx %s\n",
		       self->start, self->end, self->name);
}

void dso__set_long_name(struct dso *self, char *name)
{
	if (name == NULL)
		return;
	self->long_name = name;
	self->long_name_len = strlen(name);
}

static void dso__set_short_name(struct dso *self, const char *name)
{
	if (name == NULL)
		return;
	self->short_name = name;
	self->short_name_len = strlen(name);
}

static void dso__set_basename(struct dso *self)
{
	dso__set_short_name(self, basename(self->long_name));
}

struct dso *dso__new(const char *name)
{
	struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);

	if (self != NULL) {
		int i;
		strcpy(self->name, name);
		dso__set_long_name(self, self->name);
		dso__set_short_name(self, self->name);
		for (i = 0; i < MAP__NR_TYPES; ++i)
			self->symbols[i] = self->symbol_names[i] = RB_ROOT;
		self->slen_calculated = 0;
		self->origin = DSO__ORIG_NOT_FOUND;
		self->loaded = 0;
		self->sorted_by_name = 0;
		self->has_build_id = 0;
		self->kernel = DSO_TYPE_USER;
		INIT_LIST_HEAD(&self->node);
	}

	return self;
}

static void symbols__delete(struct rb_root *self)
{
	struct symbol *pos;
	struct rb_node *next = rb_first(self);

	while (next) {
		pos = rb_entry(next, struct symbol, rb_node);
		next = rb_next(&pos->rb_node);
		rb_erase(&pos->rb_node, self);
		symbol__delete(pos);
	}
}

void dso__delete(struct dso *self)
{
	int i;
	for (i = 0; i < MAP__NR_TYPES; ++i)
		symbols__delete(&self->symbols[i]);
	if (self->long_name != self->name)
		free(self->long_name);
	free(self);
}

void dso__set_build_id(struct dso *self, void *build_id)
{
	memcpy(self->build_id, build_id, sizeof(self->build_id));
	self->has_build_id = 1;
}

static void symbols__insert(struct rb_root *self, struct symbol *sym)
{
	struct rb_node **p = &self->rb_node;
	struct rb_node *parent = NULL;
	const u64 ip = sym->start;
	struct symbol *s;

	while (*p != NULL) {
		parent = *p;
		s = rb_entry(parent, struct symbol, rb_node);
		if (ip < s->start)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}
	rb_link_node(&sym->rb_node, parent, p);
	rb_insert_color(&sym->rb_node, self);
}

static struct symbol *symbols__find(struct rb_root *self, u64 ip)
{
	struct rb_node *n;

	if (self == NULL)
		return NULL;

	n = self->rb_node;

	while (n) {
		struct symbol *s = rb_entry(n, struct symbol, rb_node);

		if (ip < s->start)
			n = n->rb_left;
		else if (ip > s->end)
			n = n->rb_right;
		else
			return s;
	}

	return NULL;
}

struct symbol_name_rb_node {
	struct rb_node	rb_node;
	struct symbol	sym;
};

static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
{
	struct rb_node **p = &self->rb_node;
	struct rb_node *parent = NULL;
	struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;

	while (*p != NULL) {
		parent = *p;
		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
		if (strcmp(sym->name, s->sym.name) < 0)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}
	rb_link_node(&symn->rb_node, parent, p);
	rb_insert_color(&symn->rb_node, self);
}

static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
{
	struct rb_node *nd;

	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
		symbols__insert_by_name(self, pos);
	}
}

static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
{
	struct rb_node *n;

	if (self == NULL)
		return NULL;

	n = self->rb_node;

	while (n) {
		struct symbol_name_rb_node *s;
		int cmp;

		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
		cmp = strcmp(name, s->sym.name);

		if (cmp < 0)
			n = n->rb_left;
		else if (cmp > 0)
			n = n->rb_right;
		else
			return &s->sym;
	}

	return NULL;
}

struct symbol *dso__find_symbol(struct dso *self,
				enum map_type type, u64 addr)
{
	return symbols__find(&self->symbols[type], addr);
}

struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
					const char *name)
{
	return symbols__find_by_name(&self->symbol_names[type], name);
}

void dso__sort_by_name(struct dso *self, enum map_type type)
{
	dso__set_sorted_by_name(self, type);
	return symbols__sort_by_name(&self->symbol_names[type],
				     &self->symbols[type]);
}

int build_id__sprintf(const u8 *self, int len, char *bf)
{
	char *bid = bf;
	const u8 *raw = self;
	int i;

	for (i = 0; i < len; ++i) {
		sprintf(bid, "%02x", *raw);
		++raw;
		bid += 2;
	}

	return raw - self;
}

size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
{
	char sbuild_id[BUILD_ID_SIZE * 2 + 1];

	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
	return fprintf(fp, "%s", sbuild_id);
}

size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
{
	struct rb_node *nd;
	size_t ret = fprintf(fp, "dso: %s (", self->short_name);

	if (self->short_name != self->long_name)
		ret += fprintf(fp, "%s, ", self->long_name);
	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
		       self->loaded ? "" : "NOT ");
	ret += dso__fprintf_buildid(self, fp);
	ret += fprintf(fp, ")\n");
	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
		ret += symbol__fprintf(pos, fp);
	}

	return ret;
}

int kallsyms__parse(const char *filename, void *arg,
		    int (*process_symbol)(void *arg, const char *name,
						     char type, u64 start))
{
	char *line = NULL;
	size_t n;
	int err = 0;
	FILE *file = fopen(filename, "r");

	if (file == NULL)
		goto out_failure;

	while (!feof(file)) {
		u64 start;
		int line_len, len;
		char symbol_type;
		char *symbol_name;

		line_len = getline(&line, &n, file);
		if (line_len < 0 || !line)
			break;

		line[--line_len] = '\0'; /* \n */

		len = hex2u64(line, &start);

		len++;
		if (len + 2 >= line_len)
			continue;

		symbol_type = toupper(line[len]);
		symbol_name = line + len + 2;

		err = process_symbol(arg, symbol_name, symbol_type, start);
		if (err)
			break;
	}

	free(line);
	fclose(file);
	return err;

out_failure:
	return -1;
}

struct process_kallsyms_args {
	struct map *map;
	struct dso *dso;
};

static int map__process_kallsym_symbol(void *arg, const char *name,
				       char type, u64 start)
{
	struct symbol *sym;
	struct process_kallsyms_args *a = arg;
	struct rb_root *root = &a->dso->symbols[a->map->type];

	if (!symbol_type__is_a(type, a->map->type))
		return 0;

	/*
	 * Will fix up the end later, when we have all symbols sorted.
	 */
	sym = symbol__new(start, 0, name);

	if (sym == NULL)
		return -ENOMEM;
	/*
	 * We will pass the symbols to the filter later, in
	 * map__split_kallsyms, when we have split the maps per module
	 */
	symbols__insert(root, sym);

	return 0;
}

/*
 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
 * so that we can in the next step set the symbol ->end address and then
 * call kernel_maps__split_kallsyms.
 */
static int dso__load_all_kallsyms(struct dso *self, const char *filename,
				  struct map *map)
{
	struct process_kallsyms_args args = { .map = map, .dso = self, };
	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
}

/*
 * Split the symbols into maps, making sure there are no overlaps, i.e. the
 * kernel range is broken in several maps, named [kernel].N, as we don't have
 * the original ELF section names vmlinux have.
 */
static int dso__split_kallsyms(struct dso *self, struct map *map,
			       symbol_filter_t filter)
{
	struct map_groups *kmaps = map__kmap(map)->kmaps;
	struct machine *machine = kmaps->machine;
	struct map *curr_map = map;
	struct symbol *pos;
	int count = 0;
	struct rb_root *root = &self->symbols[map->type];
	struct rb_node *next = rb_first(root);
	int kernel_range = 0;

	while (next) {
		char *module;

		pos = rb_entry(next, struct symbol, rb_node);
		next = rb_next(&pos->rb_node);

		module = strchr(pos->name, '\t');
		if (module) {
			if (!symbol_conf.use_modules)
				goto discard_symbol;

			*module++ = '\0';

			if (strcmp(curr_map->dso->short_name, module)) {
				if (curr_map != map &&
				    self->kernel == DSO_TYPE_GUEST_KERNEL &&
				    machine__is_default_guest(machine)) {
					/*
					 * We assume all symbols of a module are
					 * continuous in * kallsyms, so curr_map
					 * points to a module and all its
					 * symbols are in its kmap. Mark it as
					 * loaded.
					 */
					dso__set_loaded(curr_map->dso,
							curr_map->type);
				}

				curr_map = map_groups__find_by_name(kmaps,
							map->type, module);
				if (curr_map == NULL) {
					pr_err("%s/proc/{kallsyms,modules} "
					         "inconsistency while looking "
						 "for \"%s\" module!\n",
						 machine->root_dir, module);
					curr_map = map;
					goto discard_symbol;
				}

				if (curr_map->dso->loaded &&<commit_msg>perf symbols: symbol inconsistency message should be done only at verbose=1<commit_after>#define _GNU_SOURCE
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include "symbol.h"
#include "strlist.h"

#include <libelf.h>
#include <gelf.h>
#include <elf.h>
#include <limits.h>
#include <sys/utsname.h>

#ifndef NT_GNU_BUILD_ID
#define NT_GNU_BUILD_ID 3
#endif

static void dsos__add(struct list_head *head, struct dso *dso);
static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static int dso__load_kernel_sym(struct dso *self, struct map *map,
				symbol_filter_t filter);
static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
			symbol_filter_t filter);
static int vmlinux_path__nr_entries;
static char **vmlinux_path;

struct symbol_conf symbol_conf = {
	.exclude_other	  = true,
	.use_modules	  = true,
	.try_vmlinux_path = true,
};

bool dso__loaded(const struct dso *self, enum map_type type)
{
	return self->loaded & (1 << type);
}

bool dso__sorted_by_name(const struct dso *self, enum map_type type)
{
	return self->sorted_by_name & (1 << type);
}

static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
{
	self->sorted_by_name |= (1 << type);
}

bool symbol_type__is_a(char symbol_type, enum map_type map_type)
{
	switch (map_type) {
	case MAP__FUNCTION:
		return symbol_type == 'T' || symbol_type == 'W';
	case MAP__VARIABLE:
		return symbol_type == 'D' || symbol_type == 'd';
	default:
		return false;
	}
}

static void symbols__fixup_end(struct rb_root *self)
{
	struct rb_node *nd, *prevnd = rb_first(self);
	struct symbol *curr, *prev;

	if (prevnd == NULL)
		return;

	curr = rb_entry(prevnd, struct symbol, rb_node);

	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
		prev = curr;
		curr = rb_entry(nd, struct symbol, rb_node);

		if (prev->end == prev->start)
			prev->end = curr->start - 1;
	}

	/* Last entry */
	if (curr->end == curr->start)
		curr->end = roundup(curr->start, 4096);
}

static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
{
	struct map *prev, *curr;
	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);

	if (prevnd == NULL)
		return;

	curr = rb_entry(prevnd, struct map, rb_node);

	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
		prev = curr;
		curr = rb_entry(nd, struct map, rb_node);
		prev->end = curr->start - 1;
	}

	/*
	 * We still haven't the actual symbols, so guess the
	 * last map final address.
	 */
	curr->end = ~0UL;
}

static void map_groups__fixup_end(struct map_groups *self)
{
	int i;
	for (i = 0; i < MAP__NR_TYPES; ++i)
		__map_groups__fixup_end(self, i);
}

static struct symbol *symbol__new(u64 start, u64 len, const char *name)
{
	size_t namelen = strlen(name) + 1;
	struct symbol *self = calloc(1, (symbol_conf.priv_size +
					 sizeof(*self) + namelen));
	if (self == NULL)
		return NULL;

	if (symbol_conf.priv_size)
		self = ((void *)self) + symbol_conf.priv_size;

	self->start   = start;
	self->end     = len ? start + len - 1 : start;
	self->namelen = namelen - 1;

	pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);

	memcpy(self->name, name, namelen);

	return self;
}

void symbol__delete(struct symbol *self)
{
	free(((void *)self) - symbol_conf.priv_size);
}

static size_t symbol__fprintf(struct symbol *self, FILE *fp)
{
	return fprintf(fp, " %llx-%llx %s\n",
		       self->start, self->end, self->name);
}

void dso__set_long_name(struct dso *self, char *name)
{
	if (name == NULL)
		return;
	self->long_name = name;
	self->long_name_len = strlen(name);
}

static void dso__set_short_name(struct dso *self, const char *name)
{
	if (name == NULL)
		return;
	self->short_name = name;
	self->short_name_len = strlen(name);
}

static void dso__set_basename(struct dso *self)
{
	dso__set_short_name(self, basename(self->long_name));
}

struct dso *dso__new(const char *name)
{
	struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);

	if (self != NULL) {
		int i;
		strcpy(self->name, name);
		dso__set_long_name(self, self->name);
		dso__set_short_name(self, self->name);
		for (i = 0; i < MAP__NR_TYPES; ++i)
			self->symbols[i] = self->symbol_names[i] = RB_ROOT;
		self->slen_calculated = 0;
		self->origin = DSO__ORIG_NOT_FOUND;
		self->loaded = 0;
		self->sorted_by_name = 0;
		self->has_build_id = 0;
		self->kernel = DSO_TYPE_USER;
		INIT_LIST_HEAD(&self->node);
	}

	return self;
}

static void symbols__delete(struct rb_root *self)
{
	struct symbol *pos;
	struct rb_node *next = rb_first(self);

	while (next) {
		pos = rb_entry(next, struct symbol, rb_node);
		next = rb_next(&pos->rb_node);
		rb_erase(&pos->rb_node, self);
		symbol__delete(pos);
	}
}

void dso__delete(struct dso *self)
{
	int i;
	for (i = 0; i < MAP__NR_TYPES; ++i)
		symbols__delete(&self->symbols[i]);
	if (self->long_name != self->name)
		free(self->long_name);
	free(self);
}

void dso__set_build_id(struct dso *self, void *build_id)
{
	memcpy(self->build_id, build_id, sizeof(self->build_id));
	self->has_build_id = 1;
}

static void symbols__insert(struct rb_root *self, struct symbol *sym)
{
	struct rb_node **p = &self->rb_node;
	struct rb_node *parent = NULL;
	const u64 ip = sym->start;
	struct symbol *s;

	while (*p != NULL) {
		parent = *p;
		s = rb_entry(parent, struct symbol, rb_node);
		if (ip < s->start)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}
	rb_link_node(&sym->rb_node, parent, p);
	rb_insert_color(&sym->rb_node, self);
}

static struct symbol *symbols__find(struct rb_root *self, u64 ip)
{
	struct rb_node *n;

	if (self == NULL)
		return NULL;

	n = self->rb_node;

	while (n) {
		struct symbol *s = rb_entry(n, struct symbol, rb_node);

		if (ip < s->start)
			n = n->rb_left;
		else if (ip > s->end)
			n = n->rb_right;
		else
			return s;
	}

	return NULL;
}

struct symbol_name_rb_node {
	struct rb_node	rb_node;
	struct symbol	sym;
};

static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
{
	struct rb_node **p = &self->rb_node;
	struct rb_node *parent = NULL;
	struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;

	while (*p != NULL) {
		parent = *p;
		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
		if (strcmp(sym->name, s->sym.name) < 0)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}
	rb_link_node(&symn->rb_node, parent, p);
	rb_insert_color(&symn->rb_node, self);
}

static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
{
	struct rb_node *nd;

	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
		symbols__insert_by_name(self, pos);
	}
}

static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
{
	struct rb_node *n;

	if (self == NULL)
		return NULL;

	n = self->rb_node;

	while (n) {
		struct symbol_name_rb_node *s;
		int cmp;

		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
		cmp = strcmp(name, s->sym.name);

		if (cmp < 0)
			n = n->rb_left;
		else if (cmp > 0)
			n = n->rb_right;
		else
			return &s->sym;
	}

	return NULL;
}

struct symbol *dso__find_symbol(struct dso *self,
				enum map_type type, u64 addr)
{
	return symbols__find(&self->symbols[type], addr);
}

struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
					const char *name)
{
	return symbols__find_by_name(&self->symbol_names[type], name);
}

void dso__sort_by_name(struct dso *self, enum map_type type)
{
	dso__set_sorted_by_name(self, type);
	return symbols__sort_by_name(&self->symbol_names[type],
				     &self->symbols[type]);
}

int build_id__sprintf(const u8 *self, int len, char *bf)
{
	char *bid = bf;
	const u8 *raw = self;
	int i;

	for (i = 0; i < len; ++i) {
		sprintf(bid, "%02x", *raw);
		++raw;
		bid += 2;
	}

	return raw - self;
}

size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
{
	char sbuild_id[BUILD_ID_SIZE * 2 + 1];

	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
	return fprintf(fp, "%s", sbuild_id);
}

size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
{
	struct rb_node *nd;
	size_t ret = fprintf(fp, "dso: %s (", self->short_name);

	if (self->short_name != self->long_name)
		ret += fprintf(fp, "%s, ", self->long_name);
	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
		       self->loaded ? "" : "NOT ");
	ret += dso__fprintf_buildid(self, fp);
	ret += fprintf(fp, ")\n");
	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
		ret += symbol__fprintf(pos, fp);
	}

	return ret;
}

int kallsyms__parse(const char *filename, void *arg,
		    int (*process_symbol)(void *arg, const char *name,
						     char type, u64 start))
{
	char *line = NULL;
	size_t n;
	int err = 0;
	FILE *file = fopen(filename, "r");

	if (file == NULL)
		goto out_failure;

	while (!feof(file)) {
		u64 start;
		int line_len, len;
		char symbol_type;
		char *symbol_name;

		line_len = getline(&line, &n, file);
		if (line_len < 0 || !line)
			break;

		line[--line_len] = '\0'; /* \n */

		len = hex2u64(line, &start);

		len++;
		if (len + 2 >= line_len)
			continue;

		symbol_type = toupper(line[len]);
		symbol_name = line + len + 2;

		err = process_symbol(arg, symbol_name, symbol_type, start);
		if (err)
			break;
	}

	free(line);
	fclose(file);
	return err;

out_failure:
	return -1;
}

struct process_kallsyms_args {
	struct map *map;
	struct dso *dso;
};

static int map__process_kallsym_symbol(void *arg, const char *name,
				       char type, u64 start)
{
	struct symbol *sym;
	struct process_kallsyms_args *a = arg;
	struct rb_root *root = &a->dso->symbols[a->map->type];

	if (!symbol_type__is_a(type, a->map->type))
		return 0;

	/*
	 * Will fix up the end later, when we have all symbols sorted.
	 */
	sym = symbol__new(start, 0, name);

	if (sym == NULL)
		return -ENOMEM;
	/*
	 * We will pass the symbols to the filter later, in
	 * map__split_kallsyms, when we have split the maps per module
	 */
	symbols__insert(root, sym);

	return 0;
}

/*
 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
 * so that we can in the next step set the symbol ->end address and then
 * call kernel_maps__split_kallsyms.
 */
static int dso__load_all_kallsyms(struct dso *self, const char *filename,
				  struct map *map)
{
	struct process_kallsyms_args args = { .map = map, .dso = self, };
	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
}

/*
 * Split the symbols into maps, making sure there are no overlaps, i.e. the
 * kernel range is broken in several maps, named [kernel].N, as we don't have
 * the original ELF section names vmlinux have.
 */
static int dso__split_kallsyms(struct dso *self, struct map *map,
			       symbol_filter_t filter)
{
	struct map_groups *kmaps = map__kmap(map)->kmaps;
	struct machine *machine = kmaps->machine;
	struct map *curr_map = map;
	struct symbol *pos;
	int count = 0;
	struct rb_root *root = &self->symbols[map->type];
	struct rb_node *next = rb_first(root);
	int kernel_range = 0;

	while (next) {
		char *module;

		pos = rb_entry(next, struct symbol, rb_node);
		next = rb_next(&pos->rb_node);

		module = strchr(pos->name, '\t');
		if (module) {
			if (!symbol_conf.use_modules)
				goto discard_symbol;

			*module++ = '\0';

			if (strcmp(curr_map->dso->short_name, module)) {
				if (curr_map != map &&
				    self->kernel == DSO_TYPE_GUEST_KERNEL &&
				    machine__is_default_guest(machine)) {
					/*
					 * We assume all symbols of a module are
					 * continuous in * kallsyms, so curr_map
					 * points to a module and all its
					 * symbols are in its kmap. Mark it as
					 * loaded.
					 */
					dso__set_loaded(curr_map->dso,
							curr_map->type);
				}

				curr_map = map_groups__find_by_name(kmaps,
							map->type, module);
				if (curr_map == NULL) {
					pr_debug("%s/proc/{kallsyms,modules} "
					         "inconsistency while looking "
						 "for \"%s\" module!\n",
						 machine->root_dir, module);
					curr_map = map;
					goto discard_symbol;
				}

				if (curr_map->dso->loaded &&
{'fraction_non_alphanumeric': 0.14401043790263393, 'fraction_numerical': 0.005830547174427139, 'mean_word_length': 3.9063812762552512, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 259, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3678270', 'n_tokens_mistral': 10267, 'n_tokens_neox': 9495, 'n_words': 2464}