LCOV - code coverage report
Current view: top level - src - Debug.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 23 435 5.3 %
Date: 2010-12-13 Functions: 8 29 27.6 %
Branches: 12 286 4.2 %

           Branch data     Line data    Source code
       1                 :            : // Debugging support for Bro policy files.
       2                 :            : 
       3                 :            : #include "config.h"
       4                 :            : 
       5                 :            : #include <stdio.h>
       6                 :            : #include <stdarg.h>
       7                 :            : #include <signal.h>
       8                 :            : #include <ctype.h>
       9                 :            : 
      10                 :            : #include <string>
      11                 :            : using namespace std;
      12                 :            : 
      13                 :            : #include "util.h"
      14                 :            : #include "Debug.h"
      15                 :            : #include "DebugCmds.h"
      16                 :            : #include "DbgBreakpoint.h"
      17                 :            : #include "Stmt.h"
      18                 :            : #include "Func.h"
      19                 :            : #include "Scope.h"
      20                 :            : #include "PolicyFile.h"
      21                 :            : 
      22                 :            : #ifdef HAVE_READLINE
      23                 :            : #include <readline/readline.h>
      24                 :            : #include <readline/history.h>
      25                 :            : #endif
      26                 :            : 
      27                 :            : bool g_policy_debug = false;
      28                 :          6 : DebuggerState g_debugger_state;
      29                 :          3 : TraceState g_trace_state;
      30                 :          6 : PDict(Filemap) g_dbgfilemaps;
      31                 :            : 
      32                 :            : // These variables are used only to decide whether or not to print the
      33                 :            : // current context; you don't want to do it after a step or next
      34                 :            : // command unless you've exited a function.
      35                 :            : static bool step_or_next_pending = false;
      36                 :            : static Frame* last_frame;
      37                 :            : 
      38                 :          3 : DebuggerState::DebuggerState()
      39                 :            :         {
      40                 :          3 :         next_bp_id = next_watch_id = next_display_id = 1;
      41                 :          3 :         BreakBeforeNextStmt(false);
      42                 :          3 :         curr_frame_idx = 0;
      43                 :          3 :         BreakFromSignal(false);
      44                 :            : 
      45                 :            :         // ### Don't choose this arbitrary size! Extend Frame.
      46                 :          3 :         dbg_locals = new Frame(1024, /* func = */ 0, /* fn_args = */ 0);
      47                 :          3 :         }
      48                 :            : 
      49                 :          3 : DebuggerState::~DebuggerState()
      50                 :            :         {
      51                 :          3 :         Unref(dbg_locals);
      52                 :          3 :         }
      53                 :            : 
      54                 :          0 : bool StmtLocMapping::StartsAfter(const StmtLocMapping* m2)
      55                 :            :         {
      56         [ #  # ]:          0 :         if ( ! m2  )
      57                 :          0 :                 internal_error("Assertion failed: %s", "m2 != 0");
      58                 :            : 
      59                 :            :         return loc.first_line > m2->loc.first_line ||
      60                 :            :                 (loc.first_line == m2->loc.first_line &&
      61 [ #  # ][ #  # ]:          0 :                  loc.first_column > m2->loc.first_column);
                 [ #  # ]
      62                 :            :         }
      63                 :            : 
      64                 :            : 
      65                 :            : // Generic debug message output.
      66                 :          0 : int debug_msg(const char* fmt, ...)
      67                 :            :         {
      68                 :            :         va_list args;
      69                 :            :         int retval;
      70                 :            : 
      71                 :          0 :         va_start(args, fmt);
      72                 :          0 :         retval = vfprintf(stderr, fmt, args);
      73                 :          0 :         va_end(args);
      74                 :            : 
      75                 :          0 :         return retval;
      76                 :            :         }
      77                 :            : 
      78                 :            : 
      79                 :            : // Trace message output
      80                 :            : 
      81                 :          0 : FILE* TraceState::SetTraceFile(const char* filename)
      82                 :            :         {
      83                 :            :         FILE* newfile;
      84                 :            : 
      85         [ #  # ]:          0 :         if ( streq(filename, "-") )
      86                 :          0 :                 newfile = stderr;
      87                 :            :         else
      88                 :          0 :                 newfile = fopen(filename, "w");
      89                 :            : 
      90                 :          0 :         FILE* oldfile = trace_file;
      91         [ #  # ]:          0 :         if ( newfile )
      92                 :            :                 {
      93                 :          0 :                 trace_file = newfile;
      94                 :            :                 }
      95                 :            :         else
      96                 :            :                 {
      97                 :          0 :                 fprintf(stderr, "Unable to open trace file %s\n", filename);
      98                 :          0 :                 trace_file = 0;
      99                 :            :                 }
     100                 :            : 
     101                 :          0 :         return oldfile;
     102                 :            :         }
     103                 :            : 
     104                 :          0 : void TraceState::TraceOn()
     105                 :            :         {
     106                 :          0 :         fprintf(stderr, "Execution tracing ON.\n");
     107                 :          0 :         dbgtrace = true;
     108                 :          0 :         }
     109                 :            : 
     110                 :          0 : void TraceState::TraceOff()
     111                 :            :         {
     112                 :          0 :         fprintf(stderr, "Execution tracing OFF.\n");
     113                 :          0 :         dbgtrace = false;
     114                 :          0 :         }
     115                 :            : 
     116                 :          0 : int TraceState::LogTrace(const char* fmt, ...)
     117                 :            :         {
     118                 :            :         va_list args;
     119                 :            :         int retval;
     120                 :            : 
     121                 :          0 :         va_start(args, fmt);
     122                 :            : 
     123                 :            :         // Prefix includes timestamp and file/line info.
     124                 :          0 :         fprintf(trace_file, "%.6f ", network_time);
     125                 :            : 
     126                 :            :         const Stmt* stmt;
     127                 :          0 :         Location loc;
     128                 :          0 :         loc.filename = 0;
     129                 :            : 
     130   [ #  #  #  # ]:          0 :         if ( g_frame_stack.size() > 0 && g_frame_stack.back() )
                 [ #  # ]
     131                 :            :                 {
     132                 :          0 :                 stmt = g_frame_stack.back()->GetNextStmt();
     133         [ #  # ]:          0 :                 if ( stmt )
     134                 :          0 :                         loc = *stmt->GetLocationInfo();
     135                 :            :                 else
     136                 :            :                         {
     137                 :          0 :                         const BroFunc* f = g_frame_stack.back()->GetFunction();
     138         [ #  # ]:          0 :                         if ( f )
     139                 :          0 :                                 loc = *f->GetLocationInfo();
     140                 :            :                         }
     141                 :            :                 }
     142                 :            : 
     143         [ #  # ]:          0 :         if ( ! loc.filename )
     144                 :            :                 {
     145                 :          0 :                 loc.filename = "<no filename>";
     146                 :          0 :                 loc.last_line = 0;
     147                 :            :                 }
     148                 :            : 
     149                 :          0 :         fprintf(trace_file, "%s:%d", loc.filename, loc.last_line);
     150                 :            : 
     151                 :            :         // Each stack frame is indented.
     152         [ #  # ]:          0 :         for ( int i = 0; i < int(g_frame_stack.size()); ++i )
     153                 :          0 :                 fprintf(trace_file, "\t");
     154                 :            : 
     155                 :          0 :         retval = vfprintf(trace_file, fmt, args);
     156                 :            : 
     157                 :          0 :         fflush(trace_file);
     158                 :          0 :         va_end(args);
     159                 :            : 
     160                 :          0 :         return retval;
     161                 :            :         }
     162                 :            : 
     163                 :            : 
     164                 :            : // Helper functions.
     165                 :          0 : void get_first_statement(Stmt* list, Stmt*& first, Location& loc)
     166                 :            :         {
     167         [ #  # ]:          0 :         if ( ! list )
     168                 :            :                 {
     169                 :          0 :                 first = 0;
     170                 :          0 :                 return;
     171                 :            :                 }
     172                 :            : 
     173                 :          0 :         first = list;
     174         [ #  # ]:          0 :         while ( first->Tag() == STMT_LIST )
     175                 :            :                 {
     176         [ #  # ]:          0 :                 if ( first->AsStmtList()->Stmts()[0] )
     177                 :          0 :                         first = first->AsStmtList()->Stmts()[0];
     178                 :            :                 else
     179                 :          0 :                         break;
     180                 :            :                 }
     181                 :            : 
     182                 :          0 :         loc = *first->GetLocationInfo();
     183                 :            :         }
     184                 :            : 
     185                 :            : static void parse_function_name(vector<ParseLocationRec>& result,
     186                 :          0 :                                 ParseLocationRec& plr, const string& s)
     187                 :            :         { // function name
     188                 :          0 :         ID* id = lookup_ID(s.c_str(), current_module.c_str());
     189         [ #  # ]:          0 :         if ( ! id )
     190                 :            :                 {
     191                 :          0 :                 string fullname = make_full_var_name(current_module.c_str(), s.c_str());
     192                 :          0 :                 debug_msg("Function %s not defined.\n", fullname.c_str());
     193                 :          0 :                 plr.type = plrUnknown;
     194                 :          0 :                 return;
     195                 :            :                 }
     196                 :            : 
     197                 :            :         FuncType* ftype;
     198         [ #  # ]:          0 :         if ( ! (ftype = id->Type()->AsFuncType()) )
     199                 :            :                 {
     200                 :          0 :                 debug_msg("Function %s not declared.\n", id->Name());
     201                 :          0 :                 plr.type = plrUnknown;
     202                 :          0 :                 return;
     203                 :            :                 }
     204                 :            : 
     205         [ #  # ]:          0 :         if ( ! id->HasVal() )
     206                 :            :                 {
     207                 :          0 :                 debug_msg("Function %s declared but not defined.\n", id->Name());
     208                 :          0 :                 plr.type = plrUnknown;
     209                 :          0 :                 return;
     210                 :            :                 }
     211                 :            : 
     212                 :          0 :         const Func* func = id->ID_Val()->AsFunc();
     213                 :          0 :         const vector<Func::Body>& bodies = func->GetBodies();
     214                 :            : 
     215         [ #  # ]:          0 :         if ( bodies.size() == 0 )
     216                 :            :                 {
     217                 :          0 :                 debug_msg("Function %s is a built-in function\n", id->Name());
     218                 :          0 :                 plr.type = plrUnknown;
     219                 :          0 :                 return;
     220                 :            :                 }
     221                 :            : 
     222                 :          0 :         Stmt* body = 0; // the particular body we care about; 0 = all
     223                 :            : 
     224         [ #  # ]:          0 :         if ( bodies.size() == 1 )
     225                 :          0 :                 body = bodies[0].stmts;
     226                 :            :         else
     227                 :            :                 {
     228      [ #  #  # ]:          0 :                 while ( 1 )
     229                 :            :                         {
     230                 :            :                         debug_msg("There are multiple definitions of that event handler.\n"
     231                 :          0 :                                  "Please choose one of the following options:\n");
     232         [ #  # ]:          0 :                         for ( unsigned int i = 0; i < bodies.size(); ++i )
     233                 :            :                                 {
     234                 :            :                                 Stmt* first;
     235                 :          0 :                                 Location stmt_loc;
     236                 :            :                                 get_first_statement(bodies[i].stmts, first,
     237                 :          0 :                                                         stmt_loc);
     238                 :          0 :                                 debug_msg("[%d] %s:%d\n", i+1, stmt_loc.filename, stmt_loc.first_line);
     239                 :            :                                 }
     240                 :            : 
     241                 :          0 :                         debug_msg("[a] All of the above\n");
     242                 :          0 :                         debug_msg("[n] None of the above\n");
     243                 :          0 :                         debug_msg("Enter your choice: ");
     244                 :            : 
     245                 :            :                         char charinput[256];
     246         [ #  # ]:          0 :                         if ( ! fgets(charinput, sizeof(charinput) - 1, stdin) )
     247                 :            :                                 {
     248                 :          0 :                                 plr.type = plrUnknown;
     249                 :          0 :                                 return;
     250                 :            :                                 }
     251                 :            : 
     252         [ #  # ]:          0 :                         if ( charinput[strlen(charinput) - 1] == '\n' )
     253                 :          0 :                                 charinput[strlen(charinput) - 1] = 0;
     254                 :            : 
     255                 :          0 :                         string input = charinput;
     256                 :            : 
     257         [ #  # ]:          0 :                         if ( input == "a" )
     258                 :          0 :                                 break;
     259                 :            : 
     260         [ #  # ]:          0 :                         if ( input == "n" )
     261                 :            :                                 {
     262                 :          0 :                                 plr.type = plrUnknown;
     263                 :          0 :                                 return;
     264                 :            :                                 }
     265                 :            : 
     266                 :          0 :                         int option = atoi(input.c_str());
     267   [ #  #  #  # ]:          0 :                         if ( option > 0 && option <= (int) bodies.size() )
                 [ #  # ]
     268                 :            :                                 {
     269                 :          0 :                                 body = bodies[option - 1].stmts;
     270                 :            :                                 break;
     271                 :            :                                 }
     272                 :            :                         }
     273                 :            :                 }
     274                 :            : 
     275                 :          0 :         plr.type = plrFunction;
     276                 :            : 
     277                 :            :         // Find first atomic (non-STMT_LIST) statement
     278                 :            :         Stmt* first;
     279                 :          0 :         Location stmt_loc;
     280                 :            : 
     281         [ #  # ]:          0 :         if ( body )
     282                 :            :                 {
     283                 :          0 :                 get_first_statement(body, first, stmt_loc);
     284         [ #  # ]:          0 :                 if ( first )
     285                 :            :                         {
     286                 :          0 :                         plr.stmt = first;
     287                 :          0 :                         plr.filename = stmt_loc.filename;
     288                 :          0 :                         plr.line = stmt_loc.last_line;
     289                 :            :                         }
     290                 :            :                 }
     291                 :            : 
     292                 :            :         else
     293                 :            :                 {
     294                 :          0 :                 result.pop_back();
     295                 :            :                 ParseLocationRec plr;
     296                 :            : 
     297         [ #  # ]:          0 :                 for ( unsigned int i = 0; i < bodies.size(); ++i )
     298                 :            :                         {
     299                 :          0 :                         get_first_statement(bodies[i].stmts, first, stmt_loc);
     300         [ #  # ]:          0 :                         if ( ! first )
     301                 :          0 :                                 continue;
     302                 :            : 
     303                 :          0 :                         plr.type = plrFunction;
     304                 :          0 :                         plr.stmt = first;
     305                 :          0 :                         plr.filename = stmt_loc.filename;
     306                 :          0 :                         plr.line = stmt_loc.last_line;
     307                 :          0 :                         result.push_back(plr);
     308                 :            :                         }
     309                 :          0 :                 }
     310                 :            :         }
     311                 :            : 
     312                 :          0 : vector<ParseLocationRec> parse_location_string(const string& s)
     313                 :            :         {
     314                 :          0 :         vector<ParseLocationRec> result;
     315                 :          0 :         result.push_back(ParseLocationRec());
     316                 :          0 :         ParseLocationRec& plr = result[0];
     317                 :          0 :         const char* full_filename = 0;
     318                 :            : 
     319                 :            :         // If plrFileAndLine, set this to the filename you want; for
     320                 :            :         // memory management reasons, the real filename is set when looking
     321                 :            :         // up the line number to find the corresponding statement.
     322                 :          0 :         const char* loc_filename = 0;
     323                 :            : 
     324         [ #  # ]:          0 :         if ( sscanf(s.c_str(), "%d", &plr.line) )
     325                 :            :                 { // just a line number (implicitly referring to the current file)
     326                 :          0 :                 loc_filename = g_debugger_state.last_loc.filename;
     327                 :          0 :                 plr.type = plrFileAndLine;
     328                 :            :                 }
     329                 :            : 
     330                 :            :         else
     331                 :            :                 {
     332                 :          0 :                 string::size_type pos_colon = s.find(':');
     333                 :          0 :                 string::size_type pos_dblcolon = s.find("::");
     334                 :            : 
     335   [ #  #  #  # ]:          0 :                 if ( pos_colon == string::npos || pos_dblcolon != string::npos )
     336                 :          0 :                         parse_function_name(result, plr, s);
     337                 :            :                 else
     338                 :            :                         { // file:line
     339                 :          0 :                         string filename = s.substr(0, pos_colon);
     340                 :          0 :                         string line_string = s.substr(pos_colon + 1, s.length() - pos_colon);
     341                 :            : 
     342         [ #  # ]:          0 :                         if ( ! sscanf(line_string.c_str(), "%d", &plr.line) )
     343                 :          0 :                                 plr.type = plrUnknown;
     344                 :            : 
     345                 :            :                         FILE* throwaway = search_for_file(filename.c_str(), "bro",
     346                 :          0 :                                                                 &full_filename);
     347         [ #  # ]:          0 :                         if ( ! throwaway )
     348                 :            :                                 {
     349                 :          0 :                                 debug_msg("No such policy file: %s.\n", filename.c_str());
     350                 :          0 :                                 plr.type = plrUnknown;
     351                 :          0 :                                 return result;
     352                 :            :                                 }
     353                 :            : 
     354                 :          0 :                         fclose(throwaway);
     355                 :            : 
     356                 :          0 :                         loc_filename = full_filename;
     357 [ #  # ][ #  # ]:          0 :                         plr.type = plrFileAndLine;
     358                 :            :                         }
     359                 :            :                 }
     360                 :            : 
     361         [ #  # ]:          0 :         if ( plr.type == plrFileAndLine )
     362                 :            :                 {
     363                 :          0 :                 Filemap* map = g_dbgfilemaps.Lookup(loc_filename);
     364         [ #  # ]:          0 :                 if ( ! map )
     365                 :            :                         internal_error("Policy file %s should have been loaded\n",
     366                 :          0 :                                         loc_filename);
     367                 :            : 
     368         [ #  # ]:          0 :                 if ( plr.line > how_many_lines_in(loc_filename) )
     369                 :            :                         {
     370                 :          0 :                         debug_msg("No line %d in %s.\n", plr.line, loc_filename);
     371         [ #  # ]:          0 :                         delete [] full_filename;
     372                 :          0 :                         plr.type = plrUnknown;
     373                 :          0 :                         return result;
     374                 :            :                         }
     375                 :            : 
     376                 :          0 :                 StmtLocMapping* hit = 0;
     377         [ #  # ]:          0 :                 loop_over_queue(*map, i)
     378                 :            :                         {
     379                 :          0 :                         StmtLocMapping* entry = (*map)[i];
     380                 :          0 :                         plr.filename = (*map)[i]->Loc().filename;
     381                 :            : 
     382         [ #  # ]:          0 :                         if ( entry->Loc().first_line > plr.line )
     383                 :          0 :                                 break;
     384                 :            : 
     385 [ #  # ][ #  # ]:          0 :                         if ( plr.line >= entry->Loc().first_line &&
                 [ #  # ]
     386                 :            :                              plr.line <= entry->Loc().last_line )
     387                 :            :                                 {
     388                 :          0 :                                 hit = (*map)[i];
     389                 :          0 :                                 break;
     390                 :            :                                 }
     391                 :            :                         }
     392                 :            : 
     393         [ #  # ]:          0 :                 if ( hit )
     394                 :          0 :                         plr.stmt = hit->Statement();
     395                 :            :                 else
     396                 :          0 :                         plr.stmt = 0;
     397                 :            :                 }
     398                 :            : 
     399         [ #  # ]:          0 :         delete [] full_filename;
     400                 :          0 :         return result;
     401                 :            :         }
     402                 :            : 
     403                 :            : 
     404                 :            : // Interactive debugging console.
     405                 :            : 
     406                 :            : static int dbg_dispatch_cmd(DebugCmd cmd_code, const vector<string>& args);
     407                 :            : 
     408                 :            : #ifdef HAVE_READLINE
     409                 :            : 
     410                 :            : void using_history(void);
     411                 :            : 
     412                 :            : static bool init_readline()
     413                 :            :         {
     414                 :            :         // ### Set up custom completion.
     415                 :            : 
     416                 :            :         rl_outstream = stderr;
     417                 :            :         using_history();
     418                 :            : 
     419                 :            :         return false;
     420                 :            :         }
     421                 :            : 
     422                 :            : #endif
     423                 :            : 
     424                 :          0 : void break_signal(int)
     425                 :            :         {
     426                 :          0 :         g_debugger_state.BreakBeforeNextStmt(true);
     427                 :          0 :         g_debugger_state.BreakFromSignal(true);
     428                 :          0 :         }
     429                 :            : 
     430                 :          0 : int dbg_init_debugger(const char* cmdfile)
     431                 :            :         {
     432         [ #  # ]:          0 :         if ( ! g_policy_debug )
     433                 :          0 :                 return 0;       // probably shouldn't have been called
     434                 :            : 
     435                 :          0 :         init_global_dbg_constants();
     436                 :            : 
     437                 :            :         // Hit the debugger before running anything.
     438                 :          0 :         g_debugger_state.BreakBeforeNextStmt(true);
     439                 :            : 
     440         [ #  # ]:          0 :         if ( cmdfile )
     441                 :            :                 // ### Implement this
     442                 :          0 :                 debug_msg("Command files not supported. Using interactive mode.\n");
     443                 :            : 
     444                 :            :         // ### if ( interactive ) (i.e., not reading cmds from a file)
     445                 :            : #ifdef HAVE_READLINE
     446                 :            :         init_readline();
     447                 :            : #endif
     448                 :            : 
     449                 :          0 :         signal(SIGINT, &break_signal);
     450                 :          0 :         signal(SIGTERM, break_signal);
     451                 :            : 
     452                 :          0 :         return 1;
     453                 :            :         }
     454                 :            : 
     455                 :          0 : int dbg_shutdown_debugger()
     456                 :            :         {
     457                 :            :         // ### TODO: Remove signal handlers
     458                 :          0 :         return 1;
     459                 :            :         }
     460                 :            : 
     461                 :            : 
     462                 :            : // Umesh: I stole this code from libedit; I modified it here to use
     463                 :            : // <string>s to avoid memory management problems. The main command is returned
     464                 :            : // by the operation argument; the additional arguments are put in the
     465                 :            : // supplied vector.
     466                 :            : //
     467                 :            : // Parse the string into individual tokens, similarily to how shell
     468                 :            : // would do it.
     469                 :            : 
     470                 :          0 : void tokenize(const char* cstr, string& operation, vector<string>& arguments)
     471                 :            :         {
     472                 :          0 :         int num_tokens = 0;
     473                 :          0 :         char delim = '\0';
     474                 :          0 :         const string str(cstr);
     475                 :            : 
     476         [ #  # ]:          0 :         for ( int i = 0; i < (signed int) str.length(); ++i )
     477                 :            :                 {
     478         [ #  # ]:          0 :                 while ( isspace((unsigned char) str[i]) )
     479                 :          0 :                         ++i;
     480                 :            : 
     481                 :          0 :                 int start = i;
     482                 :            : 
     483         [ #  # ]:          0 :                 for ( ; str[i]; ++i )
     484                 :            :                         {
     485         [ #  # ]:          0 :                         if ( str[i] == '\\' )
     486                 :            :                                 {
     487         [ #  # ]:          0 :                                 if ( i < (signed int) str.length() )
     488                 :          0 :                                         ++i;
     489                 :            :                                 }
     490                 :            : 
     491 [ #  # ][ #  # ]:          0 :                         else if ( ! delim && (str[i] == '\'' || str[i] == '"') )
         [ #  # ][ #  # ]
     492                 :          0 :                                 delim = str[i];
     493                 :            : 
     494 [ #  # ][ #  # ]:          0 :                         else if ( delim && str[i] == delim )
                 [ #  # ]
     495                 :            :                                 {
     496                 :          0 :                                 delim = '\0';
     497                 :          0 :                                 ++i;
     498                 :          0 :                                 break;
     499                 :            :                                 }
     500                 :            : 
     501 [ #  # ][ #  # ]:          0 :                         else if ( ! delim && isspace(str[i]) )
                 [ #  # ]
     502                 :          0 :                                 break;
     503                 :            :                         }
     504                 :            : 
     505                 :          0 :                 size_t len = i - start;
     506                 :            : 
     507         [ #  # ]:          0 :                 if ( ! num_tokens )
     508                 :          0 :                         operation = string(str, start, len);
     509                 :            :                 else
     510                 :          0 :                         arguments.push_back(string(str, start, len));
     511                 :            : 
     512                 :          0 :                 ++num_tokens;
     513                 :          0 :                 }
     514                 :          0 :         }
     515                 :            : 
     516                 :            : 
     517                 :            : // Given a command string, parse it and send the command to be dispatched.
     518                 :          0 : int dbg_execute_command(const char* cmd)
     519                 :            :         {
     520                 :          0 :         bool matched_history = false;
     521                 :            : 
     522         [ #  # ]:          0 :         if ( ! cmd )
     523                 :          0 :                 return 0;
     524                 :            : 
     525         [ #  # ]:          0 :         if ( streq(cmd, "") ) // do the GDB command completion
     526                 :            :                 {
     527                 :            : #ifdef HAVE_READLINE
     528                 :            :                 int i;
     529                 :            :                 for ( i = history_length; i >= 1; --i )
     530                 :            :                         {
     531                 :            :                         HIST_ENTRY* entry = history_get(i);
     532                 :            :                         if ( ! entry )
     533                 :            :                                 return 0;
     534                 :            : 
     535                 :            :                         const DebugCmdInfo* info =
     536                 :            :                                 (const DebugCmdInfo*) entry->data;
     537                 :            : 
     538                 :            :                         if ( info && info->Repeatable() )
     539                 :            :                                 {
     540                 :            :                                 cmd = entry->line;
     541                 :            :                                 matched_history = true;
     542                 :            :                                 break;
     543                 :            :                                 }
     544                 :            :                         }
     545                 :            : #endif
     546                 :            : 
     547         [ #  # ]:          0 :                 if ( ! matched_history )
     548                 :          0 :                         return 0;
     549                 :            :                 }
     550                 :            : 
     551                 :          0 :         char* localcmd = copy_string(cmd);
     552                 :            : 
     553                 :          0 :         string opstring;
     554                 :          0 :         vector<string> arguments;
     555                 :          0 :         tokenize(localcmd, opstring, arguments);
     556                 :            : 
     557         [ #  # ]:          0 :         delete [] localcmd;
     558                 :            : 
     559                 :            :         // Make sure we know this op name.
     560                 :          0 :         const char* matching_cmds[num_debug_cmds()];
     561                 :          0 :         int num_matches = find_all_matching_cmds(opstring, matching_cmds);
     562                 :            : 
     563         [ #  # ]:          0 :         if ( ! num_matches )
     564                 :            :                 {
     565                 :          0 :                 debug_msg("No Matching command for '%s'.\n", opstring.c_str());
     566                 :          0 :                 return 0;
     567                 :            :                 }
     568                 :            : 
     569         [ #  # ]:          0 :         if ( num_matches > 1 )
     570                 :            :                 {
     571                 :          0 :                 debug_msg("Ambiguous command; could be\n");
     572                 :            : 
     573         [ #  # ]:          0 :                 for ( int i = 0; i < num_debug_cmds(); ++i )
     574         [ #  # ]:          0 :                         if ( matching_cmds[i] )
     575                 :          0 :                                 debug_msg("\t%s\n", matching_cmds[i]);
     576                 :            : 
     577                 :          0 :                 return 0;
     578                 :            :                 }
     579                 :            : 
     580                 :            :         // Matched exactly one command: find out which one.
     581                 :          0 :         DebugCmd cmd_code = dcInvalid;
     582         [ #  # ]:          0 :         for ( int i = 0; i < num_debug_cmds(); ++i )
     583         [ #  # ]:          0 :                 if ( matching_cmds[i] )
     584                 :            :                         {
     585                 :          0 :                         cmd_code = (DebugCmd) i;
     586                 :          0 :                         break;
     587                 :            :                         }
     588                 :            : 
     589                 :            : #ifdef HAVE_READLINE
     590                 :            :         // Insert command into history.
     591                 :            :         if ( ! matched_history && cmd && *cmd )
     592                 :            :                 {
     593                 :            :                 /* The prototype for add_history(), at least under MacOS,
     594                 :            :                  * has it taking a char* rather than a const char*.
     595                 :            :                  * But documentation at 
     596                 :            :                  * http://tiswww.case.edu/php/chet/readline/history.html
     597                 :            :                  * suggests that it's safe to assume it's really const char*.
     598                 :            :                  */
     599                 :            :                 add_history((char *) cmd);
     600                 :            :                 HISTORY_STATE* state = history_get_history_state();
     601                 :            :                 state->entries[state->length-1]->data = (histdata_t *) get_debug_cmd_info(cmd_code);
     602                 :            :                 }
     603                 :            : #endif
     604                 :            : 
     605         [ #  # ]:          0 :         if ( int(cmd_code) >= num_debug_cmds() )
     606                 :          0 :                 internal_error("Assertion failed: %s", "int(cmd_code) < num_debug_cmds()");
     607                 :            : 
     608                 :            :         // Dispatch to the op-specific handler (with args).
     609                 :          0 :         int retcode = dbg_dispatch_cmd(cmd_code, arguments);
     610         [ #  # ]:          0 :         if ( retcode < 0 )
     611                 :          0 :                 return retcode;
     612                 :            : 
     613                 :          0 :         const DebugCmdInfo* info = get_debug_cmd_info(cmd_code);
     614         [ #  # ]:          0 :         if ( ! info  )
     615                 :          0 :                 internal_error("Assertion failed: %s", "info");
     616                 :            : 
     617         [ #  # ]:          0 :         if ( ! info )
     618                 :          0 :                 return -2;      // ### yuck, why -2?
     619                 :            : 
     620                 :          0 :         return info->ResumeExecution();
     621                 :            :         }
     622                 :            : 
     623                 :            : // Call the appropriate function for the command.
     624                 :          0 : static int dbg_dispatch_cmd(DebugCmd cmd_code, const vector<string>& args)
     625                 :            :         {
     626 [ #  #  #  #  # :          0 :         switch ( cmd_code ) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     627                 :            :         case dcHelp:
     628                 :          0 :                 dbg_cmd_help(cmd_code, args);
     629                 :          0 :                 break;
     630                 :            : 
     631                 :            :         case dcQuit:
     632                 :          0 :                 debug_msg("Program Terminating\n");
     633                 :          0 :                 exit(0);
     634                 :            : 
     635                 :            :         case dcNext:
     636                 :          0 :                 g_frame_stack.back()->BreakBeforeNextStmt(true);
     637                 :          0 :                 step_or_next_pending = true;
     638                 :          0 :                 last_frame = g_frame_stack.back();
     639                 :          0 :                 break;
     640                 :            : 
     641                 :            :         case dcStep:
     642                 :          0 :                 g_debugger_state.BreakBeforeNextStmt(true);
     643                 :          0 :                 step_or_next_pending = true;
     644                 :          0 :                 last_frame = g_frame_stack.back();
     645                 :          0 :                 break;
     646                 :            : 
     647                 :            :         case dcContinue:
     648                 :          0 :                 g_debugger_state.BreakBeforeNextStmt(false);
     649                 :          0 :                 debug_msg("Continuing.\n");
     650                 :          0 :                 break;
     651                 :            : 
     652                 :            :         case dcFinish:
     653                 :          0 :                 g_frame_stack.back()->BreakOnReturn(true);
     654                 :          0 :                 g_debugger_state.BreakBeforeNextStmt(false);
     655                 :          0 :                 break;
     656                 :            : 
     657                 :            :         case dcBreak:
     658                 :          0 :                 dbg_cmd_break(cmd_code, args);
     659                 :          0 :                 break;
     660                 :            : 
     661                 :            :         case dcBreakCondition:
     662                 :          0 :                 dbg_cmd_break_condition(cmd_code, args);
     663                 :          0 :                 break;
     664                 :            : 
     665                 :            :         case dcDeleteBreak:
     666                 :            :         case dcClearBreak:
     667                 :            :         case dcDisableBreak:
     668                 :            :         case dcEnableBreak:
     669                 :            :         case dcIgnoreBreak:
     670                 :          0 :                 dbg_cmd_break_set_state(cmd_code, args);
     671                 :          0 :                 break;
     672                 :            : 
     673                 :            :         case dcPrint:
     674                 :          0 :                 dbg_cmd_print(cmd_code, args);
     675                 :          0 :                 break;
     676                 :            : 
     677                 :            :         case dcBacktrace:
     678                 :          0 :                 return dbg_cmd_backtrace(cmd_code, args);
     679                 :            : 
     680                 :            :         case dcFrame:
     681                 :            :         case dcUp:
     682                 :            :         case dcDown:
     683                 :          0 :                 return dbg_cmd_frame(cmd_code, args);
     684                 :            : 
     685                 :            :         case dcInfo:
     686                 :          0 :                 return dbg_cmd_info(cmd_code, args);
     687                 :            : 
     688                 :            :         case dcList:
     689                 :          0 :                 return dbg_cmd_list(cmd_code, args);
     690                 :            : 
     691                 :            :         case dcDisplay:
     692                 :            :         case dcUndisplay:
     693                 :          0 :                 debug_msg("Command not yet implemented.\n");
     694                 :          0 :                 break;
     695                 :            : 
     696                 :            :         case dcTrace:
     697                 :          0 :                 return dbg_cmd_trace(cmd_code, args);
     698                 :            : 
     699                 :            :         default:
     700                 :            :                 debug_msg("INTERNAL ERROR: "
     701                 :            :                 "Got an unknown debugger command in DbgDispatchCmd: %d\n",
     702                 :          0 :                 cmd_code);
     703                 :          0 :                 return 0;
     704                 :            :         }
     705                 :            : 
     706                 :          0 :         return 0;
     707                 :            :         }
     708                 :            : 
     709                 :          0 : static char* get_prompt(bool reset_counter = false)
     710                 :            :         {
     711                 :            :         static char prompt[512];
     712                 :            :         static int counter = 0;
     713                 :            : 
     714         [ #  # ]:          0 :         if ( reset_counter )
     715                 :          0 :                 counter = 0;
     716                 :            : 
     717                 :          0 :         safe_snprintf(prompt, sizeof(prompt), "(Bro [%d]) ", counter++);
     718                 :            : 
     719                 :          0 :         return prompt;
     720                 :            :         }
     721                 :            : 
     722                 :          0 : string get_context_description(const Stmt* stmt, const Frame* frame)
     723                 :            :         {
     724                 :            :         char buf[1024];
     725                 :          0 :         ODesc d;
     726                 :          0 :         const BroFunc* func = frame->GetFunction();
     727                 :            : 
     728         [ #  # ]:          0 :         if ( func )
     729                 :          0 :                 func->DescribeDebug(&d, frame->GetFuncArgs());
     730                 :            :         else
     731                 :          0 :                 d.Add("<unknown function>", 0);
     732                 :            : 
     733                 :          0 :         Location loc;
     734         [ #  # ]:          0 :         if ( stmt )
     735                 :          0 :                 loc = *stmt->GetLocationInfo();
     736                 :            :         else
     737                 :            :                 {
     738                 :          0 :                 loc.filename = "<no filename>";
     739                 :          0 :                 loc.last_line = 0;
     740                 :            :                 }
     741                 :            : 
     742                 :            :         safe_snprintf(buf, sizeof(buf), "In %s at %s:%d",
     743                 :          0 :                       d.Description(), loc.filename, loc.last_line);
     744                 :            : 
     745                 :          0 :         return string(buf);
     746                 :            :         }
     747                 :            : 
     748                 :          0 : int dbg_handle_debug_input()
     749                 :            :         {
     750                 :            :         static char* input_line = 0;
     751                 :          0 :         int status = 0;
     752                 :            : 
     753         [ #  # ]:          0 :         if ( g_debugger_state.BreakFromSignal() )
     754                 :            :                 {
     755                 :          0 :                 debug_msg("Program received signal SIGINT: entering debugger\n");
     756                 :            : 
     757                 :          0 :                 g_debugger_state.BreakFromSignal(false);
     758                 :            :                 }
     759                 :            : 
     760                 :          0 :         Frame* curr_frame = g_frame_stack.back();
     761                 :          0 :         const BroFunc* func = curr_frame->GetFunction();
     762         [ #  # ]:          0 :         if ( func )
     763                 :          0 :                 current_module = func->GetID()->ModuleName();
     764                 :            :         else
     765                 :          0 :                 current_module = GLOBAL_MODULE_NAME;
     766                 :            : 
     767                 :          0 :         const Stmt* stmt = curr_frame->GetNextStmt();
     768         [ #  # ]:          0 :         if ( ! stmt )
     769                 :          0 :                 internal_error("Assertion failed: %s", "stmt != 0");
     770                 :            : 
     771                 :          0 :         const Location loc = *stmt->GetLocationInfo();
     772                 :            : 
     773   [ #  #  #  # ]:          0 :         if ( ! step_or_next_pending || g_frame_stack.back() != last_frame )
                 [ #  # ]
     774                 :            :                 {
     775                 :            :                 string context =
     776                 :          0 :                         get_context_description(stmt, g_frame_stack.back());
     777                 :          0 :                 debug_msg("%s\n", context.c_str());
     778                 :            :                 }
     779                 :            : 
     780                 :          0 :         step_or_next_pending = false;
     781                 :            : 
     782                 :            :         PrintLines(loc.filename, loc.first_line,
     783                 :          0 :                         loc.last_line - loc.first_line + 1, true);
     784                 :          0 :         g_debugger_state.last_loc = loc;
     785                 :            : 
     786         [ #  # ]:          0 :         do
     787                 :            :                 {
     788                 :            :                 // readline returns a pointer to a buffer it allocates; it's
     789                 :            :                 // freed at the bottom.
     790                 :            : #ifdef HAVE_READLINE
     791                 :            :                 input_line = readline(get_prompt());
     792                 :            : #else
     793                 :          0 :                 printf ("%s", get_prompt());
     794                 :            : 
     795                 :            :                 // readline uses malloc, and we want to be consistent
     796                 :            :                 // with it.
     797                 :          0 :                 input_line = (char*) safe_malloc(1024);
     798                 :          0 :                 input_line[1023] = 0;
     799                 :            :                 // ### Maybe it's not always stdin.
     800                 :          0 :                 fgets(input_line, 1023, stdin);
     801                 :            : #endif
     802                 :            : 
     803                 :            :                 // ### Maybe not stdin; maybe do better cleanup.
     804         [ #  # ]:          0 :                 if ( feof(stdin) )
     805                 :          0 :                         exit(0);
     806                 :            : 
     807                 :          0 :                 status = dbg_execute_command(input_line);
     808                 :            : 
     809         [ #  # ]:          0 :                 if ( input_line )
     810                 :            :                         {
     811                 :          0 :                         free(input_line);       // this was malloc'ed
     812                 :          0 :                         input_line = 0;
     813                 :            :                         }
     814                 :            :                 else
     815                 :          0 :                         exit(0);
     816                 :            :                 }
     817                 :            :         while ( status == 0 );
     818                 :            : 
     819                 :            :         // Clear out some state. ### Is there a better place?
     820                 :          0 :         g_debugger_state.curr_frame_idx = 0;
     821                 :          0 :         g_debugger_state.already_did_list = false;
     822                 :            : 
     823                 :          0 :         signal(SIGINT, &break_signal);
     824                 :          0 :         signal(SIGTERM, &break_signal);
     825                 :            : 
     826                 :          0 :         return 0;
     827                 :            :         }
     828                 :            : 
     829                 :            : 
     830                 :            : // Return true to continue execution, false to abort.
     831                 :     636210 : bool pre_execute_stmt(Stmt* stmt, Frame* f)
     832                 :            :         {
     833 [ -  + ][ #  # ]:     636210 :         if ( ! g_policy_debug ||
         [ #  # ][ +  - ]
     834                 :            :              stmt->Tag() == STMT_LIST || stmt->Tag() == STMT_NULL )
     835                 :     636210 :                 return true;
     836                 :            : 
     837         [ #  # ]:          0 :         if ( g_trace_state.DoTrace() )
     838                 :            :                 {
     839                 :          0 :                 ODesc d;
     840                 :          0 :                 stmt->Describe(&d);
     841                 :            : 
     842                 :          0 :                 const char* desc = d.Description();
     843                 :          0 :                 const char* s = strchr(desc, '\n');
     844                 :            : 
     845                 :            :                 int len;
     846         [ #  # ]:          0 :                 if ( s )
     847                 :          0 :                         len = s - desc;
     848                 :            :                 else
     849                 :          0 :                         len = strlen(desc);
     850                 :            : 
     851                 :          0 :                 g_trace_state.LogTrace("%*s\n", len, desc);
     852                 :            :                 }
     853                 :            : 
     854                 :          0 :         bool should_break = false;
     855                 :            : 
     856 [ #  # ][ #  # ]:          0 :         if ( g_debugger_state.BreakBeforeNextStmt() ||
                 [ #  # ]
     857                 :            :              f->BreakBeforeNextStmt() )
     858                 :            :                 {
     859         [ #  # ]:          0 :                 if ( g_debugger_state.BreakBeforeNextStmt() )
     860                 :          0 :                         g_debugger_state.BreakBeforeNextStmt(false);
     861                 :            : 
     862         [ #  # ]:          0 :                 if ( f->BreakBeforeNextStmt() )
     863                 :          0 :                         f->BreakBeforeNextStmt(false);
     864                 :            : 
     865                 :          0 :                 should_break = true;
     866                 :            :                 }
     867                 :            : 
     868         [ #  # ]:          0 :         if ( stmt->BPCount() )
     869                 :            :                 {
     870                 :          0 :                 pair<BPMapType::iterator, BPMapType::iterator> p;
     871                 :            : 
     872                 :          0 :                 p = g_debugger_state.breakpoint_map.equal_range(stmt);
     873                 :            : 
     874         [ #  # ]:          0 :                 if ( p.first == p.second )
     875                 :          0 :                         internal_error("Breakpoint count nonzero, but no matching breakpoints");
     876                 :            : 
     877         [ #  # ]:          0 :                 for ( BPMapType::iterator i = p.first; i != p.second; ++i )
     878                 :            :                         {
     879                 :          0 :                         int break_code = i->second->ShouldBreak(stmt);
     880         [ #  # ]:          0 :                         if ( break_code == 2 )  // ### 2?
     881                 :            :                                 {
     882                 :          0 :                                 i->second->SetEnable(false);
     883         [ #  # ]:          0 :                                 delete i->second;
     884                 :            :                                 }
     885                 :            : 
     886 [ #  # ][ #  # ]:          0 :                         should_break = should_break || break_code;
     887                 :            :                         }
     888                 :            :                 }
     889                 :            : 
     890         [ #  # ]:          0 :         if ( should_break )
     891                 :          0 :                 dbg_handle_debug_input();
     892                 :            : 
     893                 :     636210 :         return true;
     894                 :            :         }
     895                 :            : 
     896                 :     636210 : bool post_execute_stmt(Stmt* stmt, Frame* f, Val* result, stmt_flow_type* flow)
     897                 :            :         {
     898                 :            :         // Handle the case where someone issues a "next" debugger command,
     899                 :            :         // but we're at a return statement, so the next statement is in
     900                 :            :         // some other function.
     901 [ +  + ][ -  + ]:     636210 :         if ( *flow == FLOW_RETURN && f->BreakBeforeNextStmt() )
                 [ -  + ]
     902                 :          0 :                 g_debugger_state.BreakBeforeNextStmt(true);
     903                 :            : 
     904                 :            :         // Handle "finish" commands.
     905 [ +  + ][ -  + ]:     636210 :         if ( *flow == FLOW_RETURN && f->BreakOnReturn() )
                 [ -  + ]
     906                 :            :                 {
     907         [ #  # ]:          0 :                 if ( result )
     908                 :            :                         {
     909                 :          0 :                         ODesc d;
     910                 :          0 :                         result->Describe(&d);
     911                 :          0 :                         debug_msg("Return Value: '%s'\n", d.Description());
     912                 :            :                         }
     913                 :            :                 else
     914                 :          0 :                         debug_msg("Return Value: <none>\n");
     915                 :            : 
     916                 :          0 :                 g_debugger_state.BreakBeforeNextStmt(true);
     917                 :          0 :                 f->BreakOnReturn(false);
     918                 :            :                 }
     919                 :            : 
     920                 :     636210 :         return true;
     921                 :            :         }
     922                 :            : 
     923                 :            : 
     924                 :            : // Evaluates the given expression in the context of the currently selected
     925                 :            : // frame.  Returns the resulting value, or nil if none (or there was an error).
     926                 :            : Expr* g_curr_debug_expr = 0;
     927                 :            : 
     928                 :            : // ### fix this hardwired access to external variables etc.
     929                 :            : struct yy_buffer_state;
     930                 :            : typedef struct yy_buffer_state* YY_BUFFER_STATE;
     931                 :            : YY_BUFFER_STATE bro_scan_string(const char*);
     932                 :            : 
     933                 :            : extern YYLTYPE yylloc;  // holds start line and column of token
     934                 :            : extern int line_number;
     935                 :            : extern const char* filename;
     936                 :            : 
     937                 :          0 : Val* dbg_eval_expr(const char* expr)
     938                 :            :         {
     939                 :            :         // Push the current frame's associated scope.
     940                 :            :         // Note: g_debugger_state.curr_frame_idx is the user-visible number,
     941                 :            :         //       while the array index goes in the opposite direction
     942                 :            :         int frame_idx =
     943                 :          0 :                 (g_frame_stack.size() - 1) - g_debugger_state.curr_frame_idx;
     944                 :            : 
     945   [ #  #  #  # ]:          0 :         if ( ! (frame_idx >= 0 && (unsigned) frame_idx < g_frame_stack.size())  )
                 [ #  # ]
     946                 :          0 :                 internal_error("Assertion failed: %s", "frame_idx >= 0 && (unsigned) frame_idx < g_frame_stack.size()");
     947                 :            : 
     948                 :          0 :         Frame* frame = g_frame_stack[frame_idx];
     949         [ #  # ]:          0 :         if ( ! (frame)  )
     950                 :          0 :                 internal_error("Assertion failed: %s", "frame");
     951                 :            : 
     952                 :          0 :         const BroFunc* func = frame->GetFunction();
     953         [ #  # ]:          0 :         if ( func )
     954                 :          0 :                 push_existing_scope(func->GetScope());
     955                 :            : 
     956                 :            :         // ### Possibly push a debugger-local scope?
     957                 :            : 
     958                 :            :         // Set up the lexer to read from the string.
     959                 :          0 :         string parse_string = string("@DEBUG ") + expr;
     960                 :          0 :         bro_scan_string(parse_string.c_str());
     961                 :            : 
     962                 :            :         // Fix filename and line number for the lexer/parser, which record it.
     963                 :          0 :         filename = "<interactive>";
     964                 :          0 :         line_number = 1;
     965                 :          0 :         yylloc.filename = filename;
     966                 :          0 :         yylloc.first_line = yylloc.last_line = line_number = 1;
     967                 :            : 
     968                 :            :         // Parse the thing into an expr.
     969                 :          0 :         Val* result = 0;
     970         [ #  # ]:          0 :         if ( yyparse() )
     971                 :            :                 {
     972         [ #  # ]:          0 :                 if ( g_curr_debug_expr )
     973                 :            :                         {
     974         [ #  # ]:          0 :                         delete g_curr_debug_expr;
     975                 :          0 :                         g_curr_debug_expr = 0;
     976                 :            :                         }
     977                 :            :                 }
     978                 :            :         else
     979                 :          0 :                 result = g_curr_debug_expr->Eval(frame);
     980                 :            : 
     981         [ #  # ]:          0 :         if ( func )
     982                 :          0 :                 pop_scope();
     983                 :            : 
     984         [ #  # ]:          0 :         delete g_curr_debug_expr;
     985                 :          0 :         g_curr_debug_expr = 0;
     986                 :            : 
     987                 :          0 :         return result;
     988 [ +  - ][ +  - ]:          6 :         }

Generated by: LCOV version 1.8