diff --git a/common/referer.cpp b/common/referer.cpp index d18f765..f30f4e2 100644 --- a/common/referer.cpp +++ b/common/referer.cpp @@ -186,13 +186,14 @@ namespace sys_util } 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 = strstr(path + 2, "/"); + const char* id = strrchr(path, '/'); uint64_t pid = 0; std::string path_name(""); @@ -212,9 +213,37 @@ namespace sys_util if (*id) return true; - path_name = get_module_path(nullptr, pid); + 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, path_name.c_str(), cb->param); + 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 @@ -283,9 +312,53 @@ namespace sys_util 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 { @@ -435,5 +508,83 @@ namespace sys_util 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; + } } diff --git a/common/referer.h b/common/referer.h index 1218c1f..2dd9ecc 100644 --- a/common/referer.h +++ b/common/referer.h @@ -123,6 +123,9 @@ namespace sys_util , bool recursive = true // walk recursive ); // return errno int32_t enum_processes(bool(*on_found)(uint64_t pid, const char* path_name, void* param), void* param); + uint32_t enum_threads(uint64_t pid, bool(*on_found)(uint64_t tid, void* start_addr, void* param), void* param); + uint32_t get_thread_callstack(uint64_t pid, uint64_t tid, bool(*on_found)(uint64_t off, const char* module, void* param), void* param); + uint32_t read_line(const char* file, bool(*on_line)(char* line, void* param), void* param); std::string get_module_path(const char* module_name = nullptr , unsigned pid = -1); // get module full path, nullptr is for main-exe @@ -165,4 +168,9 @@ namespace sys_util int32_t get_memory_info(uint64_t* total, uint64_t* available); std::string format_readable_bytes(uint64_t bytes); // convert to readable text: 512B, 1.21KB, 1.10MB, 3.45GB, 1,234.56GB ... std::string get_command_output(const char* cmd, uint16_t max_line_len = 256, bool one_line = true); + + // trim string, return whether space trimmed + bool trim_left(std::string& str, const char* space = " \t"); + bool trim_right(std::string& str, const char* space = " \t"); + uint64_t from_hex_str(const char* hex, const char** end = nullptr); // convert 0x100 to 256. parameter 'end' to receive the stopped position } diff --git a/scanner/main/main.cpp b/scanner/main/main.cpp index 72ffb5d..daf5d6b 100644 --- a/scanner/main/main.cpp +++ b/scanner/main/main.cpp @@ -10,8 +10,104 @@ #include "scanner.h" +static bool found_proc(uint64_t pid, const char* path, void* param) +{ + uint32_t* cnt = (uint32_t*)param; + + printf("%d - %ld: %s\n", ++cnt[0], pid, path); + + return true; +} +static bool found_modules(const char* path, bool is_dir, void* param) +{ + uint32_t* cnt = (uint32_t*)param; + + printf("%d - %s\n", ++cnt[0], path); + + return true; +} +static bool found_modules_norepeat(const char* path, bool is_dir, void* param) +{ + struct + { + uint32_t cnt; + std::vector modules; + }*data = nullptr; + + *(void**)&data = param; + + if (std::find(data->modules.begin(), data->modules.end(), path) == data->modules.end()) + { + printf("%d - %s\n", ++data->cnt, path); + data->modules.push_back(path); + } + + return true; +} +static bool on_found_thread(uint64_t tid, void* start_addr, void* param) +{ + uint32_t* cnt = (uint32_t*)param; + + printf("%d - %p(%u): starting at %p\n", ++cnt[0], tid, tid, start_addr); + + return true; +} +static bool on_stack(uint64_t off, const char* module, void* param) +{ + uint32_t* cnt = (uint32_t*)param; + + printf("%d - %s + %p\n", ++cnt[0], module, off); + + return true; +} + int32_t main(int32_t argc, char *argv[]) { + // uint32_t cnt = 0, err = 0; + // + // if(argc >= 2) + // { + // if(strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-?") == 0 || strcmp(argv[1], "-help") == 0) + // { + // printf("usage: proc - no options, to enum all processes\n\ + // -?/-h/-help: to show this message\n\ + // [-nrp], to enum process(pid) modules, '-nrp' do not print repeating modules\n\ + // <-t pid> [tid], to enum threads or print callstack of given thread\ + // "); + // } + // else if(argc >= 3) + // { + // if(strcmp(argv[1], "-t") == 0) + // { + // uint32_t pid = atoi(argv[2]); + // if(argc >= 4) + // err = sys_util::get_thread_callstack(pid, atoi(argv[3]), on_stack, &cnt); + // else + // err = sys_util::enum_threads(pid, on_found_thread, &cnt); + // } + // else if(strcmp(argv[2], "-nrp") == 0) + // { + // struct + // { + // uint32_t cnt = 0; + // std::vector modules; + // }data; + // err = sys_util::enum_modules(found_modules_norepeat, &data, atoi(argv[1])); + // } + // } + // else + // err = sys_util::enum_modules(found_modules, &cnt, atoi(argv[1])); + // } + // else + // { + // err = sys_util::enum_processes(found_proc, &cnt); + // } + // if(err) + // printf("error = %d (%s)\n", err, strerror(err));EINVAL; + // + // return 0; + + char *oper = argc > 1 ? argv[1] : nullptr; log_cls::initialize(nullptr);