mirror of
https://github.com/springzfx/cgproxy.git
synced 2026-01-07 13:07:56 +08:00
235 lines
4.8 KiB
C
235 lines
4.8 KiB
C
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include <sys/resource.h>
|
|
#include <time.h>
|
|
#include "trace_helpers.h"
|
|
|
|
#define min(x, y) ({ \
|
|
typeof(x) _min1 = (x); \
|
|
typeof(y) _min2 = (y); \
|
|
(void) (&_min1 == &_min2); \
|
|
_min1 < _min2 ? _min1 : _min2; })
|
|
|
|
struct ksyms {
|
|
struct ksym *syms;
|
|
int syms_sz;
|
|
int syms_cap;
|
|
char *strs;
|
|
int strs_sz;
|
|
int strs_cap;
|
|
};
|
|
|
|
static int ksyms__add_symbol(struct ksyms *ksyms, const char *name, unsigned long addr)
|
|
{
|
|
size_t new_cap, name_len = strlen(name) + 1;
|
|
struct ksym *ksym;
|
|
void *tmp;
|
|
|
|
if (ksyms->strs_sz + name_len > ksyms->strs_cap) {
|
|
new_cap = ksyms->strs_cap * 4 / 3;
|
|
if (new_cap < ksyms->strs_sz + name_len)
|
|
new_cap = ksyms->strs_sz + name_len;
|
|
if (new_cap < 1024)
|
|
new_cap = 1024;
|
|
tmp = realloc(ksyms->strs, new_cap);
|
|
if (!tmp)
|
|
return -1;
|
|
ksyms->strs = tmp;
|
|
ksyms->strs_cap = new_cap;
|
|
}
|
|
if (ksyms->syms_sz + 1 > ksyms->syms_cap) {
|
|
new_cap = ksyms->syms_cap * 4 / 3;
|
|
if (new_cap < 1024)
|
|
new_cap = 1024;
|
|
tmp = realloc(ksyms->syms, sizeof(*ksyms->syms) * new_cap);
|
|
if (!tmp)
|
|
return -1;
|
|
ksyms->syms = tmp;
|
|
ksyms->syms_cap = new_cap;
|
|
}
|
|
|
|
ksym = &ksyms->syms[ksyms->syms_sz];
|
|
/* while constructing, re-use pointer as just a plain offset */
|
|
ksym->name = (void *)(unsigned long)ksyms->strs_sz;
|
|
ksym->addr = addr;
|
|
|
|
memcpy(ksyms->strs + ksyms->strs_sz, name, name_len);
|
|
ksyms->strs_sz += name_len;
|
|
ksyms->syms_sz++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ksym_cmp(const void *p1, const void *p2)
|
|
{
|
|
const struct ksym *s1 = p1, *s2 = p2;
|
|
|
|
if (s1->addr == s2->addr)
|
|
return strcmp(s1->name, s2->name);
|
|
return s1->addr < s2->addr ? -1 : 1;
|
|
}
|
|
|
|
struct ksyms *ksyms__load(void)
|
|
{
|
|
char sym_type, sym_name[256];
|
|
struct ksyms *ksyms;
|
|
unsigned long sym_addr;
|
|
int i, ret;
|
|
FILE *f;
|
|
|
|
f = fopen("/proc/kallsyms", "r");
|
|
if (!f)
|
|
return NULL;
|
|
|
|
ksyms = calloc(1, sizeof(*ksyms));
|
|
if (!ksyms)
|
|
goto err_out;
|
|
|
|
while (true) {
|
|
ret = fscanf(f, "%lx %c %s%*[^\n]\n",
|
|
&sym_addr, &sym_type, sym_name);
|
|
if (ret == EOF && feof(f))
|
|
break;
|
|
if (ret != 3)
|
|
goto err_out;
|
|
if (ksyms__add_symbol(ksyms, sym_name, sym_addr))
|
|
goto err_out;
|
|
}
|
|
|
|
/* now when strings are finalized, adjust pointers properly */
|
|
for (i = 0; i < ksyms->syms_sz; i++)
|
|
ksyms->syms[i].name += (unsigned long)ksyms->strs;
|
|
|
|
qsort(ksyms->syms, ksyms->syms_sz, sizeof(*ksyms->syms), ksym_cmp);
|
|
|
|
fclose(f);
|
|
return ksyms;
|
|
|
|
err_out:
|
|
ksyms__free(ksyms);
|
|
fclose(f);
|
|
return NULL;
|
|
}
|
|
|
|
void ksyms__free(struct ksyms *ksyms)
|
|
{
|
|
if (!ksyms)
|
|
return;
|
|
|
|
free(ksyms->syms);
|
|
free(ksyms->strs);
|
|
free(ksyms);
|
|
}
|
|
|
|
const struct ksym *ksyms__map_addr(const struct ksyms *ksyms,
|
|
unsigned long addr)
|
|
{
|
|
int start = 0, end = ksyms->syms_sz - 1, mid;
|
|
unsigned long sym_addr;
|
|
|
|
/* find largest sym_addr <= addr using binary search */
|
|
while (start < end) {
|
|
mid = start + (end - start + 1) / 2;
|
|
sym_addr = ksyms->syms[mid].addr;
|
|
|
|
if (sym_addr <= addr)
|
|
start = mid;
|
|
else
|
|
end = mid - 1;
|
|
}
|
|
|
|
if (start == end && ksyms->syms[start].addr <= addr)
|
|
return &ksyms->syms[start];
|
|
return NULL;
|
|
}
|
|
|
|
const struct ksym *ksyms__get_symbol(const struct ksyms *ksyms,
|
|
const char *name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ksyms->syms_sz; i++) {
|
|
if (strcmp(ksyms->syms[i].name, name) == 0)
|
|
return &ksyms->syms[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void print_stars(unsigned int val, unsigned int val_max, int width)
|
|
{
|
|
int num_stars, num_spaces, i;
|
|
bool need_plus;
|
|
|
|
num_stars = min(val, val_max) * width / val_max;
|
|
num_spaces = width - num_stars;
|
|
need_plus = val > val_max;
|
|
|
|
for (i = 0; i < num_stars; i++)
|
|
printf("*");
|
|
for (i = 0; i < num_spaces; i++)
|
|
printf(" ");
|
|
if (need_plus)
|
|
printf("+");
|
|
}
|
|
|
|
void print_log2_hist(unsigned int *vals, int vals_size, char *val_type)
|
|
{
|
|
int stars_max = 40, idx_max = -1;
|
|
unsigned int val, val_max = 0;
|
|
unsigned long long low, high;
|
|
int stars, width, i;
|
|
|
|
for (i = 0; i < vals_size; i++) {
|
|
val = vals[i];
|
|
if (val > 0)
|
|
idx_max = i;
|
|
if (val > val_max)
|
|
val_max = val;
|
|
}
|
|
|
|
if (idx_max < 0)
|
|
return;
|
|
|
|
printf("%*s%-*s : count distribution\n", idx_max <= 32 ? 5 : 15, "",
|
|
idx_max <= 32 ? 19 : 29, val_type);
|
|
|
|
if (idx_max <= 32)
|
|
stars = stars_max;
|
|
else
|
|
stars = stars_max / 2;
|
|
|
|
for (i = 0; i <= idx_max; i++) {
|
|
low = (1ULL << (i + 1)) >> 1;
|
|
high = (1ULL << (i + 1)) - 1;
|
|
if (low == high)
|
|
low -= 1;
|
|
val = vals[i];
|
|
width = idx_max <= 32 ? 10 : 20;
|
|
printf("%*lld -> %-*lld : %-8d |", width, low, width, high, val);
|
|
print_stars(val, val_max, stars);
|
|
printf("|\n");
|
|
}
|
|
}
|
|
|
|
unsigned long long get_ktime_ns(void)
|
|
{
|
|
struct timespec ts;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
|
|
}
|
|
|
|
int bump_memlock_rlimit(void)
|
|
{
|
|
struct rlimit rlim_new = {
|
|
.rlim_cur = RLIM_INFINITY,
|
|
.rlim_max = RLIM_INFINITY,
|
|
};
|
|
|
|
return setrlimit(RLIMIT_MEMLOCK, &rlim_new);
|
|
}
|