Merge changes Ie70f0117,I05ef7862,I80c51246

* changes:
  kallsyms parser: move to src/kallsyms/
  traced_perf: allow collection and symbolization of kernel frames
  traced_perf: add config option for kernel frames
diff --git a/Android.bp b/Android.bp
index cd7add4..ba600ad 100644
--- a/Android.bp
+++ b/Android.bp
@@ -140,6 +140,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   defaults: [
     "perfetto_defaults",
@@ -173,6 +174,9 @@
     "include",
     "include/perfetto/base/build_configs/android_tree",
   ],
+  generated_headers: [
+    "perfetto_src_base_version_gen_h",
+  ],
   defaults: [
     "perfetto_defaults",
   ],
@@ -216,6 +220,9 @@
     "include",
     "include/perfetto/base/build_configs/android_tree",
   ],
+  generated_headers: [
+    "perfetto_src_base_version_gen_h",
+  ],
   defaults: [
     "perfetto_defaults",
   ],
@@ -367,6 +374,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   defaults: [
     "perfetto_defaults",
@@ -395,6 +403,9 @@
   static_libs: [
     "libprotoc",
   ],
+  generated_headers: [
+    "perfetto_src_base_version_gen_h",
+  ],
   defaults: [
     "perfetto_defaults",
   ],
@@ -543,6 +554,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   defaults: [
     "perfetto_defaults",
@@ -721,6 +733,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   export_generated_headers: [
     "perfetto_protos_perfetto_common_cpp_gen_headers",
@@ -764,6 +777,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   defaults: [
     "perfetto_defaults",
@@ -898,6 +912,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
     "perfetto_src_perfetto_cmd_protos_gen_headers",
   ],
   defaults: [
@@ -1089,6 +1104,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   export_generated_headers: [
     "perfetto_protos_perfetto_common_cpp_gen_headers",
@@ -1146,6 +1162,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   defaults: [
     "perfetto_defaults",
@@ -1320,6 +1337,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   export_generated_headers: [
     "perfetto_protos_perfetto_common_cpp_gen_headers",
@@ -1377,6 +1395,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   defaults: [
     "perfetto_defaults",
@@ -1732,6 +1751,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   defaults: [
     "perfetto_defaults",
@@ -6194,6 +6214,7 @@
     "src/base/unix_task_runner.cc",
     "src/base/utils.cc",
     "src/base/uuid.cc",
+    "src/base/version.cc",
     "src/base/virtual_destructors.cc",
     "src/base/waitable_event.cc",
     "src/base/watchdog_posix.cc",
@@ -6247,6 +6268,21 @@
   ],
 }
 
+// GN: //src/base:version_gen_h
+genrule {
+  name: "perfetto_src_base_version_gen_h",
+  srcs: [
+    "CHANGELOG",
+  ],
+  cmd: "python3 $(location tools/write_version_header.py) --no_git --cpp_out=$(out)",
+  out: [
+    "perfetto_version.gen.h",
+  ],
+  tool_files: [
+    "tools/write_version_header.py",
+  ],
+}
+
 // GN: //src/ipc:client
 filegroup {
   name: "perfetto_src_ipc_client",
@@ -6745,6 +6781,9 @@
   static_libs: [
     "libprotoc",
   ],
+  generated_headers: [
+    "perfetto_src_base_version_gen_h",
+  ],
   defaults: [
     "perfetto_defaults",
   ],
@@ -8446,6 +8485,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
     "perfetto_src_ipc_test_messages_cpp_gen_headers",
     "perfetto_src_ipc_test_messages_ipc_gen_headers",
     "perfetto_src_perfetto_cmd_protos_gen_headers",
@@ -8492,6 +8532,9 @@
   static_libs: [
     "libprotoc",
   ],
+  generated_headers: [
+    "perfetto_src_base_version_gen_h",
+  ],
   defaults: [
     "perfetto_defaults",
   ],
@@ -8597,6 +8640,7 @@
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
     "perfetto_src_trace_processor_importers_gen_cc_config_descriptor",
     "perfetto_src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
     "perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
@@ -8739,6 +8783,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
     "perfetto_protos_third_party_pprof_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
     "perfetto_src_trace_processor_importers_gen_cc_config_descriptor",
     "perfetto_src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
     "perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
@@ -8903,6 +8948,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
   ],
   defaults: [
     "perfetto_defaults",
@@ -9051,6 +9097,7 @@
     "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+    "perfetto_src_base_version_gen_h",
     "perfetto_src_perfetto_cmd_protos_gen_headers",
   ],
   defaults: [
diff --git a/BUILD b/BUILD
index d9c9e18..4dd68d7 100644
--- a/BUILD
+++ b/BUILD
@@ -313,6 +313,7 @@
         "include/perfetto/ext/base/unix_task_runner.h",
         "include/perfetto/ext/base/utils.h",
         "include/perfetto/ext/base/uuid.h",
+        "include/perfetto/ext/base/version.h",
         "include/perfetto/ext/base/waitable_event.h",
         "include/perfetto/ext/base/watchdog.h",
         "include/perfetto/ext/base/watchdog_noop.h",
@@ -561,6 +562,7 @@
         "src/base/unix_task_runner.cc",
         "src/base/utils.cc",
         "src/base/uuid.cc",
+        "src/base/version.cc",
         "src/base/virtual_destructors.cc",
         "src/base/waitable_event.cc",
         "src/base/watchdog_posix.cc",
@@ -569,6 +571,8 @@
         ":include_perfetto_base_base",
         ":include_perfetto_ext_base_base",
     ],
+    deps = [
+    ] + PERFETTO_CONFIG.deps.version_header,
     linkstatic = True,
 )
 
@@ -585,6 +589,20 @@
     linkstatic = True,
 )
 
+genrule(
+    name = "src_base_version_gen_h",
+    srcs = [
+        "CHANGELOG",
+    ],
+    outs = [
+        "perfetto_version.gen.h",
+    ],
+    cmd = "$(location gen_version_header_py) --cpp_out=$@",
+    exec_tools = [
+        ":gen_version_header_py",
+    ],
+)
+
 # GN target: //src/ipc:client
 filegroup(
     name = "src_ipc_client",
@@ -3455,6 +3473,21 @@
     ],
 )
 
+# This is overridden in google internal builds via
+# PERFETTO_CONFIG.deps.version_header (see perfetto_cfg.bzl).
+perfetto_cc_library(
+    name = "cc_perfetto_version_header",
+    hdrs = ["perfetto_version.gen.h"],
+)
+
+perfetto_py_binary(
+    name = "gen_version_header_py",
+    srcs = ["tools/write_version_header.py"],
+    data = ["CHANGELOG"],
+    main = "tools/write_version_header.py",
+    python_version = "PY3",
+)
+
 # Noop targets used to represent targets of the protobuf library.
 # These will be rewritten in Google3 to be dependencies on the real targets.
 
diff --git a/BUILD.extras b/BUILD.extras
index 83a17f0..65611ef 100644
--- a/BUILD.extras
+++ b/BUILD.extras
@@ -78,6 +78,21 @@
     ],
 )
 
+# This is overridden in google internal builds via
+# PERFETTO_CONFIG.deps.version_header (see perfetto_cfg.bzl).
+perfetto_cc_library(
+    name = "cc_perfetto_version_header",
+    hdrs = ["perfetto_version.gen.h"],
+)
+
+perfetto_py_binary(
+    name = "gen_version_header_py",
+    srcs = ["tools/write_version_header.py"],
+    data = ["CHANGELOG"],
+    main = "tools/write_version_header.py",
+    python_version = "PY3",
+)
+
 # Noop targets used to represent targets of the protobuf library.
 # These will be rewritten in Google3 to be dependencies on the real targets.
 
diff --git a/bazel/standalone/perfetto_cfg.bzl b/bazel/standalone/perfetto_cfg.bzl
index d319db9..2d71aa8 100644
--- a/bazel/standalone/perfetto_cfg.bzl
+++ b/bazel/standalone/perfetto_cfg.bzl
@@ -34,6 +34,12 @@
         # "perfetto_build_flags.h" file that can be included via:
         # #include "perfetto_build_flags.h".
         build_config = ["//:build_config_hdr"],
+
+        # Target exposing the PERFETTO_VERSION_STRING() and
+        # PERFETTO_VERSION_SCM_REVISION() macros. This is overridden in google
+        # internal builds.
+        version_header = ["//:cc_perfetto_version_header"],
+
         zlib = ["@perfetto_dep_zlib//:zlib"],
         jsoncpp = ["@perfetto_dep_jsoncpp//:jsoncpp"],
         linenoise = ["@perfetto_dep_linenoise//:linenoise"],
diff --git a/gn/gen_perfetto_version_header.gni b/gn/gen_perfetto_version_header.gni
new file mode 100644
index 0000000..6845eb6
--- /dev/null
+++ b/gn/gen_perfetto_version_header.gni
@@ -0,0 +1,49 @@
+# Copyright (C) 2020 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.
+
+# This action generates a perfetto_version.gen.h which exposes some
+# PERFETTO_VERSION_xxx() macros that contains the git revision and release
+# number from the CHANGELOG.
+# This template is used only in two places: in //base (for C++ code) and in
+# //ui. This teamplate exists only to keep the logic consistent and avoid that
+# base's and ui's logic diverge.
+
+import("perfetto.gni")
+
+template("gen_perfetto_version_header") {
+  action(target_name) {
+    script = "${perfetto_root_path}tools/write_version_header.py"
+    inputs = [ "${perfetto_root_path}CHANGELOG" ]
+    outputs = []
+    args = []
+    if (perfetto_build_standalone && !is_perfetto_build_generator) {
+      inputs += [ "${perfetto_root_path}.git/HEAD" ]
+    }
+
+    if (defined(invoker.cpp_out)) {
+      args += [
+        "--cpp_out",
+        rebase_path(invoker.cpp_out, root_build_dir),
+      ]
+      outputs += [ invoker.cpp_out ]
+    }
+    if (defined(invoker.ts_out)) {
+      args += [
+        "--ts_out",
+        rebase_path(invoker.ts_out, root_build_dir),
+      ]
+      outputs += [ invoker.ts_out ]
+    }
+  }
+}
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index dd79c2a..ba052c9 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -188,11 +188,12 @@
   enable_perfetto_fuzzers =
       perfetto_build_standalone && defined(is_fuzzer) && is_fuzzer
 
-  # Enables the gen_git_revision tool that generates a .h that contains a macro
-  # with the current git revision. Works only in standalone GN checkouts.
-  # If disabled, the version string will be "unknown".
+  # Enables the write_version_header.py tool that generates a .h that contains a
+  # macro with the current git revision and latest release version from
+  # CHANGELOG. If false base/version.h will return "unknown".
   enable_perfetto_version_gen =
-      perfetto_build_standalone && !is_perfetto_build_generator
+      perfetto_build_standalone || is_perfetto_build_generator ||
+      perfetto_build_with_android
 
   # Only for local development. When true the binaries (perfetto, traced, ...)
   # are monolithic and don't use a common shared library. This is mainly to
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index 3938a89..9527694 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -277,22 +277,6 @@
   }
 }
 
-config("gen_include_path") {
-  include_dirs = [ root_gen_dir ]
-}
-
-# This action generates a perfetto_version.gen.h which contains the git SHA1
-# of HEAD. The file can be included from C/C++ sources and exposes a
-# PERFETTO_GET_GIT_REVISION() macro that contains the git revision.
-action("gen_git_revision") {
-  script = "gen_git_revision.py"
-  generated_header = "${root_gen_dir}/perfetto_version.gen.h"
-  args = [ rebase_path(generated_header, root_build_dir) ]
-  inputs = []
-  outputs = [ generated_header ]
-  public_configs = [ ":gen_include_path" ]
-}
-
 # Checks that tools/install-build-deps has been run since it last changed.
 perfetto_check_build_deps("check_build_deps") {
   args = []
diff --git a/gn/standalone/gen_git_revision.py b/gn/standalone/gen_git_revision.py
deleted file mode 100755
index a45262a..0000000
--- a/gn/standalone/gen_git_revision.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python
-# Copyright (C) 2019 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.
-
-import os
-import subprocess
-import sys
-
-
-def main(argv):
-  if len(argv) != 2:
-    print('Usage: %s output_file.h' % argv[0])
-    return 1
-  script_dir = os.path.dirname(os.path.realpath(__file__))
-  revision = subprocess.check_output(
-      ['git', '-C', script_dir, 'rev-parse', 'HEAD']).strip()
-  new_contents = '#define PERFETTO_GET_GIT_REVISION() "%s"\n' % revision
-  out_file = argv[1]
-  old_contents = ''
-  if os.path.isfile(out_file):
-    with open(out_file) as f:
-      old_contents = f.read()
-  if old_contents == new_contents:
-    return 0
-  with open(out_file, 'w') as f:
-    f.write(new_contents)
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main(sys.argv))
diff --git a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
index 80d1ec5..7a34606 100644
--- a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
@@ -31,7 +31,7 @@
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_FORCE_DLOG_ON() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_FORCE_DLOG_OFF() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_VERBOSE_LOGS() (1)
-#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_VERSION_GEN() (0)
+#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_VERSION_GEN() (1)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_PERCENTILE() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_LINENOISE() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_HTTPD() (0)
diff --git a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
index fc8f06a..ae45e29 100644
--- a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
@@ -31,7 +31,7 @@
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_FORCE_DLOG_ON() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_FORCE_DLOG_OFF() (0)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_VERBOSE_LOGS() (1)
-#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_VERSION_GEN() (0)
+#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_VERSION_GEN() (1)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_PERCENTILE() (1)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_LINENOISE() (1)
 #define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_TP_HTTPD() (PERFETTO_BUILDFLAG_DEFINE_PERFETTO_OS_ANDROID() || PERFETTO_BUILDFLAG_DEFINE_PERFETTO_OS_LINUX() || PERFETTO_BUILDFLAG_DEFINE_PERFETTO_OS_MAC())
diff --git a/include/perfetto/ext/base/BUILD.gn b/include/perfetto/ext/base/BUILD.gn
index 66d3a4f..45516be 100644
--- a/include/perfetto/ext/base/BUILD.gn
+++ b/include/perfetto/ext/base/BUILD.gn
@@ -44,6 +44,7 @@
     "unix_task_runner.h",
     "utils.h",
     "uuid.h",
+    "version.h",
     "waitable_event.h",
     "watchdog.h",
     "watchdog_noop.h",
diff --git a/include/perfetto/ext/base/version.h b/include/perfetto/ext/base/version.h
new file mode 100644
index 0000000..212424a
--- /dev/null
+++ b/include/perfetto/ext/base/version.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
+#define INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
+
+namespace perfetto {
+namespace base {
+
+// The returned pointer is a static string is safe to pass around.
+const char* GetVersionString();
+
+}  // namespace base
+}  // namespace perfetto
+
+#endif  // INCLUDE_PERFETTO_EXT_BASE_VERSION_H_
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index 26c4ba9..8a229a8 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import("//build_overrides/build.gni")
+import("../../gn/gen_perfetto_version_header.gni")
 import("../../gn/perfetto.gni")
 import("../../gn/perfetto_component.gni")
 import("../../gn/test.gni")
@@ -38,6 +39,7 @@
     "time.cc",
     "utils.cc",
     "uuid.cc",
+    "version.cc",
     "virtual_destructors.cc",
     "waitable_event.cc",
     "watchdog_posix.cc",
@@ -57,6 +59,23 @@
   if (enable_perfetto_stderr_crash_dump) {
     deps += [ ":debug_crash_stack_trace" ]
   }
+
+  if (enable_perfetto_version_gen) {
+    deps += [ ":version_gen_h" ]
+  }
+}
+
+if (enable_perfetto_version_gen) {
+  config("version_gen_config") {
+    include_dirs = [ root_gen_dir ]
+  }
+
+  # Note: the build file translators (tools/gn_utils.py) depend on the hardcoded
+  # "//src/base:version_gen_h". If you rename this target, update build file
+  # translators accordingly.
+  gen_perfetto_version_header("version_gen_h") {
+    cpp_out = "${root_gen_dir}/perfetto_version.gen.h"
+  }
 }
 
 if (enable_perfetto_stderr_crash_dump) {
diff --git a/src/base/version.cc b/src/base/version.cc
new file mode 100644
index 0000000..18569d3
--- /dev/null
+++ b/src/base/version.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "perfetto/ext/base/version.h"
+
+#include "perfetto/base/build_config.h"
+
+#include <stdio.h>
+
+#if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
+#include "perfetto_version.gen.h"
+#else
+#define PERFETTO_VERSION_STRING() "v0.0"
+#define PERFETTO_VERSION_SCM_REVISION() "unknown"
+#endif
+
+namespace perfetto {
+namespace base {
+
+const char* GetVersionString() {
+  static const char* version_str = [] {
+    static constexpr size_t kMaxLen = 256;
+    char* version = new char[kMaxLen + 1];
+    snprintf(version, kMaxLen, "Perfetto %s (%s)", PERFETTO_VERSION_STRING(),
+             PERFETTO_VERSION_SCM_REVISION());
+    return version;
+  }();
+  return version_str;
+}
+
+}  // namespace base
+}  // namespace perfetto
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index e01778b..198abe2 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -41,6 +41,7 @@
 #include "perfetto/ext/base/thread_utils.h"
 #include "perfetto/ext/base/utils.h"
 #include "perfetto/ext/base/uuid.h"
+#include "perfetto/ext/base/version.h"
 #include "perfetto/ext/traced/traced.h"
 #include "perfetto/ext/tracing/core/basic_types.h"
 #include "perfetto/ext/tracing/core/trace_packet.h"
@@ -203,6 +204,7 @@
     OPT_STOP,
     OPT_QUERY,
     OPT_QUERY_RAW,
+    OPT_VERSION,
   };
   static const struct option long_options[] = {
       {"help", no_argument, nullptr, 'h'},
@@ -228,6 +230,7 @@
       {"app", required_argument, nullptr, OPT_ATRACE_APP},
       {"query", no_argument, nullptr, OPT_QUERY},
       {"query-raw", no_argument, nullptr, OPT_QUERY_RAW},
+      {"version", no_argument, nullptr, OPT_VERSION},
       {nullptr, 0, nullptr, 0}};
 
   int option_index = 0;
@@ -398,6 +401,11 @@
       continue;
     }
 
+    if (option == OPT_VERSION) {
+      printf("%s\n", base::GetVersionString());
+      return 0;
+    }
+
     return PrintUsage(argv[0]);
   }
 
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 0808519..448e482 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -349,9 +349,6 @@
       "metrics:lib",
       "util",
     ]
-    if (enable_perfetto_version_gen) {
-      deps += [ "../../gn/standalone:gen_git_revision" ]
-    }
     if (enable_perfetto_trace_processor_linenoise) {
       deps += [ "../../gn:linenoise" ]
     }
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index f5f4923..a1dc002 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -35,6 +35,7 @@
 #include "perfetto/ext/base/scoped_file.h"
 #include "perfetto/ext/base/string_splitter.h"
 #include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/version.h"
 #include "perfetto/trace_processor/read_trace.h"
 #include "perfetto/trace_processor/trace_processor.h"
 #include "src/trace_processor/metrics/chrome/all_chrome_metrics.descriptor.h"
@@ -64,12 +65,6 @@
 #include <sys/types.h>
 #endif
 
-#if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
-#include "perfetto_version.gen.h"
-#else
-#define PERFETTO_GET_GIT_REVISION() "unknown"
-#endif
-
 #if PERFETTO_HAS_SIGNAL_H()
 #include <signal.h>
 #endif
@@ -802,7 +797,7 @@
       break;  // EOF.
 
     if (option == 'v') {
-      printf("%s\n", PERFETTO_GET_GIT_REVISION());
+      printf("%s\n", base::GetVersionString());
       exit(0);
     }
 
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index 7eec236..e568855 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -35,9 +35,6 @@
     "../../../gn:default_deps",
     "../../tracing/ipc/producer",
   ]
-  if (enable_perfetto_version_gen) {
-    deps += [ "//gn/standalone:gen_git_revision" ]
-  }
   sources = [ "probes.cc" ]
 }
 
diff --git a/src/traced/probes/probes.cc b/src/traced/probes/probes.cc
index b05fd02..6ad1fe0 100644
--- a/src/traced/probes/probes.cc
+++ b/src/traced/probes/probes.cc
@@ -22,18 +22,13 @@
 
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/unix_task_runner.h"
+#include "perfetto/ext/base/version.h"
 #include "perfetto/ext/traced/traced.h"
 #include "perfetto/ext/tracing/ipc/default_socket.h"
 
 #include "src/traced/probes/ftrace/ftrace_procfs.h"
 #include "src/traced/probes/probes_producer.h"
 
-#if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
-#include "perfetto_version.gen.h"
-#else
-#define PERFETTO_GET_GIT_REVISION() "unknown"
-#endif
-
 namespace perfetto {
 
 int __attribute__((visibility("default"))) ProbesMain(int argc, char** argv) {
@@ -57,7 +52,7 @@
         HardResetFtraceState();
         return 0;
       case OPT_VERSION:
-        printf("%s\n", PERFETTO_GET_GIT_REVISION());
+        printf("%s\n", base::GetVersionString());
         return 0;
       default:
         PERFETTO_ELOG("Usage: %s [--cleanup-after-crash|--version]", argv[0]);
diff --git a/src/traced/service/BUILD.gn b/src/traced/service/BUILD.gn
index 2b7798b..2ff0007 100644
--- a/src/traced/service/BUILD.gn
+++ b/src/traced/service/BUILD.gn
@@ -42,9 +42,6 @@
     "../../tracing/core:service",
     "../../tracing/ipc/service",
   ]
-  if (enable_perfetto_version_gen) {
-    deps += [ "//gn/standalone:gen_git_revision" ]
-  }
   sources = [
     "builtin_producer.cc",
     "builtin_producer.h",
diff --git a/src/traced/service/service.cc b/src/traced/service/service.cc
index d9a884e..c7918d0 100644
--- a/src/traced/service/service.cc
+++ b/src/traced/service/service.cc
@@ -20,6 +20,7 @@
 
 #include "perfetto/ext/base/string_utils.h"
 #include "perfetto/ext/base/unix_task_runner.h"
+#include "perfetto/ext/base/version.h"
 #include "perfetto/ext/base/watchdog.h"
 #include "perfetto/ext/traced/traced.h"
 #include "perfetto/ext/tracing/ipc/default_socket.h"
@@ -36,12 +37,6 @@
 #include <unistd.h>
 #endif
 
-#if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
-#include "perfetto_version.gen.h"
-#else
-#define PERFETTO_GET_GIT_REVISION() "unknown"
-#endif
-
 namespace perfetto {
 namespace {
 #if defined(PERFETTO_SET_SOCKET_PERMISSIONS)
@@ -121,7 +116,7 @@
       break;
     switch (option) {
       case OPT_VERSION:
-        printf("%s\n", PERFETTO_GET_GIT_REVISION());
+        printf("%s\n", base::GetVersionString());
         return 0;
       case OPT_SET_SOCKET_PERMISSIONS: {
         // Check that the socket permission argument is well formed.
diff --git a/tools/gen_amalgamated b/tools/gen_amalgamated
index 63ad4dd..95e9e97 100755
--- a/tools/gen_amalgamated
+++ b/tools/gen_amalgamated
@@ -581,6 +581,13 @@
   args = parser.parse_args()
   targets = args.targets or default_targets
 
+  # The CHANGELOG mtime triggers the the perfetto_version.gen.h genrule. This is
+  # to avoid emitting a stale version information in the remote case of somebody
+  # running gen_amalgamated incrementally after having moved to another commit.
+  changelog_path = os.path.join(project_root, 'CHANGELOG')
+  assert(os.path.exists(changelog_path))
+  subprocess.check_call(['touch', '-c', changelog_path])
+
   output = args.output
   if args.check:
     output = os.path.join(tempfile.mkdtemp(), 'perfetto_amalgamated')
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index ec9c1b7..098fdac 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -747,6 +747,22 @@
   return module
 
 
+def create_gen_version_module(blueprint, target, bp_module_name):
+  module = Module('genrule', bp_module_name, gn_utils.GEN_VERSION_TARGET)
+  script_path = gn_utils.label_to_path(target.script)
+  module.genrule_headers.add(bp_module_name)
+  module.tool_files = [ script_path ]
+  module.out.update(target.outputs)
+  module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
+  module.cmd = ' '.join([
+        'python3 $(location %s)' % script_path,
+        '--no_git',
+        '--cpp_out=$(out)'
+  ])
+  blueprint.add_module(module)
+  return module
+
+
 def _get_cflags(target):
   cflags = {flag for flag in target.cflags if re.match(cflag_allowlist, flag)}
   cflags |= set("-D%s" % define
@@ -801,6 +817,9 @@
       module = create_merged_sql_metrics_module(blueprint, target)
     elif re.match('.*gen_cc_.*_descriptor$', target.name):
       module = create_cc_proto_descriptor_module(blueprint, target)
+    elif target.type == 'action' and gn_utils.label_without_toolchain(
+        target.name) == gn_utils.GEN_VERSION_TARGET:
+      module = create_gen_version_module(blueprint, target, bp_module_name)
     else:
       raise Error('Unhandled action: {}'.format(target.name))
   else:
diff --git a/tools/gen_bazel b/tools/gen_bazel
index 75bb2c7..6a9fd40 100755
--- a/tools/gen_bazel
+++ b/tools/gen_bazel
@@ -103,10 +103,10 @@
         'PERFETTO_CONFIG.deps.sqlite_ext_percentile'
     ],
     '//gn:zlib': ['PERFETTO_CONFIG.deps.zlib'],
-    '//gn/standalone:gen_git_revision': [],
     '//src/trace_processor/metrics:gen_merged_sql_metrics': [[
         ':cc_merged_sql_metrics'
-    ]]
+    ]],
+    gn_utils.GEN_VERSION_TARGET: ['PERFETTO_CONFIG.deps.version_header'],
 }
 
 
@@ -119,6 +119,15 @@
   return [label]
 
 
+def gen_version_header(target):
+  label = BazelLabel(get_bazel_label_name(target.name), 'genrule')
+  label.srcs += [re.sub('^//', '', x) for x in sorted(target.inputs)]
+  label.outs += target.outputs
+  label.cmd = r'$(location gen_version_header_py) --cpp_out=$@'
+  label.exec_tools += [':gen_version_header_py']
+  return [label]
+
+
 def gen_cc_metrics_descriptor(target):
   label = BazelLabel(
       get_bazel_label_name(target.name), 'perfetto_cc_proto_descriptor')
@@ -128,6 +137,7 @@
 
 
 custom_actions = {
+    gn_utils.GEN_VERSION_TARGET: gen_version_header,
     '//src/trace_processor/metrics:gen_merged_sql_metrics': gen_sql_metrics,
     '//src/trace_processor/metrics:gen_cc_metrics_descriptor':
       gen_cc_metrics_descriptor,
diff --git a/tools/gn_utils.py b/tools/gn_utils.py
index 015b58d..45c5885 100644
--- a/tools/gn_utils.py
+++ b/tools/gn_utils.py
@@ -28,6 +28,7 @@
 from compat import iteritems
 
 BUILDFLAGS_TARGET = '//gn:gen_buildflags'
+GEN_VERSION_TARGET = '//src/base:version_gen_h'
 TARGET_TOOLCHAIN = '//gn/standalone/toolchain:gcc_like_host'
 HOST_TOOLCHAIN = '//gn/standalone/toolchain:gcc_like_host'
 LINKER_UNIT_TYPES = ('executable', 'shared_library', 'static_library')
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index fe71f33..70b4169 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -117,9 +117,6 @@
     "trace_to_systrace.h",
     "trace_to_text.h",
   ]
-  if (enable_perfetto_version_gen) {
-    deps += [ "//gn/standalone:gen_git_revision" ]
-  }
 }
 
 # Lite target for the WASM UI. Doesn't have any dependency on libprotobuf-full.
diff --git a/tools/trace_to_text/main.cc b/tools/trace_to_text/main.cc
index 3e7cb1a..467b3fb 100644
--- a/tools/trace_to_text/main.cc
+++ b/tools/trace_to_text/main.cc
@@ -23,6 +23,7 @@
 
 #include "perfetto/base/logging.h"
 #include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/version.h"
 #include "tools/trace_to_text/deobfuscate_profile.h"
 #include "tools/trace_to_text/symbolize_profile.h"
 #include "tools/trace_to_text/trace_to_hprof.h"
@@ -31,11 +32,6 @@
 #include "tools/trace_to_text/trace_to_systrace.h"
 #include "tools/trace_to_text/trace_to_text.h"
 
-#if PERFETTO_BUILDFLAG(PERFETTO_VERSION_GEN)
-#include "perfetto_version.gen.h"
-#else
-#define PERFETTO_GET_GIT_REVISION() "unknown"
-#endif
 
 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
 #include <unistd.h>
@@ -79,7 +75,7 @@
   bool full_sort = false;
   for (int i = 1; i < argc; i++) {
     if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
-      printf("%s\n", PERFETTO_GET_GIT_REVISION());
+      printf("%s\n", base::GetVersionString());
       return 0;
     } else if (strcmp(argv[i], "-t") == 0 ||
                strcmp(argv[i], "--truncate") == 0) {
diff --git a/tools/write_version_header.py b/tools/write_version_header.py
new file mode 100755
index 0000000..7982f50
--- /dev/null
+++ b/tools/write_version_header.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+# Copyright (C) 2020 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.
+"""
+Writes the perfetto_version{.gen.h, .ts} files.
+
+This tool is run as part of a genrule from GN, SoonG and Bazel builds. It
+generates a source header (or in the case of --ts_out a TypeScript file) that
+contains:
+- The version number (e.g. v9.0) obtained parsing the CHANGELOG file.
+- The git HEAD's commit-ish (e.g. 6b330b772b0e973f79c70ba2e9bb2b0110c6715d)
+- The number of CLs from the release tag to HEAD.
+
+The latter is concatenated to the version number to distinguish builds made
+fully from release tags (e.g., v9.0.0) vs builds made from the main branch which
+are N cls ahead of the latest monthly release (e.g., v9.0.42).
+"""
+
+import argparse
+import os
+import re
+import sys
+import subprocess
+
+# Note: PROJECT_ROOT is not accurate in bazel builds, where this script is
+# executed in the bazel sandbox.
+PROJECT_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
+SCM_REV_NOT_AVAILABLE = 'N/A'
+
+
+def get_latest_release():
+  """Returns a string like 'v9.0'.
+
+  It does so by searching the latest version mentioned in the CHANGELOG."""
+  if os.path.exists('CHANGELOG'):
+    changelog_path = 'CHANGELOG'
+  else:
+    changelog_path = os.path.join(PROJECT_ROOT, 'CHANGELOG')
+  with open(changelog_path) as f:
+    for line in f.readlines():
+      m = re.match('^(v\d+[.]\d+)\s.*$', line)
+      if m is not None:
+        return m.group(1)
+  raise Exception('Failed to fetch Perfetto version from %s' % changelog_path)
+
+
+def get_git_info(last_release_tag):
+  """Returns a tuple ('deadbeef', '1234').
+
+  The first value is the SHA1 of the HEAD. The second is the number of CLs from
+  the passed |last_release_tag| to HEAD."""
+  commit_sha1 = SCM_REV_NOT_AVAILABLE
+  commits_since_release = ''
+  git_dir = os.path.join(PROJECT_ROOT, '.git')
+  if os.path.exists(git_dir):
+    try:
+      commit_sha1 = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
+                                            cwd=PROJECT_ROOT).strip().decode()
+      with open(os.devnull, 'wb') as devnull:
+        commits_since_release = subprocess.check_output(
+            [
+                'git', 'rev-list', '--count',
+                'refs/tags/%s..HEAD' % last_release_tag
+            ],
+            cwd=PROJECT_ROOT,
+            stderr=devnull).strip().decode()
+    except subprocess.CalledProcessError:
+      pass
+
+  return (commit_sha1, commits_since_release)
+
+
+def write_if_unchanged(path, content):
+  prev_content = None
+  if os.path.exists(path):
+    with open(path, 'r') as fprev:
+      prev_content = fprev.read()
+  if prev_content == content:
+    return 0
+  with open(path, 'w') as fout:
+    fout.write(content)
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      '--no_git',
+      action='store_true',
+      help='Skips running git rev-parse, emits only the version from CHANGELOG')
+  parser.add_argument('--cpp_out', help='Path of the generated .h file.')
+  parser.add_argument('--ts_out', help='Path of the generated .ts file.')
+  args = parser.parse_args()
+
+  release = get_latest_release()
+  if args.no_git:
+    git_sha1, commits_since_release = (SCM_REV_NOT_AVAILABLE, '')
+  else:
+    git_sha1, commits_since_release = get_git_info(release)
+
+  # Try to compute the number of commits since the last release. This can fail
+  # in some environments (e.g. in android builds) because the bots pull only
+  # the main branch and don't pull the whole list of tags.
+  if commits_since_release:
+    version = '%s.%s' % (release, commits_since_release)  # e.g., 'v9.0.42'.
+  else:
+    version = release  # e.g., 'v9.0'.
+
+  if args.cpp_out:
+    guard = '%s_' % args.cpp_out.upper()
+    guard = re.sub(r'[^\w]', '_', guard)
+    lines = []
+    lines.append('// Generated by %s' % __file__)
+    lines.append('')
+    lines.append('#ifndef %s' % guard)
+    lines.append('#define %s' % guard)
+    lines.append('')
+    lines.append('#define PERFETTO_VERSION_STRING() "%s"' % version)
+    lines.append('#define PERFETTO_VERSION_SCM_REVISION() "%s"' % git_sha1)
+    lines.append('')
+    lines.append('#endif  // %s' % guard)
+    lines.append('')
+    content = '\n'.join(lines)
+    write_if_unchanged(args.cpp_out, content)
+
+  if args.ts_out:
+    lines = []
+    lines.append('export const VERSION = "%s";' % version)
+    lines.append('export const SCM_REVISION = "%s";' % git_sha1)
+    content = '\n'.join(lines)
+    write_if_unchanged(args.ts_out, content)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/ui/BUILD.gn b/ui/BUILD.gn
index 2c5722d..2aec99a 100644
--- a/ui/BUILD.gn
+++ b/ui/BUILD.gn
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import("../gn/gen_perfetto_version_header.gni")
 import("../gn/perfetto.gni")
 import("../gn/perfetto_check_build_deps.gni")
 import("../gn/wasm.gni")
@@ -269,6 +270,7 @@
   deps = [
     ":dist_symlink",
     ":protos_to_ts",
+    ":version_ts_gen",
     ":wasm_gen",
   ]
   inputs = [ "tsconfig.json" ]
@@ -598,3 +600,7 @@
            rebase_path(ui_dir, root_build_dir),
          ] + dist_files
 }
+
+gen_perfetto_version_header("version_ts_gen") {
+  ts_out = "$ui_gen_dir/perfetto_version.ts"
+}
diff --git a/ui/src/assets/sidebar.scss b/ui/src/assets/sidebar.scss
index 5bdc7cb..b368214 100644
--- a/ui/src/assets/sidebar.scss
+++ b/ui/src/assets/sidebar.scss
@@ -182,6 +182,7 @@
     .sidebar-footer {
       position: absolute;
       bottom: 0;
+      width: 100%;
       padding: 2px 10px;
       display: grid;
       height: - var(--sidebar-padding-bottom);
@@ -226,6 +227,19 @@
           line-height: 11px;
         }
       }
+
+      .version {
+        position: absolute;
+        right: 8px;
+        bottom: 3px;
+        font-size: 12px;
+        font-family: 'Roboto Condensed', 'Roboto', sans-serif;
+        a {
+          color: rgba(255, 255, 255, 0.5);
+          text-decoration: none;
+        }
+        margin-top: 11px;
+      }
     }
 }
 
diff --git a/ui/src/base/logging.ts b/ui/src/base/logging.ts
index 25c37d5..75a02ca 100644
--- a/ui/src/base/logging.ts
+++ b/ui/src/base/logging.ts
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import * as version from '../gen/perfetto_version';
+
 export type ErrorHandler = (err: string) => void;
 
 let errorHandler: ErrorHandler = (_: string) => {};
@@ -55,8 +57,10 @@
     errLog += '\n';
     errLog += errStack !== undefined ? errStack : JSON.stringify(errorObj);
   }
-  errLog += `\n\nUA: ${navigator.userAgent}\n`;
+  errLog += '\n\n';
+  errLog += `${version.VERSION} ${version.SCM_REVISION}\n`;
+  errLog += `UA: ${navigator.userAgent}\n`;
 
   console.error(errLog, err);
   errorHandler(errLog);
-}
\ No newline at end of file
+}
diff --git a/ui/src/frontend/sidebar.ts b/ui/src/frontend/sidebar.ts
index 07798d8..56eeb89 100644
--- a/ui/src/frontend/sidebar.ts
+++ b/ui/src/frontend/sidebar.ts
@@ -18,6 +18,7 @@
 import {Actions} from '../common/actions';
 import {QueryResponse} from '../common/queries';
 import {EngineMode, TraceArrayBufferSource} from '../common/state';
+import * as version from '../gen/perfetto_version';
 
 import {Animation} from './animation';
 import {copyToClipboard} from './clipboard';
@@ -690,6 +691,16 @@
             'assessment')),
         m(EngineRPCWidget),
         m(ServiceWorkerWidget),
+        m(
+            '.version',
+            m('a',
+              {
+                href: `https://github.com/google/perfetto/tree/${
+                    version.SCM_REVISION}/ui`,
+                target: '_blank',
+              },
+              `${version.VERSION}`),
+            ),
     );
   }
 };