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. _______________________________________________ lldb-dev mailing list lldb-dev@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev