How to insert dynamic code? (continued)

2006-07-13 Thread jacob navia

Hi

Context:

I am writing a JIT and need to register the frame information about
the generated program within the context of a larger C++ program
compiled with g++. Stack layout is like this:

   catch established by C++
   JITTED code generated dynamically
   JITTED code
   JITTED code calls a C++ routine
   C++ routine calls other C++ routines
   C++ routine makes a THROW

The throw must go past the JITTED code to the established C++ catch.

Problem.

The stack unwinder stops with END_OF_STACK at the Jitted code. Why?
Following the code with the debugger I see that the unwider looks
for the next frame using the structures established by the dynamic loader,
specifically in the function __dl_iterate_phdr in the file
dl-iteratephdr.c in the glibc.

So, this means:

1) I am cooked and what I want to do is impossible. This means I will 
probably

  get cooked at work for proposing something stupid like this :-)

2) There is an API or a way of adding at run time a routine to the lists
  of loaded objects in the same way as the dynamic loader does.

PLEEZE do not answer with:

Just look at the code of the dynamic loader!

because I have several megabytes of code to understand already!

I am so near the end that it would be a shame to stop now. My byte codes 
for the
DWARF interpreter LOAD into the interpreter successfully, and they are 
executed

OK, what has costed me several weeks of efforts, wading through MBs of code
and missing/wrong specs.

I just would like to know a way of registering (and deregistering obviously)
code that starts at address X and is Y bytes long. JUst that.

Thanks in advance guys

jacob


Re: How to insert dynamic code? (continued)

2006-07-13 Thread Andrew Haley
jacob navia writes:
  Hi
  
  Context:
  
  I am writing a JIT and need to register the frame information about
  the generated program within the context of a larger C++ program
  compiled with g++. Stack layout is like this:
  
  catch established by C++
  JITTED code generated dynamically
  JITTED code
  JITTED code calls a C++ routine
  C++ routine calls other C++ routines
  C++ routine makes a THROW
  
  The throw must go past the JITTED code to the established C++ catch.
  
  Problem.
  
  The stack unwinder stops with END_OF_STACK at the Jitted code. Why?
  Following the code with the debugger I see that the unwider looks
  for the next frame using the structures established by the dynamic loader,
  specifically in the function __dl_iterate_phdr in the file
  dl-iteratephdr.c in the glibc.
  
  So, this means:
  
  1) I am cooked and what I want to do is impossible. This means I will 
  probably
 get cooked at work for proposing something stupid like this :-)
  
  2) There is an API or a way of adding at run time a routine to the lists
 of loaded objects in the same way as the dynamic loader does.
  
  PLEEZE do not answer with:
  
  Just look at the code of the dynamic loader!
  
  because I have several megabytes of code to understand already!
  
  I am so near the end that it would be a shame to stop now. My byte
  codes for the DWARF interpreter LOAD into the interpreter
  successfully, and they are executed OK, what has costed me several
  weeks of efforts, wading through MBs of code and missing/wrong
  specs.
  
  I just would like to know a way of registering (and deregistering
  obviously) code that starts at address X and is Y bytes long. JUst
  that.

The way you do not reply to mails replying to your questions doesn't
encourage people to help you.  Please try harder to answer.

I suspect that the gcc unwinder is relying on __dl_iterate_phdr to
scan the loaded libraries and isn't using the region that you have
registered.

But this is odd, becasue when I look at _Unwind_Find_FDE in
unwind-dw2-fde-glibc.c, I see:

  ret = _Unwind_Find_registered_FDE (pc, bases);

  ...

  
  if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, data)  0)
return NULL;

So, it looks to me as though we do call _Unwind_Find_registered_FDE
first.  If you have registered your EH data, it should be found.

So, what happens when _Unwind_Find_registered_FDE is called?  Does it
find the EH data you have registered?

Andrew.



Re: How to insert dynamic code? (continued)

2006-07-13 Thread jacob navia

Andrew Haley wrote:


The way you do not reply to mails replying to your questions doesn't
encourage people to help you.  Please try harder to answer.

 

I did answer last time but directly to the poster that replied, and 
forgot to CC the list.

Excuse me for that.


I suspect that the gcc unwinder is relying on __dl_iterate_phdr to
scan the loaded libraries and isn't using the region that you have
registered.

But this is odd, becasue when I look at _Unwind_Find_FDE in
unwind-dw2-fde-glibc.c, I see:

 ret = _Unwind_Find_registered_FDE (pc, bases);

 ...

 
 if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, data)  0)

   return NULL;

So, it looks to me as though we do call _Unwind_Find_registered_FDE
first.  If you have registered your EH data, it should be found.

 


OK, so I have to look there then. Actually this is good news because
figuring out how to mess with the dynamic loader data is not something
for the faint of heart :-)


So, what happens when _Unwind_Find_registered_FDE is called?  Does it
find the EH data you have registered?

 


Yes but then it stops there instead of going upwards and finding the catch!
It is as my insertion left the list of registered routines in a bad state.

I will look again at this part (the registering part) and will try to 
find out what

is going on.

Thanks for yourt answer. If you are right this is a very GOOD news!

jacob



Re: How to insert dynamic code? (continued)

2006-07-13 Thread Daniel Jacobowitz
On Thu, Jul 13, 2006 at 05:06:25PM +0200, jacob navia wrote:
 So, what happens when _Unwind_Find_registered_FDE is called?  Does it
 find the EH data you have registered?
 
  
 
 Yes but then it stops there instead of going upwards and finding the catch!
 It is as my insertion left the list of registered routines in a bad state.
 
 I will look again at this part (the registering part) and will try to 
 find out what
 is going on.

It sounds to me more like it used your data, and then was left pointing
somewhere garbage, not to the next frame.  That is, it sounds like
there's something wrong with your generated unwind tables.  That's the
usual cause for unexpected end of stack.

-- 
Daniel Jacobowitz
CodeSourcery


Re: How to insert dynamic code? (continued)

2006-07-13 Thread jacob navia

Daniel Jacobowitz wrote:


On Thu, Jul 13, 2006 at 05:06:25PM +0200, jacob navia wrote:
 


So, what happens when _Unwind_Find_registered_FDE is called?  Does it
find the EH data you have registered?



 


Yes but then it stops there instead of going upwards and finding the catch!
It is as my insertion left the list of registered routines in a bad state.

I will look again at this part (the registering part) and will try to 
find out what

is going on.
   



It sounds to me more like it used your data, and then was left pointing
somewhere garbage, not to the next frame.  That is, it sounds like
there's something wrong with your generated unwind tables.  That's the
usual cause for unexpected end of stack.

 


Yeah...

My fault obviously, who else?

Problem is, there are so mny undocumented stuff that I do not see how I 
could

avoid making a mistake here.

1) I generate exactly the same code now as gcc:

Prolog:

   push %ebp
   movq  %rsp,%rbp
   subqxxx,%rsp

and I do not touch the stack any more. Nothing is pushed, in the xxx 
is already the stack
space for argument pushing reserved, just as gcc does. This took me 3 
weeks to do.


Now, I write my stuff as follows:
1) CIE
2) FDE for function 1
  . 1 fde for each function
3) Empty FDE to zero terminate the stuff.
4) Table of pointers to the CIE, then to the FDE

   p = result.FunctionTable; // Starting place, where CIE, then 
FDEs are written

   p = WriteCIE(p); // Write first the CIE
   pFI = DefinedFunctions;
   nbOfFunctions=0;
   pFdeTable[nbOfFunctions++] = result.FunctionTable;
   while (pFI) { // For each function, write the FDE
   fde_start = p;
   p = Write32(0,p); // reserve place for length field (4 
bytes)
   p = Write32(p - result.FunctionTable,p); //Write offset 
to CIE

   symbolP = pFI-FunctionInfo.AssemblerSymbol;
   adr = (long long)symbolP-SymbolValue;
   adr += (unsigned long long)code_start; // code_start is 
the pointer to the Jitted code

   p = Write64(adr,p);
   p = Write64(pFI-FunctionSize,p); // Write the length in 
bytes of the function

   *p++ = 0x41;/// Write the opcodes
   *p++ = 0x0e; // This opcodes are the same as gcc writes
   *p++ = 0x10;
   *p++ = 0x86;
   *p++ = 0x02;
   *p++ = 0x43;
   *p++ = 0x0d;
   *p++ = 0x06;
   p = align8(p);
   Write32((p - fde_start)-4,fde_start);// Fix the length 
of the FDE
   pFdeTable[nbOfFunctions] = fde_start; // Save pointer to 
it in table

   nbOfFunctions++;
   pFI = pFI-Next; // loop
   }

The WriteCIE function is this:
static unsigned char *WriteCIE(unsigned char *start)
{
   start = Write32(0x14,start);
   start = Write32(0,start);
   *start++ = 1; // version 1
   *start++ = 0; // no augmentation
   *start++ = 1;
   *start++ = 0x78;
   *start++ = 0x10;
   *start++ = 0xc;
   *start++ = 7;
   *start++ = 8;
   *start++ = 0x90;
   *start++ = 1;
   *start++ = 0;
   *start++ = 0;
   start = Write32(0,start);
   return start;
}

I hope this is OK...

jacob


Re: How to insert dynamic code? (continued)

2006-07-13 Thread Andrew Haley
jacob navia writes:
  Andrew Haley wrote:
  
  I suspect that the gcc unwinder is relying on __dl_iterate_phdr to
  scan the loaded libraries and isn't using the region that you have
  registered.
  
  But this is odd, becasue when I look at _Unwind_Find_FDE in
  unwind-dw2-fde-glibc.c, I see:
  
ret = _Unwind_Find_registered_FDE (pc, bases);
  
...
  

if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, data)  0)
  return NULL;
  
  So, it looks to me as though we do call _Unwind_Find_registered_FDE
  first.  If you have registered your EH data, it should be found.
  

  
  OK, so I have to look there then. Actually this is good news because
  figuring out how to mess with the dynamic loader data is not something
  for the faint of heart :-)

True.

  So, what happens when _Unwind_Find_registered_FDE is called?  Does it
  find the EH data you have registered?
  

  
  Yes but then it stops there instead of going upwards and finding the catch!
  It is as my insertion left the list of registered routines in a bad state.

OK, so the problem is in decoding the unwinder data, and you're just
going to have to single-step through the part where it decodes the
data you've generated.

Andrew.


Re: How to insert dynamic code? (continued)

2006-07-13 Thread Mike Stump

On Jul 13, 2006, at 8:48 AM, jacob navia wrote:

1) I generate exactly the same code now as gcc:


You don't want to generate exactly the same code as gcc, unless it is  
exactly the same case; you want to generate the correct code.


Divide and concur.

Do simple things work?  For example, do:

routine() {
throw 1;
}

loadme() {
try {
routine();
} catch (...) {
printf(Hello\n);
}
_exit (42);
}

in your JIT language and then compile it, load it and dispatch it.   
You can then know if you got there, and if it printed hello and  
exited with 42.  I'd work on that problem first, if it doesn't work.


Once that works, you know that the right things are registered and  
that the information is approximately correct.  Repeat the same with  
2 layers of functions.


Then you can move onto JITing:

routine() {
throw 1;
}

and call from

void base() {
try {
jit_routine();
} catch (...) {
print(Hello);
}
_exit(42);
}

in normal C++.  This checks that yet another part of the problem.   
Does that work?


Then, you can add local variables, and print the addresses of the  
local variables across throws and ensure that the variable is at the  
address you expect after a throw.


void foo() {
int bar [200];
printf(%p\n, bar);
try {...}
catch(...) {
printf(%p\n, bar);  
}
}

if they don't have the right values, the frame information isn't yet  
correct.  Does that work?


Re: How to insert dynamic code? (continued)

2006-07-13 Thread Seongbae Park

On 7/13/06, jacob navia [EMAIL PROTECTED] wrote:

Daniel Jacobowitz wrote:

On Thu, Jul 13, 2006 at 05:06:25PM +0200, jacob navia wrote:


So, what happens when _Unwind_Find_registered_FDE is called?  Does it
find the EH data you have registered?





Yes but then it stops there instead of going upwards and finding the catch!
It is as my insertion left the list of registered routines in a bad state.

I will look again at this part (the registering part) and will try to
find out what
is going on.



It sounds to me more like it used your data, and then was left pointing
somewhere garbage, not to the next frame.  That is, it sounds like
there's something wrong with your generated unwind tables.  That's the
usual cause for unexpected end of stack.



Yeah...

My fault obviously, who else?

Problem is, there are so mny undocumented stuff that I do not see how I
could
avoid making a mistake here.

1) I generate exactly the same code now as gcc:

Prolog:

push %ebp
movq  %rsp,%rbp
subqxxx,%rsp

and I do not touch the stack any more. Nothing is pushed, in the xxx
is already the stack
space for argument pushing reserved, just as gcc does. This took me 3
weeks to do.

Now, I write my stuff as follows:
1) CIE
2) FDE for function 1
   . 1 fde for each function
3) Empty FDE to zero terminate the stuff.
4) Table of pointers to the CIE, then to the FDE

p = result.FunctionTable; // Starting place, where CIE, then
FDEs are written
p = WriteCIE(p); // Write first the CIE
pFI = DefinedFunctions;
nbOfFunctions=0;
pFdeTable[nbOfFunctions++] = result.FunctionTable;
while (pFI) { // For each function, write the FDE
fde_start = p;
p = Write32(0,p); // reserve place for length field (4
bytes)
p = Write32(p - result.FunctionTable,p); //Write offset
to CIE
symbolP = pFI-FunctionInfo.AssemblerSymbol;
adr = (long long)symbolP-SymbolValue;
adr += (unsigned long long)code_start; // code_start is
the pointer to the Jitted code
p = Write64(adr,p);
p = Write64(pFI-FunctionSize,p); // Write the length in
bytes of the function
*p++ = 0x41;/// Write the opcodes
*p++ = 0x0e; // This opcodes are the same as gcc writes
*p++ = 0x10;
*p++ = 0x86;
*p++ = 0x02;
*p++ = 0x43;
*p++ = 0x0d;
*p++ = 0x06;
p = align8(p);
Write32((p - fde_start)-4,fde_start);// Fix the length
of the FDE
pFdeTable[nbOfFunctions] = fde_start; // Save pointer to
it in table
nbOfFunctions++;
pFI = pFI-Next; // loop
}

The WriteCIE function is this:
static unsigned char *WriteCIE(unsigned char *start)
{
start = Write32(0x14,start);
start = Write32(0,start);
*start++ = 1; // version 1
*start++ = 0; // no augmentation
*start++ = 1;
*start++ = 0x78;
*start++ = 0x10;
*start++ = 0xc;
*start++ = 7;
*start++ = 8;
*start++ = 0x90;
*start++ = 1;
*start++ = 0;
*start++ = 0;
start = Write32(0,start);
return start;
}

I hope this is OK...

jacob


The above code looks incorrect, for various reasons,
not the least of which is that you're assuming CIE/FDE are fixed-length.
There are various factors that affect FDE/CIE
depending on PIC/non-PIC, C or C++, 32bit/64bit, etc -
some of them must be invariant for your JIT but some of them may not.
Also some of the datum are encoded as uleb128
(see dwarf spec for the detail of LEB128 encoding)
which is a variable-length encoding whose length depends on the value.

In short, you'd better start looking at how CIE/FDE structures are *logically*
layed out - otherwise you won't be able to generate correct entries.
--
#pragma ident Seongbae Park, compiler, http://seongbae.blogspot.com;


Re: How to insert dynamic code? (continued)

2006-07-13 Thread Daniel Jacobowitz
On Thu, Jul 13, 2006 at 11:21:04AM -0700, Seongbae Park wrote:
 The above code looks incorrect, for various reasons,
 not the least of which is that you're assuming CIE/FDE are fixed-length.
 There are various factors that affect FDE/CIE
 depending on PIC/non-PIC, C or C++, 32bit/64bit, etc -
 some of them must be invariant for your JIT but some of them may not.
 Also some of the datum are encoded as uleb128
 (see dwarf spec for the detail of LEB128 encoding)
 which is a variable-length encoding whose length depends on the value.
 
 In short, you'd better start looking at how CIE/FDE structures are 
 *logically*
 layed out - otherwise you won't be able to generate correct entries.

I highly highly recommend finding a way to dump your CIE/FDE structures
to an ELF file, so that you can use readelf to view them.  It is quite
accurate and matches the GCC implementation closely.

If it can't dump your FDEs, we probably won't unwind through them
either.

-- 
Daniel Jacobowitz
CodeSourcery


Re: How to insert dynamic code? (continued)

2006-07-13 Thread jacob navia

Seongbae Park wrote:



The above code looks incorrect, for various reasons,
not the least of which is that you're assuming CIE/FDE are fixed-length.


This is a trivial thing I will add later.


There are various factors that affect FDE/CIE
depending on PIC/non-PIC, C or C++, 32bit/64bit, etc -
some of them must be invariant for your JIT but some of them may not.


I generate always the same prologue for exactly this reason:
I do not want to mess with this stuff.


Also some of the datum are encoded as uleb128
(see dwarf spec for the detail of LEB128 encoding)
which is a variable-length encoding whose length depends on the value.


For this values the uleb128 and leb128 routines produce exactly the values
shown.



In short, you'd better start looking at how CIE/FDE structures are 
*logically*

layed out - otherwise you won't be able to generate correct entries.


So far I have understood what those opcodes do, and are the same as
gcc. Please try to understand my situation and find the bug
( or where the bug could be). It is not in here? I mean changing
*p++ = 1;
or
p = encodeuleb128(1,p);

is *the same* in this context.