Extending Functionality: an expedient and questionable approa ch

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

Extending Functionality: an expedient and questionable approa ch

chandru
Another way to look at the stack...but it is not as pretty as what you'd see
in a crash report.

(camelns)212> erlang:process_display(whereis(cns_server), backtrace).

program counter = 0x9895a0 (gen_server:loop/6 + 52)
cp = 0x85ee6c (proc_lib:init_p/5 + 164)
arity = 0

397b64   Return addr 0x85EE6C (proc_lib:init_p/5 + 164)
y(0)     []
y(1)     infinity
y(2)     cns_server
y(3)     {state,[],0,0,17000}
y(4)     cns_server
y(5)     <0.25458.2>

397b80   Return addr 0x10F9F4 (<terminate process normally>)
y(0)     Catch 0x85EE6C (proc_lib:init_p/5 + 164)
y(1)     gen
y(2)     init_it
y(3)
[gen_server,<0.25458.2>,<0.25458.2>,{local,cns_server},cns_server,normal,[]]
true

You can specify how much of the backtrace is saved using:

erlang:system_flag(backtrace_depth, Value).

-----Original Message-----
From: Chris Pressey [mailto:cpressey]
Sent: 13 March 2003 23:41
To: Shawn Pearce
Cc: erlang-questions
Subject: Re: Extending Functionality: an expedient and questionable
approach


On Thu, 13 Mar 2003 17:56:45 -0500
Shawn Pearce <spearce> wrote:

<snip>

Actually, just out of curiousity, does anyone know if there's a better way
to investigate the call stack -  better than the only method I've seen so
far, that is, to catch an intentional error and examine the result?

<snip>



 NOTICE AND DISCLAIMER:
This email (including attachments) is confidential.  If you have received
this email in error please notify the sender immediately and delete this
email from your system without copying or disseminating it or placing any
reliance upon its contents.  We cannot accept liability for any breaches of
confidence arising through use of email.  Any opinions expressed in this
email (including attachments) are those of the author and do not necessarily
reflect our opinions.  We will not accept responsibility for any commitments
made by our employees outside the scope of our business.  We do not warrant
the accuracy or completeness of such information.



Reply | Threaded
Open this post in threaded view
|

inspecting the call stack from a program (was: Re: Extending Functionality: an expedient and questionable approa ch)

Chris Pressey
On Fri, 14 Mar 2003 14:45:49 -0000
Chandrashekhar Mullaparthi <Chandrashekhar.Mullaparthi>
wrote:

> Another way to look at the stack...but it is not as pretty as what you'd
> see in a crash report.
>
> (camelns)212> erlang:process_display(whereis(cns_server),
> backtrace).
> [...]

Sorry... I should have been more specific.  I meant - a way for a program
to inspect the call stack.

I'm currently using this function:

  call_stack() ->
    {'EXIT', {Error, CallStack}} = (catch 1 = 2),
    tl(CallStack).

I find this useful in conjunction with e.g. logging (e.g. in
/jungerl/lib/ce/src/ce_log.erl)

It's just that the "(catch 1 = 2)" strikes me as, uhm, ungraceful :)

-Chris


Reply | Threaded
Open this post in threaded view
|

inspecting the call stack from a program (was: Re: Extending Functionality: an expedient and questionable approa ch)

Shawn Pearce
Chris Pressey <cpressey> wrote:

> Sorry... I should have been more specific.  I meant - a way for a program
> to inspect the call stack.
>
> I'm currently using this function:
>
>   call_stack() ->
>     {'EXIT', {Error, CallStack}} = (catch 1 = 2),
>     tl(CallStack).
>
> I find this useful in conjunction with e.g. logging (e.g. in
> /jungerl/lib/ce/src/ce_log.erl)
>
> It's just that the "(catch 1 = 2)" strikes me as, uhm, ungraceful :)

So then use

     {'EXIT', {Error, CallStack}} = (catch 1 = undefined),

:-)

This is like the old Java trick of throwing an exception, catching it,
printing it to a stream, parsing the stream to locate the text of
the method you want, and pulling that back into a variable.  Oh wait,
its still cleaner in Erlang.

--
Shawn.

  * woot is now known as woot-dinner
  * Knghtbrd sprinkles a little salt on woot
  <Knghtbrd> I've never had a woot before...  Hope they taste good
  <woot-dinner> noooo!
  <woot-dinner> don't eat me!
  * Knghtbrd decides he does not want a dinner that talks to him...  hehe


Reply | Threaded
Open this post in threaded view
|

inspecting the call stack from a program

Martin Bjorklund-2
In reply to this post by Chris Pressey
Chris Pressey <cpressey> wrote:

> On Fri, 14 Mar 2003 14:45:49 -0000
> Chandrashekhar Mullaparthi <Chandrashekhar.Mullaparthi>
> wrote:
>
> > Another way to look at the stack...but it is not as pretty as what you'd
> > see in a crash report.
> >
> > (camelns)212> erlang:process_display(whereis(cns_server),
> > backtrace).
> > [...]
>
> Sorry... I should have been more specific.  I meant - a way for a program
> to inspect the call stack.
>
> I'm currently using this function:
>
>   call_stack() ->
>     {'EXIT', {Error, CallStack}} = (catch 1 = 2),
>     tl(CallStack).

Here's a snippet from our user_default.erl, which I posted to the list
a couple of years (?) ago.  (our user_default also contains pi() for
port inspection, i/1 with a pid or registered name as argument etc).

Can be used like this from the shell:

Eshell V5.2.b1  (abort with ^G)
1> bt(self()).
program counter = 0x8168454 (unknown function)
cp = 0x8490954 (user_default:pinfo/2 + 172)

0x4009bc64 Return addr 0x849131C (user_default:bt/1 + 40)
y(0)     <0.23.0>
y(1)     backtrace

[... deleted]

----------------------------------------------------------

%% Doesn't do process_display, which means it can be used when
%% remotely connecting to a node.
bt(Pid) when pid(Pid) ->
    case pinfo(Pid, backtrace) of
        {backtrace, Bin} ->
            io:format("~s\n", [binary_to_list(Bin)]);
        _ ->
            undefined
    end;
bt(Name) when atom(Name) ->
    case whereis(Name) of
        undefined -> undefined;
        Pid -> bt(Pid)
    end.

bt(X,Y,Z) ->
    bt(c:pid(X,Y,Z)).

pinfo(Pid, Item) ->
    case is_alive() of
        true -> rpc:call(node(Pid), erlang, process_info, [Pid, Item]);
        false -> process_info(Pid, Item)
    end.



/martin


Reply | Threaded
Open this post in threaded view
|

inspecting the call stack from a program (was: Re: Extending Functionality: an expedient and questionable approa ch)

Ulf Wiger-4
In reply to this post by Chris Pressey
On Wed, 19 Mar 2003, Chris Pressey wrote:

>I'm currently using this function:
>
>  call_stack() ->
>    {'EXIT', {Error, CallStack}} = (catch 1 = 2),
>    tl(CallStack).

Not that it's necessarily better, but out of curiosity, I
tried to write a program that presented a call stack based
on process_info(Pid,backtrace) (actually, it does have the
nice property that it can be used on any process.)

Interestingly, the (badly written) regexp:first_match() in
the commented version seems to loop endlessly. Bug or
feature? The same pattern passed to egrep works fine.

I cannot guarantee that this version always gives a correct
answer. My "parsing" of the backtrace is sloppy, to say the
least.

/Uffe

all_stack() ->
    {_, Stack} = process_info(self(),backtrace),
    case format(binary_to_list(Stack)) of
        [{?MODULE,call_stack,0}|Tail] ->
            Tail;
        Other ->
            Other
    end.

% format(Str) ->
%     case regexp:first_match(
%
Str,"\\([a-z]+[a-z0-9_]*:[a-z]+[a-z0-9_]*+/[0-9]+") of
%       {match,Start,Length} ->
%           Fun = string:substr(Str,Start+1,Length-1),
%           [M,F,A] = string:tokens(Fun,":/"),
%
[{list_to_atom(M),list_to_atom(F),list_to_integer(A)}|
%            format(string:substr(Str,Start+Length))];
%       nomatch ->
%           []
%     end.

format(Str) ->
    Tokens = string:tokens(Str,"\n "),
    funs(Tokens).

funs(["(" ++ Rest|Toks]) ->
    case string:tokens(Rest,":/") of
        [M,F,A] ->

[{list_to_atom(M),list_to_atom(F),list_to_integer(A)}|
             funs(Toks)];
        _ ->
            funs(Toks)
    end;
funs([_|Toks]) ->
    funs(Toks);
funs([]) ->
    [].



--
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Strategic Product & System Management
 / / /     Ericsson AB, Connectivity and Control Nodes



Reply | Threaded
Open this post in threaded view
|

inspecting the call stack from a program (was: Re: Extending Functionality: an expedient and questionable approa ch)

Luke Gorrie-3
Ulf Wiger <etxuwig> writes:

> Interestingly, the (badly written) regexp:first_match() in
> the commented version seems to loop endlessly. Bug or
> feature? The same pattern passed to egrep works fine.

I think it's a bug in the regexp module - matching on certain regexps
fails to terminate.

> Str,"\\([a-z]+[a-z0-9_]*:[a-z]+[a-z0-9_]*+/[0-9]+") of
                                          ^^

That marked part is the most likely suspect: * can match nothing, so
*+ can match infinitely many nothings, and the current module will
consider all nothings (i.e. loop forever.)

I've reimplemented the same regexp-matching algorithm learned from
regexp.erl a couple of times and been caught out with this bug. I'm
quite curious to know of a nice fix, since it's a lovely and simple
algorithm. Sofar I haven't found a fix that's pretty enough to adopt
:-)

I think I heard rumour of a simple algorithm for transforming regexps
so that they will never hit this case, but I'm not sure.

NB: if you are passing user-supplied regexps to the regexp module,
e.g. from web-forms, this may be a serious problem.

Cheers,
Luke