[vm] Add Dart_SetDwarfStackTraceFootnoteCallback

This API allows embedder to append arbitrary footers to DWARF stack
traces. For example, embedder can append a link to a symbolizer
service, which could be used to symbolize the stack-trace.

TEST=manually tested, hard to create automatic tests because vm/cc tests  only support JIT, not AOT.

Bug: b/255741575
Change-Id: Id034b9b3194f7b91a8405574ea771c4a06fda2c2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275700
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
This commit is contained in:
Vyacheslav Egorov
2022-12-15 13:45:10 +00:00
committed by Commit Queue
parent bcbf24ec3d
commit d02e1de5b1
5 changed files with 67 additions and 0 deletions
+25
View File
@@ -4104,4 +4104,29 @@ DART_EXPORT void Dart_DumpNativeStackTrace(void* context);
*/
DART_EXPORT void Dart_PrepareToAbort(void);
/**
* Callback provided by the embedder that is used by the VM to
* produce footnotes appended to DWARF stack traces.
*
* Whenever VM formats a stack trace as a string it would call this callback
* passing raw program counters for each frame in the stack trace.
*
* Embedder can then return a string which if not-null will be appended to the
* formatted stack trace.
*
* Returned string is expected to be `malloc()` allocated. VM takes ownership
* of the returned string and will `free()` it.
*
* \param addresses raw program counter addresses for each frame
* \param count number of elements in the addresses array
*/
typedef char* (*Dart_DwarfStackTraceFootnoteCallback)(void* addresses[],
intptr_t count);
/**
* Configure DWARF stack trace footnote callback.
*/
DART_EXPORT void Dart_SetDwarfStackTraceFootnoteCallback(
Dart_DwarfStackTraceFootnoteCallback callback);
#endif /* INCLUDE_DART_API_H_ */ /* NOLINT */
+2
View File
@@ -69,6 +69,8 @@ Dart_FileWriteCallback Dart::file_write_callback_ = NULL;
Dart_FileCloseCallback Dart::file_close_callback_ = NULL;
Dart_EntropySource Dart::entropy_source_callback_ = NULL;
Dart_GCEventCallback Dart::gc_event_callback_ = nullptr;
Dart_DwarfStackTraceFootnoteCallback Dart::dwarf_stacktrace_footnote_callback_ =
nullptr;
// Structure for managing read-only global handles allocation used for
// creating global read-only handles that are pre created and initialized
+12
View File
@@ -141,6 +141,16 @@ class Dart : public AllStatic {
}
static Dart_GCEventCallback gc_event_callback() { return gc_event_callback_; }
static void set_dwarf_stacktrace_footnote_callback(
Dart_DwarfStackTraceFootnoteCallback cb) {
dwarf_stacktrace_footnote_callback_ = cb;
}
static Dart_DwarfStackTraceFootnoteCallback
dwarf_stacktrace_footnote_callback() {
return dwarf_stacktrace_footnote_callback_;
}
private:
static char* DartInit(const Dart_InitializeParams* params);
@@ -163,6 +173,8 @@ class Dart : public AllStatic {
static Dart_FileCloseCallback file_close_callback_;
static Dart_EntropySource entropy_source_callback_;
static Dart_GCEventCallback gc_event_callback_;
static Dart_DwarfStackTraceFootnoteCallback
dwarf_stacktrace_footnote_callback_;
};
} // namespace dart
+5
View File
@@ -6310,6 +6310,11 @@ DART_EXPORT void Dart_SetGCEventCallback(Dart_GCEventCallback callback) {
Dart::set_gc_event_callback(callback);
}
DART_EXPORT void Dart_SetDwarfStackTraceFootnoteCallback(
Dart_DwarfStackTraceFootnoteCallback callback) {
Dart::set_dwarf_stacktrace_footnote_callback(callback);
}
DART_EXPORT char* Dart_SetFileModifiedCallback(
Dart_FileModifiedCallback file_modified_callback) {
#if !defined(PRODUCT)
+23
View File
@@ -26508,6 +26508,14 @@ const char* StackTrace::ToCString() const {
NoSafepointScope no_allocation;
GrowableArray<const Function*> inlined_functions;
GrowableArray<TokenPosition> inlined_token_positions;
#if defined(DART_PRECOMPILED_RUNTIME)
GrowableArray<void*> addresses(10);
const bool have_footnote_callback =
FLAG_dwarf_stack_traces_mode &&
Dart::dwarf_stacktrace_footnote_callback() != nullptr;
#endif
ZoneTextBuffer buffer(zone, 1024);
#if defined(DART_PRECOMPILED_RUNTIME)
@@ -26635,6 +26643,10 @@ const char* StackTrace::ToCString() const {
const uword call_addr = is_future_listener ? pc : pc - 1;
if (FLAG_dwarf_stack_traces_mode) {
if (have_footnote_callback) {
addresses.Add(reinterpret_cast<void*>(call_addr));
}
// This output is formatted like Android's debuggerd. Note debuggerd
// prints call addresses instead of return addresses.
buffer.Printf(" #%02" Pd " abs %" Pp "", frame_index, call_addr);
@@ -26690,6 +26702,17 @@ const char* StackTrace::ToCString() const {
stack_trace = stack_trace.async_link();
} while (!stack_trace.IsNull());
#if defined(DART_PRECOMPILED_RUNTIME)
if (have_footnote_callback) {
char* footnote = Dart::dwarf_stacktrace_footnote_callback()(
&addresses[0], addresses.length());
if (footnote != nullptr) {
buffer.AddString(footnote);
free(footnote);
}
}
#endif
return buffer.buffer();
}