Initial Contribution
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
new file mode 100644
index 0000000..4968666
--- /dev/null
+++ b/libs/utils/CallStack.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CallStack"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if HAVE_DLADDR
+#include <dlfcn.h>
+#endif
+
+#if HAVE_CXXABI
+#include <cxxabi.h>
+#endif
+
+#include <unwind.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/CallStack.h>
+#include <utils/threads.h>
+
+
+/*****************************************************************************/
+namespace android {
+
+
+typedef struct {
+    size_t count;
+    size_t ignore;
+    const void** addrs;
+} stack_crawl_state_t;
+
+static
+_Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg)
+{
+    stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
+    if (state->count) {
+        void* ip = (void*)_Unwind_GetIP(context);
+        if (ip) {
+            if (state->ignore) {
+                state->ignore--;
+            } else {
+                state->addrs[0] = ip; 
+                state->addrs++;
+                state->count--;
+            }
+        }
+    }
+    return _URC_NO_REASON;
+}
+
+static
+int backtrace(const void** addrs, size_t ignore, size_t size)
+{
+    stack_crawl_state_t state;
+    state.count = size;
+    state.ignore = ignore;
+    state.addrs = addrs;
+    _Unwind_Backtrace(trace_function, (void*)&state);
+    return size - state.count;
+}
+
+/*****************************************************************************/
+
+static 
+const char *lookup_symbol(const void* addr, uint32_t *offset, char* name, size_t bufSize)
+{
+#if HAVE_DLADDR
+	Dl_info info;
+	if (dladdr(addr, &info)) {
+		*offset = (uint32_t)info.dli_saddr;
+		return info.dli_sname;
+	}
+#endif
+	return NULL;
+}
+
+static 
+int32_t linux_gcc_demangler(const char *mangled_name, char *unmangled_name, size_t buffersize)
+{
+	size_t out_len = 0;
+#if HAVE_CXXABI
+	int status = 0;
+	char *demangled = abi::__cxa_demangle(mangled_name, 0, &out_len, &status);
+	if (status == 0) {
+		// OK
+		if (out_len < buffersize) memcpy(unmangled_name, demangled, out_len);
+		else out_len = 0;
+		free(demangled);
+	} else {
+		out_len = 0;
+	}
+#endif
+	return out_len;
+}
+
+/*****************************************************************************/
+
+class MapInfo {
+    struct mapinfo {
+        struct mapinfo *next;
+        unsigned start;
+        unsigned end;
+        char name[];
+    };
+
+    const char *map_to_name(unsigned pc, const char* def) {
+        mapinfo* mi = getMapInfoList();
+        while(mi) {
+            if ((pc >= mi->start) && (pc < mi->end))
+                return mi->name;
+            mi = mi->next;
+        }
+        return def;
+    }
+
+    mapinfo *parse_maps_line(char *line) {
+        mapinfo *mi;
+        int len = strlen(line);
+        if (len < 1) return 0;
+        line[--len] = 0;
+        if (len < 50) return 0;
+        if (line[20] != 'x') return 0;
+        mi = (mapinfo*)malloc(sizeof(mapinfo) + (len - 47));
+        if (mi == 0) return 0;
+        mi->start = strtoul(line, 0, 16);
+        mi->end = strtoul(line + 9, 0, 16);
+        mi->next = 0;
+        strcpy(mi->name, line + 49);
+        return mi;
+    }
+
+    mapinfo* getMapInfoList() {
+        Mutex::Autolock _l(mLock);
+        if (milist == 0) {
+            char data[1024];
+            FILE *fp;
+            sprintf(data, "/proc/%d/maps", getpid());
+            fp = fopen(data, "r");
+            if (fp) {
+                while(fgets(data, 1024, fp)) {
+                    mapinfo *mi = parse_maps_line(data);
+                    if(mi) {
+                        mi->next = milist;
+                        milist = mi;
+                    }
+                }
+                fclose(fp);
+            }
+        }
+        return milist;
+    }
+    mapinfo*    milist;
+    Mutex       mLock;
+    static MapInfo sMapInfo;
+
+public:
+    MapInfo()
+     : milist(0) {
+    }
+
+    ~MapInfo() {
+        while (milist) {
+            mapinfo *next = milist->next;
+            free(milist);
+            milist = next;
+        }
+    }
+    
+    static const char *mapAddressToName(const void* pc, const char* def) {
+        return sMapInfo.map_to_name((unsigned)pc, def);
+    }
+
+};
+
+/*****************************************************************************/
+
+MapInfo MapInfo::sMapInfo;
+
+/*****************************************************************************/
+
+CallStack::CallStack()
+    : mCount(0)
+{
+}
+
+CallStack::CallStack(const CallStack& rhs)
+    : mCount(rhs.mCount)
+{
+    if (mCount) {
+        memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
+    }
+}
+
+CallStack::~CallStack()
+{
+}
+
+CallStack& CallStack::operator = (const CallStack& rhs)
+{
+    mCount = rhs.mCount;
+    if (mCount) {
+        memcpy(mStack, rhs.mStack, mCount*sizeof(void*));
+    }
+    return *this;
+}
+
+bool CallStack::operator == (const CallStack& rhs) const {
+    if (mCount != rhs.mCount)
+        return false;
+    return !mCount || (memcmp(mStack, rhs.mStack, mCount*sizeof(void*)) == 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(void*)) < 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(void*)) > 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 mStack[index];
+}
+
+
+void CallStack::clear()
+{
+    mCount = 0;
+}
+
+void CallStack::update(int32_t ignoreDepth, int32_t maxDepth)
+{
+    if (maxDepth > MAX_DEPTH)
+        maxDepth = MAX_DEPTH;
+    mCount = backtrace(mStack, ignoreDepth, maxDepth);
+}
+
+// Return the stack frame name on the designated level
+String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
+{
+    String8 res;
+    char namebuf[1024];
+    char tmp[256];
+    char tmp1[32];
+    char tmp2[32];
+    uint32_t offs;
+
+    const void* ip = mStack[level];
+    if (!ip) return res;
+
+    if (prefix) res.append(prefix);
+    snprintf(tmp1, 32, "#%02d  ", level);
+    res.append(tmp1);
+
+    const char* name = lookup_symbol(ip, &offs, namebuf, sizeof(namebuf));
+    if (name) {
+        if (linux_gcc_demangler(name, tmp, 256) != 0)
+            name = tmp;
+        snprintf(tmp1, 32, "0x%08x: <", (size_t)ip);
+        snprintf(tmp2, 32, ">+0x%08x", offs);
+        res.append(tmp1);
+        res.append(name);
+        res.append(tmp2);
+    } else { 
+        name = MapInfo::mapAddressToName(ip, "<unknown>");
+        snprintf(tmp, 256, "pc %08x  %s", (size_t)ip, name);
+        res.append(tmp);
+    }
+    res.append("\n");
+
+    return res;
+}
+
+// Dump a stack trace to the log
+void CallStack::dump(const char* prefix) const
+{
+    /* 
+     * Sending a single long log may be truncated since the stack levels can
+     * get very deep. So we request function names of each frame individually.
+     */
+    for (int i=0; i<int(mCount); i++) {
+        LOGD("%s", toStringSingleLevel(prefix, i).string());
+    }
+}
+
+// Return a string (possibly very long) containing the complete stack trace
+String8 CallStack::toString(const char* prefix) const
+{
+    String8 res;
+
+    for (int i=0; i<int(mCount); i++) {
+        res.append(toStringSingleLevel(prefix, i).string());
+    }
+
+    return res;
+}
+
+/*****************************************************************************/
+
+}; // namespace android