Track Program_Counter(PC)/regs of L4Linux Task

Julian Grizzard grizzard at ece.gatech.edu
Fri Dec 16 07:42:25 CET 2005


All,

Okay, so let me back up a minute from trying to understand all of these
items at the same time.  What I would like to understand first is what
are the main threads for the L4Linux server.  Based on your feedback and
some further analysis, here is what I believe are the main threads:

Thread 0 - l4env initialization, then sleeps
Thread 1 - ??
Thread 2 - runs "main" to get the L4Linux server going, then sleeps
Thread 3 - runs "l4env_linux_startup" function, then sleeps
until told that L4Linux is exiting
Thread 4 - Timer interrupt thread, handles the periodic timer for linux
   the entry functions for thread 4 are:
   timer_irq_thread --- the main handler
   l4lx_irq_timer_startup --- gets timer_irq_thread started
   l4lx_irq_timer_shutdown
   l4lx_irq_timer_enable
   l4lx_irq_timer_disable
   l4lx_irq_timer_ack
   l4lx_irq_timer_end
Additional threads >= 5, one for each IRQ (virtual not implemented yet)
   the entry functions for these threads are
   irq_dev_thread --- the main handler
   l4lx_irq_dev_startup_hw  --- gets irq_dev_thread started
   l4lx_irq_dev_shutdown_hw
   l4lx_irq_dev_enable_hw
   l4lx_irq_dev_disable_hw
   l4lx_irq_dev_ack_hw
   l4lx_irq_dev_end_hw
   l4lx_irq_dev_startup_virt
   l4lx_irq_dev_shutdown_virt
   l4lx_irq_dev_enable_virt
   l4lx_irq_dev_disable_virt
   l4lx_irq_dev_ack_virt
   l4lx_irq_dev_end_virt

Anything wrong with that description?  What does thread 1 do?  I can't
seem to track it down.  Also, which thread is responsible for handling
system calls?  Is that what thread 1 does maybe?  Which L4Linux function
does the system call handler function start?

Thanks!

Julian


Adam Lackorzynski wrote:
> On Mon Dec 12, 2005 at 15:50:17 -0500, Julian Grizzard wrote:
> 
>>to track the program counter and registers of all threads in the L4Linux
>>task.  Here's exactly what I would like to be able to do from a
>>monitoring L4 task:
> 
> 
> I'll throw in some comments.
>  
> 
>>-Obtain the PC/regs for the first thread (thread 0) for L4Linux just
>>before the thread executes it's first instruction.  It would be nice to
>>make the thread wait for a signal before beginning execution.
> 
> 
> The regs are useless is this case as they haven't been filled in with
> anything. Only ip and sp are set. Making the thread wait is possible by
> changing the startup method. The monitor must be the exception handler
> then.
> 
> 
>>-Obtain the PC/regs for any additional thread created or any thread
>>moved for L4Linux (i.e. from a l4_thread_ex_regs call) just before that
>>thread executes.  Again, it would be nice to make that thread wait for a
>>signal before beginning its execution.
> 
> 
> If the threads are started the same way as above this should be
> possible.
> 
> 
>>-Randomly preemptively obtain the PC/regs for all threads of L4Linux.
> 
> 
> Getting the ip is possible, getting all the regs is more complicated due
> to our multiple extry paths into the kernel and thus different stack
> frames.
> 
> 
>>-Obtain the PC/regs for all threads of L4Linux on demand.
> 
> 
> What's the difference from above? Works the same way, I'd guess.
> 
> 
>>-Receive notification of thread exit for all threads of L4Linux.
> 
> 
> Threads do not exit, they just go to sleep (forever). So a thread exit
> can only be a user level thing.
> 
> 
>>There are a few items that I do not yet fully understand that *may* make
>>matters more difficult:
>>
>>-The setup code executing in libloader.s.so.
>>
>>-Trampoline code
>>
>>There are a few assumptions I am willing to have for initial testing to
>>make the development easier:
>>
>>-Assume Task number of L4Linux is known by the microkernel (i.e. hard
>>code it in).
> 
> 
> I'd say that's a really minor issue you have there ;)
> 
> 
>>-Assume Task number of monitoring thread is known by the microkernel.
>>
>>As a first crack, I have added some code to the microkernel to print out
>>information on the L4Linux task, to see if that information would be
>>good to transfer to the monitoring task.  Below is a summary of things I
>>have tried and results seen:
>>
>>MODIFICATION #1
>>l4/kernel/fiasco/src/kern/context.cpp
>>Context::schedule()
>>Goal: Track current PC of L4Linux threads
>>=======================
>>...
>>/* in the for loop */
>>Sys_task_new_frame *regs =
>>sys_frame_cast<Sys_task_new_frame>(next_to_run->regs());
>>L4_uid id = regs->dst();
>>if (id.task() == 0xC) // hard coded task of L4Linux
>>  {
>>    unsigned int ip = next_to_run->regs()->ip();
>>    unsigned int sp = next_to_run->regs()->sp();
>>    printf("task: %d.%d @ ip: %08x sp: %08x\n", id.task(), id.lthread(),
>>            ip, sp);
>>  }
>>...
>>=======================
>>Results:
>>task: 12.3 @ ip: 004ccb0b sp: b00fff80
>>task: 12.3 @ ip: 004cd303 sp: b01fff7c
>>task: 12.4 @ ip: 004cca9d sp: b00fff80
>>task: 12.5 @ ip: 00402ae6 sp: 00657f50
>>=======================
>>Notes:
>>004ccb0b - right after an 'int 0x30' in timer_irq_thread
>>004cd303 - right after an 'int 0x30' in irq_thread_hw
>>004cca9d - right after an 'int 0x30' in timer_irq_thread
>>00402ae6 - right after an 'int 0x30' in l4x_idle
> 
> 
> This makes perfectly sense.
>  
> 
>>MODIFICATION #2
>>l4/kernel/fiasco/src/kern/thread-syscall.cpp
>>Thread::sys_task_new()
>>Goal: Track starting PC of main L4Linux thread (i.e. thread 0)
>>=======================
>>...
>>/* near tail of for loop, just before return */
>>if (taskno == 0xC) // hard coded L4Linux task ID
>>  {
>>    printf("new task: %d @ ip: %08x sp: %08x\n",
>>            taskno, regs->ip(), regs->sp());
>>  }
>>=======================
>>Results:
>>new task: 12 @ ip: 00015ea0 sp: 00008f6c
>>=======================
>>Notes:
>>00015ea0 - part of the libloader.s.so code
> 
> 
> This can be expected.
> 
> 
>>MODIFICATION #3
>>l4/kernel/fiasco/src/kern/thread-syscall.cpp
>>Thread::sys_thread_ex_regs()
>>Goal: Track PC entry of new L4Linux threads
>>=======================
>>...
>>if (!dst->exists())
>>  {
>>    unsigned int task_num = dst_id.task();
>>    unsigned int lthread_num = regs->thread();
>>    new_thread = true;
>>    check (new (dst_id) Thread (dst_task, dst_id, sched()->prio(),
>>
>>           mcp()) == dst);
>>    if (taskno == 0xC)
>>      {
>>        printf("new thread: %d.%d @ ip: %08x sp: %08x\n",
>>               task_num, lthread_num, regs->ip(), regs->sp());
>>      }
>>  }
>>else
>>  {
>>    unsigned int task_num = dst_id.task();
>>    unsigned int lthread_num = regs->thread();
>>    if (taskno == 0xC)
>>      {
>>        printf("modified thread: %d.%d @ ip: %08x sp: %08x\n",
>>               task_num, lthread_num, regs->ip(), regs->sp());
>>      }
>>
>>  }
>>...
>>=======================
>>Results:
>>modified thread: 12.0 @ ip: ffffffff sp: ffffffff
>>modified thread: 12.0 @ ip: ffffffff sp: ffffffff
>>new thread: 12.1 @ ip: 0001ac10 sp: afe00000
>>new thread: 12.2 @ ip: 0001ac10 sp: aff00000
>>modified thread: 12.2 @ ip: ffffffff sp: ffffffff
>>new thread: 12.3 @ ip: 0001ac10 sp: 00657ff8
>>modified thread: 12.3 @ ip: ffffffff sp: ffffffff
>>new thread: 12.4 @ ip: 0001ac10 sp: b0100000
>>modified thread: 12.3 @ ip: ffffffff sp: ffffffff
>>new thread: 12.5 @ ip: 0001ac10 sp: b0200000
>>modified thread: 12.3 @ ip: ffffffff sp: ffffffff
>>new thread: 12.6 @ ip: 0001ac10 sp: b0300000
>>new thread: 12.7 @ ip: 0001ac10 sp: b0400000
>>=======================
>>Notes:
>>0001ac10 - part of the libloader.s.so code
> 
> 
> Yup.
> 
> 
>>ffffffff - not really useful.  wrong data perhaps.
> 
> 
> No, see the spec, when ip or sp are -1 then they're not changed, i.e.
> ex_regs is giving back values only.
> 
> 
>>QUESTIONS:
>>
>>GENERAL QUESTIONS
>>-Is there any easy to delay execution of newly created threads, both new
>>task thread 0 and additional threads?
> 
> 
> What one could do is put an exception handler task between the loader
> and l4linux and intercept interesting syscalls. This way you also get
> notifications for new threads. There are probably things which need to
> be enhanced/fixed/whatever in the kernel but theoretically this could
> work this way.
> 
> 
>>-Is there an easy way to randomly interrupt L4Linux threads to check
>>their PC value?
> 
> 
> If you monitor task runs L4Linux is not running (UP system) so you can
> just exregs them to query the ip.
> 
> 
>>-Do any L4Linux threads exit?
> 
> 
> In the context of L4Linux this is possible, in the context of L4 it's
> not (see above).
> 
> 
>>MODIFICATION #1
>>-Seems like threads resume execution right after an interrupt.
> 
> 
> int 0x30 is the ipc system call.
> 
> 
>>I don't
>>see threads getting preempted in the middle of servicing a system call,
>>for example.  Any ideas why not?
> 
> 
> Bad luck. I guess you'll need some threads with a higher prio doing
> some work to actually see this.
> 
> 
>>Further, is there one thread dedicated
>>to handling system calls?
> 
> 
> Yes, only one thread is handling Linux system calls.
> 
> 
>>-Is there any better way to track where all the L4Linux threads are?
>>Maybe somewhere else besides the scheduler?  Are any other
>>classes/functions helpful to get this information?
> 
> 
> What you are doing is reading the ip and sp from the return frame, you
> can basically do this from everywhere when you run on the behalf of some
> user thread. It's not limited to the schedule function.
> 
> 
>>MODIFICATION #2
>>-I believe this is working correctly.  See anything wrong here?
> 
> 
> Possible.
> 
> 
>>MODIFICATION #3
>>-I would like to catch all instances of creating new threads for
>>L4Linux.  Will this current approach work, or is it not correct?
> 
> 
> Maybe you want to better hook into Thread::initialize so you get
> task_new and threads in one go.
> 
> 
>>If my implementation is correct:
>>-Why are L4Linux threads getting modified?
>>-Any idea why my ip and sp values are 0xffffffff for modified threads?
> 
> 
> Again, see the spec. Querying pager/preempter is done with -1 in ip and
> sp, so this can be one cause of the things you're seeing.
> 
> 
>>-Looks like all new threads start at the same place.  How would they
>>distinguish from one another in terms of functionality?  Is that encoded
>>in their stack (e.g. when they issue a 'ret', they'll return to
>>different locations or maybe arguments to their function are on the stack?)
> 
> 
> The thread lib is doing this for us. All threads are executing some
> setup code before they're branched to their actual function (see
> l4/pkg/thread/lib/src/create.c).
> 
> 
> 
> Adam





More information about the l4-hackers mailing list