> On Sep 27, 2016, at 1:09 PM, Daniel Austin Noland via lldb-dev 
> <lldb-dev@lists.llvm.org> wrote:
> 
> I have been giving study to the private and public classes for 
> break/watchpoints and I have some ideas for how to improve them.  I am 
> looking for comments from the community on this now to avoid wasted work and 
> invite suggestion for improvements and any objections you may have.
> 
> Some problems with things as they stand:
> 
> 1. The Watchpoint and SBWatchpoint classes share very little implementation 
> with the Breakpoint and SBBreakpoint classes.  Both Breakpoint and Watchpoint 
> inherit from Stoppoint, but that class provides very little functionality and 
> not much of an interface. This is both a waste and a potential hazard (in the 
> sense that we run the risk of allowing breakpoints and watchpoints to evolve 
> in parallel thus complicating the API and making things more difficult to 
> merge later).
> 2. The SBWatchpoint class lacks feature parity with SBBreakpoint (e.g. no 
> callback implementation in SBWatchpoint).

It would be great to add any needed features internally (lldb_private::*) and 
in the public API (lldb::*).

> 3. The Breakpoint class has grown an ecosystem of support classes which are 
> unnecessarily specific to it.  For example, I don't see a huge reason to 
> maintain a totally distinct implementation for BreakpointList and 
> WatchpointList.

Internally we can use virtual functions and have the list be a list of some 
shared base class, that is fine. I don't believe we export the lists across the 
public API so that shouldn't be a problem.

> 4. All of these classes are "old school" (not necessarily bad, but 
> potentially a problem).  For example:
>  a. lots of const char* running around.

Feel free to use llvm::StringRef internally (lldb_private namespace), but not 
in the public API. Anything in the "lldb" namespace can't change as we maintain 
backward compatibility. The main gist in the public API:
- no inheritance
- fixed ivars that never change that are either one of: std::shared_ptr, 
std::unique_ptr, or raw pointer.
- no virtual functions
- can't remove functions, you can add, but not remove or change. If you need to 
change, just add an overloaded version with different args.


>  b. DISALLOW_COPY_AND_ASSIGN(BreakpointEventData) to make ctors and such 
> private rather than using ctor() = delete (which provides better compiler 
> errors)

Change the DISALLOW_COPY_AND_ASSIGN macro. Done.

>  c. use of Error& args in function signatures as opposed to 
> Expected<ReturnType>.

Not sure I would tackle this. It would need to happen everywhere and would need 
to not lose any lldb_private::Error functionality.

>  d. callback implementation uses function pointers (an ever confusing topic, 
> especially for new programmers) where I think we could use templated methods 
> (or just a parent Callback class) to significant effect.

Internally fine, but the public API needs a simple function pointer. I don't 
see the need to require templates.
> 5. Confusing or simply wrong documentation (e.g. 
> Breakpoint::ResolveBreakpointInModules has arguments marked as @param[in] 
> when the description of those arguments clearly indicates that they will be 
> the output of the function).

Feel free to fix.

> 6. We simply don't have a Finishpoint class (triggers callback at the 
> conclusion of the function or scope)
> 
> My plan:
> 
> I would like to refactor this in a few phases.
> 
> Phase 1: Low hanging fruit
> --------------------------
> 
> * Kick as much functionality as is reasonable from Breakpoint up to 
> Stoppoint.  At a minimum I would expand the Stoppoint API to include features 
> which should logically be available to Breakpoint, Watchpoint, a hypothetical 
> Finishpoint, and any future *point class.  I would also try to refactor the 
> Breakpoint support classes (e.g. BreakpointID) to derive from a new class 
> (i.e. StoppointID) and kick functionality up the chain there as well.  This 
> would include methods like GetDescription, SetOptions, GetOptions, AddName, 
> and so on.

fine
> 
> * Review and clean the source docs

fine

> 
> * Expand test coverage where that seems easy (perhaps there are tests hiding 
> somewhere I didn't see?)

fine
> 
> I would try to break private APIs minimally if at all.  SB api will not be 
> broken.

No worries, improve the internals as much as you want as long as the SB APIs do 
not change.

> 
> This should go a long ways toward resolving problems 1, 2, 3, and 5.
> 
> Phase 2: Restructure / Modernize the Private API / Implementation
> -----------------------------------------------------------------
> 
> * Change Error& out parameters to Expected<ReturnType>.

I am fine trying this out on a few classes like Watchpoint internally to see 
how we like it. 

> * Get rid of all the const char* vars / args in favor of a better string type 
> (which?)

StringRef is fine as long as the ownership is never assumed to transfer, so 
these are perfect for arguments, but not for storing a reference to a string 
that is passed in as an argument inside an instance variable of a class. So 
"const char *" in the public API, and llvm::StringRef internally is fine.

> * Prefer explicitly deleted copy ctor / assignments over multiline macro 
> DISALLOW_COPY_AND_ASSIGN

Just change the macro. Do that quickly as a separate change list if you want as 
we will OK that right away.

> * Try to reduce the (perhaps excessive) use of friendship between the support 
> classes.  For instance, is it necessary to give BreakpointLocation access to 
> private data members from BreakpointLocationList, Process, BreakpointSite, 
> and StopInfoBreakpoint?  Wouldn't it be better to expand the functionality of 
> those other classes?

Feel free to give us patches, we can review these on a case by case basis.
> 
> A more significant change could be a rewrite of the callback functionality.
> 
> There are some problems with the way callbacks are implemented in terms of 
> maintainability and extensibility.  I think that using templates and simple 
> inheritance we could shift to using callback objects instead of function 
> pointers.  I have a crude code sketch of this plan in the works now, and I 
> will submit that if there is interest in this idea.  Essentially, the idea is 
> to let the user define their own Breakpoint or Watchpoint (or whatever) child 
> class which overrides a pure virtual run method from a parent 
> StoppointCallback templated class.  The template parameter of 
> StoppointCallback would allow us to define a std::unique_ptr<UserData> member 
> where the user can hang any data they want for the callback.  That saves us 
> from void pointers (which I find very awkward).
> 
> template <class UserData>
> class StoppointCallback {
> private:
>   std::unique_ptr<UserData> m_data;
> // ...
> };

I would switch to use std::function internally so we can use lambdas. I don't 
see the need to templatize anything since you can do almost anything with 
function objects and lambdas, both which work in place of a std::function. No 
need to invent anything. We didn't have C++11 and C++14 back when this was 
first coded, so we didn't use it back then. Public APIs will need to use 
standard function callbacks. So "std::*" or "llvm::*" in the public API.

> I also think that such a decision requires significant thought before we pull 
> that trigger.  It does constitute a significant addition to the SB api, tho I 
> don't think it would break the SB api per se since we can always use 
> overloading and template specialization to keep the old functionality.  On 
> the other hand, ABI compatibility may be a problem.  I don't know that much 
> about SWIG or the needs of LLDB from a ABI stability perspective, so please 
> speak up if I'm suggesting something crazy.

No templates in the public API please. 
> 
> That said, it is somewhat difficult to keep the API consistent between 
> Breakpoint and Watchpoint using function pointers; the signature associated 
> with each will differ (e.g. Watchpoint should provide old and new values of 
> the subject variable, while that does not apply to Breakpoint at all).  I 
> welcome any suggestions which allow us to avoid logic duplication.  My goto 
> just happens to be templates here.

Not sure why they are better. Again, use std::function internally will buy us 
labmdas, function pointers, and function object support, and in the public API 
we must keep it simple and use function pointers.

> 
> Doing even a subset of phase 2 would go a long ways toward fixing problem 4.
> 
> Phase 3: Expanded Feature Set
> -----------------------------
> 
> I would love to see these features:
> 
> * Watch variables from a function in every scope of that function OR in only 
> select invocations.  Perhaps this already exists, but I can only get it to 
> watch from a particular scope.

You would run out of watchpoints so quickly these would probably not be very 
useful. Most things we use have 2 - 4 watchpoints at most. If you watched every 
instance it would quickly run out. What should happen when it runs out of 
resources? Just stop?

> * Better (read functional) remote GDB server break / watch.  As has been 
> disused in other threads, this is not really easy but is very desirable.  For 
> instance, I would very much like to see lldb play nice with valgrind's vgdb 
> server as it offers some amazing break / watch functionality.  As of today I 
> need to do a great many hacks to make that work properly.

If something does support infinite watchpoints, we should be able to take 
advantage of that and your case above could just work.

> * Finishpoints.  This just seems obvious. (problem 6)

no problems with adding this once we have other support.

> * GDB style tracepoints.  This may be very difficult but it seems very 
> desirable.

I don't know these, but I know Jim does.

Watchpoints are in need of some serious work, so I am happy to see someone 
willing to dive in. I think you have a pretty good idea of where we stand now, 
let me know what you think of my comments.

Greg Clayton

_______________________________________________
lldb-dev mailing list
lldb-dev@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev

Reply via email to