[lldb-dev] Make a StackFrame return immediately

Filipe Cabecinhas filcab+lldb-dev at gmail.com
Fri Jul 29 16:15:05 PDT 2011


But it's not doing that. After some "frame return" commands, it will simply
complain that there's no selected thread (at first). In subsequent "thread
step-over" commands, everything will be fine. But it won't use the first
thread for the first command, it will simply yield an error.

Regards,

  Filipe

On Fri, Jul 29, 2011 at 15:34, Greg Clayton <gclayton at apple.com> wrote:

>
> On Jul 29, 2011, at 3:09 PM, Filipe Cabecinhas wrote:
>
> > Hi,
> >
> > For now the command is in frame and only returns from the current thread
> (not from other threads, which simplifies the command), but if it's desired,
> I'm more than happy to add that feature.
> >
> > Since we're supposed to use the interpreter for the ground truth, then is
> the code from CommandObjectThreadStepWithTypeAndScope at fault here, since
> it's not using the interpreter's execution context?
>
> No, the CommandObjectThreadStepWithTypeAndScope should be using the
> currently selected thread since you want to select a thread and then type
> "thread step-in", and this should act on the currently selected thread.
>
> Is there no selected thread, this should then default to the first thread
> (thread at index zero (not thread index, but just raw index zero).
>
> >
> >     virtual bool
> >     Execute
> >     (
> >         Args& command,
> >         CommandReturnObject &result
> >     )
> >     {
> >         Process *process = m_interpreter.GetExecutionContext().process;
> >         bool synchronous_execution = m_interpreter.GetSynchronous();
> >
> >         if (process == NULL)
> >         {
> >             // ...
> >         }
> >         else
> >         {
> >             const uint32_t num_threads =
> process->GetThreadList().GetSize();
> >             Thread *thread = NULL;
> >             if (command.GetArgumentCount() == 0)
> >             {
> >                 thread =
> process->GetThreadList().GetSelectedThread().get();
> >                 if (thread == NULL)
> >                 {
> >                     // right after running a "frame return", the
> condition is true.
> >                     result.AppendError ("no selected thread in process");
> >                     result.SetStatus (eReturnStatusFailed);
> >                     return false;
> >                 }
> >             }
> >
> > Thanks for the information,
> >
> >   Filipe
> >
> > On Fri, Jul 29, 2011 at 14:52, Greg Clayton <gclayton at apple.com> wrote:
> > You should always be looking at the m_interpreter for the correct
> execution context to use. The selected thread is for use in the command
> interpreter:
> >
> > (lldb) thread select 12
> > (lldb) <command>
> >
> > Now when <command> is executed, it might cause the process to run (as is
> happening in your case), and the selected thread might change or get
> invalidated.
> >
> > In this case the selected thread
> (exe_ctx.process->GetThreadList().GetSelectedThread()) matches the
> interpreter thread (m_interpreter.GetExecutionContext().thread), but this
> isn't always true.
> >
> > So at the start of your command execution, you should remember the thread
> (and the frame if you need that) that was selected if that is important to
> you by storing it away (copy the thread shared pointer) in your
> CommandObject subclass. Later you might also need to verify that your thread
> is still alive and well by checking for the thread in the process using the
> >
> > ThreadSP
> > ThreadList::FindThreadByIndexID (uint32_t index_id, bool can_update);
> >
> > The index id is a unique thread index that will continue to increase as
> new threads come and go. This guarantees that if a system can re-use thread
> ids (not thread index ids, but thread ids or tid), that if a thread comes
> and goes that we can track that we were actually trying to step on the
> correct thread.
> >
> > Other answers below:
> >
> > On Jul 29, 2011, at 2:10 PM, Filipe Cabecinhas wrote:
> >
> > > Hi,
> > >
> > > Is it normal for these two threads to differ?
> >
> > Very normal. The interpreter's execution context is what you should
> always be using.
> > >
> > > exe_ctx = m_interpreter.GetExecutionContext();
> > >
> > > exe_ctx.thread: 0x107900610,
> exe_ctx.process->GetThreadList().GetSelectedThread(): 0x0
> > >
> > > Also, if we only have one thread, shouldn't that thread always be
> selected?
> >
> > Yes, but then your code would fail if there were more than one thread
> where thread 1 was selected yet somehow you tried to return from thread 2.
> This could be possibly done as:
> >
> > (lldb) thread select 1
> > (lldb) thread return --thread 2 <return value>
> >
> > The currently selected thread would be 1, but your command should be
> acting on thread 2...
> >
> >
> > > Somehow the ThreadList.m_selected_thread is being set to
> LLDB_INVALID_THREADID right after I run my command.
> >
> > Again, don't rely on the selected thread, use the interpreter's execution
> context as the truth, as anything that causes the program to execute can
> change what thread is selected.
> >
> > For example if you run from thread 1 and hit a breakpoint in thread 2,
> the selected thread will be changed to thread 2 when the process stop event
> is delivered...
> >
> > So the quick rules are:
> > 1 - trust the execution context in the interpreter as truth
> > 2 - if you run the program in any way, the execution context in
> m_interpreter might change
> > 3 - save any interpreter execution context you may need in your command
> prior to resuming the target in any way and verify your process, thread or
> frame objects are still around after you stop again to make sure the
> process/thread didn't exit, or to make sure you didn't go higher in the
> stack for frames where your frame doesn't exist anymore...
> >
> > Does this help?
> >
> > Greg
> >
> > >
> > > Regards,
> > >
> > >   Filipe
> > >
> > > On Wed, Jul 27, 2011 at 10:27, Filipe Cabecinhas <
> filcab+lldb-dev at gmail.com> wrote:
> > > Hi,
> > >
> > > I did that, and tried watching the thread list, to see when it changed…
> Couldn't find anything. I'll continue searching the code and debugging to
> see where the selected thread may be changing. Or is it something that
> shouldn't happen?
> > >
> > > I will also try this with a Cocoa program, to check the objective-c
> returns and if having more threads change anything.
> > >
> > > Regards,
> > >
> > >   Filipe Cabecinhas
> > >
> > >
> > > On Tue, Jul 26, 2011 at 17:36, Enrico Granata <egranata at apple.com>
> wrote:
> > > Hi Filipe,
> > > thanks for all the hard work you are doing on LLDB.
> > >
> > > While I have not really delved into your patch, I think a good way to
> find out why you get this persistent error on stepping-over after your new
> command would be to set a breakpoint in
> CommandObjectThreadStepWithTypeAndScope::Execute
> > >
> > > The way I usually do this is creating an instance of LLDB debugging my
> inferior process (a test program in your case), and then in another Terminal
> window, opening a second LLDB and attaching it to the first instance (you
> can use the process attach -p command to do so).
> > > Then start to play with the first LLDB, and when you get to the point
> where you would type thread step-over and get in trouble, just set a
> breakpoint into the CommandObjectThreadStepWithTypeAndScope::Execute call in
> the second LLDB instance.
> > >
> > > Now, you can step through the command's code and check where it's
> failing exactly (and hopefully figure out why).
> > >
> > > Sincerely,
> > > Enrico Granata
> > > ✆ 408.974.5572 | ✉ egranata@.com
> > >
> > > On Jul 26, 2011, at 5:29 PM, Filipe Cabecinhas wrote:
> > >
> > >> Hi all,
> > >>
> > >> Multi-level returns were not working as intended, as I would write to
> the frame's RegisterContext (yielding an error), instead of writing to the
> live RegisterContext. I have fixed that and created another test-case for
> it.
> > >>
> > >> I still have the problem of not rebuilding the StackFrameList, and the
> first "thread step-over" command right after a "frame return" is yielding an
> error. Subsequent commands work fine.
> > >>
> > >> Regards,
> > >>
> > >>   Filipe
> > >>
> > >> On Mon, Jul 25, 2011 at 15:08, Filipe Cabecinhas <
> filcab+lldb-dev at gmail.com> wrote:
> > >> Hi all,
> > >>
> > >> I've refactored the code to put most of the work on the StackFrameList
> class, but I still have one problem:
> > >> The state of execution isn't being updated.
> > >>
> > >> - If I try to print the pc register after returning, it will just give
> me the old value (still in the function).
> > >> - The first thread step-over command after returning from a function
> isn't working, too. But that may have to do with:
> > >> - I can't update the stackframe list. thread backtrace always puts me
> inside the function.
> > >>
> > >> These three problems may be interconnected. I'll try to debug further.
> > >>
> > >> I also can't do what Jim suggested. I got the Block reference, from
> the frame. I can see if it's inlined and its size, but can't tell where it
> starts/ends.
> > >>
> > >> I'll send two patches: They're the same except for the implemented
> command.
> > >>
> > >> In one, the command is "thread return", in the other it is "frame
> return".
> > >>
> > >> My problem is… Except for "frame select", the frame commands only work
> on the current frame (not on other frames), so I would see "frame return" as
> return only from the current frame. While "thread return" could return from
> any frame (defaulting for the current thread). What do you think?
> > >>
> > >> I'm also sending a test directory, using the "thread return"
> variation.
> > >>
> > >> Regards,
> > >>
> > >>   Filipe Cabecinhas
> > >>
> > >>
> > >> On Fri, Jul 22, 2011 at 16:25, Filipe Cabecinhas <
> filcab+lldb-dev at gmail.com> wrote:
> > >> Thanks for the help and advice. I will ping back the list with more
> stuff when I'm done.
> > >>
> > >> Regards,
> > >>
> > >>   Filipe
> > >>
> > >>
> > >> On Fri, Jul 22, 2011 at 16:23, Jim Ingham <jingham at apple.com> wrote:
> > >>
> > >> On Jul 22, 2011, at 3:46 PM, Filipe Cabecinhas wrote:
> > >>
> > >> >
> > >> >
> > >> > On Fri, Jul 22, 2011 at 15:18, Jim Ingham <jingham at apple.com>
> wrote:
> > >> > Filipe,
> > >> >
> > >> > Thanks for working on this.
> > >> >
> > >> > Note, gdb's "return" command doesn't do anything to attempt to clean
> up local objects.  It just pops the frames off the stack & returns the
> value.  This, like moving the PC by hand, is one of those commands that you
> just shouldn't use if you don't know what could go wrong...  Anyway, people
> mostly use this to hack system routines to do something else, in which case
> you stop at the very beginning and return directly - you haven't gotten far
> enough to need to do any cleanup.
> > >> >
> > >> > Seems to me that the sensible thing to do about the return
> expression is take whatever the user gives you and cast it to the return
> type of the function you are returning from, if you know it.  If you don't
> then just write it as whatever they have given you, and the user will have
> to get it right when they write the expression.  That's the best you can do
> in this case.
> > >> >
> > >> > OK.
> > >> >
> > >> > It also seems to me that much more of this could be generic.  The
> algorithm gdb uses is to get the register context one frame up on the stack,
> and write that to the real registers, and then throw away the cached stack
> and remake it from the changed registers.  That can all be done generically.
>  Mind there are target specific bits but they are all hidden under the
> register code.  It is the unwinder's job to know what the register state of
> the functions up on the stack are, you should rely on that.
> > >> >
> > >> > The only ABI specific bit is that you need to ask the ABI where to
> store the return value.  For things smaller than a register that is easy.
>  For struct returns it can be hard, because the compiler usually passes in a
> pointer to the save location, but you would have to track the history of
> that value to know where it is stored at the point you are trying to return
> from, and that's not trivial.  Again, if you are at the beginning of the
> function you're returning from, this is easy to do.
> > >> >
> > >> > Ok. You're suggesting taking the code out of the ABI and putting it
> on the command (or maybe the StackFrame)? I initially wrote the code
> thinking calling conventions could vary a lot but, for the returns, they
> don't vary that much (and lldb allows us to abstract most of what varies).
> Or would it be preferred to just contain the code in the command object?
> > >>
> > >> Yes. This functionality seems generally useful, so the code to do this
> should go somewhere in the core.  Then the command would just be a thin
> wrapper.  StackFrame doesn't seem right to me, since you are operating on
> the list of frames more than the individual frame.  So either
> StackFrameList, or its owner Thread, seem good places.
> > >>
> > >> >
> > >> > I suppose the command should also be changed to the "frame" command,
> to mimic gdb (it returns from the current frame, not the bottom-most).
> > >> >
> > >>
> > >> Yes, that makes sense, you would either return from the currently
> selected frame, or from a frame given explicitly in the command.  Note in
> general in lldb we try to avoid positional arguments, so I would do:
> > >>
> > >> frame return --frame <FRAME NUMBER> <expression>
> > >>
> > >> BTW, you can also make LLDB commands "RAW" commands, which means that
> everything after the options is passed unparsed to the command.  That's very
> convenient for commands that take an expression as their argument, since
> then you don't end up having to backslash yourself to death.  See the
> "expression" command for an example of this.
> > >>
> > >> Oh, yeah, another thing, though very trivial, since you defined your
> command with:
> > >>
> > >>                       eFlagProcessMustBeLaunched |
> eFlagProcessMustBePaused
> > >>
> > >> you don't have to check whether the process & target are valid, the
> command interpreter shouldn't call you if they are not.
> > >>
> > >> Again, thanks for working on this!
> > >>
> > >> Jim
> > >>
> > >>
> > >> > You can also check whether the block you are in is inlined, and if
> it is, then all you do is move the PC to the end of the block.  You can't
> really do anything about the return value then, because you can't really
> tell where it is going, but at least you can return properly from the
> inlined function.
> > >> >
> > >> > Hope that helps...
> > >> > I will try that one too, thanks.
> > >> >
> > >> > Regards,
> > >> >
> > >> >   Filipe
> > >> >
> > >> >
> > >> > Jim
> > >> >
> > >> > On Jul 22, 2011, at 12:35 PM, Filipe Cabecinhas wrote:
> > >> >
> > >> > >
> > >> > >
> > >> > > On Mon, Jul 18, 2011 at 18:05, Greg Clayton <gclayton at apple.com>
> wrote:
> > >> > > On Jul 18, 2011, at 5:23 PM, Filipe Cabecinhas wrote:
> > >> > >
> > >> > > > Hi,
> > >> > > >
> > >> > > > Is there a way to mimic gdb's "return <expr>" command?
> > >> > >
> > >> > > Not if you want to change the return value.
> > >> > >
> > >> > > If you don't want to change the return value you can use "thread
> step-out". "thread step-out" (which is aliased to "finish"), is context
> sensitive to the frame you are currently in, so if you run and stop in a
> frame and then do a "frame select 12", and then to a "thread step-out", you
> will return to frame 13.
> > >> > >
> > >> > > Yes, that command will run until the frame returns (like gdb's
> finish command), but what if we want to return immediately?
> > >> > >
> > >> > > > (gdb) help return
> > >> > > > Make selected stack frame return to its caller.
> > >> > > > Control remains in the debugger, but when you continue
> > >> > > > execution will resume in the frame above the one now selected.
> > >> > > > If an argument is given, it is an expression for the value to
> return.
> > >> > > >
> > >> > > >
> > >> > > > I've been looking at the StackFrame class, but it doesn't look
> like it can do that.
> > >> > > > If I wanted to implement it, where should I look first? I can
> get the return address
> (StackFrame.GetRegisterContext().get().GetReturnAddress(), I think) write it
> to the PC (StackFrame.ChangePC()), but I have no idea how to get the
> expression's result into the return registers/memory.
> > >> > >
> > >> > > LLDB currently doesn't have any real idea of where the return
> address goes, we currently let the compiler handle all ABI issues by the way
> we make expressions.
> > >> > >
> > >> > > There is another issue where if a function isn't external, the
> compiler can make a call to this function and how the function returns the
> value, violate the ABI. In most cases you won't get affected by this, but it
> would be nice if we knew for sure from the compiler or debug info where the
> return value is. The old ARM compiler used to inject artificial
> DW_TAG_variable debug information entries into the DWARF that would tell you
> the result of functions which has a location that describes the returned
> value and where it is.
> > >> > >
> > >> > >
> > >> > > > ClangExpression isn't a big help there, since the result comes
> to debugger-land.
> > >> > >
> > >> > > Yep, and even so there is the issue that internal functions can
> violate the ABI...
> > >> > >
> > >> > > FYI: anything ABI related is currently in the ABI plug-ins:
> > >> > >
> > >> > > lldb/source/Plugins/ABI/*
> > >> > >
> > >> > > The ABI function:
> > >> > >
> > >> > >    virtual bool
> > >> > >    ABI::GetReturnValue (Thread &thread,
> > >> > >                         Value &value) const = 0;
> > >> > >
> > >> > > Take a look a the ABIMacOSX_i386 and ABIMacOSX_x86_64 versions of
> this function and see if this does close to what you want. You can also fill
> in more functionality inside these for types you want it to support.
> Currently we fill the "value" argument with the result, but we don't fill in
> the context (See the "void Value::SetContext (ContextType context_type, void
> *p)" function for details, but the  ABI::GetReturnValue functions can be
> modified to fill in the register context for return values that are returned
> in registers, and the address (See the "Value::SetValueType (...)" function)
> if needed.
> > >> > >
> > >> > > These functions currently will attempt to extract the return value
> for a function according to the ABI rules for simple pointer size or less
> types only (no structs, floats, complex etc). So this might help you for the
> simple cases. If you were to implement this command you would want to add a
> new "return" subcommand in the "thread" multi-word command. In the "Execute"
> function of the new "return" command you would want to evaluate an
> expression an store the result, set a breakpoint at the return address,
> install a breakpoint callback and run and hit the breakpoint, then try and
> instert the expression result into the appropriate location (you would need
> to modify the "ABI::GetReturnValue(...)" to fill in the "value" param more
> completely with the location of the return type.
> > >> > >
> > >> > > Greg Clayton
> > >> > >
> > >> > >
> > >> > > I implemented a thread return command, which works (right now) for
> integers and pointers, for i386 and x86-64. The command has some caveats
> (like the ones discussed here), but it works (at least) for a few simple
> examples in C.
> > >> > >
> > >> > > "thread return <expr>" returns the result of evaluating that
> expression. I'm not casting the expression, so there may be some problems
> (especially when returning floating point types is implemented).
> > >> > >
> > >> > > But…
> > >> > > We have no idea if the compiler generated a stackframe for this
> function or not. We may be returning from two functions, and not one.
> > >> > > We have no ideia if the compiler changed the calling conventions
> for this code.
> > >> > > We don't know about the callee-saved registers (I suppose there
> isn't a way to find out the epilogue of the function… Especially since it
> may be mixed with "regular code")
> > >> > >
> > >> > > There are a lot more issues for C++ code (e.g: calling dtors).
> > >> > >
> > >> > > I also have some problems updating the state lldb thinks the
> thread is in.
> > >> > >
> > >> > > "register read pc" won't read the real value
> > >> > > "thread backtrace" doesn't get updated.
> > >> > >
> > >> > > How can I fix that? I am also looking for comments on stuff to
> fix/improve.
> > >> > >
> > >> > > I also have some tests (a directory to put in lldb/test/).
> > >> > >
> > >> > > Regards,
> > >> > >
> > >> > >   Filipe Cabecinhas
> > >> > >
> > >> > > P.S: Converting between a ValueObject object and
> > >> > >
> <thread-return.patch><thread_return.zip>_______________________________________________
> > >> > > lldb-dev mailing list
> > >> > > lldb-dev at cs.uiuc.edu
> > >> > > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
> > >> >
> > >> >
> > >>
> > >>
> > >>
> > >>
> > >>
> <frame_return.zip><frame-return.patch>_______________________________________________
> > >>
> > >> lldb-dev mailing list
> > >> lldb-dev at cs.uiuc.edu
> > >> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
> > >
> > > Enrico Granata
> > > ✆ 408.974.5572 | ✉ egranata@.com
> > >
> > >
> > >
> > >
> > >
> > >
> > > _______________________________________________
> > > lldb-dev mailing list
> > > lldb-dev at cs.uiuc.edu
> > > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
> >
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20110729/28ec7ead/attachment.html>


More information about the lldb-dev mailing list