| 1 | \chapter{Extending GDB for \uC} | 
|---|
| 2 |  | 
|---|
| 3 | \section{Introduction} | 
|---|
| 4 | A sequential program has a single call stack. A debugger knows about this call stack and provides | 
|---|
| 5 | commands to walk up/down the call frames to examine the values of local variables, as well as global | 
|---|
| 6 | variables. A concurrent program has multiple call stacks (for coroutines/tasks), so a debugger must | 
|---|
| 7 | be extended to locate these stacks for examination, similar to a sequential stack.  For example, | 
|---|
| 8 | when a concurrent program deadlocks, looking at the task's call stack can locate the resource and | 
|---|
| 9 | the blocking cycle that resulted in the deadlock. Hence, it is very useful to display the call stack | 
|---|
| 10 | of each task to know where it is executing and what values it is currently computing. Because each | 
|---|
| 11 | programming language's concurrency is different, GDB has to be specifically extended for \uC. | 
|---|
| 12 |  | 
|---|
| 13 | \section{Design Constraints} | 
|---|
| 14 | As mentioned in Chapter \ref{GDB}, there are several ways to extend GDB. However, there are a few | 
|---|
| 15 | design constraints on the selected mechanism. All the functions implemented should maintain similar | 
|---|
| 16 | functionality to existing GDB commands. In addition to functional requirements, usability and | 
|---|
| 17 | flexibility are requirements for this project. These final requirements enable developers to be | 
|---|
| 18 | productive quickly and do more with the extensions. The extensions created for \uC are simple to use | 
|---|
| 19 | and versatile. | 
|---|
| 20 |  | 
|---|
| 21 | The following new GDB command are all implemented through the Python API for GDB.  Python is a | 
|---|
| 22 | scripting language with built-in data structures and functions that enables the development of more | 
|---|
| 23 | complex operations and saves time on development. | 
|---|
| 24 |  | 
|---|
| 25 | \section{\uC source-code example} | 
|---|
| 26 | Listing \ref{uC-src-code} shows a \uC program that implicitly creates two clusters, system and user, | 
|---|
| 27 | which implicitly have a processor (kernel thread) and processor task. The program explicitly creates | 
|---|
| 28 | three additional processors and ten tasks on the user cluster. | 
|---|
| 29 |  | 
|---|
| 30 | \begin{figure} | 
|---|
| 31 | \begin{lstlisting}[numbers=left, xleftmargin=4.0ex, style=C++, caption={\uC source code used for GDB commands},label={uC-src-code}, basicstyle=\small] | 
|---|
| 32 | _Task T { | 
|---|
| 33 | const int tid; | 
|---|
| 34 | std::string name; | 
|---|
| 35 |  | 
|---|
| 36 | void f(int param) { | 
|---|
| 37 | if ( param != 0 ) f( param - 1 );       // recursion | 
|---|
| 38 | for ( volatile size_t i = 0; i < 100000000; i += 1 ); // delay | 
|---|
| 39 | int x = 3; | 
|---|
| 40 | std::string y = "example"; | 
|---|
| 41 | }                                           // breakpoint | 
|---|
| 42 | void main() { | 
|---|
| 43 | if ( tid != 0 )                         // T0 goes first | 
|---|
| 44 | for ( volatile size_t i = 0; i < 1000000000; i += 1 ) // delay | 
|---|
| 45 | if ( i % 10000000 == 0 ) yield(); // execute other tasks | 
|---|
| 46 | f(3); | 
|---|
| 47 | } | 
|---|
| 48 | public: | 
|---|
| 49 | T(const int tid) : tid( tid ) { | 
|---|
| 50 | name = "T" + std::to_string(tid); | 
|---|
| 51 | setName(name.c_str()); | 
|---|
| 52 | } | 
|---|
| 53 | }; | 
|---|
| 54 | int main() { | 
|---|
| 55 | uProcessor procs[3];                        // extra processors | 
|---|
| 56 | const int numTasks = 10; | 
|---|
| 57 | T * tasks[numTasks];                        // extra tasks | 
|---|
| 58 | // allocate tasks with different names | 
|---|
| 59 | for (int id = 0; id < numTasks; id += 1) { | 
|---|
| 60 | tasks[id] = new T(id); | 
|---|
| 61 | } | 
|---|
| 62 | // deallocate tasks | 
|---|
| 63 | for (int id = 0; id < numTasks; id += 1) { | 
|---|
| 64 | delete tasks[id]; | 
|---|
| 65 | } | 
|---|
| 66 | } | 
|---|
| 67 | \end{lstlisting} | 
|---|
| 68 | \end{figure} | 
|---|
| 69 |  | 
|---|
| 70 | \section{Existing User-defined GDB Commands} | 
|---|
| 71 | Listing \ref{uC-callstack} shows the GDB output at the base case of the recursion for one of the | 
|---|
| 72 | tasks created in the \uC program in listing \ref{uC-src-code}.  The task is stopped at line 10. The | 
|---|
| 73 | backtrace shows the three calls to function \verb|f|, started in the task's \verb|main|. The top two | 
|---|
| 74 | frames (5 and 6) are administrative frames from \uC. The values of the argument and local variables | 
|---|
| 75 | are printed. | 
|---|
| 76 | \begin{lstlisting}[caption={Call stack of function \texttt{a} in the \uC | 
|---|
| 77 | program from listing \ref{uC-src-code}}, label={uC-callstack}, basicstyle=\small\tt] | 
|---|
| 78 | (gdb) backtrace | 
|---|
| 79 | #0  T::f (this=0xa4f950, param=0) at test.cc:10 | 
|---|
| 80 | #1  0x000000000041e509 in T::f (this=0xa4f950, param=1) at test.cc:6 | 
|---|
| 81 | #2  0x000000000041e509 in T::f (this=0xa4f950, param=2) at test.cc:6 | 
|---|
| 82 | #3  0x000000000041e509 in T::f (this=0xa4f950, param=3) at test.cc:6 | 
|---|
| 83 | #4  0x000000000041e654 in T::main (this=0xa4f950) at test.cc:15 | 
|---|
| 84 | #5  0x0000000000428de2 in ...::invokeTask (This=...) at ... | 
|---|
| 85 | #6  0x0000000000000000 in ?? () | 
|---|
| 86 | (gdb) info args | 
|---|
| 87 | this = 0xa4f950 | 
|---|
| 88 | param = 0 | 
|---|
| 89 | (gdb) info locals | 
|---|
| 90 | x = 3 | 
|---|
| 91 | y = "example" | 
|---|
| 92 | \end{lstlisting} | 
|---|
| 93 |  | 
|---|
| 94 | \subsection{Listing all clusters in a \uC program} | 
|---|
| 95 | Listing \ref{clusters-command} shows the new command \verb|clusters| to list all program clusters | 
|---|
| 96 | along with their associated address.  The output shows the two \uC implicitly created clusters. | 
|---|
| 97 | \begin{lstlisting}[caption={clusters command}, label={clusters-command}, basicstyle=\small\tt] | 
|---|
| 98 | (gdb) clusters | 
|---|
| 99 | Name           Address | 
|---|
| 100 | systemCluster          0x65a300 | 
|---|
| 101 | userCluster          0x7ca300 | 
|---|
| 102 | \end{lstlisting} | 
|---|
| 103 |  | 
|---|
| 104 | \subsection{Listing all processors in a cluster} | 
|---|
| 105 | Listing \ref{cluster-procs} shows the new command \verb|processors|, which requires a cluster | 
|---|
| 106 | argument to show all the processors in that cluster. In particular, this example shows that there | 
|---|
| 107 | are four processors in the \verb|userCluster|, with their associated address, PID, preemption and | 
|---|
| 108 | spin. | 
|---|
| 109 | \begin{lstlisting}[caption={processors command}, label={cluster-procs}, basicstyle=\small\tt] | 
|---|
| 110 | (gdb) processors | 
|---|
| 111 | Address                 PID          Preemption                Spin | 
|---|
| 112 | 0x7ccc30             8421504                  10                1000 | 
|---|
| 113 | 0x8c9b50             9478272                  10                1000 | 
|---|
| 114 | 0x8c9d10            10002560                  10                1000 | 
|---|
| 115 | 0x8c9ed0            10530944                  10                1000 | 
|---|
| 116 | \end{lstlisting} | 
|---|
| 117 |  | 
|---|
| 118 | \subsection{Listing all tasks in all clusters} | 
|---|
| 119 | Listing \ref{tasks} shows the new command \verb|task| with the \verb|all| argument to list all the | 
|---|
| 120 | tasks in a \uC program at this point in the execution snapshot.  The internal \uC threads | 
|---|
| 121 | (implicitly created) are numbered with negative identifiers, while those created by the application | 
|---|
| 122 | are numbered with zero/positive. The \verb|*| indicates the \uC thread (\verb|T0|) that encountered | 
|---|
| 123 | the breakpoint at line 10. GDB stops all execution and the states of the other threads are ready, | 
|---|
| 124 | running, or blocked. If the argument \verb|all| is removed, only internal information about the | 
|---|
| 125 | \verb|userCluster| and its implicitly created threads is printed, which is sufficient for most | 
|---|
| 126 | applications. | 
|---|
| 127 | \begin{lstlisting}[caption={task command for displaying all tasks for all clusters}, label={tasks}, basicstyle=\footnotesize\tt] | 
|---|
| 128 | (gdb) task all | 
|---|
| 129 | Cluster Name           Address | 
|---|
| 130 | systemCluster          0x65a300 | 
|---|
| 131 | ID           Task Name           Address                    State | 
|---|
| 132 | -1      uProcessorTask          0x6c99c0       uBaseTask::Blocked | 
|---|
| 133 | -2         uSystemTask          0x789f40       uBaseTask::Blocked | 
|---|
| 134 | userCluster          0x7ca300 | 
|---|
| 135 | ID           Task Name           Address                    State | 
|---|
| 136 | -1      uProcessorTask          0x80ced0       uBaseTask::Blocked | 
|---|
| 137 | -2           uBootTask          0x659dd0       uBaseTask::Blocked | 
|---|
| 138 | 0                main    0x7fffffffe490       uBaseTask::Blocked | 
|---|
| 139 | -3      uProcessorTask          0x90e810       uBaseTask::Blocked | 
|---|
| 140 | -4      uProcessorTask          0x98ee00       uBaseTask::Blocked | 
|---|
| 141 | -5      uProcessorTask          0xa0f3f0       uBaseTask::Blocked | 
|---|
| 142 | * 1                  T0          0xa4f950       uBaseTask::Running | 
|---|
| 143 | 2                  T1          0xa8fce0       uBaseTask::Running | 
|---|
| 144 | 3                  T2          0xad0070       uBaseTask::Running | 
|---|
| 145 | 4                  T3          0xb10400         uBaseTask::Ready | 
|---|
| 146 | 5                  T4          0xb50790         uBaseTask::Ready | 
|---|
| 147 | 6                  T5          0xb90b20         uBaseTask::Ready | 
|---|
| 148 | 7                  T6          0xbd0eb0         uBaseTask::Ready | 
|---|
| 149 | 8                  T7          0xc11240         uBaseTask::Ready | 
|---|
| 150 | 9                  T8          0xc515d0       uBaseTask::Running | 
|---|
| 151 | 10                  T9          0xc91960         uBaseTask::Ready | 
|---|
| 152 | \end{lstlisting} | 
|---|
| 153 |  | 
|---|
| 154 | \subsection{Listing all tasks in a cluster} | 
|---|
| 155 | Listing \ref{cluster-tasks} shows the new command \verb|task| with a cluster argument to list only | 
|---|
| 156 | the names of the tasks on that cluster.  In this version of the command \verb|task|, the associated | 
|---|
| 157 | address for each task and its state is displayed. | 
|---|
| 158 | \begin{lstlisting}[caption={task command for displaying all tasks in a cluster}, label={cluster-tasks}, basicstyle=\small\tt] | 
|---|
| 159 | (gdb) task systemCluster | 
|---|
| 160 | ID           Task Name           Address                    State | 
|---|
| 161 | -1      uProcessorTask          0x6c99c0       uBaseTask::Blocked | 
|---|
| 162 | -2         uSystemTask          0x789f40       uBaseTask::Blocked | 
|---|
| 163 | \end{lstlisting} | 
|---|
| 164 |  | 
|---|
| 165 | \section{Changing Stacks} | 
|---|
| 166 | The next extension for displaying information is writing new commands that allow stepping from one | 
|---|
| 167 | \uC task to another. Each switching remembers the task tour in a LIFO way. This semantics means push | 
|---|
| 168 | and pop commands are needed. The push is performed by the \verb|task| command with a task argument. | 
|---|
| 169 | The pop is performed by the new command \verb|prevtask| or shorthand \verb|prev|. | 
|---|
| 170 |  | 
|---|
| 171 | \subsection{Task Switching} | 
|---|
| 172 | The task argument for pushing is a relative id within a cluster or absolute address on any | 
|---|
| 173 | cluster. For instance, to switch from any task to task \verb|T2| seen in listing \ref{tasks}, the | 
|---|
| 174 | first command in listing \ref{task-addr-arguments} uses relative id (3) implicitly from the | 
|---|
| 175 | \verb|userCluster|, the second command uses an absolute address (\verb|0xad0070|), and the third | 
|---|
| 176 | command uses relative id (3) with the explicit \verb|userCluster|. Core functionality of these | 
|---|
| 177 | approaches is the same. Finally, the \verb|prevtask| command is used to unwind the stack until it is | 
|---|
| 178 | empty. | 
|---|
| 179 | \begin{lstlisting}[caption={task command arguments}, label={task-addr-arguments}, basicstyle=\small\tt] | 
|---|
| 180 | (gdb) task 3 | 
|---|
| 181 | (gdb) task 0xad0070 | 
|---|
| 182 | (gdb) task 3 userCluster | 
|---|
| 183 | (gdb) prevtask | 
|---|
| 184 | ... | 
|---|
| 185 | (gdb) prev | 
|---|
| 186 | ... | 
|---|
| 187 | (gdb) prev | 
|---|
| 188 | ... | 
|---|
| 189 | (gdb) prev | 
|---|
| 190 | empty stack | 
|---|
| 191 | \end{lstlisting} | 
|---|
| 192 |  | 
|---|
| 193 |  | 
|---|
| 194 | \subsection{Switching Implementation} | 
|---|
| 195 | To implement the task tour, it is necessary to store the context information for every context | 
|---|
| 196 | switching. This requirement means the \verb|task| command needs to store this information every time | 
|---|
| 197 | it is invoked. | 
|---|
| 198 |  | 
|---|
| 199 | \begin{figure} | 
|---|
| 200 | \centering | 
|---|
| 201 | \includegraphics[width=8cm]{uContext_stack} | 
|---|
| 202 | \caption{Machine context (uMachContext) for each task} | 
|---|
| 203 | \label{machine-context} | 
|---|
| 204 |  | 
|---|
| 205 | \vspace*{0.5in} | 
|---|
| 206 |  | 
|---|
| 207 | \begin{lstlisting}[style=Python, caption={Abridged \texttt{push\_task} source code}, label={pushtask-code}, basicstyle=\small\tt] | 
|---|
| 208 | # get GDB type of uContext_t * | 
|---|
| 209 | uContext_t_ptr_type = gdb.lookup_type('UPP::uMachContext::uContext_t').pointer() | 
|---|
| 210 |  | 
|---|
| 211 | # retrieve the context object from a task and cast it to the type uContext_t * | 
|---|
| 212 | task_context = task['context'].cast(uContext_t_ptr_type) | 
|---|
| 213 |  | 
|---|
| 214 | # the offset where sp would be starting from uSwitch function | 
|---|
| 215 | sp_address_offset = 48 | 
|---|
| 216 | # lookup the value of stack pointer (sp), frame pointer (fp), | 
|---|
| 217 | # program counter (pc) | 
|---|
| 218 | xsp = task_context['SP'] + sp_address_offset | 
|---|
| 219 | xfp = task_context['FP'] | 
|---|
| 220 | if not gdb.lookup_symbol('uSwitch'): | 
|---|
| 221 | print('uSwitch symbol is unavailable') | 
|---|
| 222 | return | 
|---|
| 223 |  | 
|---|
| 224 | # This value is calculated here because we always here when the task is in | 
|---|
| 225 | # blocked state | 
|---|
| 226 | xpc = get_addr(gdb.parse_and_eval('uSwitch').address + 28) | 
|---|
| 227 | # must switch back to frame-0 to set 'pc' register with the value of xpc | 
|---|
| 228 | gdb.execute('select-frame 0') | 
|---|
| 229 |  | 
|---|
| 230 | # retrieve register values and push sp, fp, pc into a global stack | 
|---|
| 231 | global STACK | 
|---|
| 232 | sp = gdb.parse_and_eval('$sp') | 
|---|
| 233 | fp = gdb.parse_and_eval('$fp') | 
|---|
| 234 | pc = gdb.parse_and_eval('$pc') | 
|---|
| 235 | stack_info = StackInfo(sp = sp, fp = fp, pc = pc) | 
|---|
| 236 | STACK.append(stack_info) | 
|---|
| 237 |  | 
|---|
| 238 | # update registers for new task | 
|---|
| 239 | gdb.execute('set $rsp={}'.format(xsp)) | 
|---|
| 240 | gdb.execute('set $rbp={}'.format(xfp)) | 
|---|
| 241 | gdb.execute('set $pc={}'.format(xpc)) | 
|---|
| 242 | \end{lstlisting} | 
|---|
| 243 | \end{figure} | 
|---|
| 244 |  | 
|---|
| 245 | Figure \ref{machine-context} shows a task points to a structure containing a \verb|uContext_t| data | 
|---|
| 246 | structure, storing the stack and frame pointer, and the stack pointer. Listing \ref{pushtask-code} | 
|---|
| 247 | shows these pointers are copied into an instance of the Python tuple \verb|StackInfo| for every | 
|---|
| 248 | level of task switching. This tuple also stores information about the program counter that is | 
|---|
| 249 | calculated from the address of the \verb|uSwitch| assembly function because a task always stops in | 
|---|
| 250 | \verb|uSwitch| when its state is blocked.  Similarly, switching commands retrieve this context | 
|---|
| 251 | information but from the task that a user wants to switch to, and sets the equivalent registers to | 
|---|
| 252 | the new values. | 
|---|
| 253 |  | 
|---|
| 254 | To push using the \verb|task| command, the value of the hardware stack pointer \verb|rsp| register, | 
|---|
| 255 | frame pointer \verb|rbp| register, and program counter register \verb|pc| are copied from the | 
|---|
| 256 | blocked task's save-area to the Python stack.  To pop using the \verb|prevtask| command, the three | 
|---|
| 257 | registers are moved from the Python stack to the appropriate hardware registers. Popping an empty | 
|---|
| 258 | stack prints a warning. | 
|---|
| 259 |  | 
|---|
| 260 | Note, for tasks running when a breakpoint is encountered, the task's save-area is out-of-date; i.e., | 
|---|
| 261 | the save area is only updated on a context switch, and a running task's stack represents the current | 
|---|
| 262 | unstored state for that task, which will be stored at the next context switch. Hence, to examine | 
|---|
| 263 | running tasks, it is necessary to use the GDB \verb|info threads| and \verb|thread| commands to | 
|---|
| 264 | examine and then step onto running tasks. | 
|---|
| 265 |  | 
|---|
| 266 | Listing \ref{rr-tasks} shows how to examine ready and running tasks. Task \verb|T3| is ready (see | 
|---|
| 267 | Listing \ref{tasks}) because it was forced to context switch because of a time-slice preemption. | 
|---|
| 268 | Switching to \verb|T3|, which is relative id 4, and listing its the backtrace (stack frames) shows | 
|---|
| 269 | frames 0--6, which are the execution sequence for a time-slice preemption (and can be ignored), and | 
|---|
| 270 | frames 7--9, which are the frames at the point of preemption.  Frame 7 shows \verb|T3| is at line 14 | 
|---|
| 271 | in the test program (see Listing \ref{uC-src-code}). Switching to running task \verb|T1|, which is | 
|---|
| 272 | relative id 2 (see Listing \ref{tasks}), and listing its backtrace shows a similar backtrace to | 
|---|
| 273 | ready task \verb|T3|. However, this backtrace contains stale information.  The GDB command | 
|---|
| 274 | \verb|info threads| shows the status of each kernel thread in the application, which represents the | 
|---|
| 275 | true location of each running thread. By observation, it can be seen that thread 2 is executing task | 
|---|
| 276 | \verb|0xa8fce0|, which is task \verb|T1|. Switching to kernel thread 2 via GDB command | 
|---|
| 277 | \verb|thread 2| and listing its backtrace show that task \verb|T1| is current executing at line 13 | 
|---|
| 278 | in the test program. | 
|---|
| 279 |  | 
|---|
| 280 | \begin{figure} | 
|---|
| 281 | \begin{lstlisting}[numbers=left, xleftmargin=3.0ex, caption={Examine ready/running tasks}, label={rr-tasks}, basicstyle=\footnotesize\tt] | 
|---|
| 282 | (gdb) task 4 | 
|---|
| 283 | #0  T::f (this=0xa4f950, param=0) at test.cc:10 | 
|---|
| 284 | (gdb) backtrace | 
|---|
| 285 | #0  uSwitch () at /u0/usystem/software/u++-7.0.0/src/kernel/uSwitch-x86_64.S:64 | 
|---|
| 286 | #1  0x000000000042bd5c in uBaseCoroutine::taskCxtSw (this=0x8c9d28) ... | 
|---|
| 287 | #2  0x000000000042fff4 in UPP::uProcessorKernel::scheduleInternal ... | 
|---|
| 288 | #3  0x000000000042d4b6 in uBaseTask::uYieldInvoluntary ... | 
|---|
| 289 | #4  0x000000000042172f in uKernelModule::rollForward ... | 
|---|
| 290 | #5  0x000000000042f4fe in UPP::uSigHandlerModule::sigAlrmHandler ... | 
|---|
| 291 | #6  <signal handler called> | 
|---|
| 292 | #7  0x000000000041e620 in T::main (`this=0xb10400`) at test.cc:14 | 
|---|
| 293 | #8  0x0000000000428de2 in UPP::uMachContext::invokeTask (This=...) ... | 
|---|
| 294 | #9  0x0000000000000000 in ?? () | 
|---|
| 295 | (gdb) task 2 | 
|---|
| 296 | (gdb) backtrace | 
|---|
| 297 | #0  uSwitch () at /u0/usystem/software/u++-7.0.0/src/kernel/uSwitch-x86_64.S:64 | 
|---|
| 298 | #1  0x000000000042bd70 in uBaseCoroutine::taskCxtSw (this=0x8c9b68) ... | 
|---|
| 299 | #2  0x000000000042fff4 in UPP::uProcessorKernel::scheduleInternal ... | 
|---|
| 300 | #3  0x000000000042d4b6 in uBaseTask::uYieldInvoluntary ... | 
|---|
| 301 | #4  0x000000000042172f in uKernelModule::rollForward ... | 
|---|
| 302 | #5  0x000000000042f50c in UPP::uSigHandlerModule::sigAlrmHandler ... | 
|---|
| 303 | #6  <signal handler called> | 
|---|
| 304 | #7  0x000000000041e620 in T::main (`this=0xa8fce0`) at test.cc:14 | 
|---|
| 305 | #8  0x0000000000428de2 in UPP::uMachContext::invokeTask (This=...) ... | 
|---|
| 306 | #9  0x0000000000000000 in ?? () | 
|---|
| 307 | (gdb) info threads | 
|---|
| 308 | Id Target Id                           Frame | 
|---|
| 309 | 1  Thread 0x7ffff7fc8780 (LWP 7425) "a.out" 0x00007ffff6d74826 in ... | 
|---|
| 310 | 2  Thread 0x808080 (LWP 7923) "a.out"  0x41e5fc in T::main `(this=0xa8fce0`) at test.cc:13 | 
|---|
| 311 | * 3  Thread 0x90a080 (LWP 7926) "a.out"  uSwitch () ... | 
|---|
| 312 | 4  Thread 0x98a080 (LWP 7929) "a.out"  T::main (this=0xad0070) at test.cc:14 | 
|---|
| 313 | 5  Thread 0xa0b080 (LWP 7931) "a.out"  0x41e629 in T::main (this=0xc515d0) at test.cc:14 | 
|---|
| 314 | (gdb) thread 2 | 
|---|
| 315 | #1  0x000000000041e509 in T::f (this=0xa4f950, param=1) at test.cc:6 | 
|---|
| 316 | 6               if ( param != 0 ) f( param - 1 );       // recursion | 
|---|
| 317 | [Switching to thread 2 (Thread 0x808080 (LWP 7923))] | 
|---|
| 318 | #0  0x000000000041e5fc in T::main (`this=0xa8fce0`) at test.cc:13 | 
|---|
| 319 | 13                  for ( volatile size_t i = 0; i < 1000000000; i += 1 ) // delay | 
|---|
| 320 | (gdb) backtrace | 
|---|
| 321 | #0  0x000000000041e5fc in T::main (`this=0xa8fce0`) at test.cc:13 | 
|---|
| 322 | #1  0x0000000000428de2 in UPP::uMachContext::invokeTask (This=...) ... | 
|---|
| 323 | #2  0x0000000000000000 in ?? () | 
|---|
| 324 | \end{lstlisting} | 
|---|
| 325 | \end{figure} | 
|---|
| 326 |  | 
|---|
| 327 | \subsection{Continuing Implementation} | 
|---|
| 328 | When a breakpoint or error is encountered, all concurrent execution stops.  The state of the program | 
|---|
| 329 | can now be examined and changed; after which the program may be continued. Continuation must always | 
|---|
| 330 | occur from the top of the stack (current call) for each task, and at the specific task where GDB | 
|---|
| 331 | stopped execution. | 
|---|
| 332 |  | 
|---|
| 333 | However, during a task tour, the new GDB commands change the notion of the task where execution | 
|---|
| 334 | stopped to make it possible to walk other stacks.  Hence, it is a requirement for continuation that | 
|---|
| 335 | the task walk always return to frame-0 of the original stopped task before any program continuation | 
|---|
| 336 | \cite{Reference11}. | 
|---|
| 337 |  | 
|---|
| 338 | % For every new function call, a new stack frame is created and the values of all the registers are | 
|---|
| 339 | % changed for that frame. Therefore, in order to see the true value of hardware registers, innermost | 
|---|
| 340 | % frame that is frame-0 must be selected \cite{Reference11}. However, it is possible to not be in | 
|---|
| 341 | % frame-0, so prior to setting these values, the command must switch back to the innermost | 
|---|
| 342 | % (currently executing) frame first. | 
|---|
| 343 |  | 
|---|
| 344 | To provide for this requirement, the original stop task is implicitly remembered, and there is a new | 
|---|
| 345 | \verb|reset| command that \emph{must} be explicitly executed before any continuation to restore the | 
|---|
| 346 | locate state.  To prevent errors from forgetting to call the \verb|reset| command, additional hooks | 
|---|
| 347 | are added to the existing built-in GDB continuation commands to implicitly call \verb|reset|. The | 
|---|
| 348 | following list of these commands results from GDB documentation \cite{Reference15} and similar work | 
|---|
| 349 | done for KOS \cite{Reference14}. | 
|---|
| 350 | \begin{lstlisting}[caption={Built-in GDB commands that allow continuation of a program}, label={continue-cmds}, basicstyle=\small\tt] | 
|---|
| 351 | continue,next,nexti,step,stepi,finish,advance,jump,signal,until,run,thread, | 
|---|
| 352 | reverse-next,reverse-step,reverse-stepi,reverse-continue,reverse-finish | 
|---|
| 353 | \end{lstlisting} | 
|---|
| 354 |  | 
|---|
| 355 | % These hooks call a new command called \verb|reset| prior to executing the command to enable | 
|---|
| 356 | % continuation of a program to ensure that the program's context is automatically switched back to | 
|---|
| 357 | % the context of the task that initiates the first context switch. The \verb|reset| command behaves | 
|---|
| 358 | % as same as the command \verb|prevtask|, however, it goes back directly to where the task is when | 
|---|
| 359 | % the program last stops, which is the first task in the task tour. | 
|---|
| 360 |  | 
|---|
| 361 | \section{Result} | 
|---|
| 362 | The current implementation successfully allows users to display a snapshot of \uC execution with | 
|---|
| 363 | respect to clusters, processors, and tasks. With this information it is possible to tour the call | 
|---|
| 364 | stacks of the tasks to see execution locations and data values. Additionally, users are allowed to | 
|---|
| 365 | continue the execution where the program last pauses assuming that the program has not crashed. The | 
|---|
| 366 | continuation of execution is done by automatically reversing the task walk from any existing GDB | 
|---|
| 367 | commands such as \verb|continue|, or a user can manually reverse the task walk using the command | 
|---|
| 368 | \verb|prevtask| and then continue. | 
|---|