fix StrSplit

This commit is contained in:
tqcq
2024-03-30 17:44:15 +08:00
parent f1f1f4b240
commit 00f8125757
8 changed files with 517 additions and 20 deletions

View File

@ -0,0 +1,25 @@
#include "sled/debugging/symbolize.h"
#ifdef _WIN32
void
InitializeSymbolizer(const char *argv0)
{}
bool
Symbolize(const void *pc, char *out, int out_size)
{
return false;
}
#elif defined(__APPLE__)
void
InitializeSymbolizer(const char *argv0)
{}
bool
Symbolize(const void *pc, char *out, int out_size)
{
return false;
}
#elif defined(__linux__)
#include "sled/debugging/symbolize_elf.inc"
#endif

View File

@ -0,0 +1,10 @@
#ifndef SLED_DEBUGGING_SYMBOLIZE_H
#define SLED_DEBUGGING_SYMBOLIZE_H
#pragma once
namespace sled {
void InitializeSymbolizer(const char *argv0);
bool Symbolize(const void *pc, char *out, int out_size);
bool ReadAddrMap();
}// namespace sled
#endif// SLED_DEBUGGING_SYMBOLIZE_H

View File

@ -0,0 +1,140 @@
#include <array>
#include <cxxabi.h>
#include <dlfcn.h>
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <link.h>
#include <sled/log/log.h>
#include <sled/strings/utils.h>
#include <sstream>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
namespace sled {
static constexpr char kTag[] = "symbolizer";
static char *g_exe = nullptr;
static const uint64_t
GetHex(const char *start, const char *end)
{
uint64_t hex = 0;
for (const char *p = start; p < end; ++p) {
int ch = *p;
if (ch >= '0' && ch <= '9') {
hex = hex * 16 + (ch - '0');
} else if (ch >= 'a' && ch <= 'f') {
hex = hex * 16 + (ch - 'a' + 10);
} else if (ch >= 'A' && ch <= 'F') {
hex = hex * 16 + (ch - 'A' + 10);
} else {
break;
}
}
return hex;
}
static const uint64_t
GetHex(const std::string &str)
{
return GetHex(str.c_str(), str.c_str() + str.size());
}
struct ObjFile {
ObjFile() : filename(nullptr), start_addr(nullptr), end_addr(nullptr), offset(0), fd(-1), elf_type(-1)
{
memset(&elf_header, 0, sizeof(elf_header));
memset(phdrs.data(), 0, sizeof(ElfW(Phdr)) * phdrs.size());
}
char *filename;
const void *start_addr;
const void *end_addr;
uint64_t offset;
int fd;
int elf_type;
ElfW(Ehdr) elf_header;
std::array<ElfW(Phdr), 16> phdrs;
};
std::string
ReadFullFile(int fd)
{
std::stringstream ss;
char buf[4096];
ssize_t n;
while ((n = read(fd, buf, sizeof(buf))) > 0) { ss.write(buf, n); }
return ss.str();
}
bool
ReadAddrMap()
{
char maps_path[80];
snprintf(maps_path, sizeof(maps_path), "/proc/self/task/%d/maps", getpid());
int maps_fd;
do {
maps_fd = open(maps_path, O_RDONLY);
} while (maps_fd < 0 && errno == EINTR);
if (maps_fd < 0) {
LOGE(kTag, "open {} failed, {}", maps_path, strerror(errno));
return false;
}
std::string full_file = ReadFullFile(maps_fd);
auto lines = sled::StrSplit(full_file, "\n");
// maps start_addr-end_addr permission offset dev inode pathname
for (const auto &line : lines) {
auto fields = sled::StrSplit(line, " \n\t", true);
if (fields.size() < 6) { continue; }
auto addrs = sled::StrSplit(fields[0], "-", false);
uint64_t start_addr = GetHex(addrs[0]);
uint64_t end_addr = GetHex(addrs[1]);
uint64_t offset = GetHex(fields[2]);
LOGD(kTag, "addr: {}-{} {} {} {}", start_addr, end_addr, offset, fields[1], fields[5]);
}
return true;
}
class Symbolizer {};
void
InitializeSymbolizer(const char *argv0)
{
if (g_exe) {
free(g_exe);
g_exe = nullptr;
}
if (argv0 && argv0[0] != '\0') { g_exe = strdup(argv0); }
}
bool
Symbolize(const void *pc, char *out, int out_size)
{
Dl_info info;
if (!dladdr(pc, &info)) { return false; }
if (info.dli_fname && out_size > 0) {
strncpy(out, info.dli_fname, out_size);
const auto end_pos = static_cast<size_t>(out_size) - 1;
if (out[end_pos] != '\0') {
// add ...
out[end_pos] = '\0';
}
}
return true;
}
}// namespace sled

View File

@ -0,0 +1,43 @@
#include <gtest/gtest.h>
#include <sled/debugging/symbolize.h>
#include <sled/make_unique.h>
void
TestFunc1()
{}
static char try_symbolize_buffer[4096];
static const char *
TrySymbolizeWithLimit(void *pc, int limit)
{
// ASSERT_LE(limit, 4096);
auto heap_buffer = sled::MakeUnique<char[]>(4096);
bool found = sled::Symbolize(pc, heap_buffer.get(), sizeof(try_symbolize_buffer));
strncpy(try_symbolize_buffer, heap_buffer.get(), sizeof(try_symbolize_buffer) - 1);
try_symbolize_buffer[sizeof(try_symbolize_buffer) - 1] = '\0';
return try_symbolize_buffer;
}
static const char *
TrySymbolize(void *pc)
{
return TrySymbolizeWithLimit(pc, 4096);
}
// TEST(Symbolize, base)
// {
// char buf[1024];
// EXPECT_EQ("TestFunc1", TrySymbolize((void *) &TestFunc1));
// }
TEST(Symbolize, ReadAddrMap) { sled::ReadAddrMap(); }
int
main(int argc, char *argv[])
{
sled::InitializeSymbolizer(argv[0]);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -54,15 +54,31 @@ StrSplit(const std::string &str, const std::string &delim, bool skip_empty)
std::vector<std::string> result;
if (str.empty()) { return result; }
size_t start = 0;
size_t start = 0;
size_t next_pos = str.find_first_of(delim, start);
while (next_pos != std::string::npos) {
if (!skip_empty || next_pos > start) { result.emplace_back(str.substr(start, next_pos - start)); }
start = next_pos + 1;
next_pos = str.find_first_of(delim, start);
if ((!skip_empty && next_pos == start) || next_pos > start) {
result.emplace_back(str.begin() + start, str.begin() + next_pos);
}
if (!skip_empty) {
start = next_pos + 1;
next_pos = str.find_first_of(delim, start);
} else {
start = str.find_first_not_of(delim, next_pos);
if (start == std::string::npos) {
// all remaining characters are delimiters
break;
}
next_pos = str.find_first_of(delim, start);
}
}
if (start < str.size()) { result.emplace_back(str.substr(start)); }
if (start < str.size()) {
result.emplace_back(str.substr(start));
} else if (!skip_empty && !str.empty() && delim.find(str.back()) != std::string::npos) {
result.emplace_back("");
}
return result;
}

View File

@ -0,0 +1,99 @@
#include <gtest/gtest.h>
#include <sled/strings/utils.h>
TEST(ToLower, Char)
{
EXPECT_EQ(sled::ToLower('A'), 'a');
EXPECT_EQ(sled::ToLower('Z'), 'z');
EXPECT_EQ(sled::ToLower('a'), 'a');
EXPECT_EQ(sled::ToLower('z'), 'z');
EXPECT_EQ(sled::ToLower(' '), ' ');
EXPECT_EQ(sled::ToLower('\0'), '\0');
}
TEST(ToUpper, Char)
{
EXPECT_EQ(sled::ToUpper('A'), 'A');
EXPECT_EQ(sled::ToUpper('Z'), 'Z');
EXPECT_EQ(sled::ToUpper('a'), 'A');
EXPECT_EQ(sled::ToUpper('z'), 'Z');
EXPECT_EQ(sled::ToUpper(' '), ' ');
EXPECT_EQ(sled::ToUpper('\0'), '\0');
}
TEST(ToLower, String)
{
EXPECT_EQ(sled::ToLower("Hello World"), "hello world");
EXPECT_EQ(sled::ToLower("HELLO WORLD"), "hello world");
EXPECT_EQ(sled::ToLower("hello world"), "hello world");
EXPECT_EQ(sled::ToLower(" "), " ");
EXPECT_EQ(sled::ToLower(""), "");
}
TEST(ToUpper, String)
{
EXPECT_EQ(sled::ToUpper("Hello World"), "HELLO WORLD");
EXPECT_EQ(sled::ToUpper("HELLO WORLD"), "HELLO WORLD");
EXPECT_EQ(sled::ToUpper("hello world"), "HELLO WORLD");
EXPECT_EQ(sled::ToUpper(" "), " ");
EXPECT_EQ(sled::ToUpper(""), "");
}
TEST(StrJoin, Empty)
{
EXPECT_EQ(sled::StrJoin({}, ","), "");
EXPECT_EQ(sled::StrJoin({}, ",", true), "");
EXPECT_EQ(sled::StrJoin({}, ",", false), "");
}
TEST(StrJoin, Delim)
{
EXPECT_EQ(sled::StrJoin({"a", "b", "c"}, ","), "a,b,c");
EXPECT_EQ(sled::StrJoin({"a", "b", "c"}, ",", true), "a,b,c");
EXPECT_EQ(sled::StrJoin({"a", "b", "c"}, ",", false), "a,b,c");
}
TEST(StrJoin, DelimSkipEmpty)
{
EXPECT_EQ(sled::StrJoin({"a", "", "c"}, ","), "a,,c");
EXPECT_EQ(sled::StrJoin({"a", "", "c"}, ",", true), "a,c");
EXPECT_EQ(sled::StrJoin({"a", "", "c"}, ",", false), "a,,c");
}
TEST(StrSplit, Empty)
{
EXPECT_EQ(sled::StrSplit("", ","), std::vector<std::string>());
EXPECT_EQ(sled::StrSplit("", ",", true), std::vector<std::string>());
EXPECT_EQ(sled::StrSplit("", ",", false), std::vector<std::string>());
}
TEST(StrSplit, Delim)
{
// single delim
EXPECT_EQ(sled::StrSplit("a,b,c", ","), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b,c", ",", true), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b,c", ",", false), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b,c,", ","), std::vector<std::string>({"a", "b", "c", ""}));
EXPECT_EQ(sled::StrSplit("a,b,c,", ",", true), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b,c,", ",", false), std::vector<std::string>({"a", "b", "c", ""}));
EXPECT_EQ(sled::StrSplit(",a,b,c", ","), std::vector<std::string>({"", "a", "b", "c"}));
EXPECT_EQ(sled::StrSplit(",a,b,c", ",", true), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit(",a,b,c", ",", false), std::vector<std::string>({"", "a", "b", "c"}));
// multi delim
EXPECT_EQ(sled::StrSplit(",,a,b,c", ",", true), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit(",,a,b,c", ",", false), std::vector<std::string>({"", "", "a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b,c,,", ",", true), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b,c,,", ",", false), std::vector<std::string>({"a", "b", "c", "", ""}));
EXPECT_EQ(sled::StrSplit("a,,b,c", ",", true), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,,b,c", ",", false), std::vector<std::string>({"a", "", "b", "c"}));
}
TEST(StrSplit, MultiDelim)
{
EXPECT_EQ(sled::StrSplit("a,b;c", ",;", true), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b;c", ",;", false), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b;c,", ",;", true), std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(sled::StrSplit("a,b;c,", ",;", false), std::vector<std::string>({"a", "b", "c", ""}));
EXPECT_EQ(sled::StrSplit("a,b;c,", ";,", true), std::vector<std::string>({"a", "b", "c"}));
}