jingham added a comment.
I addressed the individual concerns in the comments. There were a couple of
overall points:
1. Could we avoid adding AddLocation by having the callback return a list of
addresses to set breakpoints. I actually like directly saying "Set me a
location there" and I have another use for the return value. So I'd prefer to
keep that as it it. But I'm up for being convinced if you have a strong reason.
2. Making some lldb_private -> SB object constructors public. The other option
is to friend the SWIGPythonCreateScriptedBreakpointResolver to these classes.
I think friend classes are uglier, but I don't have a strong feeling about this.
3. Names for callbacks. I was mostly following the convention that Enrico
seems to have used in the past. If we are going to remove underscores we
should get rid of them for all the functions you are supposed to provide. In
my mind the underscores were to make the functions we are forcing you to
provide less likely to collide with normal function names. But if that doesn't
seem a valuable enough goal, I'll happily dump them.
================
Comment at: include/lldb/API/SBBreakpoint.h:26-27
+ SBBreakpoint(const lldb::BreakpointSP &bp_sp);
+
~SBBreakpoint();
----------------
clayborg wrote:
> Why does this need to be public?
See the reply in LLDBSwigPythonCreateScriptedBreakpointResolver...
================
Comment at: include/lldb/API/SBStructuredData.h:26-27
+
+ SBStructuredData(lldb_private::StructuredDataImpl *impl);
~SBStructuredData();
----------------
clayborg wrote:
> Why does this need to be public?
See the reply in LLDBSwigPythonCreateScriptedBreakpointResolver...
================
Comment at: include/lldb/API/SBSymbolContext.h:29-30
+ SBSymbolContext(const lldb_private::SymbolContext *sc_ptr);
+
~SBSymbolContext();
----------------
clayborg wrote:
> Why does this need to be public?
See the reply in LLDBSwigPythonCreateScriptedBreakpointResolver...
================
Comment at: include/lldb/lldb-enumerations.h:260-267
+ eSearchDepthInvalid = 0,
+ eSearchDepthTarget,
eSearchDepthModule,
eSearchDepthCompUnit,
eSearchDepthFunction,
eSearchDepthBlock,
eSearchDepthAddress,
----------------
clayborg wrote:
> Since this is public API we shouldn't change the enumeration values as this
> can cause problems with LLDBRPC.framework. Change eSearchDepthInvalid to be
> -1 and leave all other enums the same (including not renaming
> kNumSearchDepthKinds)?
This was not public API before this checkin. Before that it was an enum in an
lldb_private class (Searcher). So there aren't any compatibility issues with
other uses.
================
Comment at:
packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py:4
+class Resolver:
+ got_files = 0
+ def __init__(self, bkpt, extra_args, dict):
----------------
clayborg wrote:
> Do you want this to be a class global? Seems like this belongs as an actual
> member variable and should be initialized in the constructor
This is just for testing purposes, this would not be good general practice. I
want a way to discover whether, when the __get_depth__ call returns Module, the
search callback gets called at the module depth and ditto for CompUnit.
However, I have no way in the test to get my hands on the specific Python
instantiation for a given breakpoint resolver, so I can't ask it questions.
But I can query class statics. So I have the instance record how it was called
in the global, and then I can assert it in the test. I only use this in the
initial breakpoint setting - because I know that only one
ScriptedBreakpointResolver is going to get to run then. If you tried to use
it, for instance, on module load it clearly wouldn't work. But it serves the
testing purposes.
I didn't intend this to be a model, I'll make an example for the examples
directory that doesn't have this testing specific goo.
================
Comment at:
packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py:5-7
+ def __init__(self, bkpt, extra_args, dict):
+ self.bkpt = bkpt
+ self.extra_args = extra_args
----------------
clayborg wrote:
> Might be better to not do any work of consequence in the constructor and
> maybe only give the breakpoint as the only arg? Maybe something like:
> ```
> def __init__(self, bkpt):
> self.bkpt = bkpt
> self.args = None
>
> def initialize(self, args):
> self.args = args
> # Check args and return an SBError if they are bad
> return lldb.SBError()
> ```
>
> This allows you to reject the arguments if they are invalid
>
There isn't currently a way for a breakpoint to fail to be made. Right now we
really only have breakpoints that find no locations. So that is a concept we'd
have to add before this was really useful. I think that's a good idea but its
out of scope for what I have time for with this checkin.
But even when we do that, I'd prefer to have an optional is_valid method on the
Python class, and you would check the args in the constructor and if you didn't
like them you would return false for is_valid. The reason for that is that I'd
like to keep the interface for people writing these dingi as simple as
possible. We aren't ever going to call __init__ w/o calling initialize so the
separation doesn't really meaningfully postpone work. And I'd rather not make
people define two methods if they don't have to.
Doing it the way I suggested, you only HAVE to write the init, and validating
is optional so you don't have to do anything if you don't need to.
================
Comment at:
packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py:9
+
+ def __callback__(self, sym_ctx):
+ sym_name = "not_a_real_function_name"
----------------
clayborg wrote:
> Do we want this to be named something besides the callback operator?
I was back and forth on that. This is an object whose job is to provide a
search callback. So it seemed like calling the callback "search_callback" was
redundant. But I don't have a strong feeling about that. It there something
you think would be clearer?
================
Comment at:
packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py:20-23
+ if sym_ctx.module.IsValid():
+ sym = sym_ctx.module.FindSymbol(sym_name, lldb.eSymbolTypeCode)
+ if sym.IsValid():
+ self.bkpt.AddLocation(sym.GetStartAddress())
----------------
clayborg wrote:
> Why do we need to manually add the breakpoint here? Can we just return True
> or False from this function to ok the symbol context? Or is the idea that we
> might move the address around a bit or add multiple locations give a single
> symbol context?
The latter. If your resolver returns "Module" as its depth, it will get called
ONCE per module, with the Symbol Context containing that module and nothing
below it. But you might very well want to make more than one breakpoint
location in that module. So we can't use a True or False.
I thought about having the callback return a vector of addresses, which I would
then turn into breakpoints, but to tell the truth getting that to work through
the generic Script & ScriptPython interfaces was more trouble than it was worth.
================
Comment at:
packages/Python/lldbsuite/test/functionalities/breakpoint/scripted_bkpt/resolver.py:28-31
+class ResolverModuleDepth(Resolver):
+ def __get_depth__ (self):
+ return lldb.eSearchDepthModule
+
----------------
clayborg wrote:
> Seems like "__get_depth__" should just be a normal method name. The double
> underscore indicates this function is private. Any reason this needs to be
> private?
I never really knew what the logic for these names in other similar constructs
was. I had assumed that the double underscores were to make the names unlikely
to collide with other common names more than to indicate they are private.
\_\_callback\_\_
is no more or less private than \_\_get_depth\_\_, so if we remove the
underscores we should do so for both. I don't have a strong feeling here
except that it does seem useful to keep the names we require from colliding
with other common names folks might use.
================
Comment at: scripts/Python/python-wrapper.swig:358
+
+ lldb::SBBreakpoint *bkpt_value = new lldb::SBBreakpoint(breakpoint_sp);
+
----------------
clayborg wrote:
> Isn't the code generated by this internal to LLDB? Would be nice to not have
> to make the shared pointer constructor for lldb::SBBreakpoint public if
> possible?
I didn't see much harm in making it public. It won't go into the Python API
(since I didn't add it to the .i file) and it is clearly something you can't
make from the SB API layer in C++ since you can't get your hands on the
internal object.
The other option was to friend LLDBSwigPythonCreateScriptedBreakpointResolver
to SBBreakpoint & SBStructuredData. That seemed to me uglier, but I don't have
a strong opinion. If you prefer the friend route I'm happy to make that change.
================
Comment at: scripts/interface/SBBreakpoint.i:229-232
+ // Can only be called from a ScriptedBreakpointResolver...
+ SBError
+ AddLocation(SBAddress &address);
+
----------------
clayborg wrote:
> Do we enforce the limitation mentioned in the comment? If not, then remove
> the comment? Else it would be great if this wasn't public. One solution to
> avoid making the function public would be to have the Resolver.__callback__
> function return a list of lldb.SBAddress() objects. The internal LLDB code
> that made the callback call could then add the locations to the breakpoint
> itself from inside LLDB's private layer?
I do enforce the restriction (around line 507 in the SBBreakpoint.cpp). I even
return a helpful error if you try to misuse it.
As we both noted, the other option is to return a list of SBAddress objects.
I was intending to use the return value to allow you to pop up one level in the
search. That's useful if you want to have the Searcher do the CompUnit
iteration for you, so you return CompUnit for the depth, but then you find the
comp unit you were looking for in this module, you can return false to indicate
that you are done with this level of iteration. Then the Searcher would "pop
up one level" - i.e. move on to the next module. This isn't fully hooked up
yet, but that was my plan for the callback return.
I also think this makes what you are doing in the Resolver less magical - you
are directly adding locations rather than handing out a list of addresses.
That seems clearer to me.
And (though this is less important) it was also just a PITN to make passing the
list back work through the Script -> PythonScript API's, so unless you really
object to this, I'd rather do it the way it is currently done. Seems to me
making these scripting interfaces - which we are going to have to pipe through
any language we ultimately support - as simple as possible is not a bad
principle...
I could also change the name to "AddLocationInScriptedResolver" to make it
clear this isn't a general purpose function, if that would make things clearer.
================
Comment at: scripts/interface/SBStringList.i:42
Clear ();
+
};
----------------
clayborg wrote:
> remove whitespace change
Oops... Will do when I answer the other concerns.
Repository:
rLLDB LLDB
https://reviews.llvm.org/D51830
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits