LCOV - code coverage report
Current view: directory - src/trusted/debug_stub - nacl_debug.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 87 0 0.0 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : 
       8                 : #include <vector>
       9                 : #include <map>
      10                 : 
      11                 : /*
      12                 :  * NaCl Functions for intereacting with debuggers
      13                 :  */
      14                 : 
      15                 : #include "native_client/src/trusted/gdb_rsp/session.h"
      16                 : #include "native_client/src/trusted/gdb_rsp/target.h"
      17                 : #include "native_client/src/trusted/port/platform.h"
      18                 : #include "native_client/src/trusted/port/thread.h"
      19                 : 
      20                 : #include "native_client/src/include/nacl_string.h"
      21                 : #include "native_client/src/shared/platform/nacl_check.h"
      22                 : #include "native_client/src/shared/platform/nacl_log.h"
      23                 : #include "native_client/src/shared/platform/nacl_exit.h"
      24                 : #include "native_client/src/shared/platform/nacl_threads.h"
      25                 : #include "native_client/src/trusted/debug_stub/debug_stub.h"
      26                 : #include "native_client/src/trusted/debug_stub/nacl_debug.h"
      27                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      28                 : #include "native_client/src/trusted/service_runtime/nacl_debug_init.h"
      29                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      30                 : 
      31                 : /* To enable debugging */
      32                 : // #define NACL_DEBUG_STUB 1
      33                 : 
      34                 : using port::IPlatform;
      35                 : using port::IThread;
      36                 : using port::ITransport;
      37                 : 
      38                 : using gdb_rsp::Session;
      39                 : using gdb_rsp::Target;
      40                 : 
      41                 : #ifdef WIN32
      42                 : /* Disable warning for unwind disabled when exceptions used */
      43                 : #pragma warning(disable:4530)
      44                 : #endif
      45                 : 
      46                 : /*
      47                 :  * These macro wraps all debugging stub calls to prevent C++ code called
      48                 :  * by the debugging stub to throw and exception past the C API.  We use
      49                 :  * this technique to allow the use of STL templates.   We catch bad_alloc
      50                 :  * separately purely to provide information for debugging purposes.
      51                 :  */
      52                 : #define DBG_CATCH_ALL                                                       \
      53                 :   catch(std::bad_alloc) {                                                  \
      54                 :     NaClLog(LOG_FATAL, "nacl_debug(%d) : Failed to allocate.\n", __LINE__); \
      55                 :     NaClExit(-1);                                                          \
      56                 :   }                                                                         \
      57                 :   catch(std::exception e) {                                                \
      58                 :     NaClLog(LOG_FATAL, "nacl_debug(%d) : Caught exception: %s.\n",          \
      59                 :             __LINE__ , e.what());                                           \
      60                 :     NaClExit(-1);                                                          \
      61                 :   }                                                                         \
      62                 :   catch(...) {                                                             \
      63                 :     NaClLog(LOG_FATAL, "nacl_debug(%d) : Unexpected exception.\n", __LINE__);\
      64                 :     NaClExit(-1);                                                           \
      65                 :   }
      66                 : 
      67                 : 
      68                 : enum NaClDebugStatus {
      69                 :   NDS_DISABLED = 0,
      70                 :   NDS_ENABLED = 1,
      71                 :   NDS_STOPPED = 2
      72                 : };
      73                 : 
      74                 : struct NaClDebugState {
      75               0 :   NaClDebugState() : target_(NULL), app_(NULL),
      76               0 :                      errCode_(0), status_(NDS_DISABLED) {}
      77                 : 
      78               0 :   bool Init() {
      79               0 :     NaClDebugStubInit();
      80               0 :     target_ = new Target();
      81                 : 
      82               0 :     CHECK((NULL != target_) && (target_->Init()));
      83                 : 
      84               0 :     status_ = NDS_ENABLED;
      85               0 :     return true;
      86                 :   }
      87                 : 
      88                 :   ~NaClDebugState() {
      89                 :     /*
      90                 :      * TODO(mlinck): It is not safe to call this destructor, since there is an
      91                 :      * unjoinable thread potentially accessing target_.
      92                 :      */
      93                 :     delete target_;
      94                 :   }
      95                 : 
      96                 :   Target* target_;
      97                 :   struct NaClApp *app_;
      98                 :   volatile int errCode_;
      99                 :   NaClDebugStatus status_;
     100                 :   std::vector<const char *> arg_;
     101                 :   std::vector<const char *> env_;
     102                 : };
     103                 : 
     104                 : static struct NaClDebugCallbacks debug_callbacks = {
     105                 :   NaClDebugThreadPrepDebugging,
     106                 :   NaClDebugThreadStopDebugging,
     107                 :   NaClDebugStop,
     108                 : };
     109                 : 
     110                 : static NaClDebugState *g_nacl_debug_state = NULL;
     111                 : 
     112               0 : bool NaClDebugIsEnabled(void) throw() {
     113               0 :   if (NULL != g_nacl_debug_state &&
     114                 :       NDS_ENABLED == g_nacl_debug_state->status_) {
     115               0 :     return true;
     116                 :   }
     117               0 :   return false;
     118                 : }
     119                 : 
     120               0 : void WINAPI NaClStubThread(void *ptr) {
     121               0 :   Target *targ = reinterpret_cast<Target*>(ptr);
     122               0 :   while (1) {
     123               0 :     ITransport* trans = NULL;
     124               0 :     Session* ses = NULL;
     125                 : 
     126                 :     try {
     127                 :       // Wait for a connection.
     128               0 :       trans = ITransport::Accept("127.0.0.1:4014");
     129               0 :       if (NULL == trans) continue;
     130                 : 
     131                 :       // Create a new session for this connection
     132               0 :       ses = new Session();
     133               0 :       ses->Init(trans);
     134               0 :       ses->SetFlags(Session::DEBUG_MASK);
     135                 : 
     136                 :       // Run this session for as long as it lasts
     137               0 :       targ->Run(ses);
     138                 :     }
     139               0 :     catch(...) {
     140               0 :       delete ses;
     141               0 :       ITransport::Free(trans);
     142                 :     }
     143                 :   }
     144                 : }
     145                 : 
     146               0 : void NaClExceptionCatcher(uint32_t id, int8_t sig, void *cookie) {
     147               0 :   Target* targ = static_cast<Target*>(cookie);
     148                 : 
     149                 :   /* Signal the target that we caught something */
     150               0 :   IPlatform::LogWarning("Caught signal %d on thread %Xh.\n", sig, id);
     151               0 :   targ->Signal(id, sig, true);
     152               0 : }
     153                 : 
     154                 : 
     155               0 : void NaClDebugSetAppInfo(struct NaClApp *app) throw() {
     156               0 :   if (NaClDebugIsEnabled()) {
     157               0 :     g_nacl_debug_state->app_ = app;
     158                 :   }
     159               0 : }
     160                 : 
     161                 : 
     162                 : void NaClDebugSetAppEnvironment(int argc, char const * const argv[],
     163               0 :                                 int envc, char const * const envv[]) throw() {
     164               0 :   if (NaClDebugIsEnabled()) {
     165                 :     int a;
     166                 :     try {
     167                 :       /*
     168                 :        * Copy the pointer arrays.  We use ptrs instead of strings
     169                 :        * since the data persits and it prevents an extra copy.
     170                 :        */
     171               0 :       g_nacl_debug_state->arg_.resize(argc);
     172               0 :       for (a = 0; a < argc; a++) g_nacl_debug_state->arg_[a] = argv[a];
     173               0 :       g_nacl_debug_state->env_.resize(envc);
     174               0 :       for (a = 0; a < envc; a++) g_nacl_debug_state->env_[a] = envv[a];
     175               0 :     } DBG_CATCH_ALL
     176                 :   }
     177               0 : }
     178                 : 
     179               0 : void NaClDebugThreadPrepDebugging(struct NaClAppThread *natp) throw() {
     180                 :   UNREFERENCED_PARAMETER(natp);
     181                 : 
     182               0 :   if (NaClDebugIsEnabled()) {
     183               0 :     uint32_t id = IPlatform::GetCurrentThread();
     184               0 :     IThread* thread = IThread::Acquire(id, true);
     185               0 :     g_nacl_debug_state->target_->SetMemoryBase(natp->nap->mem_start);
     186               0 :     g_nacl_debug_state->target_->TrackThread(thread);
     187                 : 
     188                 :     /*
     189                 :      * TODO(noelallen) We need to associate the natp with this thread
     190                 :      * so we can get to the untrusted context preserved on a syscall.
     191                 :      */
     192                 :   }
     193               0 : }
     194                 : 
     195               0 : void NaClDebugThreadStopDebugging(struct NaClAppThread *natp) throw() {
     196                 :   UNREFERENCED_PARAMETER(natp);
     197                 : 
     198               0 :   if (NaClDebugIsEnabled()) {
     199               0 :     uint32_t id = IPlatform::GetCurrentThread();
     200               0 :     IThread* thread = IThread::Acquire(id, false);
     201               0 :     g_nacl_debug_state->target_->IgnoreThread(thread);
     202               0 :     IThread::Release(thread);
     203                 : 
     204                 :     /*
     205                 :      * TODO(noelallen) We need to associate the natp with this thread
     206                 :      * so we can get to the thread once we support freeing a thread
     207                 :      * from a different thread than the executing one.
     208                 :      */
     209                 :   }
     210               0 : }
     211                 : 
     212               0 : int NaClDebugStart(void) throw() {
     213               0 :   if (NaClDebugIsEnabled()) {
     214               0 :     NaClThread *thread = new NaClThread;
     215                 : 
     216               0 :     if (NULL == thread) return false;
     217                 : 
     218                 :     /* Add a temp breakpoint. */
     219               0 :     struct NaClApp* app = g_nacl_debug_state->app_;
     220               0 :     if (0 != app->user_entry_pt) {
     221                 :       g_nacl_debug_state->target_->AddTemporaryBreakpoint(app->user_entry_pt +
     222               0 :                                                           app->mem_start);
     223                 :     }
     224                 :     g_nacl_debug_state->target_->AddTemporaryBreakpoint(app->initial_entry_pt +
     225               0 :                                                         app->mem_start);
     226                 : 
     227               0 :     NaClLog(LOG_WARNING, "nacl_debug(%d) : Debugging started.\n", __LINE__);
     228                 :     IThread::SetExceptionCatch(NaClExceptionCatcher,
     229               0 :                                g_nacl_debug_state->target_);
     230                 :     return NaClThreadCtor(thread, NaClStubThread, g_nacl_debug_state->target_,
     231               0 :                           NACL_KERN_STACK_SIZE);
     232                 :   }
     233               0 :   return 0;
     234                 : }
     235                 : 
     236               0 : void NaClDebugStop(int ErrCode) throw() {
     237                 :   /*
     238                 :    * We check if debugging is enabled since this check is the only
     239                 :    * mechanism for allocating the state object.  We free the
     240                 :    * resources but not the object itself.  Instead we mark it as
     241                 :    * STOPPED to prevent it from getting recreated.
     242                 :    */
     243               0 :   if (NaClDebugIsEnabled()) {
     244               0 :     g_nacl_debug_state->status_ = NDS_STOPPED;
     245               0 :     g_nacl_debug_state->errCode_ = ErrCode;
     246                 :     try {
     247               0 :       NaClDebugStubFini();
     248               0 :     } DBG_CATCH_ALL
     249                 :   }
     250               0 : }
     251                 : 
     252                 : /*
     253                 :  * This function is implemented for the service runtime.  The service runtime
     254                 :  * declares the function so it does not need to be declared in our header.
     255                 :  */
     256                 : int NaClDebugInit(struct NaClApp *nap,
     257                 :                   int argc, char const *const argv[],
     258               0 :                   int envc, char const *const envv[]) {
     259                 :   static bool initialised = 0;
     260               0 :   CHECK(!initialised && NULL == g_nacl_debug_state);
     261               0 :   initialised = 1;
     262               0 :   nap->debug_stub_callbacks = &debug_callbacks;
     263               0 :   NaClDebugStubInit();
     264               0 :   g_nacl_debug_state = new NaClDebugState();
     265               0 :   CHECK(g_nacl_debug_state->Init());
     266               0 :   NaClDebugSetAppInfo(nap);
     267               0 :   NaClDebugSetAppEnvironment(argc, argv, envc, envv);
     268               0 :   NaClDebugStart();
     269               0 :   return 1;
     270                 : }

Generated by: LCOV version 1.7