code_scanner/common/referer.cpp

591 lines
12 KiB
C++

#include "referer.h"
#include "log_util.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// refer
refer::refer() : ref_(1)
{
on_born();
}
refer::~refer()
{
on_dead();
}
void refer::on_born(void)
{}
void refer::on_dead(void)
{}
int32_t refer::add_ref(void)
{
LOCKER lock(mutex_);
return ++ref_;
}
int32_t refer::release(void)
{
int32_t ref = 0;
{
LOCKER lock(mutex_);
ref = --ref_;
}
if (ref == 0)
delete this;
return ref;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// chronograph
#include <sys/time.h>
chronograph::chronograph()
{
reset();
}
chronograph::~chronograph()
{}
bool chronograph::now(struct timeval* tv)
{
struct timezone tz = { 0 };
return gettimeofday(tv, &tz) == 0;
}
bool chronograph::now(uint64_t* seconds, uint64_t* u_seconds)
{
struct timeval tv = { 0 };
struct timezone tz = { 0 };
if (gettimeofday(&tv, &tz) == 0)
{
if (seconds)
*seconds = tv.tv_sec;
if (u_seconds)
*u_seconds = tv.tv_usec;
return true;
}
else
{
return false;
}
}
std::string chronograph::now(bool with_ms/*whether with milliseconds*/) // return '2022-11-30 10:38:42.123', no '.123' if with_ms was false
{
struct timeval tv = { 0 };
if (!chronograph::now(&tv))
return "";
char buf[40] = { 0 };
time_t t = tv.tv_sec;
struct tm* l = localtime(&t);
if (with_ms)
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday
, l->tm_hour, l->tm_min, l->tm_sec, tv.tv_usec);
else
sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday
, l->tm_hour, l->tm_min, l->tm_sec);
return buf;
}
uint64_t chronograph::elapse_s(void)
{
struct timeval tv = { 0 };
chronograph::now(&tv);
return tv.tv_sec - bgn_.tv_sec;
}
uint64_t chronograph::elapse_ms(void)
{
struct timeval tv = { 0 };
uint64_t dif = 0;
chronograph::now(&tv);
dif = SEC_2_MS(tv.tv_sec - bgn_.tv_sec);
dif += tv.tv_usec / MSEC_2_US(1);
dif -= bgn_.tv_usec / MSEC_2_US(1);
return dif;
}
uint64_t chronograph::elapse_us(void)
{
struct timeval tv = { 0 };
uint64_t dif = 0;
chronograph::now(&tv);
dif = SEC_2_US(tv.tv_sec - bgn_.tv_sec);
dif += tv.tv_usec;
dif -= bgn_.tv_usec;
return dif;
}
void chronograph::reset()
{
chronograph::now(&bgn_);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sys utility
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
namespace sys_util
{
static bool find_module(const char* path, bool is_dir, void* param)
{
std::string* para = (std::string*)param;
if (para[0].empty())
{
para[1] = path;
return false;
}
else
{
const char* name = strrchr(path, '/');
if (name++ == nullptr)
name = path;
if (strstr(name, para[0].c_str()))
{
para[1] = path;
return false;
}
return true;
}
}
typedef struct _enum_proc_cb
{
bool process;
bool(*on_found)(uint64_t pid, const char* path_name, void* param);
void* param;
}ENPROCCB, * LPENPROCCB;
static bool found_process(const char* path, bool is_dir, void* param)
{
LPENPROCCB cb = (LPENPROCCB)param;
const char* id = strrchr(path, '/');
uint64_t pid = 0;
std::string path_name("");
if (id++ == nullptr)
{
id = path;
}
while (*id)
{
if (*id < '0' || *id > '9')
break;
pid *= 10;
pid += *id - '0';
id++;
}
if (*id)
return true;
if (cb->process)
{
path_name = get_module_path(nullptr, pid);
id = path_name.c_str();
}
else
{
// get start address of pid to path_name
id = 0;
}
return cb->on_found(pid, id, cb->param);
}
static bool on_stack_line_read(char* line, void* param)
{
LPENPROCCB cb = (LPENPROCCB)param;
std::string m(line);
uint64_t off = 0;
size_t pos = m.find("]");
if (pos++ != std::string::npos)
m.erase(0, pos);
trim_left(m);
pos = m.find("+0x");
if (pos != std::string::npos)
{
off = from_hex_str(m.c_str() + pos + 3);
m.erase(pos);
}
return cb->on_found(off, m.c_str(), cb->param);
}
int32_t enum_modules(bool(*on_found)(const char* path_module_name, bool is_dir, void* param),// return false to stop enumeratin
void* param, // user defined data, passed into callback on_found
unsigned pid // process id, -1 is self
) // return errno
{
char path[128] = { 0 };
if (pid == -1)
pid = getpid();
sprintf(path, "/proc/%u/map_files/", pid);
return enum_files(path, on_found, param, false);
}
int32_t enum_files(const char* dir, // dir path
bool(*on_found)(const char* path_name, bool is_dir, void* param), // return false to stop enumeratin
void* param // user defined data, passed into callback on_found
, bool recursive
) // return errno
{
int32_t ret = 0;
DIR* pdir = nullptr;
struct dirent* ent = nullptr;
pdir = opendir(dir);
if (!pdir)
return errno;
while ((ent = readdir(pdir)))
{
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
continue;
std::string file(dir);
file += "/";
file += ent->d_name;
if ((ent->d_type & DT_DIR) == 0)
file = read_link(file.c_str());
if (!on_found(file.c_str(), ent->d_type & DT_DIR, param))
{
ret = 0x5e17;
break;
}
if ((ent->d_type & DT_DIR) && recursive)
{
std::string sub(dir);
sub += "/";
sub += ent->d_name;
ret = enum_files(sub.c_str(), on_found, param, recursive);
if (ret == 0x5e17)
break;
}
}
closedir(pdir);
return ret == 0x5e17 ? 0 : ret;
}
int32_t enum_processes(bool(*on_found)(uint64_t pid, const char* path_name, void* param), void* param)
{
ENPROCCB cb;
cb.on_found = on_found;
cb.param = param;
cb.process = true;
return enum_files("/proc", found_process, &cb, false);
}
uint32_t enum_threads(uint64_t pid, bool(*on_found)(uint64_t tid, void* start_addr, void* param), void* param)
{
ENPROCCB cb;
cb.process = false;
cb.param = param;
*(void**)&cb.on_found = *(void**)&on_found;
return enum_files(("/proc/" + std::to_string(pid) + "/task").c_str(), found_process, &cb, false);
}
uint32_t get_thread_callstack(uint64_t pid, uint64_t tid, bool(*on_found)(uint64_t off, const char* module, void* param), void* param)
{
ENPROCCB cb;
cb.process = false;
cb.param = param;
*(void**)&cb.on_found = *(void**)&on_found;
return read_line(("/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/stack").c_str(), on_stack_line_read, &cb);
}
uint32_t read_line(const char* file, bool(*on_line)(char* line, void* param), void* param)
{
FILE* src = fopen(file, "rb");
int err = 0;
if (!src)
return errno;
size_t ll = 1024;
char* line = new char[ll];
while (fgets(line, ll - 1, src))
{
if (!on_line(line, param))
break;
memset(line, 0, ll);
}
err = errno;
delete[] line;
fclose(src);
return err;
}
std::string get_module_path(const char* module_name, unsigned pid) // get module full path, nullptr is for main-exe
{
std::string param[] = { module_name ? module_name : "", "" };
enum_modules(find_module, param, pid);
return param[1];
}
std::string read_link(const char* lnk)
{
char path[512] = { 0 };
readlink(lnk, path, sizeof(path) - 1);
return path;
}
size_t get_page_size(void)
{
size_t size = sysconf(_SC_PAGESIZE);
if (size < 1024 || (size & 0x0fe0000ff)) // nKB && < 16MB
size = getpagesize();
return size;
}
bool create_folder(const char* dir)
{
bool ret = mkdir(dir, S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST;
if(errno == ENOENT)
{
std::string path(dir), cur("");
size_t pos = path.find("/", 1);
while(pos != std::string::npos)
{
ret = mkdir(path.substr(0, pos).c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST;
if(!ret)
{
printf("mkdir(%s) = %d(%s)\n", path.substr(0, pos).c_str(), errno, strerror(errno));
break;
}
pos = path.find("/", pos + 1);
}
if(ret)
ret = mkdir(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) == 0;
}
return ret;
}
int32_t get_memory_info(uint64_t* total, uint64_t* available)
{
if (!total && !available)
return 0;
char line[128] = { 0 };
FILE* src = fopen("/proc/meminfo", "rb");
int32_t count = total && available ? 2 : 1;
unsigned long val = 0;
if (!src)
return log_cls::log_when_err(-1, "fopen('/proc/meminfo', 'rb')", LOG_LEVEL_FATAL);
while (fgets(line, sizeof(line) - 1, src))
{
if (sscanf(line, "MemTotal: %ld", &val))
{
if (total)
{
*total = val * 1024;
if (--count == 0)
break;
}
}
else if (sscanf(line, "MemFree: %ld", &val))
{
if (available)
{
*available = val * 1024;
if (--count == 0)
break;
}
}
}
fclose(src);
return 0;
}
std::string format_readable_bytes(uint64_t bytes)
{
std::string str("\0", 80);
if (bytes >= SIZE_GB(1))
{
double v = bytes * 1.0f / (SIZE_GB(1));
size_t pos = 0;
sprintf(&str[0], "%.2fGB", v);
pos = str.find(".");
while (pos > 3)
{
pos -= 3;
str.insert(pos, ",");
}
}
else if (bytes >= SIZE_MB(1))
{
double v = bytes * 1.0f / (SIZE_MB(1));
sprintf(&str[0], "%.2fMB", v);
}
else if (bytes >= SIZE_KB(1))
{
double v = bytes * 1.0f / (SIZE_KB(1));
sprintf(&str[0], "%.2fKB", v);
}
else
{
sprintf(&str[0], "%uB", (unsigned)bytes);
}
return str;
}
std::string get_command_output(const char* cmd, uint16_t max_line_len, bool one_line)
{
FILE* src = popen(cmd, "r");
std::string ret("");
if (src)
{
char* buf = new char[max_line_len + 4];
if (buf)
{
memset(buf, 0, max_line_len + 4);
fgets(buf, max_line_len, src);
ret = buf;
while (!one_line && fgets(buf, max_line_len, src))
ret += "\n" + std::string(buf);
delete[] buf;
}
pclose(src);
}
return ret;
}
static bool is_char_in(const char* str, char ch)
{
if (ch == 0)
return false;
while (*str)
{
if (*str++ == ch)
return true;
}
return false;
}
bool trim_left(std::string& str, const char* space)
{
int off = 0;
for (; off < str.length(); ++off)
{
if (!is_char_in(space, str[off]))
break;
}
if (off)
str.erase(0, off);
return off > 0;
}
bool trim_right(std::string& str, const char* space)
{
int off = str.length() - 1;
for (; off >= 0; --off)
{
if (!is_char_in(space, str[off]))
break;
}
if (off < str.length() - 1)
{
str.erase(off + 1);
return true;
}
return false;
}
uint64_t from_hex_str(const char* hex, const char** end)
{
uint64_t val = 0;
for (int i = 0; i < 16; ++i)
{
if (*hex >= '0' && *hex <= '9')
{
val <<= 4;
val += *hex - '0';
}
else if (*hex >= 'a' && *hex <= 'f')
{
val <<= 4;
val += *hex - 'a' + 10;
}
else if (*hex >= 'A' && *hex <= 'F')
{
val <<= 4;
val += *hex - 'A' + 10;
}
else
{
break;
}
hex++;
}
if (end)
*end = hex;
return val;
}
}