Add auto-run functionality via the `-run` flag and refactor target launch logic

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2026-01-17 02:36:18 +0100
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2026-01-17 02:36:18 +0100
Commit 38f07f6e9d29a85f13ea37950d36fe88d34cd5c5 (patch)
-rw-r--r-- README.md 8
-rw-r--r-- tdbg.cpp 103
2 files changed, 65 insertions, 46 deletions
diff --git a/README.md b/README.md
...
40
./tdbg ./example -b example.c:54 -b example.c:60
40
./tdbg ./example -b example.c:54 -b example.c:60
41
```
41
```
42
  
42
  
  
43
Example with auto run:
  
44
  
  
45
```sh
  
46
./tdbg -run ./example
  
47
./tdbg -run ./example arg1 arg2 arg3
  
48
./tdbg -run ./example -e MYENV=qwe -- arg1 arg2 arg3
  
49
```
  
50
  
43
### Interactive Commands
51
### Interactive Commands
44
  
52
  
45
| Key | Action                                                            |
53
| Key | Action                                                            |
...
diff --git a/tdbg.cpp b/tdbg.cpp
...
665
  
665
  
666
	int ty = y + 2;
666
	int ty = y + 2;
667
	int tx = x + 3;
667
	int tx = x + 3;
668
	
668
  
669
	auto d = [&](const std::string& key, const std::string& desc) {
669
	auto d = [&](const std::string& key, const std::string& desc) {
670
		draw_text(tx, ty, TB_YELLOW | TB_BOLD, TB_DEFAULT, key);
670
		draw_text(tx, ty, TB_YELLOW | TB_BOLD, TB_DEFAULT, key);
671
		draw_text(tx + 13, ty, TB_DEFAULT, TB_DEFAULT, desc);
671
		draw_text(tx + 13, ty, TB_DEFAULT, TB_DEFAULT, desc);
...
712
	draw_text(1, height - 1, TB_BLACK, TB_WHITE, state_str);
712
	draw_text(1, height - 1, TB_BLACK, TB_WHITE, state_str);
713
}
713
}
714
  
714
  
  
715
SBProcess launch_target(SBTarget& target, const std::string& target_path, const std::vector<std::string>& debuggee_args, const std::vector<std::string>& target_env, std::vector<std::string>& log_buffer) {
  
716
	if (target.GetNumBreakpoints() == 0) {
  
717
		SBBreakpoint bp = target.BreakpointCreateByName("main");
  
718
		if (bp.IsValid() && bp.GetNumLocations() > 0) {
  
719
			log_msg(log_buffer, "No breakpoints. Added breakpoint at 'main'");
  
720
		} else {
  
721
			log_msg(log_buffer, "No breakpoints. Failed to add breakpoint at 'main'");
  
722
		}
  
723
	}
  
724
	log_msg(log_buffer, "Launching...");
  
725
  
  
726
	std::vector<const char*> launch_argv;
  
727
	launch_argv.push_back(target_path.c_str());
  
728
	for (const auto& arg : debuggee_args) {
  
729
		launch_argv.push_back(arg.c_str());
  
730
	}
  
731
	launch_argv.push_back(nullptr);
  
732
  
  
733
	std::vector<const char*> launch_env;
  
734
	for (const auto& env : target_env) {
  
735
		launch_env.push_back(env.c_str());
  
736
	}
  
737
	launch_env.push_back(nullptr);
  
738
  
  
739
	SBLaunchInfo launch_info(launch_argv.data());
  
740
	launch_info.SetEnvironmentEntries(launch_env.data(), true);
  
741
	launch_info.SetWorkingDirectory(".");
  
742
  
  
743
	SBError error;
  
744
	SBProcess process = target.Launch(launch_info, error);
  
745
  
  
746
	if (!process.IsValid() || error.Fail()) {
  
747
		std::string err_msg = "Launch failed";
  
748
		if (error.GetCString()) {
  
749
			err_msg += ": ";
  
750
			err_msg += error.GetCString();
  
751
		}
  
752
		log_msg(log_buffer, err_msg);
  
753
	} else {
  
754
		log_msg(log_buffer, "Launched");
  
755
	}
  
756
	return process;
  
757
}
  
758
  
715
int main(int argc, char** argv) {
759
int main(int argc, char** argv) {
716
	std::vector<std::string> target_env;
760
	std::vector<std::string> target_env;
717
	std::vector<std::string> startup_breakpoints;
761
	std::vector<std::string> startup_breakpoints;
718
	std::vector<std::string> debuggee_args;
762
	std::vector<std::string> debuggee_args;
719
	std::string target_path;
763
	std::string target_path;
  
764
	bool auto_run = false;
720
  
765
  
721
	for (int i = 1; i < argc; ++i) {
766
	for (int i = 1; i < argc; ++i) {
722
		std::string arg = argv[i];
767
		std::string arg = argv[i];
...
724
			target_env.push_back(argv[++i]);
769
			target_env.push_back(argv[++i]);
725
		} else if (arg == "-b" && i + 1 < argc) {
770
		} else if (arg == "-b" && i + 1 < argc) {
726
			startup_breakpoints.push_back(argv[++i]);
771
			startup_breakpoints.push_back(argv[++i]);
  
772
		} else if (arg == "-run") {
  
773
			auto_run = true;
727
		} else if (arg == "--") {
774
		} else if (arg == "--") {
728
			for (int j = i + 1; j < argc; ++j) {
775
			for (int j = i + 1; j < argc; ++j) {
729
				debuggee_args.push_back(argv[j]);
776
				debuggee_args.push_back(argv[j]);
...
737
	}
784
	}
738
  
785
  
739
	if (target_path.empty()) {
786
	if (target_path.empty()) {
740
		std::cerr << "Usage: " << argv[0] << " [-e KEY=VALUE] [-b BREAKPOINT] ... <target_executable> [-- arg1 arg2 ...]\n";
787
		std::cerr << "Usage: " << argv[0] << " [-e KEY=VALUE] [-b BREAKPOINT] [-run] ... <target_executable> [-- arg1 arg2 ...]\n";
741
		return 1;
788
		return 1;
742
	}
789
	}
743
  
790
  
...
767
		}
814
		}
768
	}
815
	}
769
  
816
  
770
	SBProcess process; 
817
	SBProcess process;
771
	SBThread thread;
818
	if (auto_run) {
  
819
		process = launch_target(target, target_path, debuggee_args, target_env, log_buffer);
  
820
	}
772
  
821
  
  
822
	SBThread thread;
773
	TermboxGuard tb_guard;
823
	TermboxGuard tb_guard;
774
  
824
  
775
	bool running = true;
825
	bool running = true;
...
848
					if (ev.ch == 'q') {
898
					if (ev.ch == 'q') {
849
						running = false;
899
						running = false;
850
					} else if (ev.ch == 'r') {
900
					} else if (ev.ch == 'r') {
851
						if (!process.IsValid()) {
901
						if (!process.IsValid() || process.GetState() == eStateExited) {
852
							if (target.GetNumBreakpoints() == 0) {
902
							process = launch_target(target, target_path, debuggee_args, target_env, log_buffer);
853
								SBBreakpoint bp = target.BreakpointCreateByName("main");
  
854
								if (bp.IsValid() && bp.GetNumLocations() > 0) {
  
855
									log_msg(log_buffer, "No breakpoints. Added breakpoint at 'main'");
  
856
								} else {
  
857
									log_msg(log_buffer, "No breakpoints. Failed to add breakpoint at 'main'");
  
858
								}
  
859
							}
  
860
							log_msg(log_buffer, "Launching...");
  
861
  
  
862
							std::vector<const char*> launch_argv;
  
863
							launch_argv.push_back(target_path.c_str());
  
864
							for (const auto& arg : debuggee_args) {
  
865
								launch_argv.push_back(arg.c_str());
  
866
							}
  
867
							launch_argv.push_back(nullptr);
  
868
  
  
869
							std::vector<const char*> launch_env;
  
870
							for (const auto& env : target_env) {
  
871
								launch_env.push_back(env.c_str());
  
872
							}
  
873
							launch_env.push_back(nullptr);
  
874
  
  
875
							SBLaunchInfo launch_info(launch_argv.data());
  
876
							launch_info.SetEnvironmentEntries(launch_env.data(), true);
  
877
							launch_info.SetWorkingDirectory(".");
  
878
  
  
879
							SBError error;
  
880
							process = target.Launch(launch_info, error);
  
881
  
  
882
							if (!process.IsValid() || error.Fail()) {
  
883
								std::string err_msg = "Launch failed";
  
884
								if (error.GetCString()) {
  
885
									err_msg += ": ";
  
886
									err_msg += error.GetCString();
  
887
								}
  
888
								log_msg(log_buffer, err_msg);
  
889
							} else {
  
890
								log_msg(log_buffer, "Launched");
  
891
							}
  
892
						} else {
903
						} else {
893
							log_msg(log_buffer, "Already running");
904
							log_msg(log_buffer, "Already running");
894
						}
905
						}
...
916
								case 'c': process.Continue(); break;
927
								case 'c': process.Continue(); break;
917
							}
928
							}
918
						}
929
						}
919
						
930
  
920
						if (ev.key == TB_KEY_ARROW_LEFT && (ev.mod & TB_MOD_CTRL)) {
931
						if (ev.key == TB_KEY_ARROW_LEFT && (ev.mod & TB_MOD_CTRL)) {
921
							layout_config.sidebar_width = std::min(width - 20, layout_config.sidebar_width + 2);
932
							layout_config.sidebar_width = std::min(width - 20, layout_config.sidebar_width + 2);
922
						} else if (ev.key == TB_KEY_ARROW_RIGHT && (ev.mod & TB_MOD_CTRL)) {
933
						} else if (ev.key == TB_KEY_ARROW_RIGHT && (ev.mod & TB_MOD_CTRL)) {
...