This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: The root cause for SEGV in evaluating fortran function call,any solution or suggestion?


Hi Daniel,

On Sun, 6 Nov 2005, Daniel Jacobowitz wrote:

> On Fri, Nov 04, 2005 at 11:18:00AM +0800, Wu Zhou wrote:
> > > Allocating memory on the stack is actually quite eazy.  Just
> > > substract/add the amount of space you need from/to the stack pointer,
> > > and use the new/old stack pointer as the address for the memory.
> > > Whether you should substract or add depends on whether the stack grows
> > > downward or upward.  Use gdbarch_inner_than(gdbarch, 1, 2) to check.
> > > There's quite a bit of code in infcall.c that uses this trick.
> > > 
> > 
> > Thanks.  I did some tests following this way.  But didn't get any success. 
> > So I had to post here again to see if anybody can help me out.  
> > 
> > My basic idea is to create a value which hold the address to the original 
> > argument. This is done in valur_addr for these argument which is not lval 
> > and whose type is TYPE_CODE_INT.  Then I use the above method to get a new 
> > value which hold the address to the original address.  Although it doesn't 
> > report SEGV or "can not access memory" message, it didn't ouptut the 
> > correct result I expected.  I expect 4 (which is 2 * 2), but it return 
> > different number for me every time I run it.
> > 
> > Following is the changed I made to valur_arg_coerce and value_addr.  Could 
> > anyone help me pointed out what is the reason why it fail.  Thanks a lot!
> 
> It's not quite as simple as Mark makes it out to be - in concept, sure,
> but not in execution.  You have to _allocate_ the space on the stack;
> not just find empty space off the side of the stack and write the
> argument there.
> 
> By the type that we're calling value_arg_coerce, we've already
> allocated some space on the stack, and saved the old stack pointer. 
> But we'll allocate more space on the stack below, when we push
> arguments.  And you have to be careful to keep the stack aligned
> properly through all of this.  Read through the surrounding bits of
> infcall.c to see how this works for struct returns; that is the closest
> analogue we have today.
> 
> Maybe if you pass the sp value by reference to value_arg_coerce and
> adjust it there...

You are quite right.  Following your pointer, I made another patch and it 
now passed with both g77 (3.4.4) and gfortran (4.0.1) on a x86 box.  I 
didn't consider the red zone in AMD64 architecture, so maybe it won't work 
on it.  I will try to find a chance to test it on other platform, such as 
ppc64 or any other platform I can get access to.

Appended is the patch.  Any comments and suggestion are highly 
appreciated!

Index: infcall.c
===================================================================
RCS file: /cvs/src/src/gdb/infcall.c,v
retrieving revision 1.73
diff -c -3 -p -r1.73 infcall.c
*** infcall.c	2 Sep 2005 19:02:44 -0000	1.73
--- infcall.c	7 Nov 2005 04:36:39 -0000
*************** Unwinding of stack if a signal is receiv
*** 100,106 ****
  
  static struct value *
  value_arg_coerce (struct value *arg, struct type *param_type,
! 		  int is_prototyped)
  {
    struct type *arg_type = check_typedef (value_type (arg));
    struct type *type
--- 100,106 ----
  
  static struct value *
  value_arg_coerce (struct value *arg, struct type *param_type,
! 		  int is_prototyped, CORE_ADDR *sp)
  {
    struct type *arg_type = check_typedef (value_type (arg));
    struct type *type
*************** value_arg_coerce (struct value *arg, str
*** 109,118 ****
    switch (TYPE_CODE (type))
      {
      case TYPE_CODE_REF:
        if (TYPE_CODE (arg_type) != TYPE_CODE_REF
  	  && TYPE_CODE (arg_type) != TYPE_CODE_PTR)
  	{
! 	  arg = value_addr (arg);
  	  deprecated_set_value_type (arg, param_type);
  	  return arg;
  	}
--- 109,119 ----
    switch (TYPE_CODE (type))
      {
      case TYPE_CODE_REF:
+     case TYPE_CODE_PTR:
        if (TYPE_CODE (arg_type) != TYPE_CODE_REF
  	  && TYPE_CODE (arg_type) != TYPE_CODE_PTR)
  	{
! 	  arg = value_addr_stack (arg, sp);
  	  deprecated_set_value_type (arg, param_type);
  	  return arg;
  	}
*************** value_arg_coerce (struct value *arg, str
*** 154,160 ****
  	  type = lookup_pointer_type (TYPE_TARGET_TYPE (type));
        break;
      case TYPE_CODE_UNDEF:
-     case TYPE_CODE_PTR:
      case TYPE_CODE_STRUCT:
      case TYPE_CODE_UNION:
      case TYPE_CODE_VOID:
--- 155,160 ----
*************** call_function_by_hand (struct value *fun
*** 528,534 ****
  	else
  	  param_type = NULL;
  	
! 	args[i] = value_arg_coerce (args[i], param_type, prototyped);
  
  	/* elz: this code is to handle the case in which the function
  	   to be called has a pointer to function as parameter and the
--- 528,534 ----
  	else
  	  param_type = NULL;
  	
! 	args[i] = value_arg_coerce (args[i], param_type, prototyped, &sp);
  
  	/* elz: this code is to handle the case in which the function
  	   to be called has a pointer to function as parameter and the
Index: valops.c
===================================================================
RCS file: /cvs/src/src/gdb/valops.c,v
retrieving revision 1.161
diff -c -3 -p -r1.161 valops.c
*** valops.c	27 May 2005 04:39:32 -0000	1.161
--- valops.c	7 Nov 2005 04:36:47 -0000
*************** value_addr (struct value *arg1)
*** 886,891 ****
--- 886,963 ----
    return arg2;
  }
  
+ /* Mostly the same as value_addr.  But when the argument passed is a constant
+    and the value is not a lval, we allocate a block of memory for that value
+    on the stack and return the value which contains that address.  This is 
+    only used for value_arg_coerce at this time.  */
+ 
+ struct value *
+ value_addr_stack (struct value *arg1, CORE_ADDR *sp)
+ {
+   struct value *arg2;
+ 
+   struct type *type = check_typedef (value_type (arg1));
+   if (TYPE_CODE (type) == TYPE_CODE_REF)
+     {
+       /* Copy the value, but change the type from (T&) to (T*).
+          We keep the same location information, which is efficient,
+          and allows &(&X) to get the location containing the reference. */
+       arg2 = value_copy (arg1);
+       deprecated_set_value_type (arg2, lookup_pointer_type (TYPE_TARGET_TYPE (type)));
+       return arg2;
+     }
+   if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+     return value_coerce_function (arg1);
+ 
+   if (TYPE_CODE (type) == TYPE_CODE_INT  && VALUE_LVAL (arg1) == not_lval)
+     {
+       int len = TYPE_LENGTH (type);
+       CORE_ADDR addr;
+ 
+       if (gdbarch_frame_align_p (current_gdbarch))
+ 	*sp = gdbarch_frame_align (current_gdbarch, *sp);
+       if (INNER_THAN (1, 2))
+ 	{
+ 	  /* stack grows downward */
+ 	  if (gdbarch_frame_align_p (current_gdbarch))
+ 	    *sp = gdbarch_frame_align (current_gdbarch, *sp - len);
+ 	  else
+ 	    *sp -= len;
+ 	  /* ... so the address of the thing we push is the
+ 	     stack pointer after we push it.  */
+ 	  addr = *sp;
+ 	}
+       else
+ 	{
+ 	  /* The stack grows up, so the address of the thing
+ 	     we push is the stack pointer before we push it.  */
+ 	  addr = *sp;
+ 	  if (gdbarch_frame_align_p (current_gdbarch))
+ 	    *sp = gdbarch_frame_align (current_gdbarch, *sp + len);
+ 	  else
+ 	    *sp += len;
+ 	}
+ 
+       write_memory (addr, value_contents_all (arg1), len);
+       arg2 = value_from_pointer (lookup_pointer_type (type), addr);
+ 
+       return arg2;
+     }
+ 
+   /* Get target memory address */
+   arg2 = value_from_pointer (lookup_pointer_type (value_type (arg1)),
+ 			     (VALUE_ADDRESS (arg1)
+ 			      + value_offset (arg1)
+ 			      + value_embedded_offset (arg1)));
+ 
+   /* This may be a pointer to a base subobject; so remember the
+      full derived object's type ... */
+   arg2 = value_change_enclosing_type (arg2, lookup_pointer_type (value_enclosing_type (arg1)));
+   /* ... and also the relative position of the subobject in the full object */
+   set_value_pointed_to_offset (arg2, value_embedded_offset (arg1));
+   return arg2;
+ }
+ 
  /* Given a value of a pointer type, apply the C unary * operator to it.  */
  
  struct value *

Regards
- Wu Zhou


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]