-
Cpptrace는 Linux, macOS에서 C++11 이상을 지원하는 간단하고 휴대하기 편리한 C++ 스택 추적 라이브러리입니다.
- MinGW와 Cygwin 환경을 포함한 Windows 지원
-
목표: 스택 추적을 한 번에 간단하게 만듭니다.
-
Cpptrace에는 C API도 있습니다.
- 자세한 내용은 여기에서 확인하세요.
- 스택 추적을 생성하는 것은 다음과 같이 쉽습니다.
#include <cpptrace/cpptrace.hpp>
void trace() {
cpptrace::generate_trace().print();
}
- Cpptrace는 최적화된 릴리스 빌드에서 함수 인라인 정보를 검색할 수도 있습니다.
- Cpptrace는 해결된 스택 추적과 가벼운 원시 추적(주소만)에 대한 액세스를 제공합니다. 나중에 해결됨:
const auto raw_trace = cpptrace::generate_raw_trace();
// then later
raw_trace.resolve().print();
- Cpptrace는 임의의 예외에 대한 스택 추적을 생성하는 방법을 제공합니다.
#include <cpptrace/from_current.hpp>
void foo() {
throw std::runtime_error("foo failed");
}
int main() {
CPPTRACE_TRY {
foo();
} CPPTRACE_CATCH(const std::exception& e) {
std::cerr<<"Exception: "<<e.what()<<std::endl;
cpptrace::from_current_exception().print();
}
}
예외 처리의 내부 구조에 해당하는 스택의 맨 위에 몇 개의 외부 프레임이 있습니다. 표준 라이브러리. 이는 모든 예외에 대한 스택 추적을 위해 지불해야 할 작은 대가입니다.
- Cpptrace는 또한 throw될 때 스택 추적을 저장하는 소수의 추적된 예외 객체를 제공합니다. 이것은 다음과 같은 경우에 유용합니다. 예외는 `CPPTRACE_CATCH`로 포착되지 않을 수 있습니다.
#include <cpptrace/cpptrace.hpp>
void trace() {
throw cpptrace::logic_error("This wasn't supposed to happen!");
}
주목할 만한 추가 기능:
- 디맹글링(demangling) 유틸리티
std::exception
을 포착하고 추적된 예외에 래핑(wrapping)하기 위한 유틸리티- 신호-안전(Signal-safe) 스택(stack) 추적
- 추적(traces)의 소스 코드 스니펫(snippets )
include(FetchContent)
FetchContent_Declare(
cpptrace
GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git
GIT_TAG v0.7.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(cpptrace)
target_link_libraries(your_target cpptrace::cpptrace)
# Needed for shared library builds on windows: copy cpptrace.dll to the same directory as the
# executable for your_target
if(WIN32)
add_custom_command(
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:cpptrace::cpptrace>
$<TARGET_FILE_DIR:your_target>
)
endif()
심볼 및 줄의 경우 -DCMAKE_BUILD_TYPE=Debug
또는 -DCMAKE_BUILD_TYPE=RelWithDebInfo
로 구성해야 합니다.
macOS에서는 .dSYM
파일을 생성하는 것이 좋습니다. 아래 플랫폼 로지스틱스(Platform Logistics)를 참조하세요.
패키지 관리자, 시스템 전체 설치 또는 플랫폼 등 라이브러리를 사용하는 다른 방법의 경우 인터넷 접속이 없는 경우 아래의 라이브러리를 포함하는 방법을 참조하세요.
언젠가 C++23의 <stacktrace>
가 널리 쓰일 것입니다. 그리고 언젠가 msvc 구현이 수용될 수도 있을 것입니다.
cpptrace의 원래 동기는 이전 C++ 표준을 사용하는 프로젝트를 지원하는 것이었으며 라이브러리가 커지면서
기능이 표준 라이브러리 구현을 넘어 확장되었습니다.
Cpptrace는 표준 라이브러리가 제공하는 기능이나 구현이 제공하는 기능 이상의 기능을 제공합니다. 예를 들어 다음과 같습니다.
- 인라인 함수 호출 진행
- "원시 추적(raw traces)"에 대한 가벼운 인터페이스 제공
- 함수 매개변수 유형 확인
- 추적된 예외 개체 제공
- 신호-안전(signal-safe) 스택 추적 생성을 위한 API 제공
- 특별한 cpptrace 추적 예외뿐만 아니라 임의의 예외에서 스택 추적을 검색하는 방법 제공 객체. 이는 C++26에 추가되는 기능이지만 cpptrace는 C++11에 대한 솔루션을 제공합니다.
boost stacktrace 및 backward-cpp와 같은 기타 C++ stacktrace 라이브러리는 이식성 측면에서 부족합니다. 사용 편의성. 테스트에서 나는 어느 쪽도 다양한 환경을 충분히 커버하지 못한다는 것을 발견했습니다. 심지어 그들이 할 수 있을 때조차도. 최종 사용자의 수동 구성이 필요한 환경에서 작동하도록 만들어졌으며 수동 구성이 필요할 수 있습니다. 타사 종속성 설치. 이는 특히 다음과 같은 경우 사용자에게 부과하기에 매우 바람직하지 않은 부담입니다. 핵심 기능이 아닌 진단만 제공하는 소프트웨어 패키지의 경우. 또한 cpptrace는 다음을 제공합니다. DWARF 심볼에 대한 인라인 호출을 기본적으로 해결하기 위한 지원(boost는 이를 수행하지 않지만 backward-cpp는 이를 수행할 수 있음) 다른 기능들 중에서도 특히, 일부 백엔드에만 해당), 전체 함수 시그니처 해결에 대한 더 나은 지원, 더 좋은 API 등이 있습니다.
# 필수 조건
Note
디버그 정보(-g
//Z7
//Zi
//DEBUG
/-DBUILD_TYPE=Debug
/-DBUILD_TYPE=RelWithDebInfo
)가 추적 정보를 완료하는데 필요합니다.
cpptrace::generate_trace()
는 현재 호출 사이트에서 stacktrace
객체를 생성하는 데 사용할 수 있습니다. 해결된 프레임은 .frames
를 사용하여 이 객체에서 액세스할 수 있으며 추적은 .print()
를 사용하여 인쇄할 수 있습니다. Cpptrace는 또한 다음을 제공합니다.
cpptrace::generate_raw_trace()
를 사용하여 프로그램 카운터의 벡터에 불과한 가벼운 원시 추적을 얻는 방법
이는 나중에 해결될 수 있습니다.
달리 언급하지 않는 한 모든 기능은 스레드로부터 안전합니다.
핵심 해결 스택 추적 개체.
cpptrace::generate_trace()
로 추적을 생성하거나 cpptrace::stacktrace::current()
.
도우미 함수 집합 위에 struct stacktrace
가 허용됩니다.
프레임과 반복자에 직접 액세스할 수 있습니다.
cpptrace::stacktrace::print
를 사용하여 스택 추적을 인쇄할 수 있습니다. cpptrace::stacktrace::print_with_snippets
를 사용하여 스택 추적을 인쇄할 수 있습니다.
소스 코드 조각으로 스택 추적을 인쇄합니다.
namespace cpptrace {
// Some type sufficient for an instruction pointer, currently always an alias to std::uintptr_t
using frame_ptr = std::uintptr_t;
struct stacktrace_frame {
frame_ptr raw_address; // address in memory
frame_ptr object_address; // address in the object file
// nullable<T> represents a nullable integer. More docs later.
nullable<std::uint32_t> line;
nullable<std::uint32_t> column;
std::string filename;
std::string symbol;
bool is_inline;
bool operator==(const stacktrace_frame& other) const;
bool operator!=(const stacktrace_frame& other) const;
object_frame get_object_info() const; // object_address is stored but if the object_path is needed this can be used
std::string to_string() const;
/* operator<<(ostream, ..) and std::format support exist for this object */
};
struct stacktrace {
std::vector<stacktrace_frame> frames;
// here as a drop-in for std::stacktrace
static stacktrace current(std::size_t skip = 0);
static stacktrace current(std::size_t skip, std::size_t max_depth);
void print() const;
void print(std::ostream& stream) const;
void print(std::ostream& stream, bool color) const;
void print_with_snippets() const;
void print_with_snippets(std::ostream& stream) const;
void print_with_snippets(std::ostream& stream, bool color) const;
std::string to_string(bool color = false) const;
void clear();
bool empty() const noexcept;
/* operator<<(ostream, ..), std::format support, and iterators exist for this object */
};
stacktrace generate_trace(std::size_t skip = 0);
stacktrace generate_trace(std::size_t skip, std::size_t max_depth);
}
개체 추적에는 현재 실행 중인 스택 추적 외부에서 스택 추적을 구성하는 데 필요한 가장 기본적인 정보가 포함되어 있습니다. 실행 파일입니다. 여기에는 원시 주소, 바이너리의 주소(ASLR 및 개체 파일의 메모리 공간 등)가 포함됩니다. 해결됨) 및 명령 포인터가 위치한 개체의 경로입니다.
namespace cpptrace {
struct object_frame {
std::string object_path;
frame_ptr raw_address;
frame_ptr object_address;
};
struct object_trace {
std::vector<object_frame> frames;
static object_trace current(std::size_t skip = 0);
static object_trace current(std::size_t skip, std::size_t max_depth);
stacktrace resolve() const;
void clear();
bool empty() const noexcept;
/* iterators exist for this object */
};
object_trace generate_object_trace(std::size_t skip = 0);
object_trace generate_object_trace(std::size_t skip, std::size_t max_depth);
}
원시 추적 액세스(Raw trace access): 프로그램 카운터 벡터(vector). 이는 나중에 해결하려는 빠르고 저렴한 추적에 이상적입니다.
메모리에 있는 실행 파일과 공유 라이브러리가 어떻게든 매핑 해제되지 않는 것이 중요합니다. 그렇지 않으면 libdl 호출(및 Windows의 GetModuleFileName
)은 프로그램 카운터가 어디에 해당하는지 알아내는 데 실패합니다.
namespace cpptrace {
struct raw_trace {
std::vector<frame_ptr> frames;
static raw_trace current(std::size_t skip = 0);
static raw_trace current(std::size_t skip, std::size_t max_depth);
object_trace resolve_object_trace() const;
stacktrace resolve() const;
void clear();
bool empty() const noexcept;
/* iterators exist for this object */
};
raw_trace generate_raw_trace(std::size_t skip = 0);
raw_trace generate_raw_trace(std::size_t skip, std::size_t max_depth);
}
cpptrace::demangle
은 이름 디매글링을 위한 도우미 함수를 제공합니다. 왜냐하면 이 도우미 함수를 내부적으로 구현해야 하기 때문입니다. 어쨌든.
cpptrace::get_snippet
은 가능한 경우 주어진 소스 파일에 대해 +/- context_size
줄에 대한 텍스트 스니펫을 가져옵니다. 선(line)
주위로.
cpptrace::isatty
와 fileno 정의는 스택 추적을 인쇄할 때 색상을 사용할지 여부를 결정하는 데 유용합니다.
cpptrace::register_terminate_handler()
는 사용자 정의 std::terminate
핸들러를 설정하는 도우미 함수입니다.
cpptrace 예외에서 스택 추적(자세한 내용은 아래 참조)을 수행하고 그 외에는 일반 종료 핸들러처럼 동작합니다.
namespace cpptrace {
std::string demangle(const std::string& name);
std::string get_snippet(
const std::string& path,
std::size_t line,
std::size_t context_size,
bool color = false
);
bool isatty(int fd);
extern const int stdin_fileno;
extern const int stderr_fileno;
extern const int stdout_fileno;
void register_terminate_handler();
}
cpptrace::absorb_trace_exceptions
: 라이브러리가 내부 예외를 자동으로 흡수하고 계속 진행할지 여부를 구성합니다. 기본값은 true입니다.
cpptrace::ctrace_enable_inlined_call_resolution
: 라이브러리가 인라인 호출을 해결하려고 시도할지 여부를 구성합니다. 릴리스 빌드에 대한 정보입니다. 기본값은 true입니다.
cpptrace::experimental::set_cache_mode
: 라이브러리 내에서 시간-메모리 트레이드오프를 제어합니다. 기본적으로 속도는 우선순위가 지정되었습니다. 이 기능을 사용하는 경우 추적이 시작되기 전에 프로그램 시작 시 캐시 모드를 설정하십시오.
namespace cpptrace {
void absorb_trace_exceptions(bool absorb);
void ctrace_enable_inlined_call_resolution(bool enable);
enum class cache_mode {
// Only minimal lookup tables
prioritize_memory,
// Build lookup tables but don't keep them around between trace calls
hybrid,
// Build lookup tables as needed
prioritize_speed
};
namespace experimental {
void set_cache_mode(cache_mode mode);
}
}
Cpptrace는 현재 스택 추적을 수집할 수 있는 CPPTRACE_TRY
및 CPPTRACE_CATCH
매크로를 제공합니다.
throws 예외 객체, throws되지 않는 경로에서 오버헤드가 최소화되거나 전혀 없음:
#include <cpptrace/from_current.hpp>
void foo() {
throw std::runtime_error("foo failed");
}
int main() {
CPPTRACE_TRY {
foo();
} CPPTRACE_CATCH(const std::exception& e) {
std::cerr<<"Exception: "<<e.what()<<std::endl;
cpptrace::from_current_exception().print();
}
}
이 기능은 전적으로 선택 사항이며, 접근하려면 #include <cpptrace/from_current.hpp>
를 사용하세요.
모든 선언자 catch
는 ...
를 포함하여 CPPTRACE_CATCH
와 함께 작동합니다. 이것은 던져진 모든 객체와 함께 작동합니다.
std::exceptions
는 throw 0;
와도 작동합니다.
표준 라이브러리 예외 처리에 해당하는 스택 맨 위에 몇 개의 외부 프레임이 있습니다. 내부. 이는 모든 예외에 대한 스택 추적에 대한 작은 대가입니다.
API 함수:
cpptrace::raw_trace_from_current_exception
: 현재 예외에서const raw_trace&
를 반환합니다.cpptrace::from_current_exception
: 현재 예외에서 해결된const stacktrace&
를 반환합니다. 무효화합니다.cpptrace::raw_trace_from_current_exception
에서 반환된 추적에 대한 참조.
이 기능에는 성능 저하가 있습니다. 즉, try-block은 오버헤드가 전혀 없을 수 있습니다. 던지기 경로(throwing path)에서 잠재적인 비용이 발생하는 던지지 않는(non-throwing path) 경로 또는 시도 블록의 오버헤드가 매우 최소화될 수 있습니다. 던지는 경로의 비용에 대한 보증이 있는 회계로 인해 던지지 않는 경로에서. 자세한 내용은 이 트레이드오프는 아래입니다. Cpptrace는 이 트레이드오프의 양쪽에 대한 매크로를 제공합니다.
CPPTRACE_TRY
/CPPTRACE_CATCH
: throw하지 않는 경로에서 최소 오버헤드(x86에서 하나의mov
, 이는 다음과 같을 수 있음) 컴파일러가 가능하다면 최적화됨)CPPTRACE_TRYZ
/CPPTRACE_CATCHZ
: 던지지 않는 경로에서는 오버헤드가 없고 던지는 경로에서는 추가 비용이 발생할 가능성이 있음
참고: Z
변형(variants)과 Z
가 아닌(non-) 변형(variants)을 섞지 않는 것이 중요합니다.
안타깝게도 try/catch 매크로는 검색 풀기 단계에서 추적을 수행하기 위한 마법을 삽입하는 데 필요합니다.
여러 개의 catch 대안을 사용하려면 CPPTRACE_CATCH_ALT
또는 일반 catch
를 사용해야 합니다.
CPPTRACE_TRY {
foo();
} CPPTRACE_CATCH(const std::exception&) { // <- First catch must be CPPTRACE_CATCH
// ...
} CPPTRACE_CATCH_ALT(const std::exception&) { // <- Ok
// ...
} catch(const std::exception&) { // <- Also Ok
// ...
} CPPTRACE_CATCH(const std::exception&) { // <- Not Ok
// ...
}
참고: 현재 예외는 cpptrace try-catch 매크로 블록에서 가장 최근에 확인된 예외입니다.
CPPTRACE_TRY {
throw std::runtime_error("foo");
} CPPTRACE_CATCH(const std::exception& e) {
cpptrace::from_current_exception().print(); // the trace for std::runtime_error("foo")
CPPTRACE_TRY {
throw std::runtime_error("bar");
} CPPTRACE_CATCH(const std::exception& e) {
cpptrace::from_current_exception().print(); // the trace for std::runtime_error("bar")
}
cpptrace::from_current_exception().print(); // the trace for std::runtime_error("bar"), again
}
CPPTRACE_TRY
는 타이핑하기 약간 번거롭습니다. CPPTRACE_
접두사를 제거하려면 다음을 사용할 수 있습니다.
CPPTRACE_UNPREFIXED_TRY_CATCH
cmake 옵션 또는 CPPTRACE_UNPREFIXED_TRY_CATCH
전처리기 정의:
TRY {
foo();
} CATCH(const std::exception& e) {
std::cerr<<"Exception: "<<e.what()<<std::endl;
cpptrace::from_current_exception().print();
}
이것은 매크로 안전/위생상의 이유로 기본적으로 수행되지 않습니다. TRY
/CATCH
매크로를 정의하지 않으려는 경우, 일반적인 매크로 이름이므로 다음 스니펫을 쉽게 수정하여 고유한 별칭을 제공할 수 있습니다.
#define TRY CPPTRACE_TRY
#define CATCH(param) CPPTRACE_CATCH(param)
#define TRYZ CPPTRACE_TRYZ
#define CATCHZ(param) CPPTRACE_CATCHZ(param)
#define CATCH_ALT(param) CPPTRACE_CATCH_ALT(param)
C++는 예외가 발생할 때 스택 추적을 수집하기 위한 언어 지원을 제공하지 않지만 예외 Itanium ABI와 SEH(Windows에서 C++ 예외를 구현하는 데 사용됨) 모두에서 처리하려면 다음을 풀어야 합니다. 두 번 스택합니다. 첫 번째 언와인은 적절한 catch
핸들러를 검색하고 두 번째 언와인은 실제로 스택을 언와인드합니다. 소멸자를 호출합니다. 검색 단계 동안 스택이 그대로 유지되므로 스택 추적을 수집할 수 있습니다. catch
가 예외와 일치하는 것으로 간주될 때 오버헤드가 거의 없거나 전혀 없습니다. cpptrace에 대한 try/catch 매크로는 다음과 같이 설정합니다. 검색 단계에서 스택 추적을 수집할 수 있는 특별한 try/catch 시스템을 만들었습니다.
참고: 이 메커니즘은 P2490R3 P2490R3에서도 논의됩니다.
이 기능의 기본 메커니즘은 catch 블록이 고려될 때 추적을 생성하는 것입니다.
예외 처리기 검색 단계. 내부적으로 가벼운 원시 추적이 고려 사항에 따라 생성되며 이는 매우
빠릅니다. 이 원시 추적은 cpptrace::from_current_exception
이 호출되거나 사용자가 수동으로
cpptrace::raw_trace_from_current_exception
에서 추적을 해결합니다.
그러나 도서관의 관점에서 캐치가 결국 일치하는지 확인하는 것은 까다롭습니다. 도서관은 단순히
그러나 CPPTRACE_CATCH
가 고려될 때마다 추적을 생성하지만 예를 들어 catch가 깊이 중첩된 경우에는
재귀, 일치하는 핸들러를 신속하게 찾을 수 없는 경우 던지기 패턴에 경미하지 않은 비용이 발생할 수 있습니다.
스택을 여러 번 추적하는 것과 같습니다. 따라서 작은 회계 기록과 방지를 위한 성능 트레이드오프가 있습니다.
말하자면, 추적을 중복하거나 총알을 물고 던지는 경로에서 여러 번 풀기를 반복합니다.
Tip
예외 처리기의 Z
및 Z가 아닌
(제로 오버헤드 및 0이 아닌 오버헤드) 변형(variants) 간의 선택은 다음과 같아야 합니다.
99%의 경우는 중요하지 않지만, 중요한 경우에는 둘 다 제공됩니다.
CPPTRACE_TRY
/CPPTRACE_CATCH
는 컴파일러가 최적화할 수 없는 핫 루프에서 사용되는 경우에만 성능을 저하시킬 수 있습니다.
내부 회계를 없애지 않으면 회계는 완전히 무시할 수 있을 것입니다.
CPPTRACE_TRYZ
/CPPTRACE_CATCHZ
는 예외가 매우 깊게 중첩되어 있는 경우에만 성능을 저하시킬 수 있습니다.
일치하는 핸들러보다 먼저 호출 스택에 있는 핸들러.
제로 오버헤드 변형의 성능 고려 사항에 대한 자세한 정보:
대부분의 애플리케이션에서는 던지기 경로에서 스택을 여러 번 추적하는 것이 문제가 되지 않습니다. 그 이유는 다음과 같습니다.
- 성능은 경로 던지기에 매우 중요하지 않으며 예외는 매우 드물어야 합니다.
- 예외 처리가 일반적으로 사용되지 않는 이유는 처리기를 찾기 전에 처리기를 깊이 중첩할 수 있기 때문입니다. 매칭 핸들러
- 대부분의 호출 스택은 상당히 얕습니다.
이 성능 고려 사항의 규모를 관점에 맞춰 설명하자면 벤치마킹에서 원시 생성을 발견했습니다.
프레임당 100ns
의 순서로 추적합니다. 따라서 일치하는 핸들러가 100개라도 일치되지 않는 핸들러가 일치하기 전에 100개라도
100개의 깊이로 된 호출 스택에 핸들러가 있어도 총 시간은 여전히 1밀리초 수준이 될 것입니다.
그럼에도 불구하고 나는 더 나은 안전성을 제공하기 때문에 CPPTRACE_TRY
/CPPTRACE_CATCH
에 대한 기본 회계 동작을 선택했습니다.
가장 일반적인 사용자 집합에 대한 성능 보장.
Cpptrace는 throw될 때 자동으로 스택 추적을 수집하는 소수의 추적된 예외 클래스를 제공합니다. 이러한
CPPTRACE_CATCH
로 포착할 수 없는 예외를 발생시킬 때 유용합니다.
기본 추적 예외 클래스는 cpptrace::exception
이고 cpptrace는 작업을 위한 소수의 도우미 클래스를 제공합니다.
추적된 예외가 있습니다. 이러한 예외는 비교적 가벼운 원시 추적을 생성하고 심볼과 줄 번호를 확인합니다.
요청이 있을 경우 게으르게 처리합니다.
이러한 기능은 유용한 유틸리티와 추적된 예외에 대한 참조 구현으로 제공됩니다.
기본 인터페이스는 다음과 같습니다.
namespace cpptrace {
class exception : public std::exception {
public:
virtual const char* what() const noexcept = 0; // The what string both the message and trace
virtual const char* message() const noexcept = 0;
virtual const stacktrace& trace() const noexcept = 0;
};
}
추적된 예외 객체에 대한 접근 방법에는 두 가지가 있습니다. 추적은 열렬히 또는 느리게 해결될 수 있습니다. Cpptrace는 다음을 제공합니다. 예외의 기본 구현을 게으른 예외로 합니다. 구현에 대한 어떤 것도 노출되는 것을 싫어합니다. 인터페이스나 유형 시스템을 사용할 수도 있지만 이것이 가장 좋은 방법인 듯합니다.
namespace cpptrace {
class lazy_exception : public exception {
// lazy_trace_holder is basically a std::variant<raw_trace, stacktrace>, more docs later
mutable detail::lazy_trace_holder trace_holder;
mutable std::string what_string;
public:
explicit lazy_exception(
raw_trace&& trace = detail::get_raw_trace_and_absorb()
) noexcept : trace_holder(std::move(trace)) {}
const char* what() const noexcept override;
const char* message() const noexcept override;
const stacktrace& trace() const noexcept override;
};
}
cpptrace::lazy_exception
은 자유롭게 throw되거나 오버라이드될 수 있습니다. 일반적으로 message()
는 오버라이드할 유일한 필드입니다.
마지막으로 cpptrace는 사용자가 제공한 메시지인 cpptrace::exception_with_message
를 사용하는 예외 클래스를 제공합니다.
<stdexcept>
와 유사한 여러 가지 추적된 예외 클래스도 있습니다.
namespace cpptrace {
class exception_with_message : public lazy_exception {
mutable std::string user_message;
public:
explicit exception_with_message(
std::string&& message_arg,
raw_trace&& trace = detail::get_raw_trace_and_absorb()
) noexcept : lazy_exception(std::move(trace)), user_message(std::move(message_arg)) {}
const char* message() const noexcept override;
};
// All stdexcept errors have analogs here. All but system_error have the constructor:
// explicit the_error(
// std::string&& message_arg,
// raw_trace&& trace = detail::get_raw_trace_and_absorb()
// ) noexcept
// : exception_with_message(std::move(message_arg), std::move(trace)) {}
class logic_error : public exception_with_message { ... };
class domain_error : public exception_with_message { ... };
class invalid_argument : public exception_with_message { ... };
class length_error : public exception_with_message { ... };
class out_of_range : public exception_with_message { ... };
class runtime_error : public exception_with_message { ... };
class range_error : public exception_with_message { ... };
class overflow_error : public exception_with_message { ... };
class underflow_error : public exception_with_message { ... };
class system_error : public runtime_error {
public:
explicit system_error(
int error_code,
std::string&& message_arg,
raw_trace&& trace = detail::get_raw_trace_and_absorb()
) noexcept;
const std::error_code& code() const noexcept;
};
}
Note
이 섹션은 cpptrace가 예외 추적 수집을 위한 더 나은 메커니즘을 제공하므로 이제 거의 사용되지 않습니다.
Cpptrace 예외는 사용자 제어 예외에 대한 훌륭한 정보를 제공할 수 있습니다. 예를 들어 표준 라이브러리인 cpptrace는 제어하는 코드 외부에서 시작되며 이를 통해 래퍼 유틸리티를 제공할 수 있습니다. 추적된 cpptrace 예외에 중첩된 이러한 예외를 다시 throw합니다. 추적은 완벽하지 않을 것이며 추적은 다음 위치에서 시작됩니다. 래퍼가 그것을 잡았지만, 이 유틸리티는 좋은 진단 정보를 제공할 수 있습니다. 불행히도 이것이 최고입니다. 제가 아는 한, 이 문제에 대한 해결책은 다음과 같습니다.
std::vector<int> foo = {1, 2, 3};
CPPTRACE_WRAP_BLOCK(
foo.at(4) = 2;
foo.at(5)++;
);
std::cout<<CPPTRACE_WRAP(foo.at(12))<<std::endl;
Note
이 섹션은 cpptrace에서 추적된 예외 개체와 관련이 있으며 임의의 예외 추적(traces-from-exceptions) 수집 메커니즘과는 관련이 없습니다.
코드에서 cpptrace 예외 작업:
try {
foo();
} catch(cpptrace::exception& e) {
// Prints the exception info and stack trace, conditionally enabling color codes depending on
// whether stderr is a terminal
std::cerr << "Error: " << e.message() << '\n';
e.trace().print(std::cerr, cpptrace::isatty(cpptrace::stderr_fileno));
} catch(std::exception& e) {
std::cerr << "Error: " << e.what() << '\n';
}
Cpptrace는 스택 추적을 인쇄하는 동시에 일반적인 것과 같이 동작하는 사용자 정의 std::terminate
핸들러를 제공합니다.
std::terminate
핸들러. cpptrace 예외 객체가 std::terminate
에 도달하면 해당 예외의 추적은 다음과 같습니다.
인쇄되지 않으면 종료 핸들러 지점에서 스택 추적이 생성됩니다. 종종 std::terminate
가 호출됩니다.
풀지 않고 바로 이어붙여 흔적을 보존합니다.
이 사용자 정의 핸들러를 등록하려면:
cpptrace::register_terminate_handler();
신호 안전 스택 추적은 SIGSEGV와 같은 애플리케이션 충돌을 디버깅하는 데 매우 유용합니다. SIGTRAP은 올바르게 수행하기가 매우 어렵고 내가 온라인에서 본 대부분의 구현이 이를 수행합니다. 틀리게.
이 전체 프로세스를 안전하게 수행하려면 신호에서 기본 정보를 수집하는 것이 좋습니다. 처리기에서 처리한 다음 나중에 해결하거나 해당 정보를 다른 프로세스에 전달하여 해결합니다.
cpptrace::generate_trace().print()
를 호출하는 것만큼 간단하지는 않지만 다음과 같은 작업을 수행할 수 있습니다.
그런 건 필요 없지만, 정말 안전하게 하려면 이게 필요합니다.
안전한 API는 다음과 같습니다.
namespace cpptrace {
std::size_t safe_generate_raw_trace(frame_ptr* buffer, std::size_t size, std::size_t skip = 0);
std::size_t safe_generate_raw_trace(frame_ptr* buffer, std::size_t size, std::size_t skip, std::size_t max_depth);
struct safe_object_frame {
frame_ptr raw_address;
frame_ptr address_relative_to_object_start; // object base address must yet be added
char object_path[CPPTRACE_PATH_MAX + 1];
object_frame resolve() const; // To be called outside a signal handler. Not signal safe.
};
void get_safe_object_frame(frame_ptr address, safe_object_frame* out);
bool can_signal_safe_unwind();
}
Important
현재 신호 안전 스택 풀림은 libunwind
로만 가능하며,
수동으로 활성화됨. 신호 안전 풀기가 지원되지 않으면 safe_generate_raw_trace
가
빈 추적을 생성합니다. can_signal_safe_unwind
는 신호 안전 풀림 지원을 확인하는 데 사용할 수 있습니다. 객체가
정보가 신호 안전 방식으로 확인될 수 없으면 get_safe_object_frame
은 다음 필드를 채우지 않습니다.
원시 주소
.
Important
_dl_find_object
는 신호 안전 스택 추적에 필요합니다. 이것은 glibc에 비교적 최근에 추가된 것으로,
glibc 2.35.
Caution
공유 객체에 대한 호출은 공유 객체에 대한 첫 번째 호출이 신호 안전이 아닌 함수를 호출하는 경우 지연 로드될 수 있습니다.
malloc()
와 같은 경우. 이를 피하려면 라이브러리를 "워밍업"하기 위해 신호 처리기보다 앞서 main()
에서 이러한 루틴을 호출합니다.
신호 안전 추적은 복잡한 프로세스이므로 포괄적인 개요를 작성했습니다.
몇 가지 유틸리티 유형을 사용하여 라이브러리에 좋은 인터페이스를 제공합니다.
nullable<T>
는 nullable 정수 유형에 사용됩니다. 내부적으로 T
의 최대값은 다음과 같이 사용됩니다.
sentinel. 이 라이브러리가 c++11이 아니라면 std::optional
이 사용될 것입니다. 하지만 nullable<T>
는 다음을 제공합니다.
std::optional
과 유사한 인터페이스이며 이 용도에서는 std::optional
보다 덜 무겁습니다.
detail::lazy_trace_holder
는 lazy_exception
대신 사용되는 유틸리티 유형입니다.
std::variant<원시 추적, 스택 추적>
.
namespace cpptrace {
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
struct nullable {
T raw_value;
nullable& operator=(T value)
bool has_value() const noexcept;
T& value() noexcept;
const T& value() const noexcept;
T value_or(T alternative) const noexcept;
void swap(nullable& other) noexcept;
void reset() noexcept;
bool operator==(const nullable& other) const noexcept;
bool operator!=(const nullable& other) const noexcept;
constexpr static nullable null() noexcept; // returns a null instance
};
namespace detail {
class lazy_trace_holder {
bool resolved;
union {
raw_trace trace;
stacktrace resolved_trace;
};
public:
// constructors
lazy_trace_holder() : trace() {}
explicit lazy_trace_holder(raw_trace&& _trace);
explicit lazy_trace_holder(stacktrace&& _resolved_trace);
// logistics
lazy_trace_holder(const lazy_trace_holder& other);
lazy_trace_holder(lazy_trace_holder&& other) noexcept;
lazy_trace_holder& operator=(const lazy_trace_holder& other);
lazy_trace_holder& operator=(lazy_trace_holder&& other) noexcept;
~lazy_trace_holder();
// access
const raw_trace& get_raw_trace() const;
stacktrace& get_resolved_trace();
const stacktrace& get_resolved_trace() const; // throws if not already resolved
private:
void clear();
};
}
}
Cpptrace는 포함을 최소화하기 위해 몇 가지 헤더를 제공합니다.
헤더 | 내용 |
---|---|
cpptrace/forward.hpp |
cpptrace::frame_ptr 및 몇 가지 추적 클래스 전방 선언 |
cpptrace/basic.hpp |
추적 클래스 및 기본 추적 API에 대한 정의(스택 추적(stack-traces), 객체 추적(object-traces), 원시 추적(raw-traces), 신호 안전 추적(signal-safe-tracing)) |
cpptrace/exceptions.hpp |
추적된 예외 개체(traced-exception-objects) 및 관련 유틸리티(std::exceptions 래핑(wrapping-stdexceptions) |
cpptrace/from_current.hpp |
모든 예외의 추적(traces-from-all-exceptions) |
cpptrace/io.hpp |
std::ostream 과 std::formatter 에 대한 operator<< 오버로드 |
cpptrace/utils.hpp |
유틸리티 함수, 구성 함수 및 종료 유틸리티(utilities), 구성(configuration) 및 종료 처리(terminate-handling)) |
주요 cpptrace 헤더는 cpptrace/cpptrace.hpp
이며 여기에는 from_current.hpp
를 제외한 모든 내용이 포함됩니다.
형식 | 지원 |
---|---|
이진법의 DWARF | ✔️ |
GNU 디버그 링크 | ️️✔️ |
분할 드워프(디버그 분열(fission)) | ✔️ |
dSYM의 DWARF | ✔️ |
Mach-O 디버그 맵을 통한 DWARF | ✔️ |
PDB의 Windows 디버그 심볼 | ✔️ |
DWARF5는 DWARF 패키지 파일을 추가했습니다. 제가 아는 한 아직 이를 구현하는 컴파일러는 없습니다.
CMake FetchContent를 사용하여:
include(FetchContent)
FetchContent_Declare(
cpptrace
GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git
GIT_TAG v0.7.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(cpptrace)
target_link_libraries(your_target cpptrace::cpptrace)
그렇게 간단합니다. Cpptrace는 시스템에 맞게 자동으로 구성됩니다. 참고: Windows 및 macOS에서는 일부 추가 작업이 필요합니다. 아래의 플랫폼 물류(platform-logistics)를 참조하세요.
심볼 및 줄의 경우 -DCMAKE_BUILD_TYPE=Debug
또는 -DCMAKE_BUILD_TYPE=RelWithDebInfo
로 구성해야 합니다.
정보.
git clone https://github.com/jeremy-rifkin/cpptrace.git
git checkout v0.7.2
mkdir cpptrace/build
cd cpptrace/build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j
sudo make install
cmake를 통해 사용:
find_package(cpptrace REQUIRED)
target_link_libraries(<your target> cpptrace::cpptrace)
심볼 및 줄의 경우 -DCMAKE_BUILD_TYPE=Debug
또는 -DCMAKE_BUILD_TYPE=RelWithDebInfo
로 구성해야 합니다.
정보.
또는 -lcpptrace
로 컴파일합니다.
g++ main.cpp -o main -g -Wall -lcpptrace
./main
Important
cmake를 사용하지 않고 정적으로 링크하는 경우 -DCPPTRACE_STATIC_DEFINE
을 수동으로 지정해야 합니다.
다음과 같은 오류가 발생하는 경우
공유 라이브러리를 로드하는 동안 오류가 발생했습니다: libcpptrace.so: 공유 개체 파일을 열 수 없습니다: 해당 파일이나 디렉토리가 없습니다.
필요한 링크를 생성하고 캐시를 업데이트하려면 sudo /sbin/ldconfig
를 실행해야 할 수 있습니다. 그래야 시스템이 찾을 수 있습니다.
libcpptrace.so(Ubuntu에서 이걸 해야 했음). 시스템 전체에 설치할 때만. 일반적으로 패키지 관리자가 이 작업을 수행함
새로운 라이브러리를 설치할 때.
Note
Libdwarf에는 비교적 새로운 버전의 libdwarf가 필요합니다. 때때로 이전에 설치된 시스템 전체 libdwarf가 너무 오래되어서 문제가 발생합니다. Libdwarf 8 이상은 작동하는 것으로 알려져 있습니다.
git clone https://github.com/jeremy-rifkin/cpptrace.git
git checkout v0.7.2
mkdir cpptrace/build
cd cpptrace/build
cmake .. -DCMAKE_BUILD_TYPE=Release
msbuild cpptrace.sln
msbuild INSTALL.vcxproj
참고: 개발자 PowerShell에서 관리자 권한으로 실행하거나 Visual Studio에서 배포된 vcvarsall.bat을 사용해야 합니다. 스튜디오에서 올바른 환경 변수를 설정하세요.
로컬 사용자(또는 사용자 정의 접두사)만을 위해 설치하려면:
git clone https://github.com/jeremy-rifkin/cpptrace.git
git checkout v0.7.2
mkdir cpptrace/build
cd cpptrace/build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/wherever
make -j
make install
cmake를 통해 사용:
find_package(cpptrace REQUIRED PATHS $ENV{HOME}/wherever)
target_link_libraries(<your target> cpptrace::cpptrace)
수동으로 사용:
g++ main.cpp -o main -g -Wall -I$HOME/wherever/include -L$HOME/wherever/lib -lcpptrace
Important
cmake를 사용하지 않고 정적으로 링크하는 경우 -DCPPTRACE_STATIC_DEFINE
을 수동으로 지정해야 합니다.
cmake 없이 라이브러리를 사용하려면 먼저 설치 지침을 따르십시오. 시스템 전체 설치(system-wide-installation), 로컬 사용자 설치(local-user-installation), 또는 패키지 관리자(package-managers).
컴파일러에 cpptrace가 설치된 위치를 알려주기 위해 include나 라이브러리 경로 외에도 지정해야 합니다. cpptrace의 일반적인 종속성은 다음과 같습니다.
컴파일러 | 플랫폼 | 종속성 |
---|---|---|
gcc, clang, intel 등 | Linux/macos/unix | -lcpptrace -ldwarf -lz -lzstd -ldl |
gcc | 윈도우 | -lcpptrace -ldbghelp -ldwarf -lz -lzstd |
msvc | 윈도우 | cpptrace.lib dbghelp.lib |
clang | 윈도우 | -lcpptrace -ldbghelp |
참고: 새로운 libdwarf에는 -lzstd
가 필요하지만, 이전 libdwarf에는 필요하지 않습니다.
Important
정적으로 링크하는 경우 -DCPPTRACE_STATIC_DEFINE
도 지정해야 합니다.
서로 다른 백엔드를 수동으로 선택한 경우 종속성이 달라질 수 있습니다.
일부 사용자는 패키지 관리자나 fetchcontent 없이 cpptrace를 설치하는 것을 선호하거나 설치해야 할 수도 있습니다(예: 시스템이 인터넷 접속이 불가능합니다). libdwarf와 cpptrace를 설치하는 방법에 대한 지침은 아래와 같습니다.
다음은 cpptrace 및 libdwarf를 빌드하는 방법에 대한 예입니다. ~/scratch/cpptrace-test
는 작업 디렉토리로 사용됩니다.
라이브러리는 ~/scratch/cpptrace-test/resources
에 설치됩니다.
mkdir -p ~/scratch/cpptrace-test/resources
cd ~/scratch/cpptrace-test
git clone https://github.com/facebook/zstd.git
cd zstd
git checkout 63779c798237346c2b245c546c40b72a5a5913fe
cd build/cmake
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=~/scratch/cpptrace-test/resources -DZSTD_BUILD_PROGRAMS=On -DZSTD_BUILD_CONTRIB=On -DZSTD_BUILD_TESTS=On -DZSTD_BUILD_STATIC=On -DZSTD_BUILD_SHARED=On -DZSTD_LEGACY_SUPPORT=On
make -j
make install
cd ~/scratch/cpptrace-test
git clone https://github.com/jeremy-rifkin/libdwarf-lite.git
cd libdwarf-lite
git checkout 6dbcc23dba6ffd230063bda4b9d7298bf88d9d41
mkdir build
cd build
cmake .. -DPIC_ALWAYS=On -DBUILD_DWARFDUMP=Off -DCMAKE_PREFIX_PATH=~/scratch/cpptrace-test/resources -DCMAKE_INSTALL_PREFIX=~/scratch/cpptrace-test/resources
make -j
make install
cd ~/scratch/cpptrace-test
git clone https://github.com/jeremy-rifkin/cpptrace.git
cd cpptrace
git checkout v0.7.2
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=On -DCPPTRACE_USE_EXTERNAL_LIBDWARF=On -DCMAKE_PREFIX_PATH=~/scratch/cpptrace-test/resources -DCMAKE_INSTALL_PREFIX=~/scratch/cpptrace-test/resources
make -j
make install
~/scratch/cpptrace-test/resources
디렉토리는 설치된 모든 파일을 함께 제공할 수 있는 번들 역할도 합니다.
cpptrace와 그 종속성.
Cpptrace는 conan의 https://conan.io/center/recipes/cpptrace에서 이용할 수 있습니다.
[requires]
cpptrace/0.7.2
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layout
# ...
find_package(cpptrace REQUIRED)
# ...
target_link_libraries(YOUR_TARGET cpptrace::cpptrace)
vcpkg install cpptrace
find_package(cpptrace CONFIG REQUIRED)
target_link_libraries(main PRIVATE cpptrace::cpptrace)
Windows와 macOS에서는 모든 것을 올바른 위치에 배치하려면 약간의 추가 작업이 필요합니다.
Windows에서 라이브러리 .dll
복사:
# Copy the cpptrace.dll on windows to the same directory as the executable for your_target.
# Not required if static linking.
if(WIN32)
add_custom_command(
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:cpptrace::cpptrace>
$<TARGET_FILE_DIR:your_target>
)
endif()
macOS에서는 프로그램의 디버그 정보가 포함된 dSYM
파일을 생성하는 것이 좋습니다.
cpptrace가 디버그 정보를 찾고 읽는 데 많은 노력을 기울이기 때문에 이것은 필요하지 않습니다.
이것 없이도 dSYM
파일을 갖는 것이 가장 강력한 방법입니다.
CMake와 함께 Xcode를 사용하는 경우 다음을 사용하여 이 작업을 수행할 수 있습니다.
set_target_properties(your_target PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym")
Xcode 외부에서는 dsymutil yourbinary
를 사용하여 이 작업을 수행할 수 있습니다.
# Create a .dSYM file on macOS
if(APPLE)
add_custom_command(
TARGET your_target
POST_BUILD
COMMAND dsymutil $<TARGET_FILE:your_target>
)
endif()
Cpptrace는 스택 추적을 생성하기 위해 여러 백엔드를 지원합니다. 스택 추적은 대략 3단계로 생성됩니다. 풀기, 심볼 해결, 디맹글링.
라이브러리의 CMake는 시스템이 지원하는 것에 대해 자동으로 자체를 구성합니다. 이상적인 구성은 다음과 같습니다. 다음과 같습니다:
플랫폼 | 풀림 | 심볼 | 디맨글링 |
---|---|---|---|
리눅스 | _Unwind |
libdwarf | cxxabi.h |
MacOS | gcc용 _Unwind , clang 및 apple clang용 execinfo.h |
libdwarf | cxxabi.h |
Windows | StackWalk64 |
dbghelp | 디매글링 필요 없음 |
MinGW | StackWalk64 |
libdwarf + dbghelp | cxxabi.h |
이러한 백엔드에 대한 지원은 주요 개발 초점이며 잘 작동해야 합니다. 다른 것을 사용하려는 경우 예를 들어 addr2line과 같은 백엔드의 경우 라이브러리를 구성하여 해당 작업을 수행할 수 있습니다.
풀기 (Unwinding)
라이브러리 | CMake 구성 | 플랫폼 | 정보 |
---|---|---|---|
libgcc unwind | CPPTRACE_UNWIND_WITH_UNWIND |
linux, macos, mingw | 프레임은 libgcc의 _Unwind_Backtrace 로 캡처되며, 현재 gcc/clang/mingw에서 가장 정확한 스택 추적을 생성합니다. Libgcc는 종종 기본적으로 연결되고 llvm에는 동등한 것이 있습니다. |
execinfo.h | CPPTRACE_UNWIND_WITH_EXECINFO |
linux, macos | 프레임은 linux/unix 시스템의 libc의 일부인 execinfo.h 의 backtrace 로 캡처됩니다. |
winapi | CPPTRACE_UNWIND_WITH_WINAPI |
windows, mingw | 프레임은 CaptureStackBackTrace 로 캡처됩니다. |
dbghelp | CPPTRACE_UNWIND_WITH_DBGHELP |
windows, mingw | 프레임은 StackWalk64 로 캡처됩니다. |
libunwind | CPPTRACE_UNWIND_WITH_LIBUNWIND |
linux, macos, windows, mingw | 프레임은 libunwind로 캡처됩니다. 참고: 이것은 사용자가 라이브러리를 설치해야 하는 유일한 백엔드이며 CMAKE_PREFIX_PATH 도 필요할 수 있습니다. |
N/A | CPPTRACE_UNWIND_WITH_NOTHING |
all | 풀림이 수행되지 않아 스택 추적이 비어 있음. |
일부 백엔드(execinfo 및 CaptureStackBackTrace
)에서는 주소를 읽기 위해 고정 버퍼를 생성해야 합니다.
풀기 중. 기본적으로 버퍼는 400개 프레임(스킵
프레임 이상)에 대한 주소를 보유할 수 있습니다. 이것은
CPPTRACE_HARD_MAX_FRAMES
로 구성 가능합니다.
심볼 결의 (Symbol resolution)
라이브러리 | CMake 구성 | 플랫폼 | 정보 |
---|---|---|---|
libdwarf | CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF |
linux, macos, mingw | Libdwarf는 cpptrace의 심볼 해결을 위한 선호되는 방법입니다. Cpptrace는 CPPTRACE_USE_EXTERNAL_LIBDWARF 에 따라 FetchContent 또는 find_package를 통해 가져옵니다. |
dbghelp | CPPTRACE_GET_SYMBOLS_WITH_DBGHELP |
windows | Dbghelp.h는 msvc/clang에서 심볼을 확인하는 데 권장되는 방법이며 모든 Windows 컴퓨터에서 지원됩니다. |
libbacktrace | CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE |
linux, macos*, mingw* | Libbacktrace는 대부분 시스템에 이미 설치되어 있거나 컴파일러를 통해 직접 사용할 수 있습니다. clang의 경우 CPPTRACE_BACKTRACE_PATH 를 사용하여 backtrace.h 의 절대 경로를 지정해야 합니다. |
addr2line | CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE |
linux, macos, mingw | fork() (linux/unix에서는 popen , mingw에서는 addr2line )(또는 mac에서는 atos )를 호출하여 심볼을 해결합니다. |
libdl | CPPTRACE_GET_SYMBOLS_WITH_LIBDL |
linux, macos | Libdl은 동적 내보내기 정보를 사용합니다. 심볼 정보를 검색하려면 -rdynamic 으로 컴파일해야 합니다. 줄 번호는 검색할 수 없습니다. |
N/A | CPPTRACE_GET_SYMBOLS_WITH_NOTHING |
all | 심볼을 확인하려는 시도가 이루어지지 않습니다. |
*: 설치가 필요합니다
하나의 백엔드를 사용해야 합니다. MinGW의 경우 CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
및 CPPTRACE_GET_SYMBOLS_WITH_DBGHELP
를 사용할 수 있습니다.
접속사로 사용할 수 있습니다.
addr2line에 대한 참고사항: 기본적으로 cmake는 라이브러리에 굽기 위해 addr2line에 대한 절대 경로를 확인합니다. 이 경로는
CPPTRACE_ADDR2LINE_PATH
로 구성되거나 CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH
를 사용하여 라이브러리를 가질 수 있습니다.
런타임에 시스템 경로에서 addr2line
을 검색합니다. 이는 경로 주입 공격을 방지하기 위한 기본값이 아닙니다.
디맹글링
마지막으로, 사용된 다른 백엔드에 따라 디매글러 백엔드가 필요할 수 있습니다.
라이브러리 | CMake 구성 | 플랫폼 | 정보 |
---|---|---|---|
cxxabi.h | CPPTRACE_DEMANGLE_WITH_CXXABI |
Linux, macos, mingw | msvc 이외의 모든 곳에서 사용할 수 있어야 합니다. |
dbghelp.h | CPPTRACE_DEMANGLE_WITH_WINAPI |
Windows | UnDecorateSymbolName 로 디맨글링합니다. |
N/A | CPPTRACE_DEMANGLE_WITH_NOTHING |
all | 심볼 확인 백엔드가 하는 것 이상의 작업을 시도하지 마십시오. |
더(More)?
언와인딩, 디버그 정보 파싱, 디매글링에 사용할 수 있는 라이브러리가 훨씬 더 많습니다. 앞으로 더 많은 백엔드를 추가할 수 있습니다. 이상적으로는 이 라이브러리가 추가 설치 작업 없이 시스템에서 "그냥 작동"할 수 있습니다.
모든 라이브러리 구성 옵션 요약:
백엔드:
- CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF=On/Off
- CPPTRACE_GET_SYMBOLS_WITH_DBGHELP=On/Off
- CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE=On/Off
- CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE=On/Off
- CPPTRACE_GET_SYMBOLS_WITH_LIBDL=On/Off
- CPPTRACE_GET_SYMBOLS_WITH_NOTHING=On/Off
- CPPTRACE_UNWIND_WITH_UNWIND=On/Off
- CPPTRACE_UNWIND_WITH_LIBUNWIND=On/Off
- CPPTRACE_UNWIND_WITH_EXECINFO=On/Off
- CPPTRACE_UNWIND_WITH_WINAPI=On/Off
- CPPTRACE_UNWIND_WITH_DBGHELP=On/Off
- CPPTRACE_UNWIND_WITH_NOTHING=On/Off
- CPPTRACE_DEMANGLE_WITH_CXXABI=On/Off
- CPPTRACE_DEMANGLE_WITH_WINAPI=On/Off
- CPPTRACE_DEMANGLE_WITH_NOTHING=On/Off
백엔드 구성:
CPPTRACE_BACKTRACE_PATH=<string>
: clang/으로 컴파일할 때 필요한 libbacktrace backtrace.h에 대한 경로CPPTRACE_HARD_MAX_FRAMES=<숫자>
: 일부 백엔드는 고정 크기 버퍼에 씁니다. 이는 해당 버퍼의 크기입니다. 기본값은400
입니다.CPPTRACE_ADDR2LINE_PATH=<string>
: cpptrace가 호출할 addr2line 바이너리의 절대 경로를 지정합니다. 기본적으로 구성 스크립트는 바이너리를 검색하고 해당 절대 경로를 사용합니다(이것은 경로에 대한 방지를 위한 것입니다. 주입).CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH=On/Off
: cpptrace가 시스템이 PATH를 검색하도록 허용해야 하는지 여부를 지정합니다. 바이너리에 대한 환경 변수 디렉토리.
기타 유용한 구성:
CPPTRACE_BUILD_SHARED=On/Off
:BUILD_SHARED_LIBS
를 재정의합니다.CPPTRACE_INCLUDES_WITH_SYSTEM=On/Off
: cpptrace 헤더를SYSTEM
으로 표시하여 경고가 표시되지 않는 경우 이를 숨깁니다. 프로젝트의 오류입니다. 기본값은 켜짐입니다.CPPTRACE_INSTALL_CMAKEDIR
: cmake 구성에 대한 설치 경로를 재정의합니다.CPPTRACE_USE_EXTERNAL_LIBDWARF=On/Off
:FetchContent
가 아닌find_package
에서 libdwarf를 가져옵니다.CPPTRACE_POSITION_INDEPENDENT_CODE=On/Off
: 라이브러리를 위치 독립 코드(PIE)로 컴파일합니다. 기본값은 On입니다.CPPTRACE_STD_FORMAT=On/Off
:<format>
의 포함과std::formatter
특수화의 제공을 제어합니다. cpptrace.hpp. 이것은 또한 매크로CPPTRACE_NO_STD_FORMAT
로 제어할 수 있습니다.
테스트:
CPPTRACE_BUILD_TESTING
작은 데모 및 테스트 프로그램 빌드CPPTRACE_BUILD_TEST_RDYNAMIC
테스트 프로그램을 컴파일할 때-rdynamic
을 사용하세요
Cpptrace는 현재 통합 및 기능 테스트를 사용하고 있으며 백엔드의 모든 조합에서 빌드하고 실행합니다.
옵션. 구현은 github actions matrices를 기반으로 하며 다음 위치에 있는 Python 스크립트로 구동됩니다.
ci 폴더. 테스트는 github actions matrices에서 직접 수행되었지만 수백 개의 두 가지를 시작하면서
두 번째 직업은 매우 비효율적이었습니다. 테스트 출력은 다음 위치에 있는 예상 출력과 비교됩니다.
test/expected/
. 스택 추적 주소는 명령어에 따라 다음 주소를 가리킬 수 있습니다.
백엔드를 풀고, 파이썬 스크립트는 그에 따라 정확하거나 거의 일치하는 항목을 확인합니다.
대체로 저는 라이브러리의 상태에 만족합니다. 하지만 개선의 여지가 있고 문제점도 있을 것이라고 확신합니다. 존재할 것입니다. 문제가 발생하면 알려주세요! 라이브러리에서 문제점을 발견하면 알려주세요. 나도 그걸 알고 있어.
성능에 대한 참고사항: DWARF 심볼 처리를 위해서는 성능 최적화를 위해 탐색할 수 있는 여지가 많이 있습니다. 그리고 시간-메모리 트레이드오프. 현재 구현이 느리거나 메모리를 너무 많이 사용한다고 생각되면 기쁠 것입니다. 이러한 옵션 중 일부를 살펴보겠습니다.
앞으로 개선하고 싶은 몇 가지 사항은 다음과 같습니다.
- dbghelp(msvc/clang)를 사용하여 심볼을 수집하는 Windows에서 매개변수 유형은 거의 완벽하지만 제한 사항으로 인해 dbghelp에서 라이브러리는 const 및 volatile 한정자 또는 rvalue 참조를 정확하게 표시할 수 없습니다. 포인터).
저는 이 라이브러리에서 받은 도움에 감사드리며 기여를 환영합니다! 기여에 대한 정보는 CONTRIBUTING를 참조하세요.
이 라이브러리는 MIT 라이선스에 따라 운영됩니다.
Cpptrace는 다른 것을 사용하도록 구성되지 않은 한 linux, macos 및 mingw/cygwin에서 libdwarf를 사용합니다. 이 라이브러리가 libdwarf와 정적으로 링크되면 라이브러리 바이너리 자체는 LGPL이 됩니다.
'C C++' 카테고리의 다른 글
Argengine : C++ 프로젝트를 위한 간단한 CLI 인수(argument) 파서(parser) (0) | 2024.10.17 |
---|---|
엔트로피아 파일 시스템 워처 (Entropia File System Watcher) (0) | 2024.10.17 |
FLUX 시퀀스 지향 프로그래밍을 위한 C++20 라이브러리 (0) | 2024.10.16 |
inja C++용 템플릿 엔진 (0) | 2024.10.10 |
Modern C++ 날짜 date 시간 time (0) | 2024.10.10 |