@@ -26,108 +26,115 @@ namespace rr {
2626// Special-sauce macros defined by rr when launching the gdb client,
2727// which implement functionality outside of the gdb remote protocol.
2828// (Don't stare at them too long or you'll go blind ;).)
29- static const string& gdb_rr_macros () {
30- static string s;
31-
32- if (s.empty ()) {
33- stringstream ss;
34- ss << DebuggerExtensionCommandHandler::gdb_macros ()
35- // gdb warns about redefining inbuilt commands, silence that by
36- // wrapping it in python code
37- << " python gdb.execute('define jump\\ nrr-denied jump\\ nend')\n "
38- << " python gdb.execute('define restart\\ nrun c$arg0\\ nend')\n "
39- << " document restart\n "
40- << " restart at checkpoint N\n "
41- << " checkpoints are created with the 'checkpoint' command\n "
42- << " end\n "
43- << " define seek-ticks\n "
44- << " run t$arg0\n "
45- << " end\n "
46- << " document seek-ticks\n "
47- << " restart at given ticks value\n "
48- << " end\n "
49- // In gdb version "Fedora 7.8.1-30.fc21", a raw "run" command
50- // issued before any user-generated resume-execution command
51- // results in gdb hanging just after the inferior hits an internal
52- // gdb breakpoint. This happens outside of rr, with gdb
53- // controlling gdbserver, as well. We work around that by
54- // ensuring *some* resume-execution command has been issued before
55- // restarting the session. But, only if the inferior hasn't
56- // already finished execution ($_thread != 0). If it has and we
57- // issue the "stepi" command, then gdb refuses to restart
58- // execution.
59- << " define hook-run\n "
60- << " rr-hook-run\n "
61- << " end\n "
62- << " define hookpost-continue\n "
63- << " rr-set-suppress-run-hook 1\n "
64- << " end\n "
65- << " define hookpost-step\n "
66- << " rr-set-suppress-run-hook 1\n "
67- << " end\n "
68- << " define hookpost-stepi\n "
69- << " rr-set-suppress-run-hook 1\n "
70- << " end\n "
71- << " define hookpost-next\n "
72- << " rr-set-suppress-run-hook 1\n "
73- << " end\n "
74- << " define hookpost-nexti\n "
75- << " rr-set-suppress-run-hook 1\n "
76- << " end\n "
77- << " define hookpost-finish\n "
78- << " rr-set-suppress-run-hook 1\n "
79- << " end\n "
80- << " define hookpost-reverse-continue\n "
81- << " rr-set-suppress-run-hook 1\n "
82- << " end\n "
83- << " define hookpost-reverse-step\n "
84- << " rr-set-suppress-run-hook 1\n "
85- << " end\n "
86- << " define hookpost-reverse-stepi\n "
87- << " rr-set-suppress-run-hook 1\n "
88- << " end\n "
89- << " define hookpost-reverse-finish\n "
90- << " rr-set-suppress-run-hook 1\n "
91- << " end\n "
92- << " define hookpost-run\n "
93- << " rr-set-suppress-run-hook 0\n "
94- << " end\n "
95- << " set unwindonsignal on\n "
96- << " set non-stop off\n "
97- << " handle SIGURG stop\n "
98- << " set prompt (rr) \n "
99- // Try both "set target-async" and "maint set target-async" since
100- // that changed recently.
101- << " python\n "
102- << " import re\n "
103- << " m = re.compile(r"
104- << " '[^0-9]*([0-9]+)\\ .([0-9]+)(\\ .([0-9]+))?'"
105- << " ).match(gdb.VERSION)\n "
106- << " ver = int(m.group(1))*10000 + int(m.group(2))*100\n "
107- << " if m.group(4):\n "
108- << " ver = ver + int(m.group(4))\n "
109- << " \n "
110- << " if ver == 71100:\n "
111- << " gdb.write("
112- << " 'This version of gdb (7.11.0) has known bugs that break rr. "
113- << " Install 7.11.1 or later.\\ n', gdb.STDERR)\n "
114- << " \n "
115- << " if ver < 71101:\n "
116- << " gdb.execute('set target-async 0')\n "
117- << " gdb.execute('maint set target-async 0')\n "
118- << " end\n " ;
119- s = ss.str ();
29+ static string gdb_rr_macros (const string* file_to_delete) {
30+ stringstream ss;
31+ ss << DebuggerExtensionCommandHandler::gdb_macros ()
32+ // gdb warns about redefining inbuilt commands, silence that by
33+ // wrapping it in python code
34+ << " python gdb.execute('define jump\\ nrr-denied jump\\ nend')\n "
35+ << " python gdb.execute('define restart\\ nrun c$arg0\\ nend')\n "
36+ << " document restart\n "
37+ << " restart at checkpoint N\n "
38+ << " checkpoints are created with the 'checkpoint' command\n "
39+ << " end\n "
40+ << " define seek-ticks\n "
41+ << " run t$arg0\n "
42+ << " end\n "
43+ << " document seek-ticks\n "
44+ << " restart at given ticks value\n "
45+ << " end\n "
46+ // In gdb version "Fedora 7.8.1-30.fc21", a raw "run" command
47+ // issued before any user-generated resume-execution command
48+ // results in gdb hanging just after the inferior hits an internal
49+ // gdb breakpoint. This happens outside of rr, with gdb
50+ // controlling gdbserver, as well. We work around that by
51+ // ensuring *some* resume-execution command has been issued before
52+ // restarting the session. But, only if the inferior hasn't
53+ // already finished execution ($_thread != 0). If it has and we
54+ // issue the "stepi" command, then gdb refuses to restart
55+ // execution.
56+ << " define hook-run\n "
57+ << " rr-hook-run\n "
58+ << " end\n "
59+ << " define hookpost-continue\n "
60+ << " rr-set-suppress-run-hook 1\n "
61+ << " end\n "
62+ << " define hookpost-step\n "
63+ << " rr-set-suppress-run-hook 1\n "
64+ << " end\n "
65+ << " define hookpost-stepi\n "
66+ << " rr-set-suppress-run-hook 1\n "
67+ << " end\n "
68+ << " define hookpost-next\n "
69+ << " rr-set-suppress-run-hook 1\n "
70+ << " end\n "
71+ << " define hookpost-nexti\n "
72+ << " rr-set-suppress-run-hook 1\n "
73+ << " end\n "
74+ << " define hookpost-finish\n "
75+ << " rr-set-suppress-run-hook 1\n "
76+ << " end\n "
77+ << " define hookpost-reverse-continue\n "
78+ << " rr-set-suppress-run-hook 1\n "
79+ << " end\n "
80+ << " define hookpost-reverse-step\n "
81+ << " rr-set-suppress-run-hook 1\n "
82+ << " end\n "
83+ << " define hookpost-reverse-stepi\n "
84+ << " rr-set-suppress-run-hook 1\n "
85+ << " end\n "
86+ << " define hookpost-reverse-finish\n "
87+ << " rr-set-suppress-run-hook 1\n "
88+ << " end\n "
89+ << " define hookpost-run\n "
90+ << " rr-set-suppress-run-hook 0\n "
91+ << " end\n "
92+ << " set unwindonsignal on\n "
93+ << " set non-stop off\n "
94+ << " handle SIGURG stop\n "
95+ << " set prompt (rr) \n "
96+ // Try both "set target-async" and "maint set target-async" since
97+ // that changed recently.
98+ << " python\n "
99+ << " import re\n "
100+ << " import os\n "
101+ << " m = re.compile(r"
102+ << " '[^0-9]*([0-9]+)\\ .([0-9]+)(\\ .([0-9]+))?'"
103+ << " ).match(gdb.VERSION)\n "
104+ << " ver = int(m.group(1))*10000 + int(m.group(2))*100\n "
105+ << " if m.group(4):\n "
106+ << " ver = ver + int(m.group(4))\n "
107+ << " \n "
108+ << " if ver == 71100:\n "
109+ << " gdb.write("
110+ << " 'This version of gdb (7.11.0) has known bugs that break rr. "
111+ << " Install 7.11.1 or later.\\ n', gdb.STDERR)\n "
112+ << " \n "
113+ << " if ver < 71101:\n "
114+ << " gdb.execute('set target-async 0')\n "
115+ << " gdb.execute('maint set target-async 0')\n " ;
116+ if (file_to_delete) {
117+ ss << " os.unlink('" << *file_to_delete << " ')\n " ;
120118 }
121- return s;
119+ ss << " end\n " ;
120+ return ss.str ();
122121}
123122
124- static const string& lldb_python_rr_macros () {
123+ static const string& lldb_python_rr_macros (const string* file_to_delete ) {
125124 static string s;
126125
127126 if (s.empty ()) {
127+ auto cmds = DebuggerExtensionCommandHandler::lldb_python_macros ();
128128 stringstream ss;
129- ss << DebuggerExtensionCommandHandler::lldb_python_macros ()
130- << " lldb.debugger.HandleCommand('set set prompt \" (rr) \" ')\n " ;
129+ ss << cmds.toplevel_definitions
130+ << " import os\n "
131+ << " def __lldb_init_module(debugger, internal_dict):\n "
132+ << cmds.run_on_startup
133+ << " debugger.HandleCommand('set set prompt \" (rr) \" ')\n " ;
134+ if (file_to_delete) {
135+ ss << " os.unlink('" << *file_to_delete << " ')\n " ;
136+ }
137+ ss << " \n " ;
131138 s = ss.str ();
132139 }
133140 return s;
@@ -229,24 +236,6 @@ vector<string> debugger_launch_command(Task* t, int socket_domain,
229236 return cmd;
230237}
231238
232- static string create_command_file (const string& macros) {
233- TempFile file = create_temporary_file (" rr-debugger-commands-XXXXXX" );
234- // This fd is just leaked. That's fine since we only call this once
235- // per rr invocation at the moment.
236- int fd = file.fd .extract ();
237- unlink (file.name .c_str ());
238-
239- ssize_t len = macros.size ();
240- int written = write (fd, macros.c_str (), len);
241- if (written != len) {
242- FATAL () << " Failed to write gdb command file" ;
243- }
244-
245- stringstream procfile;
246- procfile << " /proc/" << getpid () << " /fd/" << fd;
247- return procfile.str ();
248- }
249-
250239string to_shell_string (const vector<string>& args) {
251240 stringstream ss;
252241 for (auto & a : args) {
@@ -290,12 +279,16 @@ void launch_debugger(ScopedFd& params_pipe_fd,
290279 cmd.push_back (debugger_file_path);
291280 vector<string> env = current_env ();
292281
282+ // LLDB 'command script import' requires the filename to be a valid Python
283+ // identifier.
284+ TempFile file = create_temporary_file (" rr_debugger_commands_XXXXXX" );
293285 switch (debugger_type) {
294286 case DebuggerType::GDB: {
295287 push_default_gdb_options (cmd, serve_files);
296- string gdb_command_file = create_command_file (gdb_rr_macros ());
288+ string script = gdb_rr_macros (&file.name );
289+ write_all (file.fd , script.data (), script.size ());
297290 cmd.push_back (" -x" );
298- cmd.push_back (gdb_command_file );
291+ cmd.push_back (file. name );
299292
300293 bool did_set_remote = false ;
301294 for (size_t i = 0 ; i < options.size (); ++i) {
@@ -317,12 +310,17 @@ void launch_debugger(ScopedFd& params_pipe_fd,
317310 cmd.push_back (" --source-quietly" );
318311 cmd.insert (cmd.end (), options.begin (), options.end ());
319312 push_lldb_target_remote_cmd (cmd, socket_domain, host, port);
320- // We have to load the commands as a Python script. If we
321- // use the "script" command to launch a nested Python interpreter,
322- // Python emits some annoying text that we dont want to see.
323- string lldb_command_file = create_command_file (lldb_python_rr_macros ());
313+ // LLDB 'command script import' requires the file to end in '.py'.
314+ string new_name = file.name + " .py" ;
315+ if (renameat2 (AT_FDCWD, file.name .c_str (), AT_FDCWD, new_name.c_str (),
316+ RENAME_NOREPLACE)) {
317+ FATAL () << " Can't fix temp file name" ;
318+ }
319+ file.name = new_name;
320+ string script = lldb_python_rr_macros (&file.name );
321+ write_all (file.fd , script.data (), script.size ());
324322 cmd.push_back (" -o" );
325- cmd.push_back (" script exec(open(' " + lldb_command_file + " ').read()) " );
323+ cmd.push_back (" command script import " + file. name );
326324 env.push_back (" LLDB_UNDER_RR=1" );
327325 break ;
328326 }
@@ -392,8 +390,8 @@ void emergency_debug(Task* t) {
392390 GdbServer::serve_emergency_debugger (std::move (dbg), t);
393391}
394392
395- string gdb_init_script () { return gdb_rr_macros (); }
393+ string gdb_init_script () { return gdb_rr_macros (nullptr ); }
396394
397- string lldb_init_script () { return lldb_python_rr_macros (); }
395+ string lldb_init_script () { return lldb_python_rr_macros (nullptr ); }
398396
399397} // namespace rr
0 commit comments