Handle munmap() and add support for tracing JNI (native) calls.

The munmap() kernel calls are traced but the tracing code wasn't doing
anything with them.  This caused the number of mapped regions in a process
to grow large in some cases and also caused symbol lookup errors in some
rare cases.  This change also adds support for new trace record types
for supporting JNI (native) calls from Java into native code. This helps
with constructing a more accurate call stack.
diff --git a/emulator/qtools/callstack.h b/emulator/qtools/callstack.h
index b73efea..8982330 100644
--- a/emulator/qtools/callstack.h
+++ b/emulator/qtools/callstack.h
@@ -32,7 +32,9 @@
     typedef SYM symbol_type;
     static const uint32_t kCausedException = 0x01;
     static const uint32_t kInterpreted     = 0x02;
-    static const uint32_t kPopBarrier      = (kCausedException | kInterpreted);
+    static const uint32_t kStartNative     = 0x04;
+    static const uint32_t kPopBarrier      = (kCausedException | kInterpreted
+        | kStartNative);
 
     symbol_type *function;      // the symbol for the function we entered
     uint32_t    addr;           // return address when this function returns
@@ -43,7 +45,7 @@
 
 template <class FRAME, class BASE = CallStackBase>
 class CallStack : public BASE {
-  public:
+public:
     typedef FRAME frame_type;
     typedef typename FRAME::symbol_type symbol_type;
     typedef typename FRAME::symbol_type::region_type region_type;
@@ -57,7 +59,7 @@
     void    threadStart(uint64_t time);
     void    threadStop(uint64_t time);
 
-    // Set to true if you don't want to see any Java methods
+    // Set to true if you don't want to see any Java methods ever
     void    setNativeOnly(bool nativeOnly) {
         mNativeOnly = nativeOnly;
     }
@@ -66,38 +68,36 @@
 
     uint64_t    getGlobalTime(uint64_t time) { return time + mSkippedTime; }
     void        showStack(FILE *stream);
-    void        showSnapshotStack(FILE *stream);
 
     int         mNumFrames;
     FRAME       *mFrames;
     int         mTop;           // index of the next stack frame to write
 
-  private:
-    enum Action { NONE, PUSH, POP };
+private:
+    enum Action { NONE, PUSH, POP, NATIVE_PUSH };
 
     Action      getAction(BBEvent *event, symbol_type *function);
-    Action      getMethodAction(BBEvent *event, symbol_type *function);
+    void        doMethodAction(BBEvent *event, symbol_type *function);
+    void        doMethodPop(BBEvent *event, uint32_t addr, const uint32_t flags);
     void        doSimplePush(symbol_type *function, uint32_t addr,
-                             uint64_t time);
+                             uint64_t time, int flags);
     void        doSimplePop(uint64_t time);
     void        doPush(BBEvent *event, symbol_type *function);
     void        doPop(BBEvent *event, symbol_type *function, Action methodAction);
 
-    void        transitionToJava();
-    void        transitionFromJava(uint64_t time);
-
     TraceReaderType *mTrace;
+
+    // This is a global switch that disables Java methods from appearing
+    // on the stack.
     bool        mNativeOnly;
+  
+    // This keeps track of whether native frames are currently allowed on the
+    // stack.
+    bool        mAllowNativeFrames;
 
     symbol_type mDummyFunction;
     region_type mDummyRegion;
 
-    int         mJavaTop;
-
-    int         mSnapshotNumFrames;
-    FRAME       *mSnapshotFrames;
-    int         mSnapshotTop;   // index of the next stack frame to write
-
     symbol_type *mPrevFunction;
     BBEvent     mPrevEvent;
 
@@ -125,10 +125,7 @@
     mNumFrames = numFrames;
     mFrames = new FRAME[mNumFrames];
     mTop = 0;
-
-    mSnapshotNumFrames = numFrames;
-    mSnapshotFrames = new FRAME[mSnapshotNumFrames];
-    mSnapshotTop = 0;
+    mAllowNativeFrames = true;
 
     memset(&mDummyFunction, 0, sizeof(symbol_type));
     memset(&mDummyRegion, 0, sizeof(region_type));
@@ -139,7 +136,6 @@
     memset(&mUserEvent, 0, sizeof(BBEvent));
     mSkippedTime = 0;
     mLastRunTime = 0;
-    mJavaTop = 0;
 
     // Read the first two methods from the trace if we haven't already read
     // from the method trace yet.
@@ -169,11 +165,29 @@
         // instead.
         if (function->vm_sym != NULL)
             function = function->vm_sym;
+    } else {
+        doMethodAction(event, function);
     }
 
     Action action = getAction(event, function);
-    Action methodAction = getMethodAction(event, function);
 
+    // Allow native frames if we are executing in the kernel.
+    if (!mAllowNativeFrames
+        && (function->region->flags & region_type::kIsKernelRegion) == 0) {
+        action = NONE;
+    }
+
+    if (function->vm_sym != NULL) {
+        function = function->vm_sym;
+        function->vm_sym = NULL;
+    }
+    if (action == PUSH) {
+        doPush(event, function);
+    } else if (action == POP) {
+        doPop(event, function, NONE);
+    }
+
+#if 0
     // Pop off native functions before pushing or popping Java methods.
     if (action == POP && mPrevFunction->vm_sym == NULL) {
         // Pop off the previous function first.
@@ -198,11 +212,16 @@
             doPush(event, function);
         }
     }
+#endif
 
     // If the stack is now empty, then push the current function.
     if (mTop == 0) {
         uint64_t time = event->time - mSkippedTime;
-        doSimplePush(function, 0, time);
+        int flags = 0;
+        if (function->vm_sym != NULL) {
+            flags = FRAME::kInterpreted;
+        }
+        doSimplePush(function, 0, time, 0);
     }
 
     mPrevFunction = function;
@@ -465,12 +484,19 @@
     if ((function->flags & symbol_type::kIsVectorStart) && mTop > 0)
         mFrames[mTop - 1].flags |= FRAME::kCausedException;
 
-    doSimplePush(function, retAddr, time);
+    // If the function being pushed is a Java method, then mark it on
+    // the stack so that we don't pop it off until we get a matching
+    // trace record from the method trace file.
+    int flags = 0;
+    if (function->vm_sym != NULL) {
+        flags = FRAME::kInterpreted;
+    }
+    doSimplePush(function, retAddr, time, flags);
 }
 
 template<class FRAME, class BASE>
-void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function,
-                                          uint32_t addr, uint64_t time)
+void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function, uint32_t addr,
+                                          uint64_t time, int flags)
 {
     // Check for stack overflow
     if (mTop >= mNumFrames) {
@@ -479,30 +505,12 @@
         exit(1);
     }
 
-    // Keep track of the number of Java methods we push on the stack.
-    if (!mNativeOnly && function->vm_sym != NULL) {
-        // If we are pushing the first Java method on the stack, then
-        // save a snapshot of the stack so that we can clean things up
-        // later when we pop off the last Java stack frame.
-        if (mJavaTop == 0) {
-            transitionToJava();
-        }
-        mJavaTop += 1;
-    }
-
     mFrames[mTop].addr = addr;
     mFrames[mTop].function = function;
-    mFrames[mTop].flags = 0;
+    mFrames[mTop].flags = flags;
     mFrames[mTop].time = time;
     mFrames[mTop].global_time = time + mSkippedTime;
 
-    // If the function being pushed is a Java method, then mark it on
-    // the stack so that we don't pop it off until we get a matching
-    // trace record from the method trace file.
-    if (function->vm_sym != NULL) {
-        mFrames[mTop].flags = FRAME::kInterpreted;
-    }
-
     mFrames[mTop].push(mTop, time, this);
     mTop += 1;
 }
@@ -517,17 +525,25 @@
     mTop -= 1;
     mFrames[mTop].pop(mTop, time, this);
 
-    // Keep track of the number of Java methods we have on the stack.
-    symbol_type *function = mFrames[mTop].function;
-    if (!mNativeOnly && function->vm_sym != NULL) {
-        mJavaTop -= 1;
+    if (mNativeOnly)
+        return;
 
-        // When there are no more Java stack frames, then clean up
-        // the client's stack.  We need to do this because the client
-        // doesn't see the changes to the native stack underlying the
-        // fake Java stack until the last Java method is popped off.
-        if (mJavaTop == 0) {
-            transitionFromJava(time);
+    // If the stack is empty, then allow more native frames.
+    // Otherwise, if we are transitioning from Java to native, then allow
+    // more native frames.
+    // Otherwise, if we are transitioning from native to Java, then disallow
+    // more native frames.
+    if (mTop == 0) {
+        mAllowNativeFrames = true;
+    } else {
+        bool newerIsJava = (mFrames[mTop].flags & FRAME::kInterpreted) != 0;
+        bool olderIsJava = (mFrames[mTop - 1].flags & FRAME::kInterpreted) != 0;
+        if (newerIsJava && !olderIsJava) {
+            // We are transitioning from Java to native
+            mAllowNativeFrames = true;
+        } else if (!newerIsJava && olderIsJava) {
+            // We are transitioning from native to Java
+            mAllowNativeFrames = false;
         }
     }
 }
@@ -671,20 +687,45 @@
 }
 
 template<class FRAME, class BASE>
-typename CallStack<FRAME, BASE>::Action
-CallStack<FRAME, BASE>::getMethodAction(BBEvent *event, symbol_type *function)
+void CallStack<FRAME, BASE>::doMethodPop(BBEvent *event, uint32_t addr,
+                                         const uint32_t flags)
 {
-    if (function->vm_sym == NULL && mPrevFunction->vm_sym == NULL) {
-        return NONE;
+    uint64_t time = event->time - mSkippedTime;
+
+    // Search the stack from the top down for a frame that contains a
+    // matching method.
+    int stackLevel;
+    for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
+        if (mFrames[stackLevel].flags & flags) {
+            // If we are searching for a native method, then don't bother trying
+            // to match the address.
+            if (flags == FRAME::kStartNative)
+                break;
+            symbol_type *func = mFrames[stackLevel].function;
+            uint32_t methodAddr = func->region->base_addr + func->addr;
+            if (methodAddr == addr) {
+                break;
+            }
+        }
     }
 
-    Action action = NONE;
-    uint32_t prevAddr = mPrevFunction->addr + mPrevFunction->region->base_addr;
-    uint32_t addr = function->addr + function->region->base_addr;
+    // If we found a matching frame then pop the stack up to and including
+    // that frame.
+    if (stackLevel >= 0) {
+        // Pop the stack frames
+        for (int ii = mTop - 1; ii >= stackLevel; --ii)
+            doSimplePop(time);
+    }
+}
 
+template<class FRAME, class BASE>
+void CallStack<FRAME, BASE>::doMethodAction(BBEvent *event, symbol_type *function)
+{
     // If the events get ahead of the method trace, then read ahead until we
     // sync up again.  This can happen if there is a pop of a method in the
-    // method trace for which we don't have a previous push.
+    // method trace for which we don't have a previous push.  Such an unmatched
+    // pop can happen because the user can start tracing at any time and so
+    // there might already be a stack when we start tracing.
     while (event->time >= sNextMethod.time) {
         sCurrentMethod = sNextMethod;
         if (mTrace->ReadMethod(&sNextMethod)) {
@@ -693,59 +734,26 @@
     }
 
     if (event->time >= sCurrentMethod.time && event->pid == sCurrentMethod.pid) {
-        if (addr == sCurrentMethod.addr || prevAddr == sCurrentMethod.addr) {
-            action = (sCurrentMethod.flags == 0) ? PUSH : POP;
-            // We found a match, so read the next record.
-            sCurrentMethod = sNextMethod;
-            if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
-                sNextMethod.time = ~0ull;
-            }
-        }
-    }
-    return action;
-}
-
-// When the first Java method is pushed on the stack, this method is
-// called to save a snapshot of the current native stack so that the
-// client's view of the native stack can be patched up later when the
-// Java stack is empty.
-template<class FRAME, class BASE>
-void CallStack<FRAME, BASE>::transitionToJava()
-{
-    mSnapshotTop = mTop;
-    for (int ii = 0; ii < mTop; ++ii) {
-        mSnapshotFrames[ii] = mFrames[ii];
-    }
-}
-
-// When the Java stack becomes empty, the native stack becomes
-// visible.  This method is called when the Java stack becomes empty
-// to patch up the client's view of the native stack, which may have
-// changed underneath the Java stack.  The stack snapshot is used to
-// create a sequence of pops and pushes to make the client's view of
-// the native stack match the current native stack.
-template<class FRAME, class BASE>
-void CallStack<FRAME, BASE>::transitionFromJava(uint64_t time)
-{
-    int top = mTop;
-    if (top > mSnapshotTop) {
-        top = mSnapshotTop;
-    }
-    for (int ii = 0; ii < top; ++ii) {
-        if (mSnapshotFrames[ii].function->addr == mFrames[ii].function->addr) {
-            continue;
+        uint64_t time = event->time - mSkippedTime;
+        int flags = sCurrentMethod.flags;
+        if (flags == kMethodEnter) {
+            doSimplePush(function, 0, time, FRAME::kInterpreted);
+            mAllowNativeFrames = false;
+        } else if (flags == kNativeEnter) {
+            doSimplePush(function, 0, time, FRAME::kStartNative);
+            mAllowNativeFrames = true;
+        } else if (flags == kMethodExit || flags == kMethodException) {
+            doMethodPop(event, sCurrentMethod.addr, FRAME::kInterpreted);
+        } else if (flags == kNativeExit || flags == kNativeException) {
+            doMethodPop(event, sCurrentMethod.addr, FRAME::kStartNative);
         }
 
-        // Pop off all the rest of the frames from the snapshot
-        for (int jj = top - 1; jj >= ii; --jj) {
-            mSnapshotFrames[jj].pop(jj, time, this);
+        // We found a match, so read the next record. When we get to the end
+        // of the trace, we set the time to the maximum value (~0).
+        sCurrentMethod = sNextMethod;
+        if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
+            sNextMethod.time = ~0ull;
         }
-
-        // Push the new frames from the native stack
-        for (int jj = ii; jj < mTop; ++jj) {
-            mFrames[jj].push(jj, time, this);
-        }
-        break;
     }
 }
 
@@ -764,16 +772,4 @@
     }
 }
 
-template<class FRAME, class BASE>
-void CallStack<FRAME, BASE>::showSnapshotStack(FILE *stream)
-{
-    fprintf(stream, "mSnapshotTop: %d\n", mSnapshotTop);
-    for (int ii = 0; ii < mSnapshotTop; ++ii) {
-        fprintf(stream, "  %d: t %d f %x 0x%08x 0x%08x %s\n",
-                ii, mSnapshotFrames[ii].time, mSnapshotFrames[ii].flags,
-                mSnapshotFrames[ii].addr, mSnapshotFrames[ii].function->addr,
-                mSnapshotFrames[ii].function->name);
-    }
-}
-
 #endif /* CALL_STACK_H */