Index: lldb/source/Commands/CommandObjectMemory.cpp =================================================================== --- lldb/source/Commands/CommandObjectMemory.cpp +++ lldb/source/Commands/CommandObjectMemory.cpp @@ -767,10 +767,11 @@ std::string path = outfile_spec.GetPath(); if (outfile_spec) { - auto open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; + File::OpenOptions open_options = + File::eOpenOptionWrite | File::eOpenOptionCanCreate; const bool append = m_outfile_options.GetAppend().GetCurrentValue(); - if (append) - open_options |= File::eOpenOptionAppend; + open_options |= + append ? File::eOpenOptionAppend : File::eOpenOptionTruncate; auto outfile = FileSystem::Instance().Open(outfile_spec, open_options); Index: lldb/test/API/functionalities/memory/read/TestMemoryRead.py =================================================================== --- lldb/test/API/functionalities/memory/read/TestMemoryRead.py +++ lldb/test/API/functionalities/memory/read/TestMemoryRead.py @@ -2,11 +2,12 @@ Test the 'memory read' command. """ - - import lldb -from lldbsuite.test.lldbtest import * import lldbsuite.test.lldbutil as lldbutil +import tempfile + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * class MemoryReadTestCase(TestBase): @@ -19,27 +20,34 @@ # Find the line number to break inside main(). self.line = line_number('main.cpp', '// Set break point at this line.') - def test_memory_read(self): - """Test the 'memory read' command with plain and vector formats.""" + def build_run_stop(self): self.build() exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Break in main() after the variables are assigned values. - lldbutil.run_break_set_by_file_and_line( - self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True) + lldbutil.run_break_set_by_file_and_line(self, + "main.cpp", + self.line, + num_expected_locations=1, + loc_exact=True) self.runCmd("run", RUN_SUCCEEDED) # The stop reason of the thread should be breakpoint. - self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + self.expect("thread list", + STOPPED_DUE_TO_BREAKPOINT, substrs=['stopped', 'stop reason = breakpoint']) # The breakpoint should have a hit count of 1. - self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE, + self.expect("breakpoint list -f", + BREAKPOINT_HIT_ONCE, substrs=[' resolved, hit count = 1']) - # Test the memory read commands. + @no_debug_info_test + def test_memory_read(self): + """Test the 'memory read' command with plain and vector formats.""" + self.build_run_stop() # (lldb) memory read -f d -c 1 `&argc` # 0x7fff5fbff9a0: 1 @@ -131,3 +139,42 @@ for o in objects_read: self.assertEqual(len(o), expected_object_length) self.assertEquals(len(objects_read), 4) + + @no_debug_info_test + def test_memory_read_file(self): + self.build_run_stop() + cmd = "memory read -f d -c 1 `&argc`" + res = lldb.SBCommandReturnObject() + self.ci.HandleCommand(cmd, res) + self.assertTrue(res.Succeeded()) + + # Record golden output. + golden_output = res.GetOutput() + + temp_file = tempfile.NamedTemporaryFile().name + + def check_file_content(expected): + with open(temp_file) as f: + lines = f.readlines() + for i, line in enumerate(lines): + expected_line = expected[i].strip() + actual_line = line.strip() + self.assertEqual( + expected_line, actual_line, + "Line {} doesn't match: expected '{}' but got '{}'". + format(i, expected_line, actual_line)) + self.assertEqual(len(expected), len(lines)) + + # Sanity check. + self.runCmd("memory read -f d -c 1 -o '{}' `&argc`".format(temp_file)) + check_file_content([golden_output]) + + # Make sure the file is truncated when we run the command again. + self.runCmd("memory read -f d -c 1 -o '{}' `&argc`".format(temp_file)) + check_file_content([golden_output]) + + # Make sure the file is appended when we run the command with --append-outfile. + self.runCmd( + "memory read -f d -c 1 -o '{}' --append-outfile `&argc`".format( + temp_file)) + check_file_content([golden_output, golden_output])