ART: Enables Debugging with LLDB for dex2oat.

Currently, there is not a flag present to enable debugging the dex2oat
compiler on host. Therefore, because we want to be able to debug the
dex2oat compiler when testing, this patch adds two flags,
"--gdb-dex2oat" and "--gdb-dex2oat-args". As a result, when the
"--gdb-dex2oat" flag is present in a test command, it will
run LLDB on dex2oat.

Note that to be compliant with the current naming convention,
the relevant variable names include the "GDB" prefix instead of "LLDB".

Additionally, we can pass arguments that are delimited by a semi-column
to LLDB with "--gdb-dex2oat-args", e.g.
"--gdb-dex2oat-args='-X'".

Note that this patch does not enable dex2oat debugging on target.

Test: art/test.py -v -j12 --host --64  -t 554-checker-rtp-checkcast\
      --run-test --optimizing --gdb-dex2oat

Change-Id: I392a57a41a90550cc5dc766ee9f148327a9c21d2
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 0d80c6a..6d89720 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -54,6 +54,8 @@
 ANDROID_FLAGS=""
 GDB=""
 GDB_ARGS=""
+GDB_DEX2OAT=""
+GDB_DEX2OAT_ARGS=""
 GDBSERVER_DEVICE="gdbserver"
 GDBSERVER_HOST="gdbserver"
 HAVE_IMAGE="y"
@@ -87,6 +89,7 @@
 USE_GDB="n"
 USE_GDBSERVER="n"
 GDBSERVER_PORT=":5039"
+USE_GDB_DEX2OAT="n"
 USE_JVM="n"
 USE_JVMTI="n"
 VERIFY="y" # y=yes,n=no,s=softfail
@@ -365,6 +368,17 @@
         gdb_arg="$1"
         GDB_ARGS="${GDB_ARGS} $gdb_arg"
         shift
+    elif [ "x$1" = "x--gdb-dex2oat" ]; then
+        USE_GDB_DEX2OAT="y"
+        DEV_MODE="y"
+        TIME_OUT="n"
+        shift
+    elif [ "x$1" = "x--gdb-dex2oat-args" ]; then
+        shift
+        for arg in $(echo $1 | tr ";" " "); do
+          GDB_DEX2OAT_ARGS+="$arg "
+        done
+        shift
     elif [ "x$1" = "x--zygote" ]; then
         ZYGOTE="-Xzygote"
         msg "Spawning from zygote"
@@ -762,6 +776,12 @@
     DALVIKVM_BOOT_OPT="-Ximage:${BOOT_IMAGE}"
 fi
 
+if [ "$USE_GDB_DEX2OAT" = "y" ]; then
+  if [ "$HOST" = "n" ]; then
+    echo "The --gdb-dex2oat option is not yet implemented for target." >&2
+    exit 1
+  fi
+fi
 
 if [ "$USE_GDB" = "y" ]; then
   if [ "$USE_GDBSERVER" = "y" ]; then
@@ -943,6 +963,47 @@
   fi
 fi
 
+function get_prebuilt_lldb_path {
+  local CLANG_BASE="prebuilts/clang/host"
+  local CLANG_VERSION="$("$ANDROID_BUILD_TOP/build/soong/scripts/get_clang_version.py")"
+  case "$(uname -s)" in
+    Darwin)
+      local PREBUILT_NAME="darwin-x86"
+      ;;
+    Linux)
+      local PREBUILT_NAME="linux-x86"
+      ;;
+    *)
+      >&2 echo "Unknown host $(uname -s). Unsupported for debugging dex2oat with LLDB."
+      return
+      ;;
+  esac
+  local CLANG_PREBUILT_HOST_PATH="$ANDROID_BUILD_TOP/$CLANG_BASE/$PREBUILT_NAME/$CLANG_VERSION"
+  # If the clang prebuilt directory exists and the reported clang version
+  # string does not, then it is likely that the clang version reported by the
+  # get_clang_version.py script does not match the expected directory name.
+  if [ -d "${ANDROID_BUILD_TOP}/${CLANG_BASE}/${PREBUILT_NAME}" ] && \
+     [ ! -d "${CLANG_PREBUILT_HOST_PATH}" ]; then
+    error_msg "The prebuilt clang directory exists, but the specific clang"\
+    "\nversion reported by get_clang_version.py does not exist in that path."\
+    "\nPlease make sure that the reported clang version resides in the"\
+    "\nprebuilt clang directory!"
+    exit 1
+  fi
+
+  # The lldb-server binary is a dependency of lldb.
+  export LLDB_DEBUGSERVER_PATH="${CLANG_PREBUILT_HOST_PATH}/runtimes_ndk_cxx/x86_64/lldb-server"
+
+  # Set the current terminfo directory to TERMINFO so that LLDB can read the
+  # termcap database.
+  local terminfo_regexp_path='\/.*\/*terminfo\/'
+  if [[ $(infocmp) =~ $terminfo_regexp_path ]] ; then
+    export TERMINFO="${BASH_REMATCH[0]}"
+  fi
+
+  prebuilt_lldb_path="$CLANG_PREBUILT_HOST_PATH/bin/lldb.sh"
+}
+
 function write_dex2oat_cmdlines {
   local name="$1"
 
@@ -963,12 +1024,20 @@
   local app_image=""
   $enable_app_image && app_image="--app-image-file=$DEX_LOCATION/oat/$ISA/$name.art --resolve-startup-const-strings=true"
 
+  if [ "$USE_GDB_DEX2OAT" = "y" ]; then
+    get_prebuilt_lldb_path
+    GDB_DEX2OAT="$prebuilt_lldb_path -f"
+    GDB_DEX2OAT_ARGS+=" -- "
+  fi
+
   local dex2oat_binary
   dex2oat_binary=${DEX2OAT_DEBUG_BINARY}
   if  [[ "$TEST_IS_NDEBUG" = "y" ]]; then
     dex2oat_binary=${DEX2OAT_NDEBUG_BINARY}
   fi
-  dex2oat_cmdline="$INVOKE_WITH $ANDROID_ART_BIN_DIR/$dex2oat_binary \
+  dex2oat_cmdline="$INVOKE_WITH $GDB_DEX2OAT \
+                      $ANDROID_ART_BIN_DIR/$dex2oat_binary \
+                      $GDB_DEX2OAT_ARGS \
                       $COMPILE_FLAGS \
                       --boot-image=${BOOT_IMAGE} \
                       --dex-file=$DEX_LOCATION/$name.jar \
@@ -982,12 +1051,13 @@
   fi
 
   # Add in a timeout. This is important for testing the compilation/verification time of
-  # pathological cases.
+  # pathological cases. We do not append a timeout when debugging dex2oat because we
+  # do not want it to exit while debugging.
   # Note: as we don't know how decent targets are (e.g., emulator), only do this on the host for
   #       now. We should try to improve this.
   #       The current value is rather arbitrary. run-tests should compile quickly.
   # Watchdog timeout is in milliseconds so add 3 '0's to the dex2oat timeout.
-  if [ "$HOST" != "n" ]; then
+  if [ "$HOST" != "n" ] && [ "$USE_GDB_DEX2OAT" != "y" ]; then
     # Use SIGRTMIN+2 to try to dump threads.
     # Use -k 1m to SIGKILL it a minute later if it hasn't ended.
     dex2oat_cmdline="timeout -k ${DEX2OAT_TIMEOUT}s -s SIGRTMIN+2 ${DEX2OAT_RT_TIMEOUT}s ${dex2oat_cmdline} --watchdog-timeout=${DEX2OAT_TIMEOUT}000"
diff --git a/test/run-test b/test/run-test
index 8a0038b..fb1b3c9 100755
--- a/test/run-test
+++ b/test/run-test
@@ -296,6 +296,11 @@
         gdb_arg="$1"
         run_args+=(--gdb-arg "$gdb_arg")
         shift
+    elif [ "x$1" = "x--gdb-dex2oat-args" ]; then
+        shift
+        gdb_dex2oat_args="$1"
+        run_args+=(--gdb-dex2oat-args "$gdb_dex2oat_args")
+        shift
     elif [ "x$1" = "x--debug" ]; then
         run_args+=(--debug)
         shift
@@ -321,6 +326,10 @@
         run_args+=(--gdb)
         dev_mode="yes"
         shift
+    elif [ "x$1" = "x--gdb-dex2oat" ]; then
+        run_args+=(--gdb-dex2oat)
+        dev_mode="yes"
+        shift
     elif [ "x$1" = "x--gdbserver-bin" ]; then
         shift
         run_args+=(--gdbserver-bin "$1")
@@ -811,12 +820,14 @@
         echo "    --with-agent <agent>  Run the test with the given agent loaded with -agentpath:"
         echo "    --debuggable          Whether to compile Java code for a debugger."
         echo "    --gdb                 Run under gdb; incompatible with some tests."
+        echo "    --gdb-dex2oat         Run dex2oat under the prebuilt lldb."
         echo "    --gdbserver           Start gdbserver (defaults to port :5039)."
         echo "    --gdbserver-port <port>"
         echo "                          Start gdbserver with the given COMM (see man gdbserver)."
         echo "    --gdbserver-bin <binary>"
         echo "                          Use the given binary as gdbserver."
         echo "    --gdb-arg             Pass an option to gdb or gdbserver."
+        echo "    --gdb-dex2oat-args    Pass options separated by ';' to lldb for dex2oat."
         echo "    --build-only          Build test files only (off by default)."
         echo "    --skip-build          Assume that test files are already built (off by default)."
         echo "    --build-path [path]   Location where to store or expect the build files."
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index 711e346..0e6f147 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -138,6 +138,8 @@
 gdb = False
 gdb_arg = ''
 dump_cfg = ''
+gdb_dex2oat = False
+gdb_dex2oat_args = ''
 csv_result = None
 csv_writer = None
 runtime_option = ''
@@ -423,6 +425,10 @@
 
   if dump_cfg:
     options_all += ' --dump-cfg ' + dump_cfg
+  if gdb_dex2oat:
+    options_all += ' --gdb-dex2oat'
+    if gdb_dex2oat_args:
+      options_all += ' --gdb-dex2oat-args ' + gdb_dex2oat_args
 
   options_all += ' ' + ' '.join(run_test_option)
 
@@ -680,7 +686,7 @@
       test_start_time = time.monotonic()
       if verbose:
         print_text("Starting %s at %s\n" % (test_name, test_start_time))
-      if gdb:
+      if gdb or gdb_dex2oat:
         proc = _popen(
           args=command.split(),
           stderr=subprocess.STDOUT,
@@ -1107,6 +1113,8 @@
   global gdb
   global gdb_arg
   global dump_cfg
+  global gdb_dex2oat
+  global gdb_dex2oat_args
   global runtime_option
   global run_test_option
   global timeout
@@ -1151,6 +1159,8 @@
   global_group.add_argument('--dump-cfg', dest='dump_cfg',
                             help="""Dump the CFG to the specified host path.
                             Example \"--dump-cfg <full-path>/graph.cfg\".""")
+  global_group.add_argument('--gdb-dex2oat', action='store_true', dest='gdb_dex2oat')
+  global_group.add_argument('--gdb-dex2oat-args', dest='gdb_dex2oat_args')
   global_group.add_argument('--run-test-option', action='append', dest='run_test_option',
                             default=[],
                             help="""Pass an option, unaltered, to the run-test script.
@@ -1226,6 +1236,11 @@
       gdb_arg = options['gdb_arg']
   if options['dump_cfg']:
     dump_cfg = options['dump_cfg']
+  if options['gdb_dex2oat']:
+    n_thread = 1
+    gdb_dex2oat = True
+    if options['gdb_dex2oat_args']:
+      gdb_dex2oat_args = options['gdb_dex2oat_args']
   runtime_option = options['runtime_option'];
   with_agent = options['with_agent'];
   run_test_option = sum(map(shlex.split, options['run_test_option']), [])