am 5f5cf779: am fe653b68: am 3d5b4b8c: am a06feb5d: am b98e5bb9: am 32bd1410: am 4df667f4: Add devsite-compatible lang ids to whitelist and add a redirect for the old uppercase ids.

* commit '5f5cf779958f3f46f67f6cb0ef61d04b1a19bbb0':
diff --git a/ide/intellij/codestyles/AndroidStyle.xml b/ide/intellij/codestyles/AndroidStyle.xml
index cd6beb4..672c4e5 100644
--- a/ide/intellij/codestyles/AndroidStyle.xml
+++ b/ide/intellij/codestyles/AndroidStyle.xml
@@ -9,40 +9,49 @@
       <option name="SMART_TABS" value="false" />
       <option name="LABEL_INDENT_SIZE" value="0" />
       <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+      <option name="USE_RELATIVE_INDENTS" value="false" />
     </value>
   </option>
-  <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
-  <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
-  <option name="ALIGN_MULTILINE_FOR" value="false" />
-  <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
-  <option name="BLANK_LINES_AROUND_FIELD" value="1" />
-  <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
   <option name="FIELD_NAME_PREFIX" value="m" />
   <option name="STATIC_FIELD_NAME_PREFIX" value="m" />
-  <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
-  <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+  <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
+  <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
   <option name="IMPORT_LAYOUT_TABLE">
     <value>
-      <package name="com.google" withSubpackages="true" />
+      <package name="com.google" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="com" withSubpackages="true" />
+      <package name="com" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="junit" withSubpackages="true" />
+      <package name="junit" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="net" withSubpackages="true" />
+      <package name="net" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="org" withSubpackages="true" />
+      <package name="org" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="android" withSubpackages="true" />
+      <package name="android" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="java" withSubpackages="true" />
+      <package name="java" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="javax" withSubpackages="true" />
+      <package name="javax" withSubpackages="true" static="false" />
       <emptyLine />
-      <package name="" withSubpackages="true" />
+      <package name="" withSubpackages="true" static="false" />
+      <emptyLine />
+      <package name="" withSubpackages="true" static="true" />
     </value>
   </option>
   <option name="RIGHT_MARGIN" value="100" />
+  <option name="JD_P_AT_EMPTY_LINES" value="false" />
+  <option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
+  <option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
+  <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
+  <option name="JD_KEEP_EMPTY_RETURN" value="false" />
+  <option name="JD_PRESERVE_LINE_FEEDS" value="true" />
+  <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
+  <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+  <option name="BLANK_LINES_AROUND_FIELD" value="1" />
+  <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
+  <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+  <option name="ALIGN_MULTILINE_FOR" value="false" />
   <option name="CALL_PARAMETERS_WRAP" value="1" />
   <option name="METHOD_PARAMETERS_WRAP" value="1" />
   <option name="EXTENDS_LIST_WRAP" value="1" />
@@ -63,9 +72,104 @@
   <option name="DOWHILE_BRACE_FORCE" value="3" />
   <option name="WHILE_BRACE_FORCE" value="3" />
   <option name="FOR_BRACE_FORCE" value="3" />
-  <option name="JD_P_AT_EMPTY_LINES" value="false" />
-  <option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
-  <option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
-  <option name="JD_KEEP_EMPTY_RETURN" value="false" />
+  <ADDITIONAL_INDENT_OPTIONS fileType="css">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="java">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="8" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="js">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="4" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="jsp">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="sql">
+    <option name="INDENT_SIZE" value="2" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="xml">
+    <option name="INDENT_SIZE" value="4" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <ADDITIONAL_INDENT_OPTIONS fileType="yml">
+    <option name="INDENT_SIZE" value="2" />
+    <option name="CONTINUATION_INDENT_SIZE" value="8" />
+    <option name="TAB_SIZE" value="4" />
+    <option name="USE_TAB_CHARACTER" value="false" />
+    <option name="SMART_TABS" value="false" />
+    <option name="LABEL_INDENT_SIZE" value="0" />
+    <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+    <option name="USE_RELATIVE_INDENTS" value="false" />
+  </ADDITIONAL_INDENT_OPTIONS>
+  <codeStyleSettings language="JavaScript">
+    <option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
+    <option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
+    <option name="BLANK_LINES_AROUND_FIELD" value="1" />
+    <option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
+    <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
+    <option name="ALIGN_MULTILINE_FOR" value="false" />
+    <option name="CALL_PARAMETERS_WRAP" value="1" />
+    <option name="METHOD_PARAMETERS_WRAP" value="1" />
+    <option name="EXTENDS_LIST_WRAP" value="1" />
+    <option name="THROWS_LIST_WRAP" value="1" />
+    <option name="EXTENDS_KEYWORD_WRAP" value="1" />
+    <option name="THROWS_KEYWORD_WRAP" value="1" />
+    <option name="METHOD_CALL_CHAIN_WRAP" value="1" />
+    <option name="BINARY_OPERATION_WRAP" value="1" />
+    <option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
+    <option name="TERNARY_OPERATION_WRAP" value="1" />
+    <option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
+    <option name="FOR_STATEMENT_WRAP" value="1" />
+    <option name="ARRAY_INITIALIZER_WRAP" value="1" />
+    <option name="ASSIGNMENT_WRAP" value="1" />
+    <option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
+    <option name="WRAP_COMMENTS" value="true" />
+    <option name="IF_BRACE_FORCE" value="3" />
+    <option name="DOWHILE_BRACE_FORCE" value="3" />
+    <option name="WHILE_BRACE_FORCE" value="3" />
+    <option name="FOR_BRACE_FORCE" value="3" />
+    <option name="PARENT_SETTINGS_INSTALLED" value="true" />
+  </codeStyleSettings>
 </code_scheme>
 
diff --git a/scripts/compare-installed-size.py b/scripts/compare-installed-size.py
new file mode 100755
index 0000000..488723d
--- /dev/null
+++ b/scripts/compare-installed-size.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""summarize and compare the component sizes in installed-files.txt."""
+
+import sys
+
+bin_size1 = {}
+bin_size2 = {}
+bin_sizes = [bin_size1, bin_size2]
+
+file_sizes = {}
+
+def PrintUsage():
+  print "usage: " + sys.argv[0] + " filename [filename2]"
+  print ""
+  print "  Input file is installed-files.txt from the build output directory."
+  print "  When only one input file is given, it will generate module_0.csv."
+  print "  When two input files are given, in addition it will generate"
+  print "  module_1.csv and comparison.csv."
+  print ""
+  print "  The module_x.csv file shows the aggregated file size in each module"
+  print "  (eg bin, lib, app, ...)"
+  print "  The comparison.cvs file shows the individual file sizes side by side"
+  print "  from two different builds"
+  print ""
+  print "  These files can be uploaded to Google Doc for further processing."
+  sys.exit(1)
+
+def ParseFile(install_file, idx):
+  input_stream = open(install_file, 'r')
+  for line in input_stream:
+    # line = "25027208  /system/lib/libchromeview.so"
+    line = line.strip()
+
+    # size = "25027208", name = "/system/lib/libchromeview.so"
+    size, name = line.split()
+
+    # components = ["", "system", "lib", "libchromeview.so"]
+    components = name.split('/')
+
+    # module = "lib"
+    module = components[2]
+
+    # filename = libchromeview.so"
+    filename = components[-1]
+
+    # sum up the file sizes by module name
+    if module not in bin_sizes[idx]:
+      bin_sizes[idx][module] = int(size)
+    else:
+      bin_sizes[idx][module] += int(size)
+
+    # sometimes a file only exists on one build but not the other - use 0 as the
+    # default size.
+    if idx == 0:
+      file_sizes[name] = [module, size, 0]
+    else:
+      if name in file_sizes:
+        file_sizes[name][-1] = size
+      else:
+        file_sizes[name] = [module, 0, size]
+
+  input_stream.close()
+
+  # output the module csv file
+  output = open("module_%d.csv" % idx, 'w')
+  total = 0
+  for key in bin_sizes[idx]:
+    output.write("%s, %d\n" % (key, bin_sizes[idx][key]))
+  output.close()
+
+def main():
+  if len(sys.argv) < 2 or len(sys.argv) > 3:
+    PrintUsage()
+  # Parse the first installed-files.txt
+  ParseFile(sys.argv[1], 0)
+
+  # Parse the second installed-files.txt
+  if len(sys.argv) == 3:
+    ParseFile(sys.argv[2], 1)
+    # comparison.csv has the following columns:
+    # filename, module, size1, size2, size2-size1
+    # eg: /system/lib/libchromeview.so, lib, 25027208, 33278460, 8251252
+    output = open("comparison.csv", 'w')
+    for key in file_sizes:
+      output.write("%s, %s, %s, %s, %d\n" %
+                   (key, file_sizes[key][0], file_sizes[key][1],
+                    file_sizes[key][2],
+                    int(file_sizes[key][2]) - int(file_sizes[key][1])))
+    output.close()
+
+if __name__ == '__main__':
+  main()
+
+# vi: ts=2 sw=2
diff --git a/scripts/stack b/scripts/stack
index 6750752..6bb8d0a 100755
--- a/scripts/stack
+++ b/scripts/stack
@@ -1,18 +1,25 @@
 #!/usr/bin/env python
 #
-# Copyright 2006 Google Inc. All Rights Reserved.
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
 
 """stack symbolizes native crash dumps."""
 
 import getopt
-import getpass
-import glob
-import os
-import re
-import subprocess
 import sys
-import urllib
 
+import stack_core
 import symbol
 
 
@@ -22,17 +29,8 @@
   print
   print "  usage: " + sys.argv[0] + " [options] [FILE]"
   print
-  print "  --symbols-dir=path"
-  print "       the path to a symbols dir, such as =/tmp/out/target/product/dream/symbols"
-  print
-  print "  --symbols-zip=path"
-  print "       the path to a symbols zip file, such as =dream-symbols-12345.zip"
-  print
-  print "  --auto"
-  print "       attempt to:"
-  print "         1) automatically find the build number in the crash"
-  print "         2) if it's an official build, download the symbols "
-  print "            from the build server, and use them"
+  print "  --arch=arm|x86"
+  print "       the target architecture"
   print
   print "  FILE should contain a stack trace in it somewhere"
   print "       the tool will find that and re-print it with"
@@ -44,347 +42,23 @@
   sys.exit(1)
 
 
-class SSOCookie(object):
-  """Creates a cookie file so we can download files from the build server."""
-
-  def __init__(self, cookiename=".sso.cookie", keep=False):
-    self.sso_server = "login.corp.google.com"
-    self.name = cookiename
-    self.keeper = keep
-    if not os.path.exists(self.name):
-      user = os.environ["USER"]
-      print "\n%s, to access the symbols, please enter your LDAP " % user,
-      sys.stdout.flush()
-      password = getpass.getpass()
-      params = urllib.urlencode({"u": user, "pw": password})
-      url = "https://%s/login?ssoformat=CORP_SSO" % self.sso_server
-      # login to SSO
-      curlcmd = ["/usr/bin/curl",
-                 "--cookie", self.name,
-                 "--cookie-jar", self.name,
-                 "--silent",
-                 "--location",
-                 "--data", params,
-                 "--output", "/dev/null",
-                 url]
-      subprocess.check_call(curlcmd)
-      if os.path.exists(self.name):
-        os.chmod(self.name, 0600)
-      else:
-        print "Could not log in to SSO"
-        sys.exit(1)
-
-  def __del__(self):
-    """Clean up."""
-    if not self.keeper:
-      os.remove(self.name)
-
-
-class NoBuildIDException(Exception):
-  pass
-
-
-def FindBuildFingerprint(lines):
-  """Searches the given file (array of lines) for the build fingerprint."""
-  fingerprint_regex = re.compile("^.*Build fingerprint:\s'(?P<fingerprint>.*)'")
-  for line in lines:
-    fingerprint_search = fingerprint_regex.match(line.strip())
-    if fingerprint_search:
-      return fingerprint_search.group("fingerprint")
-
-  return None  # didn't find the fingerprint string, so return none
-
-
-class SymbolDownloadException(Exception):
-  pass
-
-
-DEFAULT_SYMROOT = "/tmp/symbols"
-
-
-def DownloadSymbols(fingerprint, cookie):
-  """Attempts to download the symbols from the build server.
-
-  If successful, extracts them, and returns the path.
-
-  Args:
-    fingerprint: build fingerprint from the input stack trace
-    cookie: SSOCookie
-
-  Returns:
-    tuple (None, None) if no fingerprint is provided. Otherwise
-    tuple (root directory, symbols directory).
-
-  Raises:
-    SymbolDownloadException: Problem downloading symbols for fingerprint
-  """
-  if fingerprint is None:
-    return (None, None)
-  symdir = "%s/%s" % (DEFAULT_SYMROOT, hash(fingerprint))
-  if not os.path.exists(symdir):
-    os.makedirs(symdir)
-  # build server figures out the branch based on the CL
-  params = {
-      "op": "GET-SYMBOLS-LINK",
-      "fingerprint": fingerprint,
-      }
-  print "url: http://android-build/buildbot-update?" + urllib.urlencode(params)
-  url = urllib.urlopen("http://android-build/buildbot-update?",
-                       urllib.urlencode(params)).readlines()[0]
-  if not url:
-    raise SymbolDownloadException("Build server down? Failed to find syms...")
-
-  regex_str = (r"(?P<base_url>http\:\/\/android-build\/builds\/.*\/[0-9]+)"
-               r"(?P<img>.*)")
-  url_regex = re.compile(regex_str)
-  url_match = url_regex.match(url)
-  if url_match is None:
-    raise SymbolDownloadException("Unexpected results from build server URL...")
-
-  base_url = url_match.group("base_url")
-  img = url_match.group("img")
-  symbolfile = img.replace("-img-", "-symbols-")
-  symurl = base_url + symbolfile
-  localsyms = symdir + symbolfile
-
-  if not os.path.exists(localsyms):
-    print "downloading %s ..." % symurl
-    curlcmd = ["/usr/bin/curl",
-               "--cookie", cookie.name,
-               "--silent",
-               "--location",
-               "--write-out", "%{http_code}",
-               "--output", localsyms,
-               symurl]
-    p = subprocess.Popen(curlcmd,
-                         stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                         close_fds=True)
-    code = p.stdout.read()
-    err = p.stderr.read()
-    if err:
-      raise SymbolDownloadException("stderr from curl download: %s" % err)
-    if code != "200":
-      raise SymbolDownloadException("Faied to download %s" % symurl)
-  else:
-    print "using existing cache for symbols"
-
-  return UnzipSymbols(localsyms, symdir)
-
-
-def UnzipSymbols(symbolfile, symdir=None):
-  """Unzips a file to DEFAULT_SYMROOT and returns the unzipped location.
-
-  Args:
-    symbolfile: The .zip file to unzip
-    symdir: Optional temporary directory to use for extraction
-
-  Returns:
-    A tuple containing (the directory into which the zip file was unzipped,
-    the path to the "symbols" directory in the unzipped file).  To clean
-    up, the caller can delete the first element of the tuple.
-
-  Raises:
-    SymbolDownloadException: When the unzip fails.
-  """
-  if not symdir:
-    symdir = "%s/%s" % (DEFAULT_SYMROOT, hash(symbolfile))
-  if not os.path.exists(symdir):
-    os.makedirs(symdir)
-
-  print "extracting %s..." % symbolfile
-  saveddir = os.getcwd()
-  os.chdir(symdir)
-  try:
-    unzipcode = subprocess.call(["unzip", "-qq", "-o", symbolfile])
-    if unzipcode > 0:
-      os.remove(symbolfile)
-      raise SymbolDownloadException("failed to extract symbol files (%s)."
-                                    % symbolfile)
-  finally:
-    os.chdir(saveddir)
-
-  return (symdir, glob.glob("%s/out/target/product/*/symbols" % symdir)[0])
-
-
-def PrintTraceLines(trace_lines):
-  """Print back trace."""
-  maxlen = max(map(lambda tl: len(tl[1]), trace_lines))
-  print
-  print "Stack Trace:"
-  print "  RELADDR   " + "FUNCTION".ljust(maxlen) + "  FILE:LINE"
-  for tl in trace_lines:
-    (addr, symbol_with_offset, location) = tl
-    print "  %8s  %s  %s" % (addr, symbol_with_offset.ljust(maxlen), location)
-  return
-
-
-def PrintValueLines(value_lines):
-  """Print stack data values."""
-  print
-  print "Stack Data:"
-  print "  ADDR      VALUE     FILE:LINE/FUNCTION"
-  for vl in value_lines:
-    (addr, value, symbol_with_offset, location) = vl
-    print "  " + addr + "  " + value + "  " + location
-    if location:
-      print "                      " + symbol_with_offset
-  return
-
-UNKNOWN = "<unknown>"
-HEAP = "[heap]"
-STACK = "[stack]"
-
-
-def ConvertTrace(lines):
-  """Convert strings containing native crash to a stack."""
-  process_info_line = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
-  signal_line = re.compile("(signal [0-9]+ \(.*\).*)")
-  register_line = re.compile("(([ ]*[0-9a-z]{2} [0-9a-f]{8}){4})")
-  thread_line = re.compile("(.*)(\-\-\- ){15}\-\-\-")
-  # Note taht both trace and value line matching allow for variable amounts of
-  # whitespace (e.g. \t). This is because the we want to allow for the stack
-  # tool to operate on AndroidFeedback provided system logs. AndroidFeedback
-  # strips out double spaces that are found in tombsone files and logcat output.
-  #
-  # Examples of matched trace lines include lines from tombstone files like:
-  #   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so
-  # Or lines from AndroidFeedback crash report system logs like:
-  #   03-25 00:51:05.520 I/DEBUG ( 65): #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so
-  # Please note the spacing differences.
-  trace_line = re.compile("(.*)\#([0-9]+)[ \t]+(..)[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)( \((.*)\))?")  # pylint: disable-msg=C6310
-  # Examples of matched value lines include:
-  #   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so
-  #   03-25 00:51:05.530 I/DEBUG ( 65): bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
-  # Again, note the spacing differences.
-  value_line = re.compile("(.*)([0-9a-f]{8})[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)")
-  # Lines from 'code around' sections of the output will be matched before
-  # value lines because otheriwse the 'code around' sections will be confused as
-  # value lines.
-  #
-  # Examples include:
-  #   801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
-  #   03-25 00:51:05.530 I/DEBUG ( 65): 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
-  code_line = re.compile("(.*)[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[ \r\n]")  # pylint: disable-msg=C6310
-
-  trace_lines = []
-  value_lines = []
-
-  for ln in lines:
-    # AndroidFeedback adds zero width spaces into its crash reports. These
-    # should be removed or the regular expresssions will fail to match.
-    line = unicode(ln, errors='ignore')
-    header = process_info_line.search(line)
-    if header:
-      print header.group(1)
-      continue
-    header = signal_line.search(line)
-    if header:
-      print header.group(1)
-      continue
-    header = register_line.search(line)
-    if header:
-      print header.group(1)
-      continue
-    if trace_line.match(line):
-      match = trace_line.match(line)
-      (unused_0, unused_1, unused_2,
-       code_addr, area, symbol_present, symbol_name) = match.groups()
-
-      if area == UNKNOWN or area == HEAP or area == STACK:
-        trace_lines.append((code_addr, area, area))
-      else:
-        # If a calls b which further calls c and c is inlined to b, we want to
-        # display "a -> b -> c" in the stack trace instead of just "a -> c"
-        (source_symbol,
-         source_location,
-         object_symbol_with_offset) = symbol.SymbolInformation(area, code_addr)
-        if not source_symbol:
-          if symbol_present:
-            source_symbol = symbol.CallCppFilt(symbol_name)
-          else:
-            source_symbol = UNKNOWN
-        if not source_location:
-          source_location = area
-        if not object_symbol_with_offset:
-          object_symbol_with_offset = source_symbol
-        if not object_symbol_with_offset.startswith(source_symbol):
-          trace_lines.append(("v------>", source_symbol, source_location))
-          trace_lines.append((code_addr,
-                              object_symbol_with_offset,
-                              source_location))
-        else:
-          trace_lines.append((code_addr,
-                              object_symbol_with_offset,
-                              source_location))
-    if code_line.match(line):
-      # Code lines should be ignored. If this were exluded the 'code around'
-      # sections would trigger value_line matches.
-      continue;
-    if value_line.match(line):
-      match = value_line.match(line)
-      (unused_, addr, value, area) = match.groups()
-      if area == UNKNOWN or area == HEAP or area == STACK or not area:
-        value_lines.append((addr, value, area, ""))
-      else:
-        (source_symbol,
-         source_location,
-         object_symbol_with_offset) = symbol.SymbolInformation(area, value)
-        if not source_location:
-          source_location = ""
-        if not object_symbol_with_offset:
-          object_symbol_with_offset = UNKNOWN
-        value_lines.append((addr,
-                            value,
-                            object_symbol_with_offset,
-                            source_location))
-    header = thread_line.search(line)
-    if header:
-      if trace_lines:
-        PrintTraceLines(trace_lines)
-
-      if value_lines:
-        PrintValueLines(value_lines)
-      trace_lines = []
-      value_lines = []
-      print
-      print "-----------------------------------------------------\n"
-
-  if trace_lines:
-    PrintTraceLines(trace_lines)
-
-  if value_lines:
-    PrintValueLines(value_lines)
-
-
 def main():
   try:
     options, arguments = getopt.getopt(sys.argv[1:], "",
-                                       ["auto",
-                                        "symbols-dir=",
-                                        "symbols-zip=",
+                                       ["arch=",
                                         "help"])
   except getopt.GetoptError, unused_error:
     PrintUsage()
 
-  zip_arg = None
-  auto = False
-  fingerprint = None
   for option, value in options:
     if option == "--help":
       PrintUsage()
-    elif option == "--symbols-dir":
-      symbol.SYMBOLS_DIR = os.path.expanduser(value)
-    elif option == "--symbols-zip":
-      zip_arg = os.path.expanduser(value)
-    elif option == "--auto":
-      auto = True
+    elif option == "--arch":
+      symbol.ARCH = value
 
   if len(arguments) > 1:
     PrintUsage()
 
-  if auto:
-    cookie = SSOCookie(".symbols.cookie")
-
   if not arguments or arguments[0] == "-":
     print "Reading native crash info from stdin"
     f = sys.stdin
@@ -395,22 +69,8 @@
   lines = f.readlines()
   f.close()
 
-  rootdir = None
-  if auto:
-    fingerprint = FindBuildFingerprint(lines)
-    print "fingerprint:", fingerprint
-    rootdir, symbol.SYMBOLS_DIR = DownloadSymbols(fingerprint, cookie)
-  elif zip_arg:
-    rootdir, symbol.SYMBOLS_DIR = UnzipSymbols(zip_arg)
-
   print "Reading symbols from", symbol.SYMBOLS_DIR
-  ConvertTrace(lines)
-
-  if rootdir:
-    # be a good citizen and clean up...os.rmdir and os.removedirs() don't work
-    cmd = "rm -rf \"%s\"" % rootdir
-    print "\ncleaning up (%s)" % cmd
-    os.system(cmd)
+  stack_core.ConvertTrace(lines)
 
 if __name__ == "__main__":
   main()
diff --git a/scripts/stack_core.py b/scripts/stack_core.py
new file mode 100755
index 0000000..42285d4
--- /dev/null
+++ b/scripts/stack_core.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""stack symbolizes native crash dumps."""
+
+import re
+
+import symbol
+
+def PrintTraceLines(trace_lines):
+  """Print back trace."""
+  maxlen = max(map(lambda tl: len(tl[1]), trace_lines))
+  print
+  print "Stack Trace:"
+  print "  RELADDR   " + "FUNCTION".ljust(maxlen) + "  FILE:LINE"
+  for tl in trace_lines:
+    (addr, symbol_with_offset, location) = tl
+    print "  %8s  %s  %s" % (addr, symbol_with_offset.ljust(maxlen), location)
+  return
+
+
+def PrintValueLines(value_lines):
+  """Print stack data values."""
+  maxlen = max(map(lambda tl: len(tl[2]), value_lines))
+  print
+  print "Stack Data:"
+  print "  ADDR      VALUE     " + "FUNCTION".ljust(maxlen) + "  FILE:LINE"
+  for vl in value_lines:
+    (addr, value, symbol_with_offset, location) = vl
+    print "  %8s  %8s  %s  %s" % (addr, value, symbol_with_offset.ljust(maxlen), location)
+  return
+
+UNKNOWN = "<unknown>"
+HEAP = "[heap]"
+STACK = "[stack]"
+
+
+def PrintOutput(trace_lines, value_lines):
+  if trace_lines:
+    PrintTraceLines(trace_lines)
+  if value_lines:
+    PrintValueLines(value_lines)
+
+def PrintDivider():
+  print
+  print "-----------------------------------------------------\n"
+
+def ConvertTrace(lines):
+  """Convert strings containing native crash to a stack."""
+  process_info_line = re.compile("(pid: [0-9]+, tid: [0-9]+.*)")
+  signal_line = re.compile("(signal [0-9]+ \(.*\).*)")
+  register_line = re.compile("(([ ]*[0-9a-z]{2} [0-9a-f]{8}){4})")
+  thread_line = re.compile("(.*)(\-\-\- ){15}\-\-\-")
+  dalvik_jni_thread_line = re.compile("(\".*\" prio=[0-9]+ tid=[0-9]+ NATIVE.*)")
+  dalvik_native_thread_line = re.compile("(\".*\" sysTid=[0-9]+ nice=[0-9]+.*)")
+  # Note that both trace and value line matching allow for variable amounts of
+  # whitespace (e.g. \t). This is because the we want to allow for the stack
+  # tool to operate on AndroidFeedback provided system logs. AndroidFeedback
+  # strips out double spaces that are found in tombsone files and logcat output.
+  #
+  # Examples of matched trace lines include lines from tombstone files like:
+  #   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so
+  #   #00  pc 001cf42e  /data/data/com.my.project/lib/libmyproject.so (symbol)
+  # Or lines from AndroidFeedback crash report system logs like:
+  #   03-25 00:51:05.520 I/DEBUG ( 65): #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so
+  # Please note the spacing differences.
+  trace_line = re.compile("(.*)\#([0-9]+)[ \t]+(..)[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)( \((.*)\))?")  # pylint: disable-msg=C6310
+  # Examples of matched value lines include:
+  #   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so
+  #   bea4170c  8018e4e9  /data/data/com.my.project/lib/libmyproject.so (symbol)
+  #   03-25 00:51:05.530 I/DEBUG ( 65): bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
+  # Again, note the spacing differences.
+  value_line = re.compile("(.*)([0-9a-f]{8})[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)( \((.*)\))?")
+  # Lines from 'code around' sections of the output will be matched before
+  # value lines because otheriwse the 'code around' sections will be confused as
+  # value lines.
+  #
+  # Examples include:
+  #   801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
+  #   03-25 00:51:05.530 I/DEBUG ( 65): 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
+  code_line = re.compile("(.*)[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[a-f0-9]{8}[ \t]*[ \r\n]")  # pylint: disable-msg=C6310
+
+  trace_lines = []
+  value_lines = []
+  last_frame = -1
+
+  for ln in lines:
+    # AndroidFeedback adds zero width spaces into its crash reports. These
+    # should be removed or the regular expresssions will fail to match.
+    line = unicode(ln, errors='ignore')
+    process_header = process_info_line.search(line)
+    signal_header = signal_line.search(line)
+    register_header = register_line.search(line)
+    thread_header = thread_line.search(line)
+    dalvik_jni_thread_header = dalvik_jni_thread_line.search(line)
+    dalvik_native_thread_header = dalvik_native_thread_line.search(line)
+    if process_header or signal_header or register_header or thread_header \
+        or dalvik_jni_thread_header or dalvik_native_thread_header:
+      if trace_lines or value_lines:
+        PrintOutput(trace_lines, value_lines)
+        PrintDivider()
+        trace_lines = []
+        value_lines = []
+        last_frame = -1
+      if process_header:
+        print process_header.group(1)
+      if signal_header:
+        print signal_header.group(1)
+      if register_header:
+        print register_header.group(1)
+      if thread_header:
+        print thread_header.group(1)
+      if dalvik_jni_thread_header:
+        print dalvik_jni_thread_header.group(1)
+      if dalvik_native_thread_header:
+        print dalvik_native_thread_header.group(1)
+      continue
+    if trace_line.match(line):
+      match = trace_line.match(line)
+      (unused_0, frame, unused_1,
+       code_addr, area, symbol_present, symbol_name) = match.groups()
+
+      if frame <= last_frame and (trace_lines or value_lines):
+        PrintOutput(trace_lines, value_lines)
+        PrintDivider()
+        trace_lines = []
+        value_lines = []
+      last_frame = frame
+
+      if area == UNKNOWN or area == HEAP or area == STACK:
+        trace_lines.append((code_addr, "", area))
+      else:
+        # If a calls b which further calls c and c is inlined to b, we want to
+        # display "a -> b -> c" in the stack trace instead of just "a -> c"
+        info = symbol.SymbolInformation(area, code_addr)
+        nest_count = len(info) - 1
+        for (source_symbol, source_location, object_symbol_with_offset) in info:
+          if not source_symbol:
+            if symbol_present:
+              source_symbol = symbol.CallCppFilt(symbol_name)
+            else:
+              source_symbol = UNKNOWN
+          if not source_location:
+            source_location = area
+          if nest_count > 0:
+            nest_count = nest_count - 1
+            trace_lines.append(("v------>", source_symbol, source_location))
+          else:
+            if not object_symbol_with_offset:
+              object_symbol_with_offset = source_symbol
+            trace_lines.append((code_addr,
+                                object_symbol_with_offset,
+                                source_location))
+    if code_line.match(line):
+      # Code lines should be ignored. If this were exluded the 'code around'
+      # sections would trigger value_line matches.
+      continue;
+    if value_line.match(line):
+      match = value_line.match(line)
+      (unused_, addr, value, area, symbol_present, symbol_name) = match.groups()
+      if area == UNKNOWN or area == HEAP or area == STACK or not area:
+        value_lines.append((addr, value, "", area))
+      else:
+        info = symbol.SymbolInformation(area, value)
+        (source_symbol, source_location, object_symbol_with_offset) = info.pop()
+        if not source_symbol:
+          if symbol_present:
+            source_symbol = symbol.CallCppFilt(symbol_name)
+          else:
+            source_symbol = UNKNOWN
+        if not source_location:
+          source_location = area
+        if not object_symbol_with_offset:
+          object_symbol_with_offset = source_symbol
+        value_lines.append((addr,
+                            value,
+                            object_symbol_with_offset,
+                            source_location))
+
+  PrintOutput(trace_lines, value_lines)
+
+
+# vi: ts=2 sw=2
diff --git a/scripts/symbol.py b/scripts/symbol.py
index b0e94d8..0f58df6 100755
--- a/scripts/symbol.py
+++ b/scripts/symbol.py
@@ -1,6 +1,18 @@
 #!/usr/bin/python
 #
-# Copyright 2006 Google Inc. All Rights Reserved.
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
 
 """Module for looking up symbolic debugging information.
 
@@ -29,6 +41,10 @@
 
 SYMBOLS_DIR = FindSymbolsDir()
 
+ARCH = "arm"
+
+TOOLCHAIN_INFO = None
+
 def Uname():
   """'uname' for constructing prebuilt/<...> and out/host/<...> paths."""
   uname = os.uname()[0]
@@ -44,9 +60,9 @@
 def ToolPath(tool, toolchain_info=None):
   """Return a full qualified path to the specified tool"""
   if not toolchain_info:
-    toolchain_info = TOOLCHAIN_INFO
-  (label, target) = toolchain_info
-  return os.path.join(ANDROID_BUILD_TOP, "prebuilts", "gcc", Uname(), "arm", label, "bin",
+    toolchain_info = FindToolchain()
+  (label, platform, target) = toolchain_info
+  return os.path.join(ANDROID_BUILD_TOP, "prebuilts/gcc", Uname(), platform, label, "bin",
                      target + "-" + tool)
 
 def FindToolchain():
@@ -58,27 +74,32 @@
   Returns:
     A pair of strings containing toolchain label and target prefix.
   """
+  global TOOLCHAIN_INFO
+  if TOOLCHAIN_INFO is not None:
+    return TOOLCHAIN_INFO
 
   ## Known toolchains, newer ones in the front.
-  known_toolchains = [
-    ("arm-eabi-4.6", "arm-eabi"),
-    ("arm-linux-androideabi-4.4.x", "arm-linux-androideabi"),
-    ("arm-eabi-4.4.3", "arm-eabi"),
-    ("arm-eabi-4.4.0", "arm-eabi"),
-    ("arm-eabi-4.3.1", "arm-eabi"),
-    ("arm-eabi-4.2.1", "arm-eabi")
-  ]
+  if ARCH == "arm":
+    gcc_version = os.environ["TARGET_GCC_VERSION"]
+    known_toolchains = [
+      ("arm-linux-androideabi-" + gcc_version, "arm", "arm-linux-androideabi"),
+    ]
+  elif ARCH =="x86":
+    known_toolchains = [
+      ("i686-android-linux-4.4.3", "x86", "i686-android-linux")
+    ]
+  else:
+    known_toolchains = []
 
   # Look for addr2line to check for valid toolchain path.
-  for (label, target) in known_toolchains:
-    toolchain_info = (label, target);
+  for (label, platform, target) in known_toolchains:
+    toolchain_info = (label, platform, target);
     if os.path.exists(ToolPath("addr2line", toolchain_info)):
+      TOOLCHAIN_INFO = toolchain_info
       return toolchain_info
 
   raise Exception("Could not find tool chain")
 
-TOOLCHAIN_INFO = FindToolchain()
-
 def SymbolInformation(lib, addr):
   """Look up symbol information about an address.
 
@@ -87,20 +108,19 @@
     addr: string hexidecimal address
 
   Returns:
-    For a given library and address, return tuple of: (source_symbol,
-    source_location, object_symbol_with_offset) the values may be None
-    if the information was unavailable.
+    A list of the form [(source_symbol, source_location,
+    object_symbol_with_offset)].
 
-    source_symbol may not be a prefix of object_symbol_with_offset if
-    the source function was inlined in the object code of another
-    function.
+    If the function has been inlined then the list may contain
+    more than one element with the symbols for the most deeply
+    nested inlined location appearing first.  The list is
+    always non-empty, even if no information is available.
 
-    usually you want to display the object_symbol_with_offset and
-    source_location, the source_symbol is only useful to show if the
-    address was from an inlined function.
+    Usually you want to display the source_location and
+    object_symbol_with_offset from the last element in the list.
   """
   info = SymbolInformationForSet(lib, set([addr]))
-  return (info and info.get(addr)) or (None, None, None)
+  return (info and info.get(addr)) or [(None, None, None)]
 
 
 def SymbolInformationForSet(lib, unique_addrs):
@@ -111,17 +131,17 @@
     unique_addrs: set of hexidecimal addresses
 
   Returns:
-    For a given library and set of addresses, returns a dictionary of the form
-    {addr: (source_symbol, source_location, object_symbol_with_offset)}. The
-    values may be None if the information was unavailable.
+    A dictionary of the form {addr: [(source_symbol, source_location,
+    object_symbol_with_offset)]} where each address has a list of
+    associated symbols and locations.  The list is always non-empty.
 
-    For a given address, source_symbol may not be a prefix of
-    object_symbol_with_offset if the source function was inlined in the
-    object code of another function.
+    If the function has been inlined then the list may contain
+    more than one element with the symbols for the most deeply
+    nested inlined location appearing first.  The list is
+    always non-empty, even if no information is available.
 
-    Usually you want to display the object_symbol_with_offset and
-    source_location; the source_symbol is only useful to show if the
-    address was from an inlined function.
+    Usually you want to display the source_location and
+    object_symbol_with_offset from the last element in the list.
   """
   if not lib:
     return None
@@ -136,14 +156,17 @@
 
   result = {}
   for addr in unique_addrs:
-    (source_symbol, source_location) = addr_to_line.get(addr, (None, None))
+    source_info = addr_to_line.get(addr)
+    if not source_info:
+      source_info = [(None, None)]
     if addr in addr_to_objdump:
       (object_symbol, object_offset) = addr_to_objdump.get(addr)
       object_symbol_with_offset = FormatSymbolWithOffset(object_symbol,
                                                          object_offset)
     else:
       object_symbol_with_offset = None
-    result[addr] = (source_symbol, source_location, object_symbol_with_offset)
+    result[addr] = [(source_symbol, source_location, object_symbol_with_offset)
+        for (source_symbol, source_location) in source_info]
 
   return result
 
@@ -156,8 +179,13 @@
     unique_addrs: set of string hexidecimal addresses look up.
 
   Returns:
-    A dictionary of the form {addr: (symbol, file:line)}. The values may
-    be (None, None) if the address could not be looked up.
+    A dictionary of the form {addr: [(symbol, file:line)]} where
+    each address has a list of associated symbols and locations
+    or an empty list if no symbol information was found.
+
+    If the function has been inlined then the list may contain
+    more than one element with the symbols for the most deeply
+    nested inlined location appearing first.
   """
   if not lib:
     return None
@@ -167,8 +195,9 @@
   if not os.path.exists(symbols):
     return None
 
-  (label, target) = TOOLCHAIN_INFO
-  cmd = [ToolPath("addr2line"), "--functions", "--demangle", "--exe=" + symbols]
+  (label, platform, target) = FindToolchain()
+  cmd = [ToolPath("addr2line"), "--functions", "--inlines",
+      "--demangle", "--exe=" + symbols]
   child = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
 
   result = {}
@@ -176,18 +205,45 @@
   for addr in addrs:
     child.stdin.write("0x%s\n" % addr)
     child.stdin.flush()
-    symbol = child.stdout.readline().strip()
-    if symbol == "??":
-      symbol = None
-    location = child.stdout.readline().strip()
-    if location == "??:0":
-      location = None
-    result[addr] = (symbol, location)
+    records = []
+    first = True
+    while True:
+      symbol = child.stdout.readline().strip()
+      if symbol == "??":
+        symbol = None
+      location = child.stdout.readline().strip()
+      if location == "??:0":
+        location = None
+      if symbol is None and location is None:
+        break
+      records.append((symbol, location))
+      if first:
+        # Write a blank line as a sentinel so we know when to stop
+        # reading inlines from the output.
+        # The blank line will cause addr2line to emit "??\n??:0\n".
+        child.stdin.write("\n")
+        first = False
+    result[addr] = records
   child.stdin.close()
   child.stdout.close()
   return result
 
 
+def StripPC(addr):
+  """Strips the Thumb bit a program counter address when appropriate.
+
+  Args:
+    addr: the program counter address
+
+  Returns:
+    The stripped program counter address.
+  """
+  global ARCH
+
+  if ARCH == "arm":
+    return addr & ~1
+  return addr
+
 def CallObjdumpForSet(lib, unique_addrs):
   """Use objdump to find out the names of the containing functions.
 
@@ -210,13 +266,13 @@
     return None
 
   addrs = sorted(unique_addrs)
-  start_addr_hex = addrs[0]
-  stop_addr_dec = str(int(addrs[-1], 16) + 8)
+  start_addr_dec = str(StripPC(int(addrs[0], 16)))
+  stop_addr_dec = str(StripPC(int(addrs[-1], 16)) + 8)
   cmd = [ToolPath("objdump"),
          "--section=.text",
          "--demangle",
          "--disassemble",
-         "--start-address=0x" + start_addr_hex,
+         "--start-address=" + start_addr_dec,
          "--stop-address=" + stop_addr_dec,
          symbols]
 
@@ -261,7 +317,7 @@
       addr = components.group(1)
       target_addr = addrs[addr_index]
       i_addr = int(addr, 16)
-      i_target = int(target_addr, 16)
+      i_target = StripPC(int(target_addr, 16))
       if i_addr == i_target:
         result[target_addr] = (current_symbol, i_target - current_symbol_addr)
         addr_index += 1
diff --git a/tools/idegen/Android.mk b/tools/idegen/Android.mk
index d424ab6..8771160 100644
--- a/tools/idegen/Android.mk
+++ b/tools/idegen/Android.mk
@@ -2,8 +2,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-        guavalib \
+LOCAL_STATIC_JAVA_LIBRARIES := guavalib
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
diff --git a/tools/idegen/index-gen.sh b/tools/idegen/index-gen.sh
index eadaa98..5b9e24b 100755
--- a/tools/idegen/index-gen.sh
+++ b/tools/idegen/index-gen.sh
@@ -14,12 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Generates a module index file by searching through android source tree for make files.  The
-# intellij-gen.sh script automatically calls this script the first time or if you delete the
-# generated indexed file.  The only time you need to run this manually is if modules are added or
-# deleted.
+# Generates a module index file by searching through android source
+# tree for make files.  The intellij-gen.sh script automatically calls
+# this script the first time or if you delete the generated indexed
+# file.  The only time you need to run this manually is if modules are
+# added or deleted.
 #
-# To use:
+# To use, run the following command from either your repo root or
+# development/tools/idegen:
 #   index-gen.sh
 #
 # Only tested on linux.  Should work for macs but have not tried.
@@ -27,7 +29,15 @@
 set -e
 
 script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-root_dir=`readlink -f -n $script_dir/../../..`
+#root_dir=`readlink -f -n $script_dir/../../..`
+root_dir=$PWD
+if [ ! -e $root_dir/.repo ]; then
+  root_dir=$PWD/../../..
+  if [ ! -e $root_dir/.repo ]; then
+    echo "Repo root not found. Run this script from your repo root or the idegen directory."
+    exit 1
+  fi
+fi
 tmp_file=tmp.txt
 dest_file=module-index.txt
 
diff --git a/tools/idegen/intellij-gen.sh b/tools/idegen/intellij-gen.sh
index 7f00eba..d67c1f8 100755
--- a/tools/idegen/intellij-gen.sh
+++ b/tools/idegen/intellij-gen.sh
@@ -14,7 +14,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# To use:
+# To use, run the following command from either your repo root or
+# development/tools/idegen:
 #   intellij-gen.sh <module name>
 #
 # where module name is the LOCAL_PACKAGE_NAME in Android.mk for the project.
@@ -22,27 +23,38 @@
 # For example, to generate a project for Contacts, use:
 #   intellij-gen.sh Contacts
 #
-# The project directory (.idea) will be put in the root directory of the module.  Sharable iml
-# files will be put into each respective module directory.
+# The project directory (.idea) will be put in the root directory of
+# the module.  Sharable iml files will be put into each respective
+# module directory.
 #
 # Only tested on linux.  Should work for macs but have not tried.
 #
 set -e
 
-script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-root_dir=`readlink -f -n $script_dir/../../..`
-index_file=$script_dir/module-index.txt
-idegenjar=$root_dir/out/host/common/obj/JAVA_LIBRARIES/idegen_intermediates/javalib.jar
-
 progname=`basename $0`
 if [ $# -ne 1 ]
 then
     echo "Usage: $progname <module_name>"
     exit 1
 fi
-
 module_name=$1
 
+script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+root_dir=$PWD
+if [ ! -e $root_dir/.repo ]; then
+  root_dir=$PWD/../../..
+  if [ ! -e $root_dir/.repo ]; then
+    echo "Repo root not found. Run this script from your repo root or the idegen directory."
+    exit 1
+  fi
+fi
+index_file=$root_dir/module-index.txt
+idegenjar=$script_dir/idegen.jar
+if [ ! -e $idegenjar ]; then
+  # See if the jar is in the build directory.
+  idegenjar=$root_dir/out/host/linux-x86/framework/idegen.jar
+fi
+
 if [ ! -e "$index_file" ]; then
   echo "Module index file missing; generating this is only done the first time."
   echo "If any dependencies change, you should generate a new index file by running index-gen.sh."
diff --git a/tools/idegen/src/com/android/idegen/Constants.java b/tools/idegen/src/com/android/idegen/Constants.java
deleted file mode 100644
index f541dd4..0000000
--- a/tools/idegen/src/com/android/idegen/Constants.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.idegen;
-
-import java.nio.charset.Charset;
-
-/**
- * Constants
- */
-public class Constants {
-
-    public static final Charset CHARSET = Charset.forName("UTF-8");
-
-    public static final String REL_TEMPLATE_DIR = "development/tools/idegen/templates";
-    public static final String REL_MODULES_TEMPLATE = REL_TEMPLATE_DIR + "/idea/modules.xml";
-    public static final String REL_VCS_TEMPLATE = REL_TEMPLATE_DIR + "/idea/vcs.xml";
-    public static final String REL_IML_TEMPLATE = REL_TEMPLATE_DIR + "/module-template.iml";
-
-    public static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
-
-    public static final String FRAMEWORK_MODULE = "framework";
-    public static final String[] AUTO_DEPENDENCIES = new String[]{
-            FRAMEWORK_MODULE, "libcore"
-    };
-    public static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[] {
-      "packages", "vendor", "frameworks/ex", "frameworks/opt", "frameworks/support"
-    };
-
-    // Framework needs a special constant for it's intermediates because it does not follow
-    // normal conventions.
-    public static final String FRAMEWORK_INTERMEDIATES = "framework-res_intermediates";
-}
diff --git a/tools/idegen/src/com/android/idegen/DirectorySearch.java b/tools/idegen/src/com/android/idegen/DirectorySearch.java
index 1bbf99f..2ff23e3 100644
--- a/tools/idegen/src/com/android/idegen/DirectorySearch.java
+++ b/tools/idegen/src/com/android/idegen/DirectorySearch.java
@@ -21,8 +21,12 @@
 import com.google.common.collect.Sets;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FilenameFilter;
+import java.net.URISyntaxException;
 import java.util.HashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -31,6 +35,8 @@
  */
 public class DirectorySearch {
 
+    private static final Logger logger = Logger.getLogger(DirectorySearch.class.getName());
+
     private static final HashSet<String> SOURCE_DIRS = Sets.newHashSet();
     static {
         SOURCE_DIRS.add("src");
@@ -40,6 +46,9 @@
     private static final Pattern EXCLUDE_PATTERN = Pattern.compile("values-..(-.*)*");
 
     private static File repoRoot = null;
+    public static final String REL_TEMPLATE_DIR = "templates";
+    public static final String REL_TEMPLATE_PATH_FROM_ROOT = "development/tools/idegen/"
+            + REL_TEMPLATE_DIR;
 
     /**
      * Find the repo root.  This is the root branch directory of a full repo checkout.
@@ -138,4 +147,38 @@
 
         return builder.build();
     }
+
+    private static File templateDirCurrent = null;
+    private static File templateDirRoot = null;
+
+    public static File findTemplateDir() throws FileNotFoundException {
+        // Cache optimization.
+        if (templateDirCurrent != null && templateDirCurrent.exists()) return templateDirCurrent;
+        if (templateDirRoot != null && templateDirRoot.exists()) return templateDirRoot;
+
+        File currentDir = null;
+        try {
+            currentDir = new File(IntellijProject.class.getProtectionDomain().getCodeSource()
+                    .getLocation().toURI().getPath()).getParentFile();
+        } catch (URISyntaxException e) {
+            logger.log(Level.SEVERE, "Could not get jar location.", e);
+            return null;
+        }
+
+        // First check relative to current run directory.
+        templateDirCurrent = new File(currentDir, REL_TEMPLATE_DIR);
+        if (templateDirCurrent.exists()) {
+            return templateDirCurrent;
+        } else {
+            // Then check relative to root directory.
+            templateDirRoot = new File(repoRoot, REL_TEMPLATE_PATH_FROM_ROOT);
+            if (templateDirRoot.exists()) {
+                return templateDirRoot;
+            }
+        }
+        throw new FileNotFoundException(
+                "Unable to find template dir. Tried the following locations:\n" +
+                templateDirCurrent.getAbsolutePath() + "\n" +
+                templateDirRoot.getAbsolutePath());
+    }
 }
diff --git a/tools/idegen/src/com/android/idegen/FrameworkModule.java b/tools/idegen/src/com/android/idegen/FrameworkModule.java
index bfcd1fa..8743925 100644
--- a/tools/idegen/src/com/android/idegen/FrameworkModule.java
+++ b/tools/idegen/src/com/android/idegen/FrameworkModule.java
@@ -25,15 +25,19 @@
  */
 public class FrameworkModule extends StandardModule {
 
+    // Framework needs a special constant for it's intermediates because it does not follow
+    // normal conventions.
+    private static final String FRAMEWORK_INTERMEDIATES = "framework-res_intermediates";
+
     public FrameworkModule(String moduleName, String makeFile) {
-        super(Constants.FRAMEWORK_MODULE, makeFile, true);
+        super(IntellijProject.FRAMEWORK_MODULE, makeFile, true);
     }
 
     @Override
     protected String buildIntermediates() {
         StringBuilder sb = new StringBuilder();
         File intermediates = new File(repoRoot,
-                Constants.REL_OUT_APP_DIR + File.separator +  Constants.FRAMEWORK_INTERMEDIATES);
+                REL_OUT_APP_DIR + File.separator +  FRAMEWORK_INTERMEDIATES);
         ImmutableList<File> intermediateSrcDirs = DirectorySearch.findSourceDirs(intermediates);
         sb.append("    <content url=\"file://").append(intermediates).append("\">\n");
         for (File src : intermediateSrcDirs) {
diff --git a/tools/idegen/src/com/android/idegen/IntellijProject.java b/tools/idegen/src/com/android/idegen/IntellijProject.java
index d5564d5..e49a12b 100644
--- a/tools/idegen/src/com/android/idegen/IntellijProject.java
+++ b/tools/idegen/src/com/android/idegen/IntellijProject.java
@@ -22,6 +22,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.charset.Charset;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.logging.Logger;
@@ -31,9 +32,16 @@
  */
 public class IntellijProject {
 
+    public static final String FRAMEWORK_MODULE = "framework";
+    public static final Charset CHARSET = Charset.forName("UTF-8");
+
     private static final Logger logger = Logger.getLogger(IntellijProject.class.getName());
 
+    private static final String MODULES_TEMPLATE_FILE_NAME = "modules.xml";
+    private static final String VCS_TEMPLATE_FILE_NAME = "vcs.xml";
+
     ModuleCache cache = ModuleCache.getInstance();
+
     File indexFile;
     File repoRoot;
     File projectIdeaDir;
@@ -55,6 +63,11 @@
 
         // First pass, find all dependencies and cache them.
         Module module = cache.getAndCache(moduleName);
+        if (module == null) {
+            logger.info("Module '" + moduleName + "' not found." +
+                    " Module names are case senstive.");
+            return;
+        }
         projectIdeaDir = new File(module.getDir(), ".idea");
         projectIdeaDir.mkdir();
         copyTemplates();
@@ -104,19 +117,27 @@
 
     /**
      * Framework module needs special handling due to one off resource path:
-     *   frameworks/base/Android.mk
+     * frameworks/base/Android.mk
      */
     private void buildFrameWorkModule() throws IOException {
-        String makeFile = cache.getMakeFile(Constants.FRAMEWORK_MODULE);
-        logger.info("makefile: " + makeFile);
-        StandardModule frameworkModule = new FrameworkModule(Constants.FRAMEWORK_MODULE, makeFile);
-        frameworkModule.build();
-        cache.put(frameworkModule);
+        String makeFile = cache.getMakeFile(FRAMEWORK_MODULE);
+        if (makeFile == null) {
+            logger.warning("Unable to find framework module: " + FRAMEWORK_MODULE +
+                    ". Skipping.");
+        } else {
+            logger.info("makefile: " + makeFile);
+            StandardModule frameworkModule = new FrameworkModule(FRAMEWORK_MODULE,
+                    makeFile);
+            frameworkModule.build();
+            cache.put(frameworkModule);
+        }
     }
 
     private void createModulesFile(Module module) throws IOException {
-        String modulesContent = Files.toString(new File(repoRoot, Constants.REL_MODULES_TEMPLATE),
-                Constants.CHARSET);
+        String modulesContent = Files.toString(
+                new File(DirectorySearch.findTemplateDir(),
+                        "idea" + File.separator + MODULES_TEMPLATE_FILE_NAME),
+                CHARSET);
         StringBuilder sb = new StringBuilder();
         File moduleIml = module.getImlFile();
         sb.append("      <module fileurl=\"file://").append(moduleIml.getAbsolutePath())
@@ -131,12 +152,14 @@
 
         File out = new File(projectIdeaDir, "modules.xml");
         logger.info("Creating " + out.getAbsolutePath());
-        Files.write(modulesContent, out, Constants.CHARSET);
+        Files.write(modulesContent, out, CHARSET);
     }
 
     private void createVcsFile(Module module) throws IOException {
-        String vcsTemplate = Files.toString(new File(module.getRepoRoot(),
-                Constants.REL_VCS_TEMPLATE), Constants.CHARSET);
+        String vcsTemplate = Files.toString(
+                new File(DirectorySearch.findTemplateDir(),
+                        "idea" + File.separator + VCS_TEMPLATE_FILE_NAME),
+                CHARSET);
 
         StringBuilder sb = new StringBuilder();
         for (String name : module.getAllDependencies()) {
@@ -149,18 +172,17 @@
             }
         }
         vcsTemplate = vcsTemplate.replace("@VCS@", sb.toString());
-        Files.write(vcsTemplate, new File(projectIdeaDir, "vcs.xml"), Constants.CHARSET);
+        Files.write(vcsTemplate, new File(projectIdeaDir, "vcs.xml"), CHARSET);
     }
 
     private void createNameFile(String name) throws IOException {
-        File out =  new File(projectIdeaDir, ".name");
-        Files.write(name, out, Constants.CHARSET);
+        File out = new File(projectIdeaDir, ".name");
+        Files.write(name, out, CHARSET);
     }
 
     private void copyTemplates() throws IOException {
-        File templateDir = new File(repoRoot,
-                Constants.REL_TEMPLATE_DIR + File.separatorChar + "idea");
-        copyTemplates(templateDir, projectIdeaDir);
+        File templateDir = DirectorySearch.findTemplateDir();
+        copyTemplates(new File(templateDir, "idea"), projectIdeaDir);
     }
 
     private void copyTemplates(File fromDir, File toDir) throws IOException {
diff --git a/tools/idegen/src/com/android/idegen/Module.java b/tools/idegen/src/com/android/idegen/Module.java
index 7ba42a3..deb2281 100644
--- a/tools/idegen/src/com/android/idegen/Module.java
+++ b/tools/idegen/src/com/android/idegen/Module.java
@@ -34,6 +34,8 @@
 
     private static final Logger logger = Logger.getLogger(Module.class.getName());
 
+    private static final String IML_TEMPLATE_FILE_NAME = "module-template.iml";
+
     /**
      * All possible attributes for the make file.
      */
@@ -44,23 +46,35 @@
     }
 
     ModuleCache moduleCache = ModuleCache.getInstance();
+
     private File imlFile;
+
     private Set<String> allDependencies = Sets.newHashSet(); // direct + indirect
+
     private Set<File> allDependentImlFiles = Sets.newHashSet();
 
     protected abstract void build() throws IOException;
+
     protected abstract String getName();
+
     protected abstract File getDir();
+
     protected abstract boolean isAndroidModule();
+
     protected abstract List<File> getIntermediatesDirs();
+
     public abstract Set<String> getDirectDependencies();
+
     protected abstract ImmutableList<File> getSourceDirs();
+
     protected abstract ImmutableList<File> getExcludeDirs();
+
     public abstract File getRepoRoot();
 
     public void buildImlFile() throws IOException {
-        String imlTemplate = Files.toString(new File(getRepoRoot(), Constants.REL_IML_TEMPLATE),
-                Constants.CHARSET);
+        String imlTemplate = Files.toString(
+                new File(DirectorySearch.findTemplateDir(), IML_TEMPLATE_FILE_NAME),
+                IntellijProject.CHARSET);
 
         String facetXml = "";
         if (isAndroidModule()) {
@@ -100,7 +114,7 @@
 
         imlFile = new File(moduleDir, getName() + ".iml");
         logger.info("Creating " + imlFile.getAbsolutePath());
-        Files.write(imlTemplate, imlFile, Constants.CHARSET);
+        Files.write(imlTemplate, imlFile, IntellijProject.CHARSET);
     }
 
     protected String buildIntermediates() {
diff --git a/tools/idegen/src/com/android/idegen/StandardModule.java b/tools/idegen/src/com/android/idegen/StandardModule.java
index dffb95e..f7b24b0 100644
--- a/tools/idegen/src/com/android/idegen/StandardModule.java
+++ b/tools/idegen/src/com/android/idegen/StandardModule.java
@@ -17,6 +17,7 @@
 package com.android.idegen;
 
 import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
@@ -45,10 +46,18 @@
  */
 public class StandardModule extends Module {
 
+    static final String REL_OUT_APP_DIR = "out/target/common/obj/APPS";
+
     private static final Logger logger = Logger.getLogger(StandardModule.class.getName());
 
     private static final Pattern SRC_PATTERN = Pattern.compile(
             ".*\\(call all-java-files-under, (.*)\\)");
+    private static final String[] AUTO_DEPENDENCIES = new String[]{
+            IntellijProject.FRAMEWORK_MODULE, "libcore"
+    };
+    private static final String[] DIRS_WITH_AUTO_DEPENDENCIES = new String[]{
+            "packages", "vendor", "frameworks/ex", "frameworks/opt", "frameworks/support"
+    };
 
     String moduleName;
     File makeFile;
@@ -66,7 +75,8 @@
     }
 
     public StandardModule(String moduleName, String makeFile, boolean searchForSrc) {
-        this(moduleName, new File(makeFile), searchForSrc);
+        this(Preconditions.checkNotNull(moduleName), new File(Preconditions.checkNotNull(makeFile)),
+                searchForSrc);
     }
 
     public StandardModule(String moduleName, File makeFile, boolean searchForSrc) {
@@ -75,16 +85,16 @@
         this.moduleRoot = makeFile.getParentFile();
         this.repoRoot = DirectorySearch.findRepoRoot(makeFile);
         this.intermediatesDir = new File(repoRoot.getAbsolutePath() + File.separator +
-                Constants.REL_OUT_APP_DIR + File.separator + getName() + "_intermediates" +
+                REL_OUT_APP_DIR + File.separator + getName() + "_intermediates" +
                 File.separator + "src");
         this.searchForSrc = searchForSrc;
 
         // TODO: auto-detect when framework dependency is needed instead of using coded list.
-        for (String dir : Constants.DIRS_WITH_AUTO_DEPENDENCIES) {
+        for (String dir : DIRS_WITH_AUTO_DEPENDENCIES) {
             // length + 2 to account for slash
             boolean isDir = makeFile.getAbsolutePath().startsWith(repoRoot + "/" + dir);
             if (isDir) {
-                for (String dependency : Constants.AUTO_DEPENDENCIES) {
+                for (String dependency : AUTO_DEPENDENCIES) {
                     this.directDependencies.add(dependency);
                 }
             }