C++ API: Passing information from debuggee to debugger

Hi,

I need the deguggee to stop and pass some information to the debugger - if the debugger is attached, that is. And I want to do it from different threads in concurrent manner. So, I thought maybe I use run-time signals on Linux: i.e. the thread would:

  • Fill out some buffer with data the debugger needs to see

  • Send signal 35 to itself passing the address of the buffer as a payload:

  • sigval value;

  • value.sival_ptr = address;

  • sigqueue(gettid(), 35, value);

  • In the signal handler just ignore the signal

If debugger is attached, it will see the signal and inspect info->si_value.sival_ptr. But unfortunately LLDB reports only signal number and drops the value on the floor.

So, is there any other “legal” way to achieve what I need?

Thanks,
Eugene

Feel free to file a bug on the Linux support in lldb to read out this value. Darwin doesn't support this part of the real time signals spec, so we didn't have signals with values originally, but there's no reason not to support it on systems that have signal values.

Jim

Hello,

Yes, please file a bug. I been wanting to implement passing of the
struct siginfo_t from the inferior all the way up to lldb (besides
your use case, it is also useful for displaying more precise
information about segfaults, etc.). However, that is not a priority
now, so it may take a while (patches welcome though :slight_smile: ).

So, is there any other "legal" way to achieve what I need?

As I understand it, the way people do this kind of thing usually is to
have a special function in the inferior (e.g., void
my_debugger_interface(my_data *). Then the debugger can set a
breakpoint on this function and read all the data it needs from the
function arguments. If you want to be sure two threads don't call this
function simultaneously, you can protect it with a regular mutex.

pl

comment inline

Hello,

Yes, please file a bug. I been wanting to implement passing of the
struct siginfo_t from the inferior all the way up to lldb (besides
your use case, it is also useful for displaying more precise
information about segfaults, etc.). However, that is not a priority
now, so it may take a while (patches welcome though :slight_smile: ).

So, is there any other "legal" way to achieve what I need?

As I understand it, the way people do this kind of thing usually is to
have a special function in the inferior (e.g., void
my_debugger_interface(my_data *). Then the debugger can set a
breakpoint on this function and read all the data it needs from the
function arguments. If you want to be sure two threads don't call this
function simultaneously, you can protect it with a regular mutex.

For an example, the recent r238768 implements this sort of system in the RenderScript language runtime.

OK, thanks a lot!

The problem is that there are complications if the target is stripped off symbols, but I probably can work around by still sending a signal (i.e. getting reliable interrupted) and inspecting registers to find my pointer. Another vague worry is if overzealous compiler would optimize it out, but of course I can compile this specific method with optimization turned off. I.e. there are some hoops to jump through instead of just getting it work.

I do not fully understand why we need mutex here… Each thread allocates data in its own memory (either allocated or on stack) and when it breaks each thread has its own local pointer (either on stack or in register). I.e. it seems this can be made lock-free.

Thanks,
Eugene

I need the deguggee to stop and pass some information to the debugger - if the debugger is attached, that is.

This sounds like “ARM SEMI-HOSTING” but as an application under Linux,

There is a simple way to do this, I did this in a previous system it worked very well.

You need some function in the target, it needs to be a single instance, not multiple instances.

Step 1: Create some function

  int DEBUGGER_CALL( int command, intptr_t param1, intptr_t param2, … )

  You want to model this like a SYSCALL()

  Return value -1 means error
  Return value (0 or positive) means success

  Parameter 0 - is the command or request.
  Parameter 1 - is an “intptr_t” so it can handle anything
  Parmeter N is the last parameter (you need N=5 for most everything)

  Alternative: Create a “struct sys_call” and pass the structure pointer

SUPER IMPORTANT:
  DO NOT do unions
  DO NOT use VARDAC functions
  Make the API very fixed - explicitly fixed very simple
  Otherwise it does not port across targets very well.
  
These things make it hard
    Host /TARGET ENDIAN changes
    Host / TARGET - bit field ENDIAN
    Host/ TARGET structure packing changes
    Host/TARGET enum size scaling
    Host/TARGET variable sizes (i.e.: INT = 32 or 64bits?)

  I faced the above problems between our 24bit cpu, SunOS and Linux
  These things where painful hence my suggestion to you

  Thus you might do something like:

  struct debugger_syscall {
    // The request
    int request_id;
    // Debugger sets this value
    int result_code;
    intptr_t param[ 5 ];
  }

Step 2:

  The default implementation of this function is simply: “return -1”
  This would indicate DEBUGGER NOT PRESENT or ERROR

  For example it might just do this:

  void DEBUGGER_CALL( struct foo *p )
  {
    p->result_code = -1;
  }

  When you compile this function, you might want to implement it in assembly language
  Reason: If you write this in assembly, you can control the exact opcode sequence

  Otherwise different compiler options (optimizations, etc) cause problems
  Besides, this is a super tiny function about 4 instructions in assembler
  It’s not like you need to write a huge amount of code in assembly.

  Don’t forget about optimizing linkers! These can also cause problems.

  HINT: Make your code something like this, put extra NOP
  (See below for reason)

    label:
      load R0, -1 ; return value is minus 1
      return
      // these are here for use by the debugger
      NOP
      NOP
      NOP
      NOP
      NOP
      return

Step 3:
  The debugger sets a breakpoint on this function.
  
  The “breakpoint action function” (aka: your script)
  Can now examine the parameters (or structure pointer)
  And perform the requested action

In my case we had two builds of the application:

  Build(HOSTED) ran on linux (and SunOS, pre-solaris)
  Build(TARGET) - ran on our custom CPU target

When the application was under debug/test, we had 2 choices:

Option 1: Let it run as normal, the default return value was always -1

Option 2: Under LINUX/SunOS Use LD_LIBRARY_PATH to insert a replacement function that could perform additional steps.

  This is of course a huge security risk, but it worked great

  We put this local to the directory where the test was being executed.
  Thus, each ‘test directory’ could have a different “debugger hook function'

When the application was run on the target (bare metal application)

Option 3) No debugger present, the default library function just returned -1 (error)
    We shipped product this way - in masked ROM chips

Option 4) With the debugger present,

     we set a breakpoint at that function and setup a script to perform some action on that breakpoint
     In our case, we inspected the opcodes at that location
     If they where incorrect the test session was rejected as failure

     If they where correct, the debugger modified the OPCODES
  This is why we put the extra NOPs in the function
  We had extra room to do what we required

    On program load - the debugger can look for your “magic symbol name”
  If the magic symbol is present in the symbol table
  The debugger can “attach” and automate much of this process

Worked really well - same code ran on Sun SPARC, LINUX, and our custom 24bit CPU target under GDB

In our case, on the debugger side, we had some very standard code that extracted the parameter structure

At the bottom of that standard code you have a dispatch table that mapped the request ID to a handler in the debugger script

Worked great

If you implement the above in a standard way, it would be universal to all LLDB instances

Each target wanting to support this would only need to create the *very* tiny 5 to 10 opcode long “DEBUGGER_CALL” function

I would also suggest a series of standard function numbers (i.e.: the ARM semi-hosting ones are a good start)

-Duane.

The problem is that there are complications if the target is stripped off symbols,

SIMPLE - see my reply from a few minutes ago.

If you write your “DEBUGGER_CALL” function- you could decorate it with some signature pattern.

For example, in assembly language:

.ascii “DEBUGGER_CALL_FUNCTION_START===>”
DEBUGGER_CALL:
mov r0,-1
return
nop
nop
nop
nop
nop
.ascii “<====DEBUGGER_CALL_FUNCTION_END”

Then search the target text segment, you should look for and find exactly ONE instance of the strings.
Or maybe you will find others in various shared libraries that might be loaded
Again, the solution is simple - Search the text segment for your string pattern

I probably can work around by still sending a signal

DO NOT use signals - Signals do not work on targets that do not have an operating system

Another reason is you want to be able to insert these types of things in main line code that gets executed a reasonable number of times, you don’t want SIGNALS going off, they delay things

Instead, you have a single instance of a couple instructions, in a more modern computer these few opcodes live in the CPU cache and become almost ZERO overhead

Thus you can leave them in … and not really effect overall system performance meaningfully

Another vague worry is if overzealous compiler would optimize it out,

Hence you write this in assembly language, you also must worry about optimizing linkers but you can probably control that more easily.

You supply a LIBRARY (binary) that your users would link against, that library contains exactly that one function above nothing else

I do not fully understand why we need mutex here… Each thread allocates data in its own memory (either allocated or on stack) and when it breaks each thread has its own local pointer (either on stack or in register). I.e. it seems this can be made lock-free.

YES in the example I give, the “DEBUGGER_CALL” data structure would most likely live on the current threads CPU STACK Hence it is thread safe

END

-Duane.

Hi Eugene,

Thanks for the bug report!

Maybe try this: Set a breakpoint in a function. When the inferior wants to pass data to the debugger, call that function. Debugger can read whatever it wants from the inferior when it gets the breakpoint notification.

The situation I was worried about is that if two threads hit the
breakpoint in your function simultaneously, you can't tell which hit
the breakpoint _first_ -- hence no strict serialization. However, you
can still recover all the data from the function calls just fine and
as long as you don't care about the ordering between these two
function calls you are fine without a mutex.

cheers,
pl