1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "CallStack"
18
19#include <string.h>
20
21#include <utils/Log.h>
22#include <utils/Errors.h>
23#include <utils/CallStack.h>
24#include <corkscrew/backtrace.h>
25
26/*****************************************************************************/
27namespace android {
28
29CallStack::CallStack() :
30        mCount(0) {
31}
32
33CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) {
34    this->update(ignoreDepth+1, maxDepth);
35    this->dump(logtag);
36}
37
38CallStack::CallStack(const CallStack& rhs) :
39        mCount(rhs.mCount) {
40    if (mCount) {
41        memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
42    }
43}
44
45CallStack::~CallStack() {
46}
47
48CallStack& CallStack::operator = (const CallStack& rhs) {
49    mCount = rhs.mCount;
50    if (mCount) {
51        memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
52    }
53    return *this;
54}
55
56bool CallStack::operator == (const CallStack& rhs) const {
57    if (mCount != rhs.mCount)
58        return false;
59    return !mCount || memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) == 0;
60}
61
62bool CallStack::operator != (const CallStack& rhs) const {
63    return !operator == (rhs);
64}
65
66bool CallStack::operator < (const CallStack& rhs) const {
67    if (mCount != rhs.mCount)
68        return mCount < rhs.mCount;
69    return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) < 0;
70}
71
72bool CallStack::operator >= (const CallStack& rhs) const {
73    return !operator < (rhs);
74}
75
76bool CallStack::operator > (const CallStack& rhs) const {
77    if (mCount != rhs.mCount)
78        return mCount > rhs.mCount;
79    return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) > 0;
80}
81
82bool CallStack::operator <= (const CallStack& rhs) const {
83    return !operator > (rhs);
84}
85
86const void* CallStack::operator [] (int index) const {
87    if (index >= int(mCount))
88        return 0;
89    return reinterpret_cast<const void*>(mStack[index].absolute_pc);
90}
91
92void CallStack::clear() {
93    mCount = 0;
94}
95
96void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) {
97    if (maxDepth > MAX_DEPTH) {
98        maxDepth = MAX_DEPTH;
99    }
100    ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
101    mCount = count > 0 ? count : 0;
102}
103
104void CallStack::dump(const char* logtag, const char* prefix) const {
105    backtrace_symbol_t symbols[mCount];
106
107    get_backtrace_symbols(mStack, mCount, symbols);
108    for (size_t i = 0; i < mCount; i++) {
109        char line[MAX_BACKTRACE_LINE_LENGTH];
110        format_backtrace_line(i, &mStack[i], &symbols[i],
111                line, MAX_BACKTRACE_LINE_LENGTH);
112        ALOG(LOG_DEBUG, logtag, "%s%s",
113                prefix ? prefix : "",
114                line);
115    }
116    free_backtrace_symbols(symbols, mCount);
117}
118
119String8 CallStack::toString(const char* prefix) const {
120    String8 str;
121    backtrace_symbol_t symbols[mCount];
122
123    get_backtrace_symbols(mStack, mCount, symbols);
124    for (size_t i = 0; i < mCount; i++) {
125        char line[MAX_BACKTRACE_LINE_LENGTH];
126        format_backtrace_line(i, &mStack[i], &symbols[i],
127                line, MAX_BACKTRACE_LINE_LENGTH);
128        if (prefix) {
129            str.append(prefix);
130        }
131        str.append(line);
132        str.append("\n");
133    }
134    free_backtrace_symbols(symbols, mCount);
135    return str;
136}
137
138}; // namespace android
139