[K/N] Hide throwable constructor frames from stack traces.

Merge-request: KT-MR-8242
Merged-by: Alexey Glushko <aleksei.glushko@jetbrains.com>
This commit is contained in:
Aleksei.Glushko
2023-01-13 14:14:40 +00:00
committed by Space Team
parent f20e5daa92
commit 20e80401b2
16 changed files with 217 additions and 87 deletions
@@ -86,7 +86,7 @@ unwind (struct _Unwind_Context *context, void *vdata)
--pc;
if (!bdata->can_alloc)
bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, 0, NULL);
bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, 0, NULL, 0);
else
bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback,
bdata->error_callback, bdata->data);
@@ -376,6 +376,8 @@ enum dwarf_unit_type {
DW_UT_hi_user = 0xff
};
const char * const KN_nodebug_prefix = "<NODEBUG>";
#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN
/* If strnlen is not declared, provide our own version. */
@@ -601,6 +603,8 @@ struct function
/* If this is an inlined function, the column of the call
site. */
int caller_column;
/* Whether the funciton should be hidden from user-level debug output (e.g. from Kotlin stack traces). */
int is_nodebug;
/* Map PC ranges to inlined functions. */
struct function_addrs *function_addrs;
size_t function_addrs_count;
@@ -3675,15 +3679,22 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
case DW_AT_name:
/* Third name preference: don't override. */
if (function->name != NULL)
{
const char *n = NULL;
if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
ddata->is_bigendian,
u->str_offsets_base, &val,
error_callback, data, &n))
return 0;
if (n != NULL) {
if (function->name == NULL)
function->name = n;
/* nodebug prefix may not be mangled in other name variants */
if (strncmp(n, KN_nodebug_prefix, strlen(KN_nodebug_prefix)) == 0)
function->is_nodebug = 1;
}
break;
if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,
ddata->is_bigendian,
u->str_offsets_base, &val,
error_callback, data, &function->name))
return 0;
break;
}
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
/* First name preference: override all. */
@@ -3954,7 +3965,7 @@ report_inlined_functions (uintptr_t pc, struct function *function,
return ret;
/* Report this inlined call. */
ret = callback (data, pc, *filename, *lineno, *column, inlined->name);
ret = callback (data, pc, *filename, *lineno, *column, inlined->name, inlined->is_nodebug);
if (ret != 0)
return ret;
@@ -4131,7 +4142,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
if (new_data)
return dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
data, found);
return callback (data, pc, NULL, 0, 0, NULL);
return callback (data, pc, NULL, 0, 0, NULL, 0);
}
/* Search for PC within this unit. */
@@ -4178,13 +4189,13 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
entry->u->abs_filename = filename;
}
return callback (data, pc, entry->u->abs_filename, 0, 0, NULL);
return callback (data, pc, entry->u->abs_filename, 0, 0, NULL, 0);
}
/* Search for function name within this unit. */
if (entry->u->function_addrs_count == 0)
return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL);
return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL, 0);
p = ((struct function_addrs *)
bsearch (&pc, entry->u->function_addrs,
@@ -4192,7 +4203,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
sizeof (struct function_addrs),
function_addrs_search));
if (p == NULL)
return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL);
return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL, 0);
/* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are
sorted by low, so if pc > p->low we are at the end of a range of
@@ -4216,7 +4227,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
--p;
}
if (fmatch == NULL)
return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL);
return callback (data, pc, ln->filename, ln->lineno, ln->column, NULL, 0);
function = fmatch->function;
@@ -4229,7 +4240,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
if (ret != 0)
return ret;
return callback (data, pc, filename, lineno, column, function->name);
return callback (data, pc, filename, lineno, column, function->name, function->is_nodebug);
}
@@ -4279,7 +4290,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
/* FIXME: See if any libraries have been dlopen'ed. */
return callback (data, pc, NULL, 0, 0, NULL);
return callback (data, pc, NULL, 0, 0, NULL, 0);
}
/* Initialize our data structures from the DWARF debug info for a
@@ -330,7 +330,7 @@ backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
{
struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, 0, symname);
bdata->ret = bdata->full_callback (bdata->full_data, pc, NULL, 0, 0, symname, 0);
}
/* An error callback that corresponds to
@@ -99,7 +99,7 @@ extern struct backtrace_state *backtrace_create_state (
typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
const char *filename, int lineno, int column,
const char *function);
const char *function, int is_nodebug);
/* Get a full stack backtrace. SKIP is the number of frames to skip;
passing 0 will start the trace with the function calling
@@ -51,15 +51,16 @@ struct print_data
static int
print_callback (void *data, uintptr_t pc, const char *filename, int lineno, int column,
const char *function)
const char *function, int is_nodebug)
{
struct print_data *pdata = (struct print_data *) data;
fprintf (pdata->f, "0x%lx %s\n\t%s:%d:%d\n",
(unsigned long) pc,
function == NULL ? "???" : function,
filename == NULL ? "???" : filename,
lineno, column);
if (!is_nodebug) {
struct print_data *pdata = (struct print_data *) data;
fprintf (pdata->f, "0x%lx %s\n\t%s:%d:%d\n",
(unsigned long) pc,
function == NULL ? "???" : function,
filename == NULL ? "???" : filename,
lineno, column);
}
return 0;
}
@@ -24,6 +24,7 @@ class SourceInfo {
public:
int lineNumber = -1;
int column = -1;
bool nodebug = false;
std::string& getFileName() { return fileName; }
void setFilename(const char *newFileName) { fileName = newFileName ?: ""; }
};
@@ -294,10 +294,13 @@ std_support::vector<std_support::string> kotlin::GetStackTraceStrings(std_suppor
int frames_or_overflow = getSourceInfo(address, buffer, std::size(buffer));
int frames = std::min<int>(frames_or_overflow, std::size(buffer));
bool isSomethingPrinted = false;
bool isSomethingHidden = false;
char line[1024];
for (int frame = 0; frame < frames; frame++) {
auto &sourceInfo = buffer[frame];
if (!sourceInfo.getFileName().empty()) {
if (sourceInfo.nodebug) {
isSomethingHidden = true;
} else if (!sourceInfo.getFileName().empty()) {
bool is_last = frame == frames - 1;
if (is_last && frames_or_overflow != frames) {
snprintf_with_addr(line, sizeof(line) - 1, strings.size(), address, false, "[some inlined frames skipped]");
@@ -322,7 +325,7 @@ std_support::vector<std_support::string> kotlin::GetStackTraceStrings(std_suppor
strings.push_back(line);
}
}
if (!isSomethingPrinted) {
if (!isSomethingPrinted && !isSomethingHidden) {
snprintf_with_addr(line, sizeof(line) - 1, strings.size(), address, false, "%s", "");
strings.push_back(line);
}
@@ -23,7 +23,7 @@ extern "C" int Kotlin_getSourceInfo_libbacktrace(void* addr, SourceInfo *result,
callback_arg.result_ptr = 0;
callback_arg.result_size = result_size;
callback_arg.total_count = 0;
auto process_line = [](void *data, uintptr_t pc, const char *filename, int lineno, int column, const char *function) -> int {
auto process_line = [](void *data, uintptr_t pc, const char *filename, int lineno, int column, const char *function, int is_nodebug) -> int {
auto &callback_arg = *static_cast<callback_arg_t*>(data);
// Non-inlined frame would be last one, it's better to have it, then intermediate ones
if (callback_arg.result_ptr == callback_arg.result_size) {
@@ -33,6 +33,7 @@ extern "C" int Kotlin_getSourceInfo_libbacktrace(void* addr, SourceInfo *result,
info.setFilename(filename);
info.lineNumber = lineno;
info.column = column;
info.nodebug = is_nodebug;
callback_arg.result_ptr++;
callback_arg.total_count++;
// Let's stop at least at some point