[lldb-dev] break on exceptions/windows

Greg Clayton via lldb-dev lldb-dev at lists.llvm.org
Mon Apr 4 11:30:58 PDT 2016


> On Apr 4, 2016, at 11:24 AM, Zachary Turner <zturner at google.com> wrote:
> 
> It seems like we already have some precedent for conditional command arguments.  For example:
> 
> (lldb) help platform process list
> ...
>        -u <unsigned-integer> ( --uid <unsigned-integer> )
>             [POSIX] Find processes that have a matching user ID.
> 
> So on Windows this argument doesn't make sense.  Could we make an argument that is conditional on the *target* rather than the host?  Then, for example, you could have something like this:
> 
> (lldb) help break set
> ...
>        --code <hex-integer> ( --code <hex-integer> )
>             [Windows Target] Break when the exception with code <code> is raised.
> 
> How to plumb this to the ProcessWindows plugin is an open question, but should be mostly mechanical.

This is like my suggestion of:

(lldb) breakpoint set --exception-code 0x40010005

The code can be passed to the current Platform along with the current target:

Error Platform::SetExceptionBreakpointWithExceptionCode (lldb_private::Target *target, uint64_t exception_code);

The process can be extracted from the target when the breakpoint needs to be resolved.


> On Mon, Apr 4, 2016 at 11:17 AM Jim Ingham <jingham at apple.com> wrote:
> Interesting.
> 
> For the other windows exceptions, could we do something abstract like:
> 
> (lldb) break set --platform <data>
> 
> (-P for short) to set a "platform breakpoint", where "data" is a string that the current platform will understand, but the breakpoint machinery doesn't have to.
> 
> The way breakpoints work internally is that somebody provides a "BreakpointResolver" subclass which gets called when anything interesting happens in the program (rerun, shared library load, etc).  It's the BreakpointResolver's job to add locations to the breakpoint, describe itself and the like.  But this is a fairly abstract interface, and it wouldn't be hard to have a Platform function that got passed "data" and returned a breakpoint resolver to turn on the watch for these exceptions.
> 
> Then when the breakpoint gets set, the model is Breakpoints have "BreakpointLocations" which each add one place a stop might occur: a "BreakpointSite".  The division between Sites & Locations is because two logically different Locations could map to the same physical Site.  Then the Sites are used at the lowest level to map a stop reason back into the breakpoint(s) that caused it.  To date, the only BreakpointSites are PC based, so the BreakpointList gets asked "is there a site at this PC".  But that all happens in the process plugins, so it wouldn't be hard to map other stop reasons to particular sites.  The lower layers of the process (e.g. ProcessGDBRemote) figure out which site maps to the stop reason, and makes a StopInfoBreakpoint with that BreakpointSite.  And after that the Site -> Location -> Breakpoint logic is done w/o much care how the Site actually works.
> 
> 
> WRT language exceptions in specific, in lldb you say:
> 
> (lldb) break set -E c++
> 
> to break on C++ exception throws.  You would say:
> 
> (lldb) break set -E c++ -O <OBJECT_NAME>
> 
> to restrict the exception throw to a particular object type, except I haven't implemented this for anything but Swift errors yet, but it wouldn't be hard to do that.  So regardless of what we do with the other Windows exceptions, we should implement the language exceptions consistently this way at the command line level just to keep things consistent.  But again, once we're able to hand out "BreakpointResolverWindowsExceptions" in general, we could create them on Windows for the C++ ABI as well (another reason you'll probably want a Windows C++ language runtime since it's the itanium ABI that does this job on other platforms.  The object filtering is mostly runtime ABI work - to figure out the thrown exception from the throw site.  But that's just some ABI function that the general matching code would call.
> 
> This would be some work, for sure, but I don't think it would be terribly hard to do.
> 
> Jim
> 
> 
> 
> 
> > On Apr 4, 2016, at 10:46 AM, Zachary Turner <zturner at google.com> wrote:
> >
> > Windows works a little differently.  Windows has the notion of a Windows exception, which the best way I can describe it is like a signal.  But it's an arbitrary 32-bit value, and there are hundreds, if not thousands of different values.  here's a few:
> >
> > 0x40010005   Ctrl+C
> > 0x80000003  Breakpoint (e.g. int 3)
> > 0x80000004  Single Step
> > 0xC0000005  Access violation
> > 0xC000001D  Illegal Instruction
> > 0xC0000095  Integer overflow
> > 0xE06D7363 C++ Exception
> >
> > Note the last one.  It's interesting, because it illustrates that on Windows, C++ exceptions are just Windows exceptions with a different code.  And if you were to implement some other programming language such as swift on Windows, you would probably even do it the same way, by finding an unused exception code and raising it with your language-specific exception context.
> >
> > When any of these happen in the inferior, the debugger gets a notification (called a first-chance exception), and the debugger can decide what to do, such as break into the debugger, or ignore it and pass it on to the application
> >
> > It's possible this makes more sense as a windows specific debugger command, or perhaps a windows specific subcommand of the "break" command that is only available if the selected target is windows.
> >
> > Existing Windows debuggers allow exception breakpoints of this nature through a consistent interface, with the ability to drill down into different types of exceptions.  What I mean is, you can set the debugger to stop on all access violations or all C++ exceptions, but you can get more advanced for C++ exceptions and set an exception when a specific type is thrown (like a std::string, for example).  The debugger would implement this by installing a 0xE06D7363 exception breakpoint, and ignoring any where the type wasn't std::string (by analyzing the context record).
> >
> > So, there is at least one aspect of this work that shares some behavior with how C++ language exceptions might work with clang on non-Windows platforms.  Being able to say "break when a std::string is thrown" is not OS-specific and very useful.
> >
> > But the other aspect is not, and there's not an obvious way to present a consistent interface (e.g. command line command) to the OS-independent functionality across platforms, while also presenting a consistent interface to the OS specific functionality on Windows.
> >
> > On Mon, Apr 4, 2016 at 10:23 AM Jim Ingham <jingham at apple.com> wrote:
> > The exception breakpoints Greg is talking about are language exceptions (C++ throws, Swift Errors and the like.)
> >
> > I don't know what kind of exception you are talking about here, but at least from a command interface standpoint, it would be good to keep alike things that actually are alike, but only if they ARE actually alike.
> >
> > Jim
> >
> > > On Apr 4, 2016, at 10:07 AM, Greg Clayton <gclayton at apple.com> wrote:
> > >
> > > You should talk to Jim Ingham on this. We have special exception breakpoints that we did for Swift and you will want to follow the same methodology. I am not sure what the methodology is so I'm CC'ing Jim so can can comment.
> > >
> > > Greg
> > >> On Apr 4, 2016, at 9:52 AM, Zachary Turner via lldb-dev <lldb-dev at lists.llvm.org> wrote:
> > >>
> > >> Take a look at ProcessWindowsLive.cpp in Plugins/Process/Windows.  There's a function called ProcessWindowsLive::OnDebugException.  If you're working in a fork and you don't intend to upstream any changes, you could just modify the default case of the switch statement there to not return ExceptionResult::SendToApplication.
> > >>
> > >> If you wanted to upstream something, you'd probably want a way to specify what types of exceptions to break on.  For this you'd need to implement a new command so that you could do something like "break set --exception 0xC0000005" and pass that information to the ProcessWindowsLive plugin somehow, so that it could decide when to break and when to pass it on to the application for a second chance.
> > >>
> > >> On Mon, Apr 4, 2016 at 8:26 AM Carlo Kok <ck at remobjects.com> wrote:
> > >>
> > >>
> > >> Op 2016-04-04 om 16:00 schreef Zachary Turner:
> > >>> Not possible currently, although it wouldn't be too hard to add. Would
> > >>> be a welcome feature if you are interested
> > >>
> > >>
> > >> I'm (obviously?) interested. But wouldn't know where to start.
> > >>
> > >> --
> > >> Carlo Kok
> > >> RemObjects Software
> > >> _______________________________________________
> > >> lldb-dev mailing list
> > >> lldb-dev at lists.llvm.org
> > >> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
> > >
> >
> 



More information about the lldb-dev mailing list