Skip to content

Commit 0aa2a4f

Browse files
committed
Merge branch 'dev'
2 parents de17802 + 80261ce commit 0aa2a4f

20 files changed

+319
-97
lines changed

.github/workflows/ci.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,34 @@ jobs:
707707
ninja
708708
./unittest
709709
710+
unittest-linux-gcc-4-8-5:
711+
runs-on: ubuntu-24.04
712+
needs: unittest-linux
713+
steps:
714+
- uses: actions/checkout@v4
715+
- name: dependencies
716+
run: |
717+
wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-4.8/g++-4.8_4.8.5-4ubuntu8_amd64.deb
718+
wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-4.8/libstdc++-4.8-dev_4.8.5-4ubuntu8_amd64.deb
719+
wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-4.8/gcc-4.8-base_4.8.5-4ubuntu8_amd64.deb
720+
wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-4.8/gcc-4.8_4.8.5-4ubuntu8_amd64.deb
721+
wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-4.8/libgcc-4.8-dev_4.8.5-4ubuntu8_amd64.deb
722+
wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-4.8/cpp-4.8_4.8.5-4ubuntu8_amd64.deb
723+
wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-4.8/libasan0_4.8.5-4ubuntu8_amd64.deb
724+
sudo apt install ./gcc-4.8_4.8.5-4ubuntu8_amd64.deb ./gcc-4.8-base_4.8.5-4ubuntu8_amd64.deb ./libstdc++-4.8-dev_4.8.5-4ubuntu8_amd64.deb ./cpp-4.8_4.8.5-4ubuntu8_amd64.deb ./libgcc-4.8-dev_4.8.5-4ubuntu8_amd64.deb ./libasan0_4.8.5-4ubuntu8_amd64.deb ./g++-4.8_4.8.5-4ubuntu8_amd64.deb
725+
- name: build and test
726+
run: |
727+
mkdir build
728+
cd build
729+
cmake .. \
730+
-GNinja \
731+
-DCMAKE_BUILD_TYPE=Debug \
732+
-DCMAKE_CXX_COMPILER=g++-4.8 \
733+
-DCMAKE_C_COMPILER=gcc-4.8 \
734+
-DCPPTRACE_WERROR_BUILD=On \
735+
-DCPPTRACE_STD_FORMAT=Off
736+
ninja
737+
710738
unittest-windows-32-bit:
711739
runs-on: windows-2022
712740
needs: unittest-windows
@@ -736,6 +764,7 @@ jobs:
736764
fail-fast: false
737765
matrix:
738766
build_type: [Debug]
767+
arch: [x64, Win32]
739768
steps:
740769
- uses: actions/checkout@v4
741770
- name: Enable Developer Command Prompt
@@ -746,6 +775,7 @@ jobs:
746775
cd build
747776
cmake .. `
748777
-T ClangCL `
778+
-A ${{matrix.arch}} `
749779
-DCPPTRACE_WERROR_BUILD=On `
750780
-DCPPTRACE_BUILD_TESTING=On
751781
cmake --build . --config ${{matrix.build_type}}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,10 @@ target_link_libraries(main PRIVATE cpptrace::cpptrace)
15131513
Cpptrace supports C++20 modules: `import cpptrace;`. You'll need a modern toolchain in order to use C++20 modules (i.e.
15141514
relatively new compilers, cmake, etc).
15151515

1516+
For features involving macros you will have to `#include` headers with the macro definitions:
1517+
- `<cpptrace/exceptions_macros.hpp>`: `CPPTRACE_WRAP` and `CPPTRACE_WRAP_BLOCK`
1518+
- `<cpptrace/from_current_macros.hpp>`: `CPPTRACE_TRY`, `CPPTRACE_CATCH`, etc.
1519+
15161520
# Platform Logistics
15171521

15181522
Windows and macOS require a little extra work to get everything in the right place.

include/cpptrace/formatting.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,12 @@ CPPTRACE_BEGIN_NAMESPACE
5656
formatter& filtered_frame_placeholders(bool);
5757
formatter& filter(std::function<bool(const stacktrace_frame&)>);
5858
formatter& transform(std::function<stacktrace_frame(stacktrace_frame)>);
59+
formatter& break_before_filename(bool do_break = true);
5960

6061
std::string format(const stacktrace_frame&) const;
6162
std::string format(const stacktrace_frame&, bool color) const;
63+
// The last argument is the indent to use for the filename, if break_before_filename is set
64+
std::string format(const stacktrace_frame&, bool color, size_t filename_indent) const;
6265

6366
std::string format(const stacktrace&) const;
6467
std::string format(const stacktrace&, bool color) const;
@@ -67,8 +70,12 @@ CPPTRACE_BEGIN_NAMESPACE
6770
void print(const stacktrace_frame&, bool color) const;
6871
void print(std::ostream&, const stacktrace_frame&) const;
6972
void print(std::ostream&, const stacktrace_frame&, bool color) const;
73+
// The last argument is the indent to use for the filename, if break_before_filename is set
74+
void print(std::ostream&, const stacktrace_frame&, bool color, size_t filename_indent) const;
7075
void print(std::FILE*, const stacktrace_frame&) const;
7176
void print(std::FILE*, const stacktrace_frame&, bool color) const;
77+
// The last argument is the indent to use for the filename, if break_before_filename is set
78+
void print(std::FILE*, const stacktrace_frame&, bool color, size_t filename_indent) const;
7279

7380
void print(const stacktrace&) const;
7481
void print(const stacktrace&, bool color) const;

src/formatting.cpp

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ CPPTRACE_BEGIN_NAMESPACE
6464
address_mode addresses = address_mode::raw;
6565
path_mode paths = path_mode::full;
6666
bool snippets = false;
67+
bool break_before_filename = false;
6768
int context_lines = 2;
6869
bool columns = true;
6970
symbol_mode symbols = symbol_mode::full;
@@ -106,13 +107,17 @@ CPPTRACE_BEGIN_NAMESPACE
106107
void transform(std::function<stacktrace_frame(stacktrace_frame)> transform) {
107108
options.transform = std::move(transform);
108109
}
110+
void break_before_filename(bool do_break) {
111+
options.break_before_filename = do_break;
112+
}
109113

110114
std::string format(
111115
const stacktrace_frame& frame,
112-
detail::optional<bool> color_override = detail::nullopt
116+
detail::optional<bool> color_override = detail::nullopt,
117+
size_t filename_indent = 0
113118
) const {
114119
std::ostringstream oss;
115-
print_internal(oss, frame, color_override.value_or(options.color == color_mode::always));
120+
print_internal(oss, frame, color_override.value_or(options.color == color_mode::always), filename_indent);
116121
return std::move(oss).str();
117122
}
118123

@@ -128,17 +133,19 @@ CPPTRACE_BEGIN_NAMESPACE
128133
void print(
129134
std::ostream& stream,
130135
const stacktrace_frame& frame,
131-
detail::optional<bool> color_override = detail::nullopt
136+
detail::optional<bool> color_override = detail::nullopt,
137+
size_t filename_indent = 0
132138
) const {
133-
print_internal(stream, frame, color_override);
139+
print_internal(stream, frame, color_override, filename_indent);
134140
stream << "\n";
135141
}
136142
void print(
137143
std::FILE* file,
138144
const stacktrace_frame& frame,
139-
detail::optional<bool> color_override = detail::nullopt
145+
detail::optional<bool> color_override = detail::nullopt,
146+
size_t filename_indent = 0
140147
) const {
141-
auto str = format(frame, color_override);
148+
auto str = format(frame, color_override, filename_indent);
142149
str += "\n";
143150
std::fwrite(str.data(), 1, str.size(), file);
144151
}
@@ -206,15 +213,15 @@ CPPTRACE_BEGIN_NAMESPACE
206213
return do_color;
207214
}
208215

209-
void print_internal(std::ostream& stream, const stacktrace_frame& input_frame, detail::optional<bool> color_override) const {
216+
void print_internal(std::ostream& stream, const stacktrace_frame& input_frame, detail::optional<bool> color_override, size_t col_indent) const {
210217
bool color = should_do_color(stream, color_override);
211218
maybe_ensure_virtual_terminal_processing(stream, color);
212219
detail::optional<stacktrace_frame> transformed_frame;
213220
if(options.transform) {
214221
transformed_frame = options.transform(input_frame);
215222
}
216223
const stacktrace_frame& frame = options.transform ? transformed_frame.unwrap() : input_frame;
217-
write_frame(stream, frame, color);
224+
write_frame(stream, frame, color, col_indent);
218225
}
219226

220227
void print_internal(std::ostream& stream, const stacktrace& trace, detail::optional<bool> color_override) const {
@@ -223,6 +230,7 @@ CPPTRACE_BEGIN_NAMESPACE
223230
write_trace(stream, trace, color);
224231
}
225232

233+
226234
void write_trace(std::ostream& stream, const stacktrace& trace, bool color) const {
227235
if(!options.header.empty()) {
228236
stream << options.header << '\n';
@@ -245,11 +253,12 @@ CPPTRACE_BEGIN_NAMESPACE
245253
counter++;
246254
continue;
247255
}
248-
microfmt::print(stream, "#{<{}} ", frame_number_width, counter);
256+
257+
size_t filename_indent = write_frame_number(stream, frame_number_width, counter);
249258
if(filter_out_frame) {
250259
microfmt::print(stream, "(filtered)");
251260
} else {
252-
write_frame(stream, frame, color);
261+
write_frame(stream, frame, color, filename_indent);
253262
if(frame.line.has_value() && !frame.filename.empty() && options.snippets) {
254263
auto snippet = detail::get_snippet(
255264
frame.filename,
@@ -270,29 +279,45 @@ CPPTRACE_BEGIN_NAMESPACE
270279
}
271280
}
272281

273-
void write_frame(std::ostream& stream, const stacktrace_frame& frame, color_setting color) const {
274-
write_address(stream, frame, color);
282+
/// Write the frame number, and return the number of characters written
283+
size_t write_frame_number(std::ostream& stream, unsigned int frame_number_width, size_t counter) const
284+
{
285+
microfmt::print(stream, "#{<{}} ", frame_number_width, counter);
286+
return 2 + frame_number_width;
287+
}
288+
289+
void write_frame(std::ostream& stream, const stacktrace_frame& frame, color_setting color, size_t col) const {
290+
col += write_address(stream, frame, color);
275291
if(frame.is_inline || options.addresses != address_mode::none) {
276292
stream << ' ';
293+
col += 1;
277294
}
278295
if(!frame.symbol.empty()) {
279296
write_symbol(stream, frame, color);
280297
}
281298
if(!frame.symbol.empty() && !frame.filename.empty()) {
282-
stream << ' ';
299+
if(options.break_before_filename) {
300+
microfmt::print(stream, "\n{<{}}", col, "");
301+
} else {
302+
stream << ' ';
303+
}
283304
}
284305
if(!frame.filename.empty()) {
285306
write_source_location(stream, frame, color);
286307
}
287308
}
288309

289-
void write_address(std::ostream& stream, const stacktrace_frame& frame, color_setting color) const {
310+
/// Write the address of the frame, return the number of characters written
311+
size_t write_address(std::ostream& stream, const stacktrace_frame& frame, color_setting color) const {
290312
if(frame.is_inline) {
291313
microfmt::print(stream, "{<{}}", 2 * sizeof(frame_ptr) + 2, "(inlined)");
314+
return 2 * sizeof(frame_ptr) + 2;
292315
} else if(options.addresses != address_mode::none) {
293316
auto address = options.addresses == address_mode::raw ? frame.raw_address : frame.object_address;
294317
microfmt::print(stream, "{}0x{>{}:0h}{}", color.blue(), 2 * sizeof(frame_ptr), address, color.reset());
318+
return 2 * sizeof(frame_ptr) + 2;
295319
}
320+
return 0;
296321
}
297322

298323
void write_symbol(std::ostream& stream, const stacktrace_frame& frame, color_setting color) const {
@@ -399,13 +424,20 @@ CPPTRACE_BEGIN_NAMESPACE
399424
pimpl->transform(std::move(transform));
400425
return *this;
401426
}
427+
formatter& formatter::break_before_filename(bool do_break) {
428+
pimpl->break_before_filename(do_break);
429+
return *this;
430+
}
402431

403432
std::string formatter::format(const stacktrace_frame& frame) const {
404433
return pimpl->format(frame);
405434
}
406435
std::string formatter::format(const stacktrace_frame& frame, bool color) const {
407436
return pimpl->format(frame, color);
408437
}
438+
std::string formatter::format(const stacktrace_frame& frame, bool color, size_t filename_indent) const {
439+
return pimpl->format(frame, color, filename_indent);
440+
}
409441

410442
std::string formatter::format(const stacktrace& trace) const {
411443
return pimpl->format(trace);
@@ -445,12 +477,18 @@ CPPTRACE_BEGIN_NAMESPACE
445477
void formatter::print(std::ostream& stream, const stacktrace_frame& frame, bool color) const {
446478
pimpl->print(stream, frame, color);
447479
}
480+
void formatter::print(std::ostream& stream, const stacktrace_frame& frame, bool color, size_t filename_indent) const {
481+
pimpl->print(stream, frame, color, filename_indent);
482+
}
448483
void formatter::print(std::FILE* file, const stacktrace_frame& frame) const {
449484
pimpl->print(file, frame);
450485
}
451486
void formatter::print(std::FILE* file, const stacktrace_frame& frame, bool color) const {
452487
pimpl->print(file, frame, color);
453488
}
489+
void formatter::print(std::FILE* file, const stacktrace_frame& frame, bool color, size_t filename_indent) const {
490+
pimpl->print(file, frame, color, filename_indent);
491+
}
454492

455493
const formatter& get_default_formatter() {
456494
static formatter formatter;

src/from_current.cpp

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -92,42 +92,37 @@ namespace detail {
9292
// - https://github.com/ecatmur/stacktrace-from-exception/blob/main/stacktrace-from-exception.cpp
9393
// - https://github.com/catboost/catboost/blob/master/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_msvc.ipp
9494
// - https://www.geoffchappell.com/studies/msvc/language/predefined/index.htm
95-
#ifdef _WIN64
96-
#pragma pack(push, 4)
97-
struct CatchableType {
98-
std::uint32_t properties;
99-
std::int32_t pType;
100-
std::uint32_t non_virtual_adjustment; // these next three are from _PMD
101-
std::uint32_t offset_to_virtual_base_ptr;
102-
std::uint32_t virtual_base_table_index;
103-
std::uint32_t sizeOrOffset;
104-
std::int32_t copyFunction;
105-
};
106-
struct ThrowInfo {
107-
std::uint32_t attributes;
108-
std::int32_t pmfnUnwind;
109-
std::int32_t pForwardCompat;
110-
std::int32_t pCatchableTypeArray;
111-
};
112-
#pragma warning(disable:4200)
113-
#if IS_CLANG
114-
#pragma clang diagnostic push
115-
#pragma clang diagnostic ignored "-Wc99-extensions"
116-
#endif
117-
struct CatchableTypeArray {
118-
uint32_t nCatchableTypes;
119-
int32_t arrayOfCatchableTypes[];
120-
};
121-
#if IS_CLANG
122-
#pragma clang diagnostic pop
123-
#endif
124-
#pragma warning (pop)
125-
#pragma pack(pop)
126-
#else
127-
using CatchableTypeArray = ::_CatchableTypeArray;
128-
using CatchableType = ::_CatchableType;
129-
using ThrowInfo = ::_ThrowInfo;
95+
#pragma pack(push, 4)
96+
struct CatchableType {
97+
std::uint32_t properties;
98+
std::int32_t pType;
99+
std::uint32_t non_virtual_adjustment; // these next three are from _PMD
100+
std::uint32_t offset_to_virtual_base_ptr;
101+
std::uint32_t virtual_base_table_index;
102+
std::uint32_t sizeOrOffset;
103+
std::int32_t copyFunction;
104+
};
105+
struct ThrowInfo {
106+
std::uint32_t attributes;
107+
std::int32_t pmfnUnwind;
108+
std::int32_t pForwardCompat;
109+
std::int32_t pCatchableTypeArray;
110+
};
111+
#pragma warning(push)
112+
#pragma warning(disable:4200)
113+
#if IS_CLANG
114+
#pragma clang diagnostic push
115+
#pragma clang diagnostic ignored "-Wc99-extensions"
130116
#endif
117+
struct CatchableTypeArray {
118+
uint32_t nCatchableTypes;
119+
int32_t arrayOfCatchableTypes[];
120+
};
121+
#if IS_CLANG
122+
#pragma clang diagnostic pop
123+
#endif
124+
#pragma warning(pop)
125+
#pragma pack(pop)
131126

132127
static constexpr unsigned EH_MAGIC_NUMBER1 = 0x19930520; // '?msc' version magic, see ehdata.h
133128
static constexpr unsigned EH_EXCEPTION_NUMBER = 0xE06D7363; // '?msc', 'msc' | 0xE0000000
@@ -174,6 +169,7 @@ namespace detail {
174169
#ifdef _WIN64
175170
return reinterpret_cast<T>((uintptr_t)module_pointer + (uintptr_t)address);
176171
#else
172+
(void)module_pointer;
177173
return reinterpret_cast<T>(address);
178174
#endif
179175
}
@@ -575,7 +571,12 @@ namespace detail {
575571
void** type_info_vtable_pointer = *static_cast<void***>(type_info_pointer);
576572
// the type info vtable pointer points to two pointers inside the vtable, adjust it back
577573
type_info_vtable_pointer -= 2;
578-
auto* can_catch_fn = reinterpret_cast<decltype(can_catch)*>(type_info_vtable_pointer[6]);
574+
auto* can_catch_fn =
575+
#if IS_GCC
576+
// error: ISO C++ forbids casting between pointer-to-function and pointer-to-object on old gcc
577+
__extension__
578+
#endif
579+
reinterpret_cast<decltype(can_catch)*>(type_info_vtable_pointer[6]);
579580
return can_catch_fn(type, throw_type, throw_obj, outer);
580581
}
581582
#endif

src/unwind/unwind_with_dbghelp.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ namespace detail {
8686
frame.AddrFrame.Mode = AddrModeFlat;
8787
frame.AddrStack.Offset = context.Rsp;
8888
frame.AddrStack.Mode = AddrModeFlat;
89-
#elif defined(_M_IA64) || defined(__aarch64__)
89+
#elif defined(_M_IA64)
9090
machine_type = IMAGE_FILE_MACHINE_IA64;
9191
frame.AddrPC.Offset = context.StIIP;
9292
frame.AddrPC.Mode = AddrModeFlat;
@@ -96,6 +96,14 @@ namespace detail {
9696
frame.AddrBStore.Mode = AddrModeFlat;
9797
frame.AddrStack.Offset = context.IntSp;
9898
frame.AddrStack.Mode = AddrModeFlat;
99+
#elif defined(_M_ARM64) || defined(__aarch64__)
100+
machine_type = IMAGE_FILE_MACHINE_ARM64;
101+
frame.AddrPC.Offset = context.Pc;
102+
frame.AddrPC.Mode = AddrModeFlat;
103+
frame.AddrFrame.Offset = context.Fp;
104+
frame.AddrFrame.Mode = AddrModeFlat;
105+
frame.AddrStack.Offset = context.Sp;
106+
frame.AddrStack.Mode = AddrModeFlat;
99107
#else
100108
#error "Cpptrace: StackWalk64 not supported for this platform yet"
101109
#endif

0 commit comments

Comments
 (0)