#pragma once #include "backend/debug_backend.h" #include #include #include #include #include #include #include #include "util/dag.h" namespace dbgui::backend { struct LLDBBackend : Backend { struct RegSet { std::string set_name; // map from debugger reg idx to frontend reg idx // std::vector idx_map; std::vector names; // TODO: make this data structure not garbage std::vector> values; }; struct Thread { uint64_t id; uint64_t ip; uint64_t stop_extra; ThreadStopReason stop_reason; std::string name; std::string cur_display_fn; }; struct Frame { uint64_t ip; size_t lldb_idx; std::string display_name; }; struct Breakpoint { size_t id; lldb::break_id_t lldb_id; }; struct CachedDataRes { struct DisasmInfo { uint64_t range_start, range_end; std::vector bytes; }; data::result::Node node; // bool child_node; bool no_delete_on_src_delete = false; size_t src_id; // invalid = size_t::MAX // std::variant extra_info; }; struct Local { lldb::SBValue lldb_val; std::optional cached_node; }; struct VarCacheEntry { // for globals/statics compare location + expr path (bc unions) // for others compare location + expr path + symctx (without line entry) // TODO: this will repeatedly retrieve cyclic values // probably bad so maybe detect this some other way mby without expr paths? // but then we need to cache types somehow... lldb::SBValue lldb_val; lldb::SBSymbolContext sym_ctx; std::string expr_path; // NOTE: when used is set to true, this means that the var was // diffed this step already and will no longer be so careful with changing this bool used; bool global_or_static; // need to only compare compilation unit and module bool address_of_or_pointer; std::optional cached_node; }; // TODO: source_init_file: false LLDBBackend(std::string filename, bool stop_at_entry); virtual ~LLDBBackend(); void start() override; bool step_into(bool source_step) override; bool step_over(bool source_step) override; bool step_out() override; void cont() override; void pause() override; void add_data_node(const data::source::Node &) override; void remove_data_node(uint64_t id) override; void add_breakpoint(uint64_t addr, size_t id) override; bool add_breakpoint(const char *file, uint32_t line, size_t id) override; void remove_breakpoint(size_t id) override; void select_thread(uint16_t idx); void select_frame(uint16_t idx); private: void run_msg_loop(); void wait_for_debug_events(); void handle_state_change(lldb::StateType); void prepare_proc_info(BackToFront::InitialProcessInfo &, std::vector &); void dump_threads(); void dump_variables(); void check_reg_changes(); void check_thread_changes(); void check_frame_changes(); void check_data_changes(); // TODO: func to clear locals if they are no longer requested // node_id, did_change // std::pair build_locals(); data::type_info::TypeID build_type_from_lldb_type(lldb::SBType &); bool is_type_equal(data::type_info::TypeID, lldb::SBType &); std::optional build_nodes_for_var(lldb::SBValue &val, std::vector &to_send, bool address_of_or_pointer); data::result::NodeIdx build_nodes_for_var_uncached(lldb::SBValue &, std::vector &to_send, bool address_of_or_pointer); void build_nodes_for_var_cached(lldb::SBValue &, data::result::NodeIdx cache_idx, std::vector &to_send, bool address_of_or_pointer); void clear_unused_vars_from_cache(); void delete_node_and_childs(uint16_t); data::result::NodeIdx get_free_data_node(); std::optional> calc_data_res(const data::source::Node &, std::vector &data_res); std::string _filename; lldb::SBDebugger _instance; std::mutex _data_lock; lldb::SBTarget _target; std::optional _process; std::thread _msg_thread; // process state bool _first_run = true; bool _stop_at_entry = false; lldb::break_id_t _hidden_main_bp; TargetState _state = TargetState::stopped; std::vector _reg_sets = {}; std::vector _threads = {}; std::vector _frames = {}; uint16_t _selected_frame = 0; uint16_t _selected_thread = 0; util::DAG _data_dag = {}; std::vector _data_nodes = {}; std::vector _dag_linear = {}; bool _dag_linear_valid = false; // util::DAG _data_res_dag = {}; std::vector> _data_res = {}; std::unordered_map _data_src_id_to_res_idx = {}; std::vector _locals = {}; std::optional _locals_node = {}; std::optional _last_frame = {}; std::vector< std::optional>> _types = {}; std::vector _var_cache{}; // std::unordered_map _src_id_to_data_idx = {}; // std::vector _cached_data_results = {}; std::vector _breakpoints = {}; }; } // namespace dbgui::backend