// Disable optimizations so that these functions show up properly in // the backtrace. #pragma clang optimize off extern"C" __attribute__((__noinline__)) void CallTwo(std::vector<void*>& frames) { int num_frames = backtrace(frames.data(), static_cast<int>(frames.size()));
ASSERT_LT(0, num_frames);
frames.resize(static_cast<size_t>(num_frames));
}
// Verfiy that there are at least two frames.
ASSERT_LT(3U, frames.size()) << DumpFrames(frames);
VerifyCalls(frames);
}
TEST(execinfo, backtrace_cutoff_frames) { // Verify the max frames is handled properly
std::vector<void*> frames(1);
ASSERT_NO_FATAL_FAILURE(CallOne(frames));
ASSERT_EQ(1U, frames.size()) << DumpFrames(frames);
}
TEST(execinfo, backtrace_symbols_errors) { void* frames[kMaxFrames]; // glibc incorrectly returns memory when a zero is passed in. // Since we know this works properly on bionic, only verify // this there. #ifdefined(__BIONIC__)
ASSERT_EQ(nullptr, backtrace_symbols(frames, 0)); #endif
ASSERT_EQ(nullptr, backtrace_symbols(frames, -1));
}
staticvoid VerifyLineFormat(std::string& line) { // Verify that the format of the line is one of these: // elf_file(FuncName+0xFuncAddr) [0xAddress] // elf_file(+0xRelAddress) [0xAddress] // elf_file [0xAddress] // [0xAddress] #ifdefined(__GLIBC__) // For some reason, glibc will print a space before [0xAddress] for // backtrace symbols, and no space for backtrace_symbols_fd. Allow this // only for glibc.
std::regex format1("[^\\(\\s]+\\([^\\+]+\\+0x[0-9a-fA-F]+\\) ?\\[0x[0-9a-fA-F]+\\]");
std::regex format2("[^\\(\\s]+\\(+\\+0x[0-9a-fA-F]+\\) ?\\[0x[0-9a-fA-F]+\\]");
std::regex format3("[^\\(\\s]+ ?\\[0x[0-9a-fA-F]+\\]"); #else
std::regex format1("[^\\(\\s]+\\([^\\+]+\\+0x[0-9a-fA-F]+\\) \\[0x[0-9a-fA-F]+\\]");
std::regex format2("[^\\(\\s]+\\(+\\+0x[0-9a-fA-F]+\\) \\[0x[0-9a-fA-F]+\\]");
std::regex format3("[^\\(\\s]+ \\[0x[0-9a-fA-F]+\\]"); #endif
std::regex format4("\\[0x[0-9a-fA-F]+\\]");
EXPECT_TRUE(std::regex_match(line, format1) || std::regex_match(line, format2) ||
std::regex_match(line, format3) || std::regex_match(line, format4))
<< "Unknown format of line:\n"
<< line;
}
char** symbols = backtrace_symbols(frames.data(), static_cast<int>(frames.size()));
ASSERT_TRUE(symbols != nullptr); for (size_t i = 0; i < frames.size(); i++) {
ASSERT_TRUE(frames[i] != nullptr);
VerifyLineFormat(symbols[i], strlen(symbols[i]));
}
size_t call_one_idx;
size_t call_two_idx;
ASSERT_NO_FATAL_FAILURE(VerifyCalls(frames, &call_one_idx, &call_two_idx)); // Now verify that those frames contain the function names we expect.
SCOPED_TRACE(DumpFrames(frames));
ASSERT_MATCH(symbols[call_one_idx - 1], "\\(CallOne+");
ASSERT_MATCH(symbols[call_two_idx - 1], "\\(CallTwo+");
free(symbols);
}
{
TemporaryFile tf;
backtrace_symbols_fd(frames, 0, tf.fd);
close(tf.fd);
std::string content;
ASSERT_TRUE(android::base::ReadFileToString(tf.path, &content)); // Verify that no data is written to the file.
ASSERT_TRUE(content.empty());
}
{
TemporaryFile tf;
backtrace_symbols_fd(frames, -1, tf.fd);
close(tf.fd);
std::string content;
ASSERT_TRUE(android::base::ReadFileToString(tf.path, &content)); // Verify that no data is written to the file.
ASSERT_TRUE(content.empty());
}
// Verify that there isn't a crash.
backtrace_symbols_fd(frames, 0, -1);
}
if (num_lines == call_one_idx) {
EXPECT_MATCH(line, "\\(CallOne+");
} elseif (num_lines == call_two_idx) {
EXPECT_MATCH(line, "\\(CallTwo+");
}
}
ASSERT_EQ(num_lines, frames.size()) << "Number of lines in file does not match number of frames.";
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.