add counter for analyze
This commit is contained in:
parent
b6db1c8623
commit
0988c35b11
@ -120,6 +120,71 @@ class SymbolAnalysisProgressDialog(tk.Toplevel):
|
|||||||
self.set_status("Analysis failed or was aborted. Check log. You can close this window.")
|
self.set_status("Analysis failed or was aborted. Check log. You can close this window.")
|
||||||
|
|
||||||
|
|
||||||
|
class SymbolListViewerDialog(tk.Toplevel): # NUOVA DIALOG PER VISUALIZZARE LISTE
|
||||||
|
"""A simple dialog to view a list of symbols."""
|
||||||
|
def __init__(self, parent: tk.Widget, symbols: List[str], title: str = "Symbol List"):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.title(title)
|
||||||
|
|
||||||
|
parent_x = parent.winfo_x()
|
||||||
|
parent_y = parent.winfo_y()
|
||||||
|
parent_width = parent.winfo_width()
|
||||||
|
parent_height = parent.winfo_height()
|
||||||
|
width = 500
|
||||||
|
height = 450
|
||||||
|
x = parent_x + (parent_width // 2) - (width // 2)
|
||||||
|
y = parent_y + (parent_height // 2) - (height // 2)
|
||||||
|
self.geometry(f'{width}x{height}+{x}+{y}')
|
||||||
|
|
||||||
|
self.transient(parent)
|
||||||
|
self.grab_set()
|
||||||
|
|
||||||
|
main_frame = ttk.Frame(self, padding="10")
|
||||||
|
main_frame.pack(expand=True, fill=tk.BOTH)
|
||||||
|
main_frame.rowconfigure(1, weight=1)
|
||||||
|
main_frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
|
filter_frame = ttk.Frame(main_frame)
|
||||||
|
filter_frame.grid(row=0, column=0, sticky="ew", pady=(0, 5))
|
||||||
|
ttk.Label(filter_frame, text="Filter:").pack(side=tk.LEFT, padx=(0,5))
|
||||||
|
self.filter_var = tk.StringVar()
|
||||||
|
self.filter_var.trace_add("write", self._apply_filter)
|
||||||
|
ttk.Entry(filter_frame, textvariable=self.filter_var, width=40).pack(side=tk.LEFT, expand=True, fill=tk.X)
|
||||||
|
|
||||||
|
self.listbox = tk.Listbox(main_frame, selectmode=tk.SINGLE)
|
||||||
|
self.listbox.grid(row=1, column=0, sticky="nsew")
|
||||||
|
|
||||||
|
scrollbar_y = ttk.Scrollbar(main_frame, orient=tk.VERTICAL, command=self.listbox.yview)
|
||||||
|
scrollbar_y.grid(row=1, column=1, sticky="ns")
|
||||||
|
self.listbox.configure(yscrollcommand=scrollbar_y.set)
|
||||||
|
|
||||||
|
scrollbar_x = ttk.Scrollbar(main_frame, orient=tk.HORIZONTAL, command=self.listbox.xview)
|
||||||
|
scrollbar_x.grid(row=2, column=0, sticky="ew")
|
||||||
|
self.listbox.configure(xscrollcommand=scrollbar_x.set)
|
||||||
|
|
||||||
|
self._original_symbols = sorted(symbols)
|
||||||
|
self._populate_listbox(self._original_symbols)
|
||||||
|
|
||||||
|
button_frame = ttk.Frame(main_frame, padding=(0, 10, 0, 0))
|
||||||
|
button_frame.grid(row=3, column=0, columnspan=2, sticky="e")
|
||||||
|
ttk.Button(button_frame, text="Close", command=self.destroy).pack()
|
||||||
|
|
||||||
|
self.protocol("WM_DELETE_WINDOW", self.destroy)
|
||||||
|
|
||||||
|
def _populate_listbox(self, symbols_to_show: List[str]):
|
||||||
|
self.listbox.delete(0, tk.END)
|
||||||
|
for item in symbols_to_show:
|
||||||
|
self.listbox.insert(tk.END, item)
|
||||||
|
|
||||||
|
def _apply_filter(self, *args):
|
||||||
|
filter_text = self.filter_var.get().lower()
|
||||||
|
if not filter_text:
|
||||||
|
self._populate_listbox(self._original_symbols)
|
||||||
|
else:
|
||||||
|
filtered_list = [s for s in self._original_symbols if filter_text in s.lower()]
|
||||||
|
self._populate_listbox(filtered_list)
|
||||||
|
|
||||||
|
|
||||||
class ProfileManagerWindow(tk.Toplevel):
|
class ProfileManagerWindow(tk.Toplevel):
|
||||||
def __init__(self, parent: 'GDBGui', app_settings: 'AppSettings'):
|
def __init__(self, parent: 'GDBGui', app_settings: 'AppSettings'):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
@ -127,7 +192,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self.app_settings: 'AppSettings' = app_settings
|
self.app_settings: 'AppSettings' = app_settings
|
||||||
|
|
||||||
self.title("Profile Manager")
|
self.title("Profile Manager")
|
||||||
self.geometry("1050x700")
|
self.geometry("1050x750") # Aumentata leggermente l'altezza per i nuovi widget
|
||||||
|
|
||||||
self.transient(parent)
|
self.transient(parent)
|
||||||
self.grab_set()
|
self.grab_set()
|
||||||
@ -145,6 +210,12 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self._current_profile_target_exe_details_label_var = tk.StringVar(value="Target: N/A")
|
self._current_profile_target_exe_details_label_var = tk.StringVar(value="Target: N/A")
|
||||||
self._current_profile_analysis_status_label_var = tk.StringVar(value="Symbol Analysis: Not Performed")
|
self._current_profile_analysis_status_label_var = tk.StringVar(value="Symbol Analysis: Not Performed")
|
||||||
self.progress_dialog: Optional[SymbolAnalysisProgressDialog] = None
|
self.progress_dialog: Optional[SymbolAnalysisProgressDialog] = None
|
||||||
|
|
||||||
|
# StringVars per i conteggi
|
||||||
|
self.functions_count_var = tk.StringVar(value="Functions: N/A")
|
||||||
|
# self.variables_count_var = tk.StringVar(value="Globals: N/A") # Futuro
|
||||||
|
# self.types_count_var = tk.StringVar(value="Types: N/A") # Futuro
|
||||||
|
# self.sources_count_var = tk.StringVar(value="Sources: N/A") # Futuro
|
||||||
|
|
||||||
self._load_profiles_from_settings()
|
self._load_profiles_from_settings()
|
||||||
self._create_widgets()
|
self._create_widgets()
|
||||||
@ -183,15 +254,15 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
def _create_widgets(self) -> None:
|
def _create_widgets(self) -> None:
|
||||||
main_frame = ttk.Frame(self, padding="10")
|
main_frame = ttk.Frame(self, padding="10")
|
||||||
main_frame.pack(expand=True, fill=tk.BOTH)
|
main_frame.pack(expand=True, fill=tk.BOTH)
|
||||||
main_frame.columnconfigure(0, weight=1, minsize=250)
|
main_frame.columnconfigure(0, weight=1, minsize=250)
|
||||||
main_frame.columnconfigure(1, weight=3)
|
main_frame.columnconfigure(1, weight=3)
|
||||||
main_frame.rowconfigure(0, weight=1)
|
main_frame.rowconfigure(0, weight=1)
|
||||||
main_frame.rowconfigure(1, weight=0)
|
main_frame.rowconfigure(1, weight=0)
|
||||||
|
|
||||||
left_pane = ttk.Frame(main_frame)
|
left_pane = ttk.Frame(main_frame)
|
||||||
left_pane.grid(row=0, column=0, sticky="nsew", padx=(0, 10))
|
left_pane.grid(row=0, column=0, sticky="nsew", padx=(0, 10))
|
||||||
left_pane.rowconfigure(0, weight=1)
|
left_pane.rowconfigure(0, weight=1)
|
||||||
left_pane.rowconfigure(1, weight=0)
|
left_pane.rowconfigure(1, weight=0)
|
||||||
left_pane.columnconfigure(0, weight=1)
|
left_pane.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
profiles_list_frame = ttk.LabelFrame(left_pane, text="Profiles", padding="5")
|
profiles_list_frame = ttk.LabelFrame(left_pane, text="Profiles", padding="5")
|
||||||
@ -220,7 +291,8 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
right_pane.grid(row=0, column=1, sticky="nsew")
|
right_pane.grid(row=0, column=1, sticky="nsew")
|
||||||
right_pane.rowconfigure(0, weight=0)
|
right_pane.rowconfigure(0, weight=0)
|
||||||
right_pane.rowconfigure(1, weight=0)
|
right_pane.rowconfigure(1, weight=0)
|
||||||
right_pane.rowconfigure(2, weight=1)
|
right_pane.rowconfigure(2, weight=0) # Riga per Conteggi Simboli
|
||||||
|
right_pane.rowconfigure(3, weight=1) # Riga per Azioni di Debug
|
||||||
right_pane.columnconfigure(0, weight=1)
|
right_pane.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
details_form_frame = ttk.LabelFrame(right_pane, text="Profile Details", padding="10")
|
details_form_frame = ttk.LabelFrame(right_pane, text="Profile Details", padding="10")
|
||||||
@ -241,7 +313,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self.program_params_entry = ttk.Entry(details_form_frame, textvariable=self.program_params_var, state=tk.DISABLED)
|
self.program_params_entry = ttk.Entry(details_form_frame, textvariable=self.program_params_var, state=tk.DISABLED)
|
||||||
self.program_params_entry.grid(row=2, column=1, columnspan=2, sticky="ew", padx=5, pady=3)
|
self.program_params_entry.grid(row=2, column=1, columnspan=2, sticky="ew", padx=5, pady=3)
|
||||||
|
|
||||||
analysis_control_frame = ttk.LabelFrame(right_pane, text="Symbol Analysis", padding="10")
|
analysis_control_frame = ttk.LabelFrame(right_pane, text="Symbol Analysis Status & Control", padding="10")
|
||||||
analysis_control_frame.grid(row=1, column=0, sticky="new", pady=5)
|
analysis_control_frame.grid(row=1, column=0, sticky="new", pady=5)
|
||||||
analysis_control_frame.columnconfigure(0, weight=1)
|
analysis_control_frame.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
@ -254,14 +326,32 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self.analyse_symbols_button = ttk.Button(analysis_control_frame, text="Analyse Target Symbols", command=self._trigger_symbol_analysis, state=tk.DISABLED)
|
self.analyse_symbols_button = ttk.Button(analysis_control_frame, text="Analyse Target Symbols", command=self._trigger_symbol_analysis, state=tk.DISABLED)
|
||||||
self.analyse_symbols_button.grid(row=1, column=1, sticky="e", padx=5, pady=2)
|
self.analyse_symbols_button.grid(row=1, column=1, sticky="e", padx=5, pady=2)
|
||||||
|
|
||||||
|
symbols_summary_frame = ttk.LabelFrame(right_pane, text="Analyzed Symbols Summary", padding="10")
|
||||||
|
symbols_summary_frame.grid(row=2, column=0, sticky="new", pady=5)
|
||||||
|
symbols_summary_frame.columnconfigure(0, weight=1)
|
||||||
|
symbols_summary_frame.columnconfigure(1, weight=0)
|
||||||
|
|
||||||
|
row_s = 0
|
||||||
|
ttk.Label(symbols_summary_frame, textvariable=self.functions_count_var).grid(row=row_s, column=0, sticky="w", padx=5, pady=2)
|
||||||
|
self.view_functions_button = ttk.Button(symbols_summary_frame, text="View...", command=self._view_analyzed_functions, state=tk.DISABLED, width=8)
|
||||||
|
self.view_functions_button.grid(row=row_s, column=1, padx=(10,5), pady=2, sticky="w")
|
||||||
|
row_s += 1
|
||||||
|
|
||||||
|
# Placeholder per futuri conteggi e bottoni (Iterazione 3)
|
||||||
|
# ttk.Label(symbols_summary_frame, textvariable=self.variables_count_var).grid(row=row_s, column=0, sticky="w", padx=5, pady=2)
|
||||||
|
# self.view_variables_button = ttk.Button(symbols_summary_frame, text="View...", command=self._view_analyzed_variables, state=tk.DISABLED, width=8)
|
||||||
|
# self.view_variables_button.grid(row=row_s, column=1, padx=(10,5), pady=2, sticky="w")
|
||||||
|
# row_s += 1
|
||||||
|
# ... (e così via per tipi e sorgenti)
|
||||||
|
|
||||||
actions_ui_frame = ttk.LabelFrame(right_pane, text="Debug Actions", padding="10")
|
actions_ui_frame = ttk.LabelFrame(right_pane, text="Debug Actions", padding="10")
|
||||||
actions_ui_frame.grid(row=2, column=0, sticky="nsew", pady=5)
|
actions_ui_frame.grid(row=3, column=0, sticky="nsew", pady=5) # Riga 3
|
||||||
actions_ui_frame.rowconfigure(0, weight=1)
|
actions_ui_frame.rowconfigure(0, weight=1)
|
||||||
actions_ui_frame.columnconfigure(0, weight=1)
|
actions_ui_frame.columnconfigure(0, weight=1)
|
||||||
actions_ui_frame.columnconfigure(1, weight=0)
|
actions_ui_frame.columnconfigure(1, weight=0)
|
||||||
actions_ui_frame.columnconfigure(2, weight=0)
|
actions_ui_frame.columnconfigure(2, weight=0)
|
||||||
|
|
||||||
self.actions_listbox = tk.Listbox(actions_ui_frame, exportselection=False, selectmode=tk.SINGLE, height=8)
|
self.actions_listbox = tk.Listbox(actions_ui_frame, exportselection=False, selectmode=tk.SINGLE, height=6)
|
||||||
self.actions_listbox.grid(row=0, column=0, sticky="nsew", pady=5, padx=(0,5))
|
self.actions_listbox.grid(row=0, column=0, sticky="nsew", pady=5, padx=(0,5))
|
||||||
self.actions_listbox.bind("<<ListboxSelect>>", self._on_action_select_in_listbox)
|
self.actions_listbox.bind("<<ListboxSelect>>", self._on_action_select_in_listbox)
|
||||||
|
|
||||||
@ -273,11 +363,11 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
action_buttons_frame.grid(row=0, column=2, sticky="ns", padx=(5,0), pady=5)
|
action_buttons_frame.grid(row=0, column=2, sticky="ns", padx=(5,0), pady=5)
|
||||||
action_btn_width = 8
|
action_btn_width = 8
|
||||||
self.add_action_button = ttk.Button(action_buttons_frame, text="Add...", command=self._add_action, state=tk.DISABLED, width=action_btn_width)
|
self.add_action_button = ttk.Button(action_buttons_frame, text="Add...", command=self._add_action, state=tk.DISABLED, width=action_btn_width)
|
||||||
self.add_action_button.pack(fill=tk.X, pady=2)
|
self.add_action_button.pack(fill=tk.X, pady=2, anchor="n")
|
||||||
self.edit_action_button = ttk.Button(action_buttons_frame, text="Edit...", command=self._edit_action, state=tk.DISABLED, width=action_btn_width)
|
self.edit_action_button = ttk.Button(action_buttons_frame, text="Edit...", command=self._edit_action, state=tk.DISABLED, width=action_btn_width)
|
||||||
self.edit_action_button.pack(fill=tk.X, pady=2)
|
self.edit_action_button.pack(fill=tk.X, pady=2, anchor="n")
|
||||||
self.remove_action_button = ttk.Button(action_buttons_frame, text="Remove", command=self._remove_action, state=tk.DISABLED, width=action_btn_width)
|
self.remove_action_button = ttk.Button(action_buttons_frame, text="Remove", command=self._remove_action, state=tk.DISABLED, width=action_btn_width)
|
||||||
self.remove_action_button.pack(fill=tk.X, pady=2)
|
self.remove_action_button.pack(fill=tk.X, pady=2, anchor="n")
|
||||||
|
|
||||||
bottom_buttons_frame = ttk.Frame(main_frame)
|
bottom_buttons_frame = ttk.Frame(main_frame)
|
||||||
bottom_buttons_frame.grid(row=1, column=0, columnspan=2, sticky="sew", pady=(10,0))
|
bottom_buttons_frame.grid(row=1, column=0, columnspan=2, sticky="sew", pady=(10,0))
|
||||||
@ -347,14 +437,13 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
if not (0 <= index < len(self._profiles_data)):
|
if not (0 <= index < len(self._profiles_data)):
|
||||||
self._clear_profile_form()
|
self._clear_profile_form()
|
||||||
self._selected_profile_index = None
|
self._selected_profile_index = None
|
||||||
# _update_analysis_status_display() è chiamato da _clear_profile_form
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self._selected_profile_index = index
|
self._selected_profile_index = index
|
||||||
profile = self._profiles_data[index]
|
profile = self._profiles_data[index]
|
||||||
|
|
||||||
self.profile_name_var.set(profile.get("profile_name", ""))
|
self.profile_name_var.set(profile.get("profile_name", ""))
|
||||||
self.target_exe_var.set(profile.get("target_executable", "")) # Triggera _on_target_exe_changed_in_form
|
self.target_exe_var.set(profile.get("target_executable", ""))
|
||||||
self.program_params_var.set(profile.get("program_parameters", ""))
|
self.program_params_var.set(profile.get("program_parameters", ""))
|
||||||
|
|
||||||
self._populate_actions_listbox()
|
self._populate_actions_listbox()
|
||||||
@ -368,15 +457,12 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self.profiles_listbox.see(index)
|
self.profiles_listbox.see(index)
|
||||||
|
|
||||||
self.add_action_button.config(state=tk.NORMAL)
|
self.add_action_button.config(state=tk.NORMAL)
|
||||||
# _update_analysis_status_display() è chiamato da _on_target_exe_changed_in_form
|
|
||||||
# o dovrebbe essere chiamato esplicitamente qui se il set di target_exe_var non lo fa sempre.
|
|
||||||
# Per sicurezza, lo chiamiamo esplicitamente dopo aver impostato tutte le var.
|
|
||||||
self._update_analysis_status_display()
|
self._update_analysis_status_display()
|
||||||
|
|
||||||
|
|
||||||
def _clear_profile_form(self) -> None:
|
def _clear_profile_form(self) -> None:
|
||||||
self.profile_name_var.set("")
|
self.profile_name_var.set("")
|
||||||
self.target_exe_var.set("") # Triggera _on_target_exe_changed_in_form
|
self.target_exe_var.set("")
|
||||||
self.program_params_var.set("")
|
self.program_params_var.set("")
|
||||||
self._populate_actions_listbox()
|
self._populate_actions_listbox()
|
||||||
self._enable_profile_form_editing(False)
|
self._enable_profile_form_editing(False)
|
||||||
@ -392,7 +478,6 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self.target_exe_entry.config(state=state)
|
self.target_exe_entry.config(state=state)
|
||||||
self.browse_exe_button.config(state=state)
|
self.browse_exe_button.config(state=state)
|
||||||
self.program_params_entry.config(state=state)
|
self.program_params_entry.config(state=state)
|
||||||
# analyse_symbols_button state è gestito da _update_analysis_status_display
|
|
||||||
|
|
||||||
def _update_profile_action_buttons_state(self) -> None:
|
def _update_profile_action_buttons_state(self) -> None:
|
||||||
profile_selected = self._selected_profile_index is not None
|
profile_selected = self._selected_profile_index is not None
|
||||||
@ -409,7 +494,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
parent=self
|
parent=self
|
||||||
)
|
)
|
||||||
if path:
|
if path:
|
||||||
self.target_exe_var.set(path) # Triggera _on_target_exe_changed_in_form
|
self.target_exe_var.set(path)
|
||||||
|
|
||||||
def _save_current_form_to_profile_data(self, profile_index: int) -> bool:
|
def _save_current_form_to_profile_data(self, profile_index: int) -> bool:
|
||||||
if not (0 <= profile_index < len(self._profiles_data)):
|
if not (0 <= profile_index < len(self._profiles_data)):
|
||||||
@ -432,7 +517,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
old_name = target_profile.get("profile_name")
|
old_name = target_profile.get("profile_name")
|
||||||
|
|
||||||
target_profile["profile_name"] = profile_name
|
target_profile["profile_name"] = profile_name
|
||||||
target_profile["target_executable"] = self.target_exe_var.get().strip() # Questo aggiorna il path
|
target_profile["target_executable"] = self.target_exe_var.get().strip()
|
||||||
target_profile["program_parameters"] = self.program_params_var.get()
|
target_profile["program_parameters"] = self.program_params_var.get()
|
||||||
|
|
||||||
self._current_profile_modified_in_form = False
|
self._current_profile_modified_in_form = False
|
||||||
@ -443,15 +528,12 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self.profiles_listbox.insert(profile_index, profile_name)
|
self.profiles_listbox.insert(profile_index, profile_name)
|
||||||
self.profiles_listbox.selection_set(profile_index)
|
self.profiles_listbox.selection_set(profile_index)
|
||||||
|
|
||||||
# Dopo aver salvato il form, lo stato dell'analisi potrebbe dover essere rivalutato
|
|
||||||
# se target_executable è cambiato. _update_analysis_status_display lo farà.
|
|
||||||
self._update_analysis_status_display()
|
self._update_analysis_status_display()
|
||||||
logger.info(f"Profile '{profile_name}' (index {profile_index}) basic details updated.")
|
logger.info(f"Profile '{profile_name}' (index {profile_index}) basic details updated.")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _new_profile(self) -> None:
|
def _new_profile(self) -> None:
|
||||||
if self._selected_profile_index is not None and self._current_profile_modified_in_form:
|
if self._selected_profile_index is not None and self._current_profile_modified_in_form:
|
||||||
# ... (logica gestione modifiche non salvate come prima) ...
|
|
||||||
response = messagebox.askyesnocancel("Unsaved Changes",
|
response = messagebox.askyesnocancel("Unsaved Changes",
|
||||||
f"Profile '{self._profiles_data[self._selected_profile_index].get('profile_name')}' has unsaved changes in the form.\n"
|
f"Profile '{self._profiles_data[self._selected_profile_index].get('profile_name')}' has unsaved changes in the form.\n"
|
||||||
"Do you want to save them before creating a new profile?",
|
"Do you want to save them before creating a new profile?",
|
||||||
@ -462,7 +544,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
elif response is None:
|
elif response is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
new_p = json.loads(json.dumps(DEFAULT_PROFILE)) # Deep copy del template
|
new_p = json.loads(json.dumps(DEFAULT_PROFILE))
|
||||||
|
|
||||||
base_name = "New Profile"
|
base_name = "New Profile"
|
||||||
name_candidate = base_name
|
name_candidate = base_name
|
||||||
@ -489,7 +571,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
return
|
return
|
||||||
|
|
||||||
original_profile = self._profiles_data[self._selected_profile_index]
|
original_profile = self._profiles_data[self._selected_profile_index]
|
||||||
duplicated_profile = json.loads(json.dumps(original_profile)) # Deep copy
|
duplicated_profile = json.loads(json.dumps(original_profile))
|
||||||
|
|
||||||
base_name = f"{original_profile.get('profile_name', 'Profile')}_copy"
|
base_name = f"{original_profile.get('profile_name', 'Profile')}_copy"
|
||||||
name_candidate = base_name
|
name_candidate = base_name
|
||||||
@ -499,9 +581,6 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
name_candidate = f"{base_name}_{count}"
|
name_candidate = f"{base_name}_{count}"
|
||||||
count += 1
|
count += 1
|
||||||
duplicated_profile["profile_name"] = name_candidate
|
duplicated_profile["profile_name"] = name_candidate
|
||||||
# L'analisi dei simboli duplicata si riferirà all'exe originale;
|
|
||||||
# l'utente dovrà rianalizzare se cambia l'exe del profilo duplicato.
|
|
||||||
# L'impostazione del nome del profilo non dovrebbe cancellare symbol_analysis
|
|
||||||
|
|
||||||
self._profiles_data.append(duplicated_profile)
|
self._profiles_data.append(duplicated_profile)
|
||||||
self._profiles_list_changed_overall = True
|
self._profiles_list_changed_overall = True
|
||||||
@ -530,9 +609,9 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self._clear_profile_form()
|
self._clear_profile_form()
|
||||||
else:
|
else:
|
||||||
new_selection_idx = min(idx_to_delete, new_list_size - 1)
|
new_selection_idx = min(idx_to_delete, new_list_size - 1)
|
||||||
if new_selection_idx >= 0: # Assicura che l'indice sia valido
|
if new_selection_idx >= 0:
|
||||||
self._select_profile_by_index(new_selection_idx)
|
self._select_profile_by_index(new_selection_idx)
|
||||||
else: # Se la lista è diventata vuota, pulisci
|
else:
|
||||||
self._clear_profile_form()
|
self._clear_profile_form()
|
||||||
|
|
||||||
|
|
||||||
@ -544,7 +623,6 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
|
|
||||||
profile_names_seen = set()
|
profile_names_seen = set()
|
||||||
for i, profile in enumerate(self._profiles_data):
|
for i, profile in enumerate(self._profiles_data):
|
||||||
# ... (validazione nomi profili e struttura azioni come prima) ...
|
|
||||||
name = profile.get("profile_name", "").strip()
|
name = profile.get("profile_name", "").strip()
|
||||||
if not name:
|
if not name:
|
||||||
messagebox.showerror("Validation Error", f"Profile at index {i} has an empty name.", parent=self)
|
messagebox.showerror("Validation Error", f"Profile at index {i} has an empty name.", parent=self)
|
||||||
@ -572,18 +650,16 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
messagebox.showerror("Save Error", "Could not save profiles to the settings file. Check logs.", parent=self)
|
messagebox.showerror("Save Error", "Could not save profiles to the settings file. Check logs.", parent=self)
|
||||||
|
|
||||||
def _on_closing_button(self) -> None:
|
def _on_closing_button(self) -> None:
|
||||||
# ... (come prima) ...
|
|
||||||
needs_save_prompt = False
|
needs_save_prompt = False
|
||||||
prompt_message = ""
|
prompt_message = ""
|
||||||
if self._selected_profile_index is not None and self._current_profile_modified_in_form:
|
if self._selected_profile_index is not None and self._current_profile_modified_in_form:
|
||||||
needs_save_prompt = True
|
needs_save_prompt = True
|
||||||
# ... (costruzione messaggio)
|
|
||||||
profile_name = self.profile_name_var.get() or self._profiles_data[self._selected_profile_index].get('profile_name', 'current profile')
|
profile_name = self.profile_name_var.get() or self._profiles_data[self._selected_profile_index].get('profile_name', 'current profile')
|
||||||
prompt_message = f"Profile '{profile_name}' has unsaved changes in the form.\n"
|
prompt_message = f"Profile '{profile_name}' has unsaved changes in the form.\n"
|
||||||
|
|
||||||
if self._profiles_list_changed_overall: # Se la lista stessa è cambiata (add/del/rename)
|
if self._profiles_list_changed_overall:
|
||||||
needs_save_prompt = True
|
needs_save_prompt = True
|
||||||
if prompt_message: # Se già c'era un messaggio per il form
|
if prompt_message:
|
||||||
prompt_message += "Additionally, the overall list of profiles (or their content) has changed.\n"
|
prompt_message += "Additionally, the overall list of profiles (or their content) has changed.\n"
|
||||||
else:
|
else:
|
||||||
prompt_message = "The list of profiles (or their content) has changed.\n"
|
prompt_message = "The list of profiles (or their content) has changed.\n"
|
||||||
@ -593,21 +669,15 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
response = messagebox.askyesnocancel("Unsaved Changes", prompt_message, default=messagebox.CANCEL, parent=self)
|
response = messagebox.askyesnocancel("Unsaved Changes", prompt_message, default=messagebox.CANCEL, parent=self)
|
||||||
if response is True:
|
if response is True:
|
||||||
self._save_all_profiles_to_settings()
|
self._save_all_profiles_to_settings()
|
||||||
# Se il salvataggio fallisce, _save_all_profiles_to_settings mostra un errore,
|
elif response is None:
|
||||||
# ma la finestra si chiuderà comunque. Potremmo voler cambiare questo comportamento.
|
|
||||||
elif response is None: # Cancel
|
|
||||||
return
|
return
|
||||||
# Se False (No), procedi a chiudere senza salvare
|
|
||||||
|
|
||||||
if self.progress_dialog and self.progress_dialog.winfo_exists():
|
if self.progress_dialog and self.progress_dialog.winfo_exists():
|
||||||
logger.warning("Closing ProfileManagerWindow while symbol analysis dialog might be open.")
|
logger.warning("Closing ProfileManagerWindow while symbol analysis dialog might be open.")
|
||||||
# Potremmo voler provare a chiudere la dialog di progresso qui, o avvisare.
|
|
||||||
# Per ora, la dialog di progresso gestisce la sua chiusura.
|
|
||||||
|
|
||||||
self.parent_window.focus_set()
|
self.parent_window.focus_set()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
# --- Gestione Azioni (Listbox e Bottoni Azione) ---
|
|
||||||
def _populate_actions_listbox(self) -> None:
|
def _populate_actions_listbox(self) -> None:
|
||||||
self.actions_listbox.delete(0, tk.END)
|
self.actions_listbox.delete(0, tk.END)
|
||||||
self._selected_action_index_in_profile = None
|
self._selected_action_index_in_profile = None
|
||||||
@ -616,7 +686,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
profile = self._profiles_data[self._selected_profile_index]
|
profile = self._profiles_data[self._selected_profile_index]
|
||||||
actions = profile.get("actions", [])
|
actions = profile.get("actions", [])
|
||||||
for i, action in enumerate(actions):
|
for i, action in enumerate(actions):
|
||||||
bp = action.get("breakpoint_location", "N/A")[:30] # Tronca per display
|
bp = action.get("breakpoint_location", "N/A")[:30]
|
||||||
num_vars = len(action.get("variables_to_dump", []))
|
num_vars = len(action.get("variables_to_dump", []))
|
||||||
fmt = action.get("output_format", "N/A")
|
fmt = action.get("output_format", "N/A")
|
||||||
cont = "Yes" if action.get("continue_after_dump", False) else "No"
|
cont = "Yes" if action.get("continue_after_dump", False) else "No"
|
||||||
@ -657,7 +727,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
current_profile["actions"] = []
|
current_profile["actions"] = []
|
||||||
current_profile["actions"].append(new_action_data)
|
current_profile["actions"].append(new_action_data)
|
||||||
self._profiles_list_changed_overall = True
|
self._profiles_list_changed_overall = True
|
||||||
self._current_profile_modified_in_form = True # Il profilo nel form è cambiato
|
self._current_profile_modified_in_form = True
|
||||||
self._populate_actions_listbox()
|
self._populate_actions_listbox()
|
||||||
self.actions_listbox.selection_set(tk.END)
|
self.actions_listbox.selection_set(tk.END)
|
||||||
self._on_action_select_in_listbox()
|
self._on_action_select_in_listbox()
|
||||||
@ -665,6 +735,7 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
def _edit_action(self) -> None:
|
def _edit_action(self) -> None:
|
||||||
if self._selected_profile_index is None or self._selected_action_index_in_profile is None: return
|
if self._selected_profile_index is None or self._selected_action_index_in_profile is None: return
|
||||||
current_profile = self._profiles_data[self._selected_profile_index]
|
current_profile = self._profiles_data[self._selected_profile_index]
|
||||||
|
|
||||||
actions_list = current_profile.get("actions", [])
|
actions_list = current_profile.get("actions", [])
|
||||||
if not (0 <= self._selected_action_index_in_profile < len(actions_list)): return
|
if not (0 <= self._selected_action_index_in_profile < len(actions_list)): return
|
||||||
|
|
||||||
@ -692,9 +763,10 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
|
|
||||||
def _remove_action(self) -> None:
|
def _remove_action(self) -> None:
|
||||||
if self._selected_profile_index is None or self._selected_action_index_in_profile is None: return
|
if self._selected_profile_index is None or self._selected_action_index_in_profile is None: return
|
||||||
# ... (come prima) ...
|
|
||||||
profile = self._profiles_data[self._selected_profile_index]
|
profile = self._profiles_data[self._selected_profile_index]
|
||||||
action_summary_to_delete = self.actions_listbox.get(self._selected_action_index_in_profile)
|
action_summary_to_delete = self.actions_listbox.get(self._selected_action_index_in_profile)
|
||||||
|
|
||||||
if not messagebox.askyesno("Confirm Delete Action",
|
if not messagebox.askyesno("Confirm Delete Action",
|
||||||
f"Are you sure you want to delete this action?\n\n{action_summary_to_delete}",
|
f"Are you sure you want to delete this action?\n\n{action_summary_to_delete}",
|
||||||
parent=self): return
|
parent=self): return
|
||||||
@ -718,28 +790,38 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self._current_profile_target_exe_details_label_var.set("Target: N/A")
|
self._current_profile_target_exe_details_label_var.set("Target: N/A")
|
||||||
self._current_profile_analysis_status_label_var.set("Symbol Analysis: Select a profile.")
|
self._current_profile_analysis_status_label_var.set("Symbol Analysis: Select a profile.")
|
||||||
self.analyse_symbols_button.config(state=tk.DISABLED)
|
self.analyse_symbols_button.config(state=tk.DISABLED)
|
||||||
|
self.functions_count_var.set("Functions: N/A")
|
||||||
|
self.view_functions_button.config(state=tk.DISABLED)
|
||||||
return
|
return
|
||||||
|
|
||||||
profile = self._profiles_data[self._selected_profile_index]
|
profile = self._profiles_data[self._selected_profile_index]
|
||||||
target_exe_from_form = self.target_exe_var.get() # Path attuale nel form
|
target_exe_in_form = self.target_exe_var.get()
|
||||||
|
|
||||||
exe_display_name = os.path.basename(target_exe_from_form) if target_exe_from_form else "N/A"
|
exe_display_name = os.path.basename(target_exe_in_form) if target_exe_in_form else "N/A"
|
||||||
details_text_lines = [f"Target in Form: {exe_display_name}"]
|
details_text_lines = [f"Target in Form: {exe_display_name}"]
|
||||||
status_text = "Symbol Analysis: "
|
status_text = "Symbol Analysis: "
|
||||||
status_color = "blue" # Default
|
status_color = "blue"
|
||||||
|
funcs_count_text = "Functions: N/A"
|
||||||
|
view_funcs_btn_state = tk.DISABLED
|
||||||
|
|
||||||
analysis_button_state = tk.DISABLED
|
analysis_button_state = tk.DISABLED
|
||||||
if target_exe_from_form and os.path.isfile(target_exe_from_form):
|
if target_exe_in_form and os.path.isfile(target_exe_in_form):
|
||||||
analysis_button_state = tk.NORMAL # Abilita se il file nel form esiste
|
analysis_button_state = tk.NORMAL
|
||||||
|
|
||||||
if not target_exe_from_form:
|
if not target_exe_in_form:
|
||||||
status_text += "Target executable not specified in form."
|
status_text += "Target executable not specified in form."
|
||||||
elif not os.path.isfile(target_exe_from_form):
|
elif not os.path.isfile(target_exe_in_form):
|
||||||
status_text += f"Target '{exe_display_name}' not found on disk."
|
status_text += f"Target '{exe_display_name}' not found on disk."
|
||||||
status_color = "red"
|
status_color = "red"
|
||||||
else: # Il file nel form esiste, ora controlla i dati di analisi salvati
|
else:
|
||||||
analysis_data = profile.get("symbol_analysis")
|
analysis_data = profile.get("symbol_analysis")
|
||||||
if analysis_data and isinstance(analysis_data, dict):
|
if analysis_data and isinstance(analysis_data, dict):
|
||||||
|
symbols_dict = analysis_data.get("symbols", {})
|
||||||
|
num_functions = symbols_dict.get("functions_count", 0)
|
||||||
|
funcs_count_text = f"Functions: {num_functions}"
|
||||||
|
if num_functions > 0 :
|
||||||
|
view_funcs_btn_state = tk.NORMAL
|
||||||
|
|
||||||
saved_checksum = analysis_data.get("executable_checksum")
|
saved_checksum = analysis_data.get("executable_checksum")
|
||||||
saved_analysis_ts_str = analysis_data.get("analysis_timestamp")
|
saved_analysis_ts_str = analysis_data.get("analysis_timestamp")
|
||||||
saved_exe_at_analysis = analysis_data.get("analyzed_executable_path", "Unknown")
|
saved_exe_at_analysis = analysis_data.get("analyzed_executable_path", "Unknown")
|
||||||
@ -750,22 +832,28 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
details_text_lines.append(f" Analysis Date: {saved_analysis_ts_str or 'N/A'}")
|
details_text_lines.append(f" Analysis Date: {saved_analysis_ts_str or 'N/A'}")
|
||||||
details_text_lines.append(f" Saved Checksum: {saved_checksum or 'N/A'}")
|
details_text_lines.append(f" Saved Checksum: {saved_checksum or 'N/A'}")
|
||||||
|
|
||||||
current_checksum_for_form_exe = self._calculate_file_checksum(target_exe_from_form)
|
current_checksum_for_form_exe = self._calculate_file_checksum(target_exe_in_form)
|
||||||
details_text_lines.append(f" Current Form Exe Checksum: {current_checksum_for_form_exe or 'N/A (calc failed)'}")
|
details_text_lines.append(f" Current Form Exe Checksum: {current_checksum_for_form_exe or 'N/A (calc failed)'}")
|
||||||
|
|
||||||
if os.path.normpath(saved_exe_at_analysis) != os.path.normpath(target_exe_from_form):
|
if os.path.normpath(saved_exe_at_analysis) != os.path.normpath(target_exe_in_form):
|
||||||
status_text += "TARGET CHANGED since last analysis. RE-ANALYSIS RECOMMENDED."
|
status_text += "TARGET CHANGED since last analysis. RE-ANALYSIS RECOMMENDED."
|
||||||
status_color = "orange red"
|
status_color = "orange red"
|
||||||
|
# Disabilita i bottoni View se il target è cambiato
|
||||||
|
view_funcs_btn_state = tk.DISABLED
|
||||||
elif saved_checksum and current_checksum_for_form_exe and saved_checksum == current_checksum_for_form_exe:
|
elif saved_checksum and current_checksum_for_form_exe and saved_checksum == current_checksum_for_form_exe:
|
||||||
status_text += "Up-to-date."
|
status_text += "Up-to-date."
|
||||||
status_color = "dark green"
|
status_color = "dark green"
|
||||||
elif saved_checksum and current_checksum_for_form_exe and saved_checksum != current_checksum_for_form_exe:
|
elif saved_checksum and current_checksum_for_form_exe and saved_checksum != current_checksum_for_form_exe:
|
||||||
status_text += "EXECUTABLE CHANGED since last analysis. RE-ANALYSIS REQUIRED."
|
status_text += "EXECUTABLE CHANGED since last analysis. RE-ANALYSIS REQUIRED."
|
||||||
status_color = "red"
|
status_color = "red"
|
||||||
|
# Disabilita i bottoni View se l'eseguibile è cambiato
|
||||||
|
view_funcs_btn_state = tk.DISABLED
|
||||||
else: # Checksum mancanti o confronto non possibile
|
else: # Checksum mancanti o confronto non possibile
|
||||||
status_text += "Status unclear. Consider re-analysing."
|
status_text += "Status unclear. Consider re-analysing."
|
||||||
status_color = "orange red"
|
status_color = "orange red"
|
||||||
else: # Nessuna analisi salvata per questo profilo
|
# Disabilita i bottoni View se lo stato è incerto
|
||||||
|
view_funcs_btn_state = tk.DISABLED
|
||||||
|
else: # Nessuna analisi salvata
|
||||||
status_text += "Not performed. Click 'Analyse' to generate."
|
status_text += "Not performed. Click 'Analyse' to generate."
|
||||||
status_color = "blue"
|
status_color = "blue"
|
||||||
|
|
||||||
@ -773,6 +861,9 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
self._current_profile_target_exe_details_label_var.set("\n".join(details_text_lines))
|
self._current_profile_target_exe_details_label_var.set("\n".join(details_text_lines))
|
||||||
self._current_profile_analysis_status_label_var.set(status_text)
|
self._current_profile_analysis_status_label_var.set(status_text)
|
||||||
self.analysis_status_label.config(foreground=status_color)
|
self.analysis_status_label.config(foreground=status_color)
|
||||||
|
|
||||||
|
self.functions_count_var.set(funcs_count_text)
|
||||||
|
self.view_functions_button.config(state=view_funcs_btn_state)
|
||||||
|
|
||||||
def _calculate_file_checksum(self, filepath: str, hash_type: str = "md5") -> Optional[str]:
|
def _calculate_file_checksum(self, filepath: str, hash_type: str = "md5") -> Optional[str]:
|
||||||
if not os.path.isfile(filepath): return None
|
if not os.path.isfile(filepath): return None
|
||||||
@ -821,7 +912,16 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
"executable_timestamp": "N/A",
|
"executable_timestamp": "N/A",
|
||||||
"analysis_timestamp": "N/A",
|
"analysis_timestamp": "N/A",
|
||||||
"gdb_version_info": "N/A",
|
"gdb_version_info": "N/A",
|
||||||
"symbols": {"functions": []}
|
"symbols": {
|
||||||
|
"functions": [],
|
||||||
|
"functions_count": 0,
|
||||||
|
# "global_variables": [], # Per Iterazione 3
|
||||||
|
# "global_variables_count": 0,# Per Iterazione 3
|
||||||
|
# "types": [], # Per Iterazione 3
|
||||||
|
# "types_count": 0, # Per Iterazione 3
|
||||||
|
# "source_files": [], # Per Iterazione 3
|
||||||
|
# "source_files_count": 0 # Per Iterazione 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
analysis_succeeded_overall = False
|
analysis_succeeded_overall = False
|
||||||
|
|
||||||
@ -848,23 +948,31 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
gui_log("WARNING: GDB reported no debugging symbols. Analysis may be limited.")
|
gui_log("WARNING: GDB reported no debugging symbols. Analysis may be limited.")
|
||||||
|
|
||||||
gui_set_status("Fetching GDB version..."); gui_log("Fetching GDB version...")
|
gui_set_status("Fetching GDB version..."); gui_log("Fetching GDB version...")
|
||||||
analysis_data_dict["gdb_version_info"] = temp_gdb_session.get_gdb_version(timeout=command_timeout) or "N/A"
|
gdb_version = temp_gdb_session.get_gdb_version(timeout=command_timeout)
|
||||||
|
analysis_data_dict["gdb_version_info"] = gdb_version if gdb_version else "N/A"
|
||||||
gui_log(f"GDB Version: {analysis_data_dict['gdb_version_info']}")
|
gui_log(f"GDB Version: {analysis_data_dict['gdb_version_info']}")
|
||||||
|
|
||||||
gui_set_status("Fetching function list..."); gui_log("Fetching function list from GDB...")
|
gui_set_status("Fetching function list..."); gui_log("Fetching function list from GDB...")
|
||||||
functions = temp_gdb_session.list_functions(timeout=command_timeout * 3) # Dare più tempo a info functions
|
functions = temp_gdb_session.list_functions(timeout=command_timeout * 4) # Più tempo per info functions
|
||||||
analysis_data_dict["symbols"]["functions"] = functions
|
analysis_data_dict["symbols"]["functions"] = functions
|
||||||
|
analysis_data_dict["symbols"]["functions_count"] = len(functions) # Salva il conteggio
|
||||||
gui_log(f"Found {len(functions)} functions.")
|
gui_log(f"Found {len(functions)} functions.")
|
||||||
|
|
||||||
# Altre analisi (variabili, tipi) verranno qui nelle iterazioni future
|
# --- In future iterations, call methods for other symbols and store counts ---
|
||||||
# analysis_data_dict["symbols"]["global_variables"] = temp_gdb_session.list_global_variables(...)
|
# gui_set_status("Fetching global variables..."); gui_log("Fetching global variables...")
|
||||||
|
# globals_list = temp_gdb_session.list_global_variables(timeout=command_timeout * 2)
|
||||||
|
# analysis_data_dict["symbols"]["global_variables"] = globals_list
|
||||||
|
# analysis_data_dict["symbols"]["global_variables_count"] = len(globals_list)
|
||||||
|
# gui_log(f"Found {len(globals_list)} global variables.")
|
||||||
|
# ... (similarly for types and source_files) ...
|
||||||
|
|
||||||
|
|
||||||
gui_set_status("Calculating file checksum and timestamp..."); gui_log("Calculating file checksum and timestamp...")
|
gui_set_status("Calculating file checksum and timestamp..."); gui_log("Calculating file checksum and timestamp...")
|
||||||
analysis_data_dict["executable_checksum"] = self._calculate_file_checksum(target_exe_path)
|
analysis_data_dict["executable_checksum"] = self._calculate_file_checksum(target_exe_path)
|
||||||
try:
|
try:
|
||||||
mtime = os.path.getmtime(target_exe_path)
|
mtime = os.path.getmtime(target_exe_path)
|
||||||
analysis_data_dict["executable_timestamp"] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(mtime))
|
analysis_data_dict["executable_timestamp"] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(mtime))
|
||||||
except OSError: pass # Lascia N/A
|
except OSError: pass
|
||||||
|
|
||||||
gui_log(f"Checksum (MD5): {analysis_data_dict['executable_checksum'] or 'N/A'}")
|
gui_log(f"Checksum (MD5): {analysis_data_dict['executable_checksum'] or 'N/A'}")
|
||||||
gui_log(f"File Timestamp: {analysis_data_dict['executable_timestamp']}")
|
gui_log(f"File Timestamp: {analysis_data_dict['executable_timestamp']}")
|
||||||
@ -899,19 +1007,50 @@ class ProfileManagerWindow(tk.Toplevel):
|
|||||||
if success:
|
if success:
|
||||||
profile_to_update["symbol_analysis"] = analysis_data
|
profile_to_update["symbol_analysis"] = analysis_data
|
||||||
self._profiles_list_changed_overall = True
|
self._profiles_list_changed_overall = True
|
||||||
self._current_profile_modified_in_form = True # Il contenuto del profilo è cambiato
|
self._current_profile_modified_in_form = True
|
||||||
logger.info(f"Symbol analysis data updated for profile: '{profile_to_update.get('profile_name')}'.")
|
logger.info(f"Symbol analysis data updated for profile: '{profile_to_update.get('profile_name')}'.")
|
||||||
if self.winfo_exists(): # Assicura che la finestra genitore esista ancora
|
if self.winfo_exists():
|
||||||
messagebox.showinfo("Analysis Complete", "Symbol analysis has finished successfully.", parent=self)
|
messagebox.showinfo("Analysis Complete", "Symbol analysis has finished successfully.", parent=self)
|
||||||
else:
|
else:
|
||||||
# Non aggiorniamo symbol_analysis nel profilo se fallisce, ma potremmo salvare dati parziali se utile
|
|
||||||
logger.error(f"Symbol analysis failed for profile: '{profile_to_update.get('profile_name')}'.")
|
logger.error(f"Symbol analysis failed for profile: '{profile_to_update.get('profile_name')}'.")
|
||||||
if self.winfo_exists():
|
if self.winfo_exists():
|
||||||
messagebox.showerror("Analysis Failed", "Symbol analysis did not complete successfully. Check logs.", parent=self)
|
messagebox.showerror("Analysis Failed", "Symbol analysis did not complete successfully. Check logs.", parent=self)
|
||||||
|
|
||||||
if progress_dialog and progress_dialog.winfo_exists():
|
if progress_dialog and progress_dialog.winfo_exists():
|
||||||
progress_dialog.analysis_complete_or_failed(success)
|
progress_dialog.analysis_complete_or_failed(success)
|
||||||
# La dialog ora ha un bottone Close abilitato, l'utente la chiuderà.
|
|
||||||
# Oppure: self.after(2000, lambda: progress_dialog.destroy() if progress_dialog.winfo_exists() else None)
|
|
||||||
|
|
||||||
self._update_analysis_status_display()
|
self._update_analysis_status_display()
|
||||||
|
|
||||||
|
def _view_analyzed_functions(self) -> None:
|
||||||
|
if self._selected_profile_index is None or \
|
||||||
|
not (0 <= self._selected_profile_index < len(self._profiles_data)):
|
||||||
|
messagebox.showinfo("Info", "No profile selected or data available.", parent=self)
|
||||||
|
return
|
||||||
|
|
||||||
|
profile = self._profiles_data[self._selected_profile_index]
|
||||||
|
analysis_data = profile.get("symbol_analysis")
|
||||||
|
|
||||||
|
if not analysis_data or not isinstance(analysis_data.get("symbols"), dict):
|
||||||
|
messagebox.showinfo("No Analysis Data", "No symbol analysis data available for this profile.", parent=self)
|
||||||
|
return
|
||||||
|
|
||||||
|
functions_list = analysis_data["symbols"].get("functions", [])
|
||||||
|
if not functions_list:
|
||||||
|
messagebox.showinfo("No Functions", "No functions found in the last analysis for this profile.", parent=self)
|
||||||
|
return
|
||||||
|
|
||||||
|
target_exe_in_form = self.target_exe_var.get()
|
||||||
|
analyzed_exe_path = analysis_data.get("analyzed_executable_path", "")
|
||||||
|
exe_name_for_title = os.path.basename(target_exe_in_form) if target_exe_in_form else "Unknown Executable"
|
||||||
|
|
||||||
|
is_obsolete = True
|
||||||
|
if os.path.normpath(analyzed_exe_path) == os.path.normpath(target_exe_in_form):
|
||||||
|
current_checksum = self._calculate_file_checksum(target_exe_in_form)
|
||||||
|
saved_checksum = analysis_data.get("executable_checksum")
|
||||||
|
if current_checksum and saved_checksum and current_checksum == saved_checksum:
|
||||||
|
is_obsolete = False
|
||||||
|
|
||||||
|
title_suffix = " (Analysis might be obsolete)" if is_obsolete else ""
|
||||||
|
dialog_title = f"Analyzed Functions for '{exe_name_for_title}'{title_suffix}"
|
||||||
|
|
||||||
|
SymbolListViewerDialog(self, functions_list, title=dialog_title)
|
||||||
6
todo.md
6
todo.md
@ -54,6 +54,12 @@ DEBUG_STRING_TRACE: _serializ
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
questo run funziona
|
||||||
|
(gdb) run /c /t 4:"C:/__Voli/Volo_12_25maggio2025/sar_367-435/_25-05-15-12-22-52_sata_367-n69.out" /b
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Assolutamente sì, la tua idea è eccellente e va nella direzione giusta per rendere l'applicazione molto più potente e user-friendly! Sfruttare le capacità introspettive di GDB per assistere l'utente nella creazione di profili di debug è una funzionalità di grande valore.
|
Assolutamente sì, la tua idea è eccellente e va nella direzione giusta per rendere l'applicazione molto più potente e user-friendly! Sfruttare le capacità introspettive di GDB per assistere l'utente nella creazione di profili di debug è una funzionalità di grande valore.
|
||||||
|
|
||||||
**Concetto Chiave: Introspezione di GDB per l'Assistenza all'Utente**
|
**Concetto Chiave: Introspezione di GDB per l'Assistenza all'Utente**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user