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

classic Classic list List threaded Threaded
22 messages Options
12
Reply | Threaded
Open this post in threaded view
|

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

Wu Zhou
Hi all,

I had found the reason why gdb will drop into SEGV when evaluating the
fortran function calls.  In g77 (gfortran might be the same), when we try
to call FUNC_NAME (ARGS), the ARGS is passed as the pointer to the real
parameters.  

While we issue "print FUNC_NAME (ARGS), these ARGS are passed as the
original types.  So fortran code can't handle that and SEGV occurs.  
Considering this special argument-passing mechanism, do we have any
workaround for it in gdb's evaluation code?  Create a dummy memory address
for the arguments and pass that address instead?  or any others?

Your comments are highly appreciated.  Thanks a lot.

Regards
- Wu Zhou

On Mon, 22 Aug 2005, Wu Zhou wrote:

>
> I just found a problem while using gdb to debug fortran program: gdb will
> drop into SEGV error while trying to print the result of a function call.
> I had tried the same test on FC4, SLES9, FC2 and RH9, all reported the
> same error.
>
> Anyone has success experience with this?  If you do, please tell me
> the configuration.  Thanks a buch for that in advance!
>
> Maybe I need to try more ancient configuration?
>
> Regards
> - Wu Zhou
>
Reply | Threaded
Open this post in threaded view
|

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

Daniel Jacobowitz-2
On Wed, Nov 02, 2005 at 10:43:03AM +0800, Wu Zhou wrote:

> Hi all,
>
> I had found the reason why gdb will drop into SEGV when evaluating the
> fortran function calls.  In g77 (gfortran might be the same), when we try
> to call FUNC_NAME (ARGS), the ARGS is passed as the pointer to the real
> parameters.  
>
> While we issue "print FUNC_NAME (ARGS), these ARGS are passed as the
> original types.  So fortran code can't handle that and SEGV occurs.  
> Considering this special argument-passing mechanism, do we have any
> workaround for it in gdb's evaluation code?  Create a dummy memory address
> for the arguments and pass that address instead?  or any others?

I don't think there's any way to handle that right now: you'll have to
add one.  I am not sure where in the call-function process it should
be.  Probably, you will also need a way to allocate them - on the stack
would be better than malloc, which is how gdb usually allocates memory.

--
Daniel Jacobowitz
CodeSourcery, LLC
Reply | Threaded
Open this post in threaded view
|

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

Mark Kettenis
In reply to this post by Wu Zhou
> X-From_: gdb-return-22951-m.m.kettenis=[hidden email]  Wed Nov  2 03:39:44 2005
> Mailing-List: contact [hidden email]; run by ezmlm
> Sender: [hidden email]
> Date: Wed, 2 Nov 2005 10:43:03 +0800 (CST)
> From: Wu Zhou <[hidden email]>
> X-UTwente-MailScanner-Information: Scanned by MailScanner. Contact [hidden email] for more information.
> X-UTwente-MailScanner: Found to be clean
> X-MailScanner-From: gdb-return-22951-m.m.kettenis=[hidden email]
> X-Spam-Checker-Version: SpamAssassin 3.0.4 (2005-06-05) on
> elgar.sibelius.xs4all.nl
> X-Spam-Level:
> X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=failed
> version=3.0.4
>
> Hi all,
>
> I had found the reason why gdb will drop into SEGV when evaluating the
> fortran function calls.  In g77 (gfortran might be the same), when we try
> to call FUNC_NAME (ARGS), the ARGS is passed as the pointer to the real
> parameters.  
>
> While we issue "print FUNC_NAME (ARGS), these ARGS are passed as the
> original types.  So fortran code can't handle that and SEGV occurs.  
> Considering this special argument-passing mechanism, do we have any
> workaround for it in gdb's evaluation code?  Create a dummy memory address
> for the arguments and pass that address instead?  or any others?
>
> Your comments are highly appreciated.  Thanks a lot.

What you describe sounds very similar to what
gdbarch_stabs_argument_has_addr is all about.  Currently these are
only used on SPARC, and only for stabs.

One could argue that the debug information generated by g77 is wrong,
because it doesn't reflect the actual implementation of FUNC_NAME.  Or
perhaps GDB symbol reading code causes problems.  Can you post a
concrete example of a function call that goes wrong, and add a bit of
explanation about the types involved for those of us who are not very
familiar with Fortran?

Thanks,

Mark
Reply | Threaded
Open this post in threaded view
|

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

Wu Zhou
Hi Mark,

On Wed, 2 Nov 2005, Mark Kettenis wrote:

> What you describe sounds very similar to what
> gdbarch_stabs_argument_has_addr is all about.  Currently these are
> only used on SPARC, and only for stabs.

Thanks for your pointer.  It looks very much like the same (If I understand
correctly :-).  Look at the following testcase please:

        PROGRAM funcall
          integer a, b
          b = 2
          a = res(b)
        END PROGRAM

        function res(m)
          integer m
          integer res
          res = m * m
        end function

The debuginfo for function res is like this:

 <1><da>: Abbrev Number: 7 (DW_TAG_subprogram)
     DW_AT_sibling     : <10f>
     DW_AT_external    : 1
     DW_AT_name        : res_
     DW_AT_decl_file   : 1
     DW_AT_decl_line   : 23
     DW_AT_type        : <bb>
     DW_AT_low_pc      : 0x804863f
     DW_AT_high_pc     : 0x8048655
     DW_AT_frame_base  : 1 byte block: 55       (DW_OP_reg5)
 <2><f5>: Abbrev Number: 8 (DW_TAG_formal_parameter)
     DW_AT_name        : m
     DW_AT_type        : <10f>   =====> This is a const pointer to integer
     DW_AT_artificial  : 1
     DW_AT_location    : 2 byte block: 91 8     (DW_OP_fbreg: 8)

 <1><10f>: Abbrev Number: 9 (DW_TAG_const_type)
     DW_AT_type        : <114>
 <1><114>: Abbrev Number: 10 (DW_TAG_pointer_type)
     DW_AT_byte_size   : 4
     DW_AT_type        : <bb>
 <1><bb>: Abbrev Number: 6 (DW_TAG_base_type)
     DW_AT_name        : integer
     DW_AT_byte_size   : 4
     DW_AT_encoding    : 5      (signed)

So my question is: how will gdb to handle this situation if the gdbarch
shows that stabs argument has addr, especially when the command line pass
an integer type, but the debuginfo said that it need a pointer?

>
> One could argue that the debug information generated by g77 is wrong,
> because it doesn't reflect the actual implementation of FUNC_NAME.  Or
> perhaps GDB symbol reading code causes problems.  Can you post a
> concrete example of a function call that goes wrong, and add a bit of
> explanation about the types involved for those of us who are not very
> familiar with Fortran?

Both of your arguments seem reasonable.  But even in the first argument it
might also be desirable that we could handle it gracefully, right?

Here is the debugging session for the above testcase (maybe I could
convert it into a real testcase for gdb testsuite?), hoping that
it could clarify the things a little.

(gdb) r
Starting program: /root/DE/gdb-6.3/gdb/testsuite/gdb.fortran/func-call

Breakpoint 1, MAIN__ () at func-call.f:19
19                b = 2
Current language:  auto; currently fortran
(gdb) n
20                a = res(b)
(gdb) p res (2)
No symbol "res" in current context.
(gdb) p res_ (2)     =========> Use constand '2' as argument, get SEGV

Program received signal SIGSEGV, Segmentation fault.
0x08048648 in res_ (m=0x2) at func-call.f:26
26                res = m * m
The program being debugged was signaled while in a function called from
GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on"
Evaluation of the expression containing the function (res_) will be
abandoned.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /root/DE/gdb-6.3/gdb/testsuite/gdb.fortran/func-call

Breakpoint 1, MAIN__ () at func-call.f:19
19                b = 2
(gdb) n
20                a = res(b)
(gdb) p res_ (b)    =========> Use variable 'b' as argument, get SEGV

Program received signal SIGSEGV, Segmentation fault.
0x08048648 in res_ (m=0x2) at func-call.f:26
26                res = m * m
The program being debugged was signaled while in a function called from
GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on"
Evaluation of the expression containing the function (res_) will be
abandoned.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /root/DE/gdb-6.3/gdb/testsuite/gdb.fortran/func-call

Breakpoint 1, MAIN__ () at func-call.f:19
19                b = 2
(gdb) n
20                a = res(b)
(gdb) p res_ (&b)    ========> Use '&b' as argument, get correct result
$1 = 4

Regards
- Wu Zhou
Reply | Threaded
Open this post in threaded view
|

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

Wu Zhou
In reply to this post by Daniel Jacobowitz-2
Hi Daniel,

On Wed, 2 Nov 2005, Daniel Jacobowitz wrote:

> On Wed, Nov 02, 2005 at 10:43:03AM +0800, Wu Zhou wrote:
> > Hi all,
> >
> > I had found the reason why gdb will drop into SEGV when evaluating the
> > fortran function calls.  In g77 (gfortran might be the same), when we try
> > to call FUNC_NAME (ARGS), the ARGS is passed as the pointer to the real
> > parameters.  
> >
> > While we issue "print FUNC_NAME (ARGS), these ARGS are passed as the
> > original types.  So fortran code can't handle that and SEGV occurs.  
> > Considering this special argument-passing mechanism, do we have any
> > workaround for it in gdb's evaluation code?  Create a dummy memory address
> > for the arguments and pass that address instead?  or any others?
>
> I don't think there's any way to handle that right now: you'll have to
> add one.  I am not sure where in the call-function process it should
> be.  Probably, you will also need a way to allocate them - on the stack
> would be better than malloc, which is how gdb usually allocates memory.

Maybe we can convert the argument to its pointer before we enter into
call_function_by_hand (evaluate_subexp_standard: case OP_FUNCALL)?  
Normally what function you will use to allocate memory on the stack?  I am
not very familar with that kind of code.  Thanks!

Regards
- Wu Zhou
 
Reply | Threaded
Open this post in threaded view
|

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

JimB-3
In reply to this post by Mark Kettenis

Mark Kettenis <[hidden email]> writes:
> One could argue that the debug information generated by g77 is wrong,
> because it doesn't reflect the actual implementation of FUNC_NAME.  Or
> perhaps GDB symbol reading code causes problems.  Can you post a
> concrete example of a function call that goes wrong, and add a bit of
> explanation about the types involved for those of us who are not very
> familiar with Fortran?

The types in the debug information should not reflect the extra level
of indirection; the fact that they're passed by reference is just part
of the meaning of a Fortran function call.  But the location
expression should encode the extra level of indirection.

Probably value_arg_coerce should be a language method.  The C
promotion rules aren't appropriate for Fortran anyway, and the Fortran
version could take care of applying value_addr (or something like
that), and turning the array of actuals into an array of pointers to
the actuals.

Reply | Threaded
Open this post in threaded view
|

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

Wu Zhou
On Wed, 2 Nov 2005, Jim Blandy wrote:

>
> Mark Kettenis <[hidden email]> writes:
> > One could argue that the debug information generated by g77 is wrong,
> > because it doesn't reflect the actual implementation of FUNC_NAME.  Or
> > perhaps GDB symbol reading code causes problems.  Can you post a
> > concrete example of a function call that goes wrong, and add a bit of
> > explanation about the types involved for those of us who are not very
> > familiar with Fortran?
>
> The types in the debug information should not reflect the extra level
> of indirection; the fact that they're passed by reference is just part
> of the meaning of a Fortran function call.  But the location
> expression should encode the extra level of indirection.
>
> Probably value_arg_coerce should be a language method.  The C
> promotion rules aren't appropriate for Fortran anyway, and the Fortran
> version could take care of applying value_addr (or something like
> that), and turning the array of actuals into an array of pointers to
> the actuals.

Jim, it seems that you just said out what I am thinking of.  Function
value_arg_coerce is said to perform the standard coercion that are
specified for arguments to be passed to C functions (you can see that in
the comment).  But it is also used for Fortran functions (maybe all
other function GDB supports).

What is more, I find that when I pass "res_(b)" to gfortran code in gdb
command line, it will get the correct result.  All the difference is that
gfortran handle the parameters as reference to the actuals.  So
value_arg_coerce will call value_addr to convert args into the address of
them, so we can get the correct result.

However with gfortran, "print res_(2)" still doesn't get the correct
result.  But it fail more gracefully, it reports the following error
message:  
  Attempt to take address of value not located in memory.

Which is well expected with reference to the code in value_arg_coerce.

So I am thinking of a somwhat different value_arg_coerce for Fortran code:
when the parameter type is a reference (for gfortran) or pointer (for
g77), we can call something like value_addr to changed the argument into
its address.

I did some tests today, but no success so far.  Will take some more look
into this.

Any suggestion, comments on this?  Thanks!

Regards
- Wu Zhou
Reply | Threaded
Open this post in threaded view
|

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

Mark Kettenis
In reply to this post by Wu Zhou
> Date: Thu, 3 Nov 2005 11:14:51 +0800 (CST)
> From: Wu Zhou <[hidden email]>
>
> Maybe we can convert the argument to its pointer before we enter into
> call_function_by_hand (evaluate_subexp_standard: case OP_FUNCALL)?  
> Normally what function you will use to allocate memory on the stack?  I am
> not very familar with that kind of code.  Thanks!

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.

Mark
Reply | Threaded
Open this post in threaded view
|

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

Wu Zhou
Hi Mark,

On Thu, 3 Nov 2005, Mark Kettenis wrote:

> > Date: Thu, 3 Nov 2005 11:14:51 +0800 (CST)
> > From: Wu Zhou <[hidden email]>
> >
> > Maybe we can convert the argument to its pointer before we enter into
> > call_function_by_hand (evaluate_subexp_standard: case OP_FUNCALL)?  
> > Normally what function you will use to allocate memory on the stack?  I am
> > not very familar with that kind of code.  Thanks!
>
> 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!

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 4 Nov 2005 03:11:35 -0000
*************** value_arg_coerce (struct value *arg, str
*** 109,114 ****
--- 109,115 ----
    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)
  {
*************** 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 ----
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 4 Nov 2005 03:11:49 -0000
*************** value_addr (struct value *arg1)
*** 868,877 ****
      }
    if (TYPE_CODE (type) == TYPE_CODE_FUNC)
      return value_coerce_function (arg1);
!
    if (VALUE_LVAL (arg1) != lval_memory)
      error (_("Attempt to take address of value not located in memory."));
 
    /* Get target memory address */
    arg2 = value_from_pointer (lookup_pointer_type (value_type (arg1)),
      (VALUE_ADDRESS (arg1)
--- 868,905 ----
      }
    if (TYPE_CODE (type) == TYPE_CODE_FUNC)
      return value_coerce_function (arg1);
! /*
    if (VALUE_LVAL (arg1) != lval_memory)
      error (_("Attempt to take address of value not located in memory."));
+ */
+
+   if (TYPE_CODE (type) == TYPE_CODE_INT  && VALUE_LVAL (arg1) == not_lval)
+     {
+       int len = TYPE_LENGTH (type);
+       CORE_ADDR addr;
+       CORE_ADDR sp = read_sp ();
+       if (INNER_THAN (1, 2))
+ {
+  /* stack grows downward */
+  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;
+  sp += len;
+ }
+
+       addr = (CORE_ADDR) malloc (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)


Regards
- Wu Zhou
Reply | Threaded
Open this post in threaded view
|

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

Wu Zhou
I also added a testcase for this.  It should be easy to test in the coding
process.  I tested it with gfortran and mainline gdb, it report 5PASS +
1FAIL ('p res_(2)' reports "Attempt to take address of value not located
in memory").  The test with g77 and mainline gdb shows 4 PASS and 2 FAIL
(SEGV with 'p res_(2)' and 'p res_(b)').  And test with the g77 and the
latest patched gdb, it showed 5PASS + 1FAIL (error output with 'p res_(2)').

Do you think that it make sense for this goes into the testsuite tree?

Here is the patch:

Index: gdb.fortran/func-call.f
===================================================================
RCS file: gdb.fortran/func-call.f
diff -N gdb.fortran/func-call.f
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- gdb.fortran/func-call.f 4 Nov 2005 03:47:22 -0000
***************
*** 0 ****
--- 1,27 ----
+ c Copyright 2005 Free Software Foundation, Inc.
+
+ c This program is free software; you can redistribute it and/or modify
+ c it under the terms of the GNU General Public License as published by
+ c the Free Software Foundation; either version 2 of the License, or
+ c (at your option) any later version.
+ c
+ c This program is distributed in the hope that it will be useful,
+ c but WITHOUT ANY WARRANTY; without even the implied warranty of
+ c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ c GNU General Public License for more details.
+ c
+ c You should have received a copy of the GNU General Public License
+ c along with this program; if not, write to the Free Software
+ c Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+         PROGRAM funcall
+           integer a, b
+           b = 2
+           a = res(b)
+         END PROGRAM
+
+         function res(m)
+           integer m
+           integer res
+           res = m * m
+         end function
Index: gdb.fortran/func-call.exp
===================================================================
RCS file: gdb.fortran/func-call.exp
diff -N gdb.fortran/func-call.exp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- gdb.fortran/func-call.exp 4 Nov 2005 03:47:22 -0000
***************
*** 0 ****
--- 1,79 ----
+ # Copyright 2005 Free Software Foundation, Inc.
+
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 2 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ # GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+ # This file was written by Wu Zhou. ([hidden email])
+
+ if $tracelevel then {
+ strace $tracelevel
+ }
+
+ set testfile "func-call"
+ set srcfile ${testfile}.f
+ set binfile ${objdir}/${subdir}/${testfile}
+
+ if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug f77 quiet}] != "" } {
+     untested "Couldn't compile ${srcfile}"
+     return -1
+ }
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ # To test "print res_(2)"
+
+ if ![runto MAIN__] then {
+     perror "couldn't run to breakpoint MAIN__"
+     continue
+ }
+
+ gdb_breakpoint [gdb_get_line_number "a = res(b)"]
+ gdb_continue_to_breakpoint "initialize argument b"
+ gdb_test_multiple "print res_(2)" "print res_(2)" {
+     -re ".*\[0-9\]+ = 4.*$gdb_prompt $" {
+         pass "use constant 2 as the argument"
+     }
+     -re "Program received signal SIGSEGV, Segmentation fault.*$gdb_prompt $" {
+         fail "print res_(2) get SEGV"  
+     }
+     -re ".*$gdb_prompt $" {
+         fail "other unexpected error"
+     }
+ }
+
+ # To test "print res_(b)"
+
+ if ![runto MAIN__] then {
+     perror "couldn't run to breakpoint MAIN__"
+     continue
+ }
+
+ gdb_breakpoint [gdb_get_line_number "a = res(b)"]
+ gdb_continue_to_breakpoint "initialize argument b"
+ gdb_test "print res_(b)" ".*\[0-9\]+ = 4.*" "use variable 'b' as the argument"
+
+ # To test "print res_(&b)"
+
+ if ![runto MAIN__] then {
+     perror "couldn't run to breakpoint MAIN__"
+     continue
+ }
+
+ gdb_breakpoint [gdb_get_line_number "a = res(b)"]
+ gdb_continue_to_breakpoint "initialize argument b"
+ gdb_test "print res_(&b)" ".*\[0-9\]+ = 4.*" "use the address of 'b' as the argument"
+


On Fri, 4 Nov 2005, Wu Zhou wrote:

> Hi Mark,
>
> On Thu, 3 Nov 2005, Mark Kettenis wrote:
>
> > > Date: Thu, 3 Nov 2005 11:14:51 +0800 (CST)
> > > From: Wu Zhou <[hidden email]>
> > >
> > > Maybe we can convert the argument to its pointer before we enter into
> > > call_function_by_hand (evaluate_subexp_standard: case OP_FUNCALL)?  
> > > Normally what function you will use to allocate memory on the stack?  I am
> > > not very familar with that kind of code.  Thanks!
> >
> > 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!
>
> 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 4 Nov 2005 03:11:35 -0000
> *************** value_arg_coerce (struct value *arg, str
> *** 109,114 ****
> --- 109,115 ----
>     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)
>   {
> *************** 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 ----
> 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 4 Nov 2005 03:11:49 -0000
> *************** value_addr (struct value *arg1)
> *** 868,877 ****
>       }
>     if (TYPE_CODE (type) == TYPE_CODE_FUNC)
>       return value_coerce_function (arg1);
> !
>     if (VALUE_LVAL (arg1) != lval_memory)
>       error (_("Attempt to take address of value not located in memory."));
>  
>     /* Get target memory address */
>     arg2 = value_from_pointer (lookup_pointer_type (value_type (arg1)),
>       (VALUE_ADDRESS (arg1)
> --- 868,905 ----
>       }
>     if (TYPE_CODE (type) == TYPE_CODE_FUNC)
>       return value_coerce_function (arg1);
> ! /*
>     if (VALUE_LVAL (arg1) != lval_memory)
>       error (_("Attempt to take address of value not located in memory."));
> + */
> +
> +   if (TYPE_CODE (type) == TYPE_CODE_INT  && VALUE_LVAL (arg1) == not_lval)
> +     {
> +       int len = TYPE_LENGTH (type);
> +       CORE_ADDR addr;
> +       CORE_ADDR sp = read_sp ();
> +       if (INNER_THAN (1, 2))
> + {
> +  /* stack grows downward */
> +  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;
> +  sp += len;
> + }
> +
> +       addr = (CORE_ADDR) malloc (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)
>

 
 Regards
 - Wu Zhou
 
 
Reply | Threaded
Open this post in threaded view
|

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

Dave Korn
In reply to this post by Mark Kettenis
Mark Kettenis wrote:

>> Date: Thu, 3 Nov 2005 11:14:51 +0800 (CST)
>> From: Wu Zhou <[hidden email]>
>>
>> Maybe we can convert the argument to its pointer before we enter into
>> call_function_by_hand (evaluate_subexp_standard: case OP_FUNCALL)?
>> Normally what function you will use to allocate memory on the stack?  I
>> am not very familar with that kind of code.  Thanks!
>
> 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.
>
> Mark


... but beware of the red zone on 64-bit x86, right .... ?

[e.g. see http://sources.redhat.com/ml/gdb-patches/2003-08/msg00092.html ]

    cheers,
      DaveK
--
Can't think of a witty .sigline today....

Reply | Threaded
Open this post in threaded view
|

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

Daniel Jacobowitz-2
On Fri, Nov 04, 2005 at 11:20:04AM -0000, Dave Korn wrote:
> ... but beware of the red zone on 64-bit x86, right .... ?
>
> [e.g. see http://sources.redhat.com/ml/gdb-patches/2003-08/msg00092.html ]

Which is why this should be done inside the relevant bits of infcall
that already know about the redzone.

--
Daniel Jacobowitz
CodeSourcery, LLC
Reply | Threaded
Open this post in threaded view
|

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

Daniel Jacobowitz-2
In reply to this post by JimB-3
On Wed, Nov 02, 2005 at 11:42:36PM -0800, Jim Blandy wrote:
> The types in the debug information should not reflect the extra level
> of indirection; the fact that they're passed by reference is just part
> of the meaning of a Fortran function call.  But the location
> expression should encode the extra level of indirection.

This seems perfectly sensible to me.  But the example Wu posted earlier
does not agree: today gfortran apparently puts out the indirections
explicitly.

Paul Brook had this to say when I asked him:
  When a user says "p foo" they should get the value, not the address of
  the argument.

So it sounds like gfortran will need to be fixed.

--
Daniel Jacobowitz
CodeSourcery, LLC
Reply | Threaded
Open this post in threaded view
|

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

Daniel Jacobowitz-2
In reply to this post by Wu Zhou
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...


--
Daniel Jacobowitz
CodeSourcery, LLC
Reply | Threaded
Open this post in threaded view
|

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

Wu Zhou
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

Reply | Threaded
Open this post in threaded view
|

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

Daniel Jacobowitz-2
On Mon, Nov 07, 2005 at 12:51:59PM +0800, Wu Zhou wrote:
> 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!

Just to be clear: the patch is _not_ acceptable as is.  We need to
decide what gfortran's debugging information should look like, and how
the transformation should be controlled by language.  Casting an
integer to a pointer by pushing it to the stack this way is not the
correct behavior for any other language.

But thanks for testing my suggestion; the general approach looks sound,
once we figure out how to integrate it.

--
Daniel Jacobowitz
CodeSourcery, LLC
Reply | Threaded
Open this post in threaded view
|

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

Wu Zhou


On Mon, 7 Nov 2005, Daniel Jacobowitz wrote:

> On Mon, Nov 07, 2005 at 12:51:59PM +0800, Wu Zhou wrote:
> > 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!
>
> Just to be clear: the patch is _not_ acceptable as is.  We need to
> decide what gfortran's debugging information should look like, and how
> the transformation should be controlled by language.  Casting an
> integer to a pointer by pushing it to the stack this way is not the
> correct behavior for any other language.

That is okay.  I am very happy to know how gfortran should handle this
kind of case.  Will you talk with gfortran guys on this?  If possible,
would you please include me in the cc-list of your correspondence?  That
will be highly appreciated.
 
Regards
- Wu Zhou

Reply | Threaded
Open this post in threaded view
|

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

JimB-3
In reply to this post by Daniel Jacobowitz-2

Daniel Jacobowitz <[hidden email]> writes:
> On Wed, Nov 02, 2005 at 11:42:36PM -0800, Jim Blandy wrote:
>> The types in the debug information should not reflect the extra level
>> of indirection; the fact that they're passed by reference is just part
>> of the meaning of a Fortran function call.  But the location
>> expression should encode the extra level of indirection.
>
> This seems perfectly sensible to me.  But the example Wu posted earlier
> does not agree: today gfortran apparently puts out the indirections
> explicitly.

You're talking about this, where 'm' is declared as 'integer', right?

 <1><da>: Abbrev Number: 7 (DW_TAG_subprogram)
     DW_AT_sibling     : <10f>
     DW_AT_external    : 1
     DW_AT_name        : res_
     DW_AT_decl_file   : 1
     DW_AT_decl_line   : 23
     DW_AT_type        : <bb>
     DW_AT_low_pc      : 0x804863f
     DW_AT_high_pc     : 0x8048655
     DW_AT_frame_base  : 1 byte block: 55       (DW_OP_reg5)
 <2><f5>: Abbrev Number: 8 (DW_TAG_formal_parameter)
     DW_AT_name        : m
     DW_AT_type        : <10f>   =====> This is a const pointer to integer
     DW_AT_artificial  : 1
     DW_AT_location    : 2 byte block: 91 8     (DW_OP_fbreg: 8)

 <1><10f>: Abbrev Number: 9 (DW_TAG_const_type)
     DW_AT_type        : <114>
 <1><114>: Abbrev Number: 10 (DW_TAG_pointer_type)
     DW_AT_byte_size   : 4
     DW_AT_type        : <bb>
 <1><bb>: Abbrev Number: 6 (DW_TAG_base_type)
     DW_AT_name        : integer
     DW_AT_byte_size   : 4
     DW_AT_encoding    : 5      (signed)

> So it sounds like gfortran will need to be fixed.

Yep.  The types in the Dwarf information should match the types as
they appear in the source language.
Reply | Threaded
Open this post in threaded view
|

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

JimB-3
In reply to this post by Daniel Jacobowitz-2

Daniel Jacobowitz <[hidden email]> writes:
> Maybe if you pass the sp value by reference to value_arg_coerce and
> adjust it there...

Or you could pass a regcache.
Reply | Threaded
Open this post in threaded view
|

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

Daniel Jacobowitz-2
On Wed, Nov 09, 2005 at 04:55:27PM -0800, Jim Blandy wrote:
>
> Daniel Jacobowitz <[hidden email]> writes:
> > Maybe if you pass the sp value by reference to value_arg_coerce and
> > adjust it there...
>
> Or you could pass a regcache.

We're not trying to adjust the saved sp in the regcache, but the
interim SP being used in setting up the function - it's not in the
regcache until much later (after push_dummy_call).

--
Daniel Jacobowitz
CodeSourcery, LLC
12