This is an archive of the discontinued LLVM Phabricator instance.

[LLDB][GUI] Add Process Attach form
ClosedPublic

Authored by OmarEmaraDev on Jul 8 2021, 1:31 PM.

Details

Summary

This patch adds a form window to attach a process, either by PID or by
name. This patch also adds support for dynamic field visibility such
that the form delegate can hide or show certain fields based on some
conditions.

Diff Detail

Event Timeline

OmarEmaraDev created this revision.Jul 8 2021, 1:31 PM
OmarEmaraDev requested review of this revision.Jul 8 2021, 1:32 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 8 2021, 1:32 PM

I initially created two forms for attach by name and attach by PID, because the options were divided between them. Today I tried to reimplement that such that it is a single form with a choices field at the top that determines if it is by name or PID. The fields are then shown or hidden based on that enum. Additionally, other fields can control the visibility of other fields, for instance, the "Include existing processes" field. I think it works fine and the UX looks good. Here is an example, what do you think?

clayborg requested changes to this revision.Jul 12 2021, 10:39 AM
clayborg added inline comments.
lldb/source/Core/IOHandlerCursesGUI.cpp
1921

Do these actually need to be shared pointers? They can probably become std::unique_ptr<T> objects and the FieldDelegateSP would then become FieldDelegateUP after defining it as a unique_ptr

2199

Spelling issue I missed before

2300

I am guessing that the first item in the list is always selected? Might be nice to provide a way for AddChoicesField to select a different item as the default selection with another optional parameter that is the index of the item that is to be selected. Doesn't have to happen in this diff, just thought of it and wanted to mention this.

2301

remove space

2302

I would be nice if we can eventually auto complete the PID by using the platform to get a list of processes. Sometimes we are not attached to a remote platform, but we are always attached to the host platform and should be able to get a list of process IDs. A new form could be popped up with all of the process details and allowing the user to filter processes with a TextField, then a ChoicesField that contains all valid processes the user could attach to with the pid, process name and possibly other details in the text for each choice. This doesn't need to be done now, but it would be a good extra functionality step to complete later if you get everything done on your list.

2303

remove space

2304

If we have a target, it might be nice to auto populate this field with the basename of the target's main executable.

2305

remove space

2306

Might be nice to iterate over all process plug-ins and make this into a ChoicesField where the first entry is "<default>" and the rest are actual plug-in names. The names can easily be retrieved using:

static const char *GetProcessPluginNameAtIndex(uint32_t idx);

from PluginManager.h

2307

remove space

2346

We might want to pop up a dialog here asking the user if they want to kill or detach since we have a GUI. In the "process attach" command we confirm with the user if the terminal is interactive.
A few ways we can do this:

  • popup a form asking the user to kill/detach/cancel when the user hits submit on this form
  • pop up the dialog before even showing the this form and asking the user to kill or detach, then show this form after that has been handled
  • not allow the Process->Attach to happen by disabling the menu item when a process is running.
2367

We should select the target in he debugger here so that all GUI commands work correctly after this call if they ask the debugger for its selected target.

m_debugger.GetTargetList().SetSelectedTarget(...);
2420–2421

You shouldn't need to do this since you already called ProcessAttachInfo::SetContinueOnceAttached(true) on the attach_info. LLDB should take care of this for you already I think.

This revision now requires changes to proceed.Jul 12 2021, 10:39 AM
OmarEmaraDev marked 10 inline comments as done.
  • Use unique pointers for field delegates.
  • Fix typos in Select methods.
  • Set the process name to the main executable name by default.
  • Turn plugin name into a choice field.
  • Update debugger target if a new one was created.
  • Remove superfluous continue operation.
OmarEmaraDev planned changes to this revision.Jul 13 2021, 4:09 AM

Currently working on the detach/kill form.

lldb/source/Core/IOHandlerCursesGUI.cpp
2346

I think the first option is the best, because it delays this decision at the very end giving the user as much time as possible to cancel attaching without altering the debugger state.

2420–2421

In the command code, there is this snippet of code at the end, so I though it might be necessary:

// This supports the use-case scenario of immediately continuing the
// process once attached.
if (m_options.attach_info.GetContinueOnceAttached())
  m_interpreter.HandleCommand("process continue", eLazyBoolNo, result);
  • Add kill/detach form.
  • Fix forms with no fields.
OmarEmaraDev marked an inline comment as done.Jul 13 2021, 8:06 AM

Updated UI:

Kill/Detach form.

clayborg requested changes to this revision.Jul 13 2021, 11:53 AM
clayborg added inline comments.
lldb/source/Core/IOHandlerCursesGUI.cpp
1842

You don't want to return a unique_ptr here, if you do something like:

FieldDelegateUP field_up = form->GetField(1);

You have now given away the one reference to this field to the local variable and it will destruct the item when the local goes out of scope.

Easy solution: just return a pointer, not a unique_ptr. The FormDelegate owns all of its fields, so it is ok to hand out a pointer as others should temporarily use the FieldDelegate. Also we should bounds check "field_index".

1986
2153–2154
2160
2177
2209–2210
2216

No need to use a std::unique_ptr here, and GetField should return a pointer as mentioned above.

2233–2234
2273
2297

When we have interaction, we should allow the user to select kill or detach. The GetShouldDetach is only for when the user doesn't interact. Can we use a ChoicesField for this with the two options? We can even go a step further and add three options: "Detach", "Detach (stopped)", and "Kill". This is easy since lldb_private::Process has this option on detach:

Status Process::Detach(bool keep_stopped);

When you detach with "keep_stopped" set to true the process will not resume. This allows another debugger to be attached, or someone to run another tool on the process in its suspended state.

2323

Does anyone remove the sub window if the user cancels this dialog?

2341–2342

most people when attaching won't ever specify the plug-in names. I wonder if we should include an extra boolean field that enables this? Maybe:

m_show_plugin_field = AddBooleanField("Show advanced settings.", false);

And then show/hide any settings that aren't commonly used like the "Plugin Name" field?

2388–2394

While loop might be easier here?

2417

Is the form for the kill/detach done by the time it reaches this code? If so, what if the user cancels the Kill/Detach dialog? Can we return false here if the user cancels?

This revision now requires changes to proceed.Jul 13 2021, 11:53 AM
OmarEmaraDev marked 10 inline comments as done.
  • Return raw pointers instead of unique ones.
  • Add Show Advance Settings option.
  • Allow detaching and killing at the same time.
  • Allow detaching while keeping process stopped.
  • Handle review comments.

Two actions with an option:

lldb/source/Core/IOHandlerCursesGUI.cpp
1842

I see, I though returning it as a reference wouldn't case such issues.

2297

I think this might be a good place to add two actions with possible parameters, let me know if you think this would be a good idea.

2323

Yes. This is done in WindowDelegateHandleChar of the FormWindowDelegate.

2341–2342

This what I do for the launch and target creation forms. In this case, I didn't think it was worth it because it was just one field. But now that it is a choice field that takes a bit more space, maybe it would be a good idea to do this here as well.

2417

No, the return boolean here essentially denotes that a form for killing/detaching was spawned and that the attach form shouldn't continue executing. Once the user executes an action or cancels, the user will end up in the same attach from, where the user can execute attach again where it will succeed without the kill/detach dialog.

I can't think of a way to make the form block execution of another form until it is done without resorting to complicated trickery.

clayborg requested changes to this revision.Jul 13 2021, 3:47 PM

I like the new detach/kill dialog as it incorporates many of your features that you added to the forms! Very close, just a few minor issues and this will be good to go.

lldb/source/Core/IOHandlerCursesGUI.cpp
1842

You are correct unless the caller of the function doesn't use a reference. All of the call sites you had in here were using references, so there wasn't an issue. But if someone else comes along and actually wrote code like the snipped I posted above, it would transfer ownership and that would be bad.

2048–2051
2417

Ok, thanks for the explanation. It makes sense.

2421

Should be easy to verify if it is needed or not. If it is, we will need to add it back.

This revision now requires changes to proceed.Jul 13 2021, 3:47 PM
OmarEmaraDev marked an inline comment as done.
  • Manually continue if needed.
lldb/source/Core/IOHandlerCursesGUI.cpp
2421

Looks like it is actually needed. I added it it back.

clayborg accepted this revision.Jul 15 2021, 2:32 PM

Looks good!

This revision is now accepted and ready to land.Jul 15 2021, 2:32 PM
This revision was landed with ongoing or failed builds.Jul 15 2021, 3:12 PM
This revision was automatically updated to reflect the committed changes.