[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:
committed by
Commit Queue
parent
bcbf24ec3d
commit
d02e1de5b1
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user