Permalink
Browse files

auto merge of #15573 : michaelwoerister/rust/lldb-tests-rebased-09-Ju…

…l, r=alexcrichton

This PR adds the LLDB autotests to the debuginfo test suite so I don't have to keep rebasing them locally. They are still disabled by default in `tests.mk`. One of the commits also contains a Python pretty printer which can make LLDB print values with Rust syntax. This was mainly added to deal with output format differences between LLDB versions but you can also use it for your normal LLDB debugging sessions.
```
// The following LLDB commands will load and activate the Rust printers
command script import ./src/etc/lldb_rust_formatters.py
type summary add --no-value --python-function lldb_rust_formatters.print_val -x .* --category Rust
type category enable Rust
```
Expect some rough edges with these, they have not been tested apart from there use in the autotests...
  • Loading branch information...
2 parents 316719e + 3b336b2 commit 175f113cba6304f2b99052225435da5cc622e926 @bors bors committed Jul 16, 2014
Showing with 3,569 additions and 265 deletions.
  1. +11 −1 src/compiletest/compiletest.rs
  2. +10 −0 src/compiletest/runtest.rs
  3. +0 −3 src/etc/lldb_batchmode.py
  4. +232 −0 src/etc/lldb_rust_formatters.py
  5. +40 −1 src/test/debuginfo/basic-types.rs
  6. +52 −1 src/test/debuginfo/borrowed-basic.rs
  7. +18 −1 src/test/debuginfo/borrowed-c-style-enum.rs
  8. +16 −1 src/test/debuginfo/borrowed-enum.rs
  9. +55 −1 src/test/debuginfo/borrowed-managed-basic.rs
  10. +39 −2 src/test/debuginfo/borrowed-struct.rs
  11. +22 −1 src/test/debuginfo/borrowed-tuple.rs
  12. +54 −1 src/test/debuginfo/borrowed-unique-basic.rs
  13. +19 −2 src/test/debuginfo/box.rs
  14. +22 −2 src/test/debuginfo/boxed-struct.rs
  15. +38 −6 src/test/debuginfo/by-value-non-immediate-argument.rs
  16. +29 −5 src/test/debuginfo/by-value-self-argument-in-trait-impl.rs
  17. +31 −2 src/test/debuginfo/c-style-enum-in-composite.rs
  18. +31 −2 src/test/debuginfo/c-style-enum.rs
  19. +22 −2 src/test/debuginfo/closure-in-generic-function.rs
  20. +175 −25 src/test/debuginfo/destructured-fn-argument.rs
  21. +121 −2 src/test/debuginfo/destructured-local.rs
  22. +24 −2 src/test/debuginfo/evec-in-struct.rs
  23. +128 −24 src/test/debuginfo/function-arg-initialization.rs
  24. +23 −3 src/test/debuginfo/function-arguments.rs
  25. +118 −1 src/test/debuginfo/function-prologue-stepping-no-split-stack.rs
  26. +232 −0 src/test/debuginfo/function-prologue-stepping-regular.rs
  27. +34 −1 src/test/debuginfo/generic-function.rs
  28. +34 −2 src/test/debuginfo/generic-functions-nested.rs
  29. +60 −6 src/test/debuginfo/generic-method-on-generic-struct.rs
  30. +20 −2 src/test/debuginfo/generic-struct.rs
  31. +22 −2 src/test/debuginfo/generic-tuple-style-enum.rs
  32. +18 −3 src/test/debuginfo/include_string.rs
  33. +43 −3 src/test/debuginfo/lexical-scope-in-for-loop.rs
  34. +73 −8 src/test/debuginfo/lexical-scope-in-if.rs
  35. +69 −8 src/test/debuginfo/lexical-scope-in-match.rs
  36. +38 −6 src/test/debuginfo/lexical-scope-in-stack-closure.rs
  37. +70 −7 src/test/debuginfo/lexical-scope-in-unconditional-loop.rs
  38. +38 −6 src/test/debuginfo/lexical-scope-in-unique-closure.rs
  39. +71 −7 src/test/debuginfo/lexical-scope-in-while.rs
  40. +60 −7 src/test/debuginfo/lexical-scope-with-macro.rs
  41. +185 −24 src/test/debuginfo/lexical-scopes-in-block-expression.rs
  42. +2 −0 src/test/debuginfo/limited-debuginfo.rs
  43. +18 −1 src/test/debuginfo/managed-enum.rs
  44. +22 −1 src/test/debuginfo/managed-pointer-within-unique-vec.rs
  45. +17 −1 src/test/debuginfo/managed-pointer-within-unique.rs
  46. +56 −3 src/test/debuginfo/method-on-enum.rs
  47. +57 −3 src/test/debuginfo/method-on-generic-struct.rs
  48. +56 −3 src/test/debuginfo/method-on-struct.rs
  49. +56 −3 src/test/debuginfo/method-on-trait.rs
  50. +56 −3 src/test/debuginfo/method-on-tuple-struct.rs
  51. +22 −3 src/test/debuginfo/multiple-functions-equal-var-names.rs
  52. +22 −3 src/test/debuginfo/multiple-functions.rs
  53. +50 −6 src/test/debuginfo/name-shadowing-and-scope-nesting.rs
  54. +3 −0 src/test/debuginfo/nil-enum.rs
  55. +34 −6 src/test/debuginfo/option-like-enum.rs
  56. +34 −1 src/test/debuginfo/packed-struct-with-destructor.rs
  57. +27 −1 src/test/debuginfo/packed-struct.rs
  58. +2 −0 src/test/debuginfo/recursive-enum.rs
  59. +1 −0 src/test/debuginfo/recursive-struct.rs
  60. +57 −3 src/test/debuginfo/self-in-default-method.rs
  61. +60 −6 src/test/debuginfo/self-in-generic-default-method.rs
  62. +29 −3 src/test/debuginfo/shadowed-argument.rs
  63. +29 −3 src/test/debuginfo/shadowed-variable.rs
  64. +3 −0 src/test/debuginfo/simd.rs
  65. +42 −7 src/test/debuginfo/simple-lexical-scope.rs
  66. +26 −1 src/test/debuginfo/simple-struct.rs
  67. +26 −1 src/test/debuginfo/simple-tuple.rs
  68. +26 −2 src/test/debuginfo/static-method-on-struct-and-enum.rs
  69. +17 −1 src/test/debuginfo/struct-in-enum.rs
  70. +34 −1 src/test/debuginfo/struct-in-struct.rs
  71. +21 −1 src/test/debuginfo/struct-style-enum.rs
  72. +20 −1 src/test/debuginfo/struct-with-destructor.rs
  73. +1 −1 src/test/debuginfo/text-to-include-1.txt
  74. +1 −1 src/test/debuginfo/text-to-include-2.txt
  75. +1 −1 src/test/debuginfo/text-to-include-3.txt
  76. +33 −1 src/test/debuginfo/trait-generic-static-default-method.rs
  77. +2 −0 src/test/debuginfo/trait-pointers.rs
  78. +26 −1 src/test/debuginfo/tuple-in-tuple.rs
  79. +26 −1 src/test/debuginfo/tuple-struct.rs
  80. +21 −1 src/test/debuginfo/tuple-style-enum.rs
  81. +18 −1 src/test/debuginfo/unique-enum.rs
  82. +42 −2 src/test/debuginfo/var-captured-in-nested-closure.rs
  83. +16 −1 src/test/debuginfo/var-captured-in-sendable-closure.rs
  84. +22 −1 src/test/debuginfo/var-captured-in-stack-closure.rs
  85. +27 −1 src/test/debuginfo/vec-slices.rs
  86. +11 −1 src/test/debuginfo/vec.rs
@@ -30,7 +30,7 @@ use std::io::fs;
use std::from_str::FromStr;
use getopts::{optopt, optflag, reqopt};
use common::Config;
-use common::{Pretty, DebugInfoGdb, Codegen};
+use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
use util::logv;
use regex::Regex;
@@ -241,6 +241,16 @@ pub fn run_tests(config: &Config) {
os::setenv("RUST_TEST_TASKS","1");
}
+ match config.mode {
+ DebugInfoLldb => {
+ // Some older versions of LLDB seem to have problems with multiple
+ // instances running in parallel, so only run one test task at a
+ // time.
+ os::setenv("RUST_TEST_TASKS", "1");
+ }
+ _ => { /* proceed */ }
+ }
+
let opts = test_opts(config);
let tests = make_tests(config);
// sadly osx needs some file descriptor limits raised for running tests in
View
@@ -536,6 +536,16 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
// We don't want to hang when calling `quit` while the process is still running
let mut script_str = String::from_str("settings set auto-confirm true\n");
+ // Make LLDB emit its version, so we have it documented in the test output
+ script_str.push_str("version\n");
+
+ // Switch LLDB into "Rust mode"
+ script_str.push_str("command script import ./src/etc/lldb_rust_formatters.py\n");
+ script_str.push_str("type summary add --no-value ");
+ script_str.push_str("--python-function lldb_rust_formatters.print_val ");
+ script_str.push_str("-x \".*\" --category Rust\n");
+ script_str.push_str("type category enable Rust\n");
+
// Set breakpoints on every line that contains the string "#break"
for line in breakpoint_lines.iter() {
script_str.push_str(format!("breakpoint set --line {}\n",
@@ -31,9 +31,6 @@
import re
import atexit
-# Terminate the debugger
-atexit.register(lambda: lldb.SBDebugger.Terminate())
-
# Set this to True for additional output
DEBUG_OUTPUT = False
@@ -0,0 +1,232 @@
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+import lldb
+
+def print_val(val, internal_dict):
+ '''Prints the given value with Rust syntax'''
+ type_class = val.GetType().GetTypeClass()
+
+ if type_class == lldb.eTypeClassStruct:
+ return print_struct_val(val, internal_dict)
+
+ if type_class == lldb.eTypeClassUnion:
+ return print_enum_val(val, internal_dict)
+
+ if type_class == lldb.eTypeClassPointer:
+ return print_pointer_val(val, internal_dict)
+
+ if type_class == lldb.eTypeClassArray:
+ return print_fixed_size_vec_val(val, internal_dict)
+
+ return val.GetValue()
+
+
+#=--------------------------------------------------------------------------------------------------
+# Type-Specialized Printing Functions
+#=--------------------------------------------------------------------------------------------------
+
+def print_struct_val(val, internal_dict):
+ '''Prints a struct, tuple, or tuple struct value with Rust syntax'''
+ assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
+
+ if is_vec_slice(val):
+ return print_vec_slice_val(val, internal_dict)
+ else:
+ return print_struct_val_starting_from(0, val, internal_dict)
+
+def print_vec_slice_val(val, internal_dict):
+ output = "&["
+
+ length = val.GetChildAtIndex(1).GetValueAsUnsigned()
+
+ data_ptr_val = val.GetChildAtIndex(0)
+ data_ptr_type = data_ptr_val.GetType()
+ assert data_ptr_type.IsPointerType()
+
+ element_type = data_ptr_type.GetPointeeType()
+ element_type_size = element_type.GetByteSize()
+
+ start_address = data_ptr_val.GetValueAsUnsigned()
+
+ for i in range(length):
+ address = start_address + i * element_type_size
+ element_val = val.CreateValueFromAddress( val.GetName() + ("[%s]" % i), address, element_type )
+ output += print_val(element_val, internal_dict)
+
+ if i != length - 1:
+ output += ", "
+
+ output += "]"
+ return output
+
+def print_struct_val_starting_from(field_start_index, val, internal_dict):
+ '''
+ Prints a struct, tuple, or tuple struct value with Rust syntax.
+ Ignores any fields before field_start_index.
+ '''
+ assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
+
+ t = val.GetType()
+ has_field_names = type_has_field_names(t)
+ type_name = extract_type_name(t.GetName())
+ output = ""
+
+ if not type_name.startswith("("):
+ # this is a tuple, so don't print the type name
+ output += type_name
+
+ if has_field_names:
+ output += " { \n"
+ else:
+ output += "("
+
+ num_children = val.num_children
+
+ for child_index in range(field_start_index, num_children):
+ if has_field_names:
+ field_name = t.GetFieldAtIndex(child_index).GetName()
+ output += field_name + ": "
+
+ field_val = val.GetChildAtIndex(child_index)
+ output += print_val(field_val, internal_dict)
+
+ if child_index != num_children - 1:
+ output += ", "
+
+ if has_field_names:
+ output += "\n"
+
+ if has_field_names:
+ output += "}"
+ else:
+ output += ")"
+
+ return output
+
+
+def print_enum_val(val, internal_dict):
+ '''Prints an enum value with Rust syntax'''
+
+ assert val.GetType().GetTypeClass() == lldb.eTypeClassUnion
+
+ if val.num_children == 1:
+ first_variant_name = val.GetChildAtIndex(0).GetName()
+ if first_variant_name and first_variant_name.startswith("RUST$ENCODED$ENUM$"):
+ # Try to extract the
+
+ last_separator_index = first_variant_name.rfind("$")
+ if last_separator_index == -1:
+ return "<invalid enum encoding: %s>" % first_variant_name
+
+ second_last_separator_index = first_variant_name.rfind("$", 0, last_separator_index)
+ if second_last_separator_index == -1:
+ return "<invalid enum encoding: %s>" % first_variant_name
+
+ try:
+ disr_field_index = first_variant_name[second_last_separator_index + 1 :
+ last_separator_index]
+ disr_field_index = int(disr_field_index)
+ except:
+ return "<invalid enum encoding: %s>" % first_variant_name
+
+ disr_val = val.GetChildAtIndex(0).GetChildAtIndex(disr_field_index).GetValueAsUnsigned()
+
+ if disr_val == 0:
+ null_variant_name = first_variant_name[last_separator_index + 1:]
+ return null_variant_name
+ else:
+ return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
+ else:
+ return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
+
+ # extract the discriminator value by
+ disr_val = val.GetChildAtIndex(0).GetChildAtIndex(0)
+ disr_type = disr_val.GetType()
+
+ if disr_type.GetTypeClass() != lldb.eTypeClassEnumeration:
+ return "<Invalid enum value encountered: Discriminator is not an enum>"
+
+ variant_index = disr_val.GetValueAsUnsigned()
+ return print_struct_val_starting_from(1, val.GetChildAtIndex(variant_index), internal_dict)
+
+
+def print_pointer_val(val, internal_dict):
+ '''Prints a pointer value with Rust syntax'''
+ assert val.GetType().IsPointerType()
+ sigil = "&"
+ type_name = extract_type_name(val.GetType().GetName())
+ if type_name and type_name[0:1] in ["&", "~", "*"]:
+ sigil = type_name[0:1]
+
+ return sigil + hex(val.GetValueAsUnsigned()) #print_val(val.Dereference(), internal_dict)
+
+
+def print_fixed_size_vec_val(val, internal_dict):
+ assert val.GetType().GetTypeClass() == lldb.eTypeClassArray
+
+ output = "["
+
+ for i in range(val.num_children):
+ output += print_val(val.GetChildAtIndex(i), internal_dict)
+ if i != val.num_children - 1:
+ output += ", "
+
+ output += "]"
+ return output
+
+
+#=--------------------------------------------------------------------------------------------------
+# Helper Functions
+#=--------------------------------------------------------------------------------------------------
+
+unqualified_type_markers = frozenset(["(", "[", "&", "*"])
+
+def extract_type_name(qualified_type_name):
+ '''Extracts the type name from a fully qualified path'''
+ if qualified_type_name[0] in unqualified_type_markers:
+ return qualified_type_name
+
+ end_of_search = qualified_type_name.find("<")
+ if end_of_search < 0:
+ end_of_search = len(qualified_type_name)
+
+ index = qualified_type_name.rfind("::", 0, end_of_search)
+ if index < 0:
+ return qualified_type_name
+ else:
+ return qualified_type_name[index + 2:]
+
+
+def type_has_field_names(ty):
+ '''Returns true of this is a type with field names (struct, struct-like enum variant)'''
+ # This may also be an enum variant where the first field doesn't have a name but the rest has
+ if ty.GetNumberOfFields() > 1:
+ return ty.GetFieldAtIndex(1).GetName() != None
+ else:
+ return ty.GetFieldAtIndex(0).GetName() != None
+
+
+def is_vec_slice(val):
+ ty = val.GetType()
+ if ty.GetTypeClass() != lldb.eTypeClassStruct:
+ return False
+
+ if ty.GetNumberOfFields() != 2:
+ return False
+
+ if ty.GetFieldAtIndex(0).GetName() != "data_ptr":
+ return False
+
+ if ty.GetFieldAtIndex(1).GetName() != "length":
+ return False
+
+ type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
+ return type_name.startswith("&[") and type_name.endswith("]")
@@ -17,6 +17,9 @@
// ignore-android: FIXME(#10381)
// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
// gdb-command:rbreak zzz
// gdb-command:run
// gdb-command:finish
@@ -49,6 +52,42 @@
// gdb-command:print f64
// gdb-check:$14 = 3.5
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+// lldb-command:print b
+// lldb-check:[...]$0 = false
+// lldb-command:print i
+// lldb-check:[...]$1 = -1
+
+// NOTE: LLDB does not support 32bit chars
+// d ebugger:print (uint)(c)
+// c heck:$3 = 97
+
+// lldb-command:print i8
+// lldb-check:[...]$2 = 'D'
+// lldb-command:print i16
+// lldb-check:[...]$3 = -16
+// lldb-command:print i32
+// lldb-check:[...]$4 = -32
+// lldb-command:print i64
+// lldb-check:[...]$5 = -64
+// lldb-command:print u
+// lldb-check:[...]$6 = 1
+// lldb-command:print u8
+// lldb-check:[...]$7 = 'd'
+// lldb-command:print u16
+// lldb-check:[...]$8 = 16
+// lldb-command:print u32
+// lldb-check:[...]$9 = 32
+// lldb-command:print u64
+// lldb-check:[...]$10 = 64
+// lldb-command:print f32
+// lldb-check:[...]$11 = 2.5
+// lldb-command:print f64
+// lldb-check:[...]$12 = 3.5
+
#![allow(unused_variable)]
fn main() {
@@ -66,7 +105,7 @@ fn main() {
let u64: u64 = 64;
let f32: f32 = 2.5;
let f64: f64 = 3.5;
- _zzz();
+ _zzz(); // #break
}
fn _zzz() {()}
Oops, something went wrong.

0 comments on commit 175f113

Please sign in to comment.