// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/rbtree.h>
#include <linux/types.h>
#include <inttypes.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include <sys/utsname.h>
#include <perf/cpumap.h>
#include <perf/evlist.h>
#include <perf/mmap.h>
#include "debug.h"
#include "dso.h"
#include "env.h"
#include "parse-events.h"
#include "evlist.h"
#include "evsel.h"
#include "thread_map.h"
#include "machine.h"
#include "map.h"
#include "symbol.h"
#include "event.h"
#include "record.h"
#include "util/mmap.h"
#include "util/string2.h"
#include "util/synthetic-events.h"
#include "util/util.h"
#include "thread.h"
#include "tests.h"
#include <linux/ctype.h>
#define BUFSZ 1024
#define READLEN 128
struct tested_section {
struct rb_node rb_node;
u64 addr;
char *path;
};
static bool tested_code_insert_or_exists(const char *path, u64 addr,
struct rb_root *tested_sections)
{
struct rb_node **node = &tested_sections->rb_node;
struct rb_node *parent = NULL;
struct tested_section *data;
while (*node) {
int cmp;
parent = *node;
data = rb_entry(*node, struct tested_section, rb_node);
cmp = strcmp(path, data->path);
if (!cmp) {
if (addr < data->addr)
cmp = -1;
else if (addr > data->addr)
cmp = 1;
else
return true; /* already tested */
}
if (cmp < 0)
node = &(*node)->rb_left;
else
node = &(*node)->rb_right;
}
data = zalloc(sizeof(*data));
if (!data)
return true;
data->addr = addr;
data->path = strdup(path);
if (!data->path) {
free(data);
return true;
}
rb_link_node(&data->rb_node, parent, node);
rb_insert_color(&data->rb_node, tested_sections);
return false;
}
static void tested_sections__free(struct rb_root *root)
{
while (!RB_EMPTY_ROOT(root)) {
struct rb_node *node = rb_first(root);
struct tested_section *ts = rb_entry(node,
struct tested_section,
rb_node);
rb_erase(node, root);
free(ts->path);
free(ts);
}
}
static size_t read_objdump_chunk(const char **line, unsigned char **buf,
size_t *buf_len)
{
size_t bytes_read = 0;
unsigned char *chunk_start = *buf;
/* Read bytes */
while (*buf_len > 0) {
char c1, c2;
/* Get 2 hex digits */
c1 = *(*line)++;
if (!isxdigit(c1))
break;
c2 = *(*line)++;
if (!isxdigit(c2))
break;
/* Store byte and advance buf */
**buf = (hex(c1) << 4) | hex(c2);
(*buf)++;
(*buf_len)--;
bytes_read++;
/* End of chunk? */
if (isspace(**line))
break;
}
/*
* objdump will display raw insn as LE if code endian
* is LE and bytes_per_chunk > 1. In that case reverse
* the chunk we just read.
*
* see disassemble_bytes() at binutils/objdump.c for details
* how objdump chooses display endian)
*/
if (bytes_read > 1 && !host_is_bigendian()) {
unsigned char *chunk_end = chunk_start + bytes_read - 1;
unsigned char tmp;
while (chunk_start < chunk_end) {
tmp = *chunk_start;
*chunk_start = *chunk_end;
*chunk_end = tmp;
chunk_start++;
chunk_end--;
}
}
return bytes_read;
}
static size_t read_objdump_line(const char *line, unsigned char *buf,
size_t buf_len)
{
const char *p;
size_t ret, bytes_read = 0;
/* Skip to a colon */
p = strchr(line, ':');
if (!p)
return 0;
p++;
/* Skip initial spaces */
while (*p) {
if (!isspace(*p))
break;
p++;
}
do {
ret = read_objdump_chunk(&p, &buf, &buf_len);
bytes_read += ret;
p++;
} while (