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
- rG0321dbc87e43: [LLDB][GUI] Add Process Attach form
This patch adds a form window to attach a process, either by PID or by
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?
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
Spelling issue I missed before
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.
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.
If we have a target, it might be nice to auto populate this field with the basename of the target's main executable.
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);
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.
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.
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.
- 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.
Currently working on the detach/kill form.
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.
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);
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".
No need to use a std::unique_ptr here, and GetField should return a pointer as mentioned above.
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.
Does anyone remove the sub window if the user cancels this dialog?
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?
While loop might be easier here?
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?
- 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:
I see, I though returning it as a reference wouldn't case such issues.
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.
Yes. This is done in WindowDelegateHandleChar of the FormWindowDelegate.
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.
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.
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.
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.
Ok, thanks for the explanation. It makes sense.
Should be easy to verify if it is needed or not. If it is, we will need to add it back.