Merge "Move CallStack to libbacktrace."
This commit is contained in:
commit
b18f93ea5d
|
@ -18,8 +18,9 @@
|
|||
#define ANDROID_CALLSTACK_H
|
||||
|
||||
#include <android/log.h>
|
||||
#include <backtrace/backtrace.h>
|
||||
#include <utils/String8.h>
|
||||
#include <corkscrew/backtrace.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -31,42 +32,19 @@ class Printer;
|
|||
// Collect/print the call stack (function, file, line) traces for a single thread.
|
||||
class CallStack {
|
||||
public:
|
||||
enum {
|
||||
// Prune the lowest-most stack frames until we have at most MAX_DEPTH.
|
||||
MAX_DEPTH = 31,
|
||||
// Placeholder for specifying the current thread when updating the stack.
|
||||
CURRENT_THREAD = -1,
|
||||
};
|
||||
|
||||
// Create an empty call stack. No-op.
|
||||
CallStack();
|
||||
// Create a callstack with the current thread's stack trace.
|
||||
// Immediately dump it to logcat using the given logtag.
|
||||
CallStack(const char* logtag, int32_t ignoreDepth=1,
|
||||
int32_t maxDepth=MAX_DEPTH);
|
||||
// Copy the existing callstack (no other side effects).
|
||||
CallStack(const CallStack& rhs);
|
||||
CallStack(const char* logtag, int32_t ignoreDepth=1);
|
||||
~CallStack();
|
||||
|
||||
// Copy the existing callstack (no other side effects).
|
||||
CallStack& operator = (const CallStack& rhs);
|
||||
|
||||
// Compare call stacks by their backtrace frame memory.
|
||||
bool operator == (const CallStack& rhs) const;
|
||||
bool operator != (const CallStack& rhs) const;
|
||||
bool operator < (const CallStack& rhs) const;
|
||||
bool operator >= (const CallStack& rhs) const;
|
||||
bool operator > (const CallStack& rhs) const;
|
||||
bool operator <= (const CallStack& rhs) const;
|
||||
|
||||
// Get the PC address for the stack frame specified by index.
|
||||
const void* operator [] (int index) const;
|
||||
|
||||
// Reset the stack frames (same as creating an empty call stack).
|
||||
void clear();
|
||||
void clear() { mFrameLines.clear(); }
|
||||
|
||||
// Immediately collect the stack traces for the specified thread.
|
||||
void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH, pid_t tid=CURRENT_THREAD);
|
||||
// The default is to dump the stack of the current call.
|
||||
void update(int32_t ignoreDepth=1, pid_t tid=BACKTRACE_NO_TID);
|
||||
|
||||
// Dump a stack trace to the log using the supplied logtag.
|
||||
void log(const char* logtag,
|
||||
|
@ -83,11 +61,10 @@ public:
|
|||
void print(Printer& printer) const;
|
||||
|
||||
// Get the count of stack frames that are in this call stack.
|
||||
size_t size() const { return mCount; }
|
||||
size_t size() const { return mFrameLines.size(); }
|
||||
|
||||
private:
|
||||
size_t mCount;
|
||||
backtrace_frame_t mStack[MAX_DEPTH];
|
||||
Vector<String8> mFrameLines;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
~ProcessCallStack();
|
||||
|
||||
// Immediately collect the stack traces for all threads.
|
||||
void update(int32_t maxDepth = CallStack::MAX_DEPTH);
|
||||
void update();
|
||||
|
||||
// Print all stack traces to the log using the supplied logtag.
|
||||
void log(const char* logtag, android_LogPriority priority = ANDROID_LOG_DEBUG,
|
||||
|
|
|
@ -116,10 +116,12 @@ LOCAL_STATIC_LIBRARIES := \
|
|||
libcutils
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcorkscrew \
|
||||
libbacktrace \
|
||||
liblog \
|
||||
libdl
|
||||
|
||||
include external/stlport/libstlport.mk
|
||||
|
||||
LOCAL_MODULE:= libutils
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
|
@ -129,10 +131,12 @@ include $(CLEAR_VARS)
|
|||
LOCAL_MODULE:= libutils
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libutils
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
liblog \
|
||||
libbacktrace \
|
||||
libcutils \
|
||||
libdl \
|
||||
libcorkscrew
|
||||
liblog \
|
||||
|
||||
include external/stlport/libstlport.mk
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
|
|
@ -20,93 +20,33 @@
|
|||
#include <utils/Printer.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Log.h>
|
||||
#include <corkscrew/backtrace.h>
|
||||
#include <UniquePtr.h>
|
||||
|
||||
#include <backtrace/Backtrace.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
CallStack::CallStack() :
|
||||
mCount(0) {
|
||||
CallStack::CallStack() {
|
||||
}
|
||||
|
||||
CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) {
|
||||
this->update(ignoreDepth+1, maxDepth, CURRENT_THREAD);
|
||||
CallStack::CallStack(const char* logtag, int32_t ignoreDepth) {
|
||||
this->update(ignoreDepth+1);
|
||||
this->log(logtag);
|
||||
}
|
||||
|
||||
CallStack::CallStack(const CallStack& rhs) :
|
||||
mCount(rhs.mCount) {
|
||||
if (mCount) {
|
||||
memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
|
||||
}
|
||||
}
|
||||
|
||||
CallStack::~CallStack() {
|
||||
}
|
||||
|
||||
CallStack& CallStack::operator = (const CallStack& rhs) {
|
||||
mCount = rhs.mCount;
|
||||
if (mCount) {
|
||||
memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
|
||||
void CallStack::update(int32_t ignoreDepth, pid_t tid) {
|
||||
mFrameLines.clear();
|
||||
|
||||
UniquePtr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
|
||||
if (!backtrace->Unwind(ignoreDepth)) {
|
||||
ALOGW("%s: Failed to unwind callstack.", __FUNCTION__);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CallStack::operator == (const CallStack& rhs) const {
|
||||
if (mCount != rhs.mCount)
|
||||
return false;
|
||||
return !mCount || memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) == 0;
|
||||
}
|
||||
|
||||
bool CallStack::operator != (const CallStack& rhs) const {
|
||||
return !operator == (rhs);
|
||||
}
|
||||
|
||||
bool CallStack::operator < (const CallStack& rhs) const {
|
||||
if (mCount != rhs.mCount)
|
||||
return mCount < rhs.mCount;
|
||||
return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) < 0;
|
||||
}
|
||||
|
||||
bool CallStack::operator >= (const CallStack& rhs) const {
|
||||
return !operator < (rhs);
|
||||
}
|
||||
|
||||
bool CallStack::operator > (const CallStack& rhs) const {
|
||||
if (mCount != rhs.mCount)
|
||||
return mCount > rhs.mCount;
|
||||
return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) > 0;
|
||||
}
|
||||
|
||||
bool CallStack::operator <= (const CallStack& rhs) const {
|
||||
return !operator > (rhs);
|
||||
}
|
||||
|
||||
const void* CallStack::operator [] (int index) const {
|
||||
if (index >= int(mCount))
|
||||
return 0;
|
||||
return reinterpret_cast<const void*>(mStack[index].absolute_pc);
|
||||
}
|
||||
|
||||
void CallStack::clear() {
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
void CallStack::update(int32_t ignoreDepth, int32_t maxDepth, pid_t tid) {
|
||||
if (maxDepth > MAX_DEPTH) {
|
||||
maxDepth = MAX_DEPTH;
|
||||
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
|
||||
mFrameLines.push_back(String8(backtrace->FormatFrameData(i).c_str()));
|
||||
}
|
||||
ssize_t count;
|
||||
|
||||
if (tid >= 0) {
|
||||
count = unwind_backtrace_thread(tid, mStack, ignoreDepth + 1, maxDepth);
|
||||
} else if (tid == CURRENT_THREAD) {
|
||||
count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
|
||||
} else {
|
||||
ALOGE("%s: Invalid tid specified (%d)", __FUNCTION__, tid);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
mCount = count > 0 ? count : 0;
|
||||
}
|
||||
|
||||
void CallStack::log(const char* logtag, android_LogPriority priority, const char* prefix) const {
|
||||
|
@ -129,16 +69,9 @@ String8 CallStack::toString(const char* prefix) const {
|
|||
}
|
||||
|
||||
void CallStack::print(Printer& printer) const {
|
||||
backtrace_symbol_t symbols[mCount];
|
||||
|
||||
get_backtrace_symbols(mStack, mCount, symbols);
|
||||
for (size_t i = 0; i < mCount; i++) {
|
||||
char line[MAX_BACKTRACE_LINE_LENGTH];
|
||||
format_backtrace_line(i, &mStack[i], &symbols[i],
|
||||
line, MAX_BACKTRACE_LINE_LENGTH);
|
||||
printer.printLine(line);
|
||||
for (size_t i = 0; i < mFrameLines.size(); i++) {
|
||||
printer.printLine(mFrameLines[i]);
|
||||
}
|
||||
free_backtrace_symbols(symbols, mCount);
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
|
|
@ -145,6 +145,7 @@ void String8Printer::printLine(const char* string) {
|
|||
return;
|
||||
}
|
||||
|
||||
mTarget->append(mPrefix);
|
||||
mTarget->append(string);
|
||||
mTarget->append("\n");
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ void ProcessCallStack::clear() {
|
|||
mTimeUpdated = tm();
|
||||
}
|
||||
|
||||
void ProcessCallStack::update(int32_t maxDepth) {
|
||||
void ProcessCallStack::update() {
|
||||
DIR *dp;
|
||||
struct dirent *ep;
|
||||
struct dirent entry;
|
||||
|
@ -181,14 +181,13 @@ void ProcessCallStack::update(int32_t maxDepth) {
|
|||
int ignoreDepth = (selfPid == tid) ? IGNORE_DEPTH_CURRENT_THREAD : 0;
|
||||
|
||||
// Update thread's call stacks
|
||||
CallStack& cs = threadInfo.callStack;
|
||||
cs.update(ignoreDepth, maxDepth, tid);
|
||||
threadInfo.callStack.update(ignoreDepth, tid);
|
||||
|
||||
// Read/save thread name
|
||||
threadInfo.threadName = getThreadName(tid);
|
||||
|
||||
ALOGV("%s: Got call stack for tid %d (size %zu)",
|
||||
__FUNCTION__, tid, cs.size());
|
||||
__FUNCTION__, tid, threadInfo.callStack.size());
|
||||
}
|
||||
if (code != 0) { // returns positive error value on error
|
||||
ALOGE("%s: Failed to readdir from %s (errno = %d, '%s')",
|
||||
|
@ -221,13 +220,12 @@ void ProcessCallStack::printInternal(Printer& printer, Printer& csPrinter) const
|
|||
for (size_t i = 0; i < mThreadMap.size(); ++i) {
|
||||
pid_t tid = mThreadMap.keyAt(i);
|
||||
const ThreadInfo& threadInfo = mThreadMap.valueAt(i);
|
||||
const CallStack& cs = threadInfo.callStack;
|
||||
const String8& threadName = threadInfo.threadName;
|
||||
|
||||
printer.printLine("");
|
||||
printer.printFormatLine("\"%s\" sysTid=%d", threadName.string(), tid);
|
||||
|
||||
cs.print(csPrinter);
|
||||
threadInfo.callStack.print(csPrinter);
|
||||
}
|
||||
|
||||
dumpProcessFooter(printer, getpid());
|
||||
|
|
Loading…
Reference in New Issue