Move symbolizer to src/profiling/symbolizer.

This is in preparation of adding symbolization to trace_processor_shell.

Bug: 146479871
Change-Id: I4ff863f78ef676cd583b32ad1b913cc9029337ce
diff --git a/Android.bp b/Android.bp
index 3dff741..d18eb82 100644
--- a/Android.bp
+++ b/Android.bp
@@ -979,9 +979,9 @@
   name: "perfetto_include_perfetto_profiling_normalize",
 }
 
-// GN: //include/perfetto/profiling:symbolizer
+// GN: //include/perfetto/profiling:pprof_builder
 filegroup {
-  name: "perfetto_include_perfetto_profiling_symbolizer",
+  name: "perfetto_include_perfetto_profiling_pprof_builder",
 }
 
 // GN: //include/perfetto/protozero:protozero
@@ -5424,6 +5424,23 @@
   ],
 }
 
+// GN: //src/profiling/symbolizer:symbolize_database
+filegroup {
+  name: "perfetto_src_profiling_symbolizer_symbolize_database",
+  srcs: [
+    "src/profiling/symbolizer/symbolize_database.cc",
+  ],
+}
+
+// GN: //src/profiling/symbolizer:symbolizer
+filegroup {
+  name: "perfetto_src_profiling_symbolizer_symbolizer",
+  srcs: [
+    "src/profiling/symbolizer/local_symbolizer.cc",
+    "src/profiling/symbolizer/symbolizer.cc",
+  ],
+}
+
 // GN: //src/profiling:unittests
 filegroup {
   name: "perfetto_src_profiling_unittests",
@@ -6367,14 +6384,6 @@
   ],
 }
 
-// GN: //tools/trace_to_text:local_symbolizer
-filegroup {
-  name: "perfetto_tools_trace_to_text_local_symbolizer",
-  srcs: [
-    "tools/trace_to_text/local_symbolizer.cc",
-  ],
-}
-
 // GN: //tools/trace_to_text:pprofbuilder
 filegroup {
   name: "perfetto_tools_trace_to_text_pprofbuilder",
@@ -6383,14 +6392,6 @@
   ],
 }
 
-// GN: //tools/trace_to_text:symbolizer
-filegroup {
-  name: "perfetto_tools_trace_to_text_symbolizer",
-  srcs: [
-    "tools/trace_to_text/symbolizer.cc",
-  ],
-}
-
 // GN: //tools/trace_to_text:utils
 filegroup {
   name: "perfetto_tools_trace_to_text_utils",
@@ -6893,7 +6894,7 @@
     ":perfetto_include_perfetto_ext_base_base",
     ":perfetto_include_perfetto_ext_traced_sys_stats_counters",
     ":perfetto_include_perfetto_profiling_deobfuscator",
-    ":perfetto_include_perfetto_profiling_symbolizer",
+    ":perfetto_include_perfetto_profiling_pprof_builder",
     ":perfetto_include_perfetto_protozero_protozero",
     ":perfetto_include_perfetto_trace_processor_basic_types",
     ":perfetto_include_perfetto_trace_processor_storage",
@@ -6928,6 +6929,8 @@
     ":perfetto_protos_third_party_pprof_zero_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_profiling_deobfuscator",
+    ":perfetto_src_profiling_symbolizer_symbolize_database",
+    ":perfetto_src_profiling_symbolizer_symbolizer",
     ":perfetto_src_protozero_protozero",
     ":perfetto_src_trace_processor_containers_containers",
     ":perfetto_src_trace_processor_db_lib",
@@ -6940,9 +6943,7 @@
     ":perfetto_src_trace_processor_tables_tables",
     ":perfetto_tools_trace_to_text_common",
     ":perfetto_tools_trace_to_text_full",
-    ":perfetto_tools_trace_to_text_local_symbolizer",
     ":perfetto_tools_trace_to_text_pprofbuilder",
-    ":perfetto_tools_trace_to_text_symbolizer",
     ":perfetto_tools_trace_to_text_utils",
   ],
   shared_libs: [
diff --git a/BUILD b/BUILD
index 8e07f3d..ae16edc 100644
--- a/BUILD
+++ b/BUILD
@@ -332,12 +332,11 @@
     ],
 )
 
-# GN target: //include/perfetto/profiling:symbolizer
+# GN target: //include/perfetto/profiling:pprof_builder
 filegroup(
-    name = "include_perfetto_profiling_symbolizer",
+    name = "include_perfetto_profiling_pprof_builder",
     srcs = [
         "include/perfetto/profiling/pprof_builder.h",
-        "include/perfetto/profiling/symbolizer.h",
     ],
 )
 
@@ -547,6 +546,26 @@
     ],
 )
 
+# GN target: //src/profiling/symbolizer:symbolize_database
+filegroup(
+    name = "src_profiling_symbolizer_symbolize_database",
+    srcs = [
+        "src/profiling/symbolizer/symbolize_database.cc",
+        "src/profiling/symbolizer/symbolize_database.h",
+    ],
+)
+
+# GN target: //src/profiling/symbolizer:symbolizer
+filegroup(
+    name = "src_profiling_symbolizer_symbolizer",
+    srcs = [
+        "src/profiling/symbolizer/local_symbolizer.cc",
+        "src/profiling/symbolizer/local_symbolizer.h",
+        "src/profiling/symbolizer/symbolizer.cc",
+        "src/profiling/symbolizer/symbolizer.h",
+    ],
+)
+
 # GN target: //src/profiling:deobfuscator
 filegroup(
     name = "src_profiling_deobfuscator",
@@ -1177,15 +1196,6 @@
     ],
 )
 
-# GN target: //tools/trace_to_text:local_symbolizer
-filegroup(
-    name = "tools_trace_to_text_local_symbolizer",
-    srcs = [
-        "tools/trace_to_text/local_symbolizer.cc",
-        "tools/trace_to_text/local_symbolizer.h",
-    ],
-)
-
 # GN target: //tools/trace_to_text:pprofbuilder
 filegroup(
     name = "tools_trace_to_text_pprofbuilder",
@@ -1194,14 +1204,6 @@
     ],
 )
 
-# GN target: //tools/trace_to_text:symbolizer
-filegroup(
-    name = "tools_trace_to_text_symbolizer",
-    srcs = [
-        "tools/trace_to_text/symbolizer.cc",
-    ],
-)
-
 # GN target: //tools/trace_to_text:utils
 filegroup(
     name = "tools_trace_to_text_utils",
@@ -2686,15 +2688,16 @@
     name = "libpprofbuilder",
     srcs = [
         ":src_profiling_deobfuscator",
+        ":src_profiling_symbolizer_symbolize_database",
+        ":src_profiling_symbolizer_symbolizer",
         ":tools_trace_to_text_pprofbuilder",
-        ":tools_trace_to_text_symbolizer",
         ":tools_trace_to_text_utils",
     ],
     hdrs = [
         ":include_perfetto_base_base",
         ":include_perfetto_ext_base_base",
         ":include_perfetto_profiling_deobfuscator",
-        ":include_perfetto_profiling_symbolizer",
+        ":include_perfetto_profiling_pprof_builder",
         ":include_perfetto_protozero_protozero",
         ":include_perfetto_trace_processor_basic_types",
         ":include_perfetto_trace_processor_storage",
@@ -2741,13 +2744,15 @@
         ":include_perfetto_ext_trace_processor_export_json",
         ":include_perfetto_ext_traced_sys_stats_counters",
         ":include_perfetto_profiling_deobfuscator",
-        ":include_perfetto_profiling_symbolizer",
+        ":include_perfetto_profiling_pprof_builder",
         ":include_perfetto_protozero_protozero",
         ":include_perfetto_trace_processor_basic_types",
         ":include_perfetto_trace_processor_storage",
         ":include_perfetto_trace_processor_trace_processor",
         ":src_base_base",
         ":src_profiling_deobfuscator",
+        ":src_profiling_symbolizer_symbolize_database",
+        ":src_profiling_symbolizer_symbolizer",
         ":src_protozero_protozero",
         ":src_trace_processor_containers_containers",
         ":src_trace_processor_db_lib",
@@ -2761,9 +2766,7 @@
         ":src_trace_processor_tables_tables",
         ":tools_trace_to_text_common",
         ":tools_trace_to_text_full",
-        ":tools_trace_to_text_local_symbolizer",
         ":tools_trace_to_text_pprofbuilder",
-        ":tools_trace_to_text_symbolizer",
         ":tools_trace_to_text_utils",
     ],
     visibility = [
diff --git a/include/perfetto/profiling/BUILD.gn b/include/perfetto/profiling/BUILD.gn
index 03f8350..ce7c188 100644
--- a/include/perfetto/profiling/BUILD.gn
+++ b/include/perfetto/profiling/BUILD.gn
@@ -12,13 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# TODO(135923303): as part of fixing b/135923303, symbolizer.h will be removed
-# and namespacing of pprof_builder.h will be changed so do not depend on this
-# target.
-source_set("symbolizer") {
+source_set("pprof_builder") {
   sources = [
     "pprof_builder.h",
-    "symbolizer.h",
   ]
 }
 
diff --git a/include/perfetto/profiling/pprof_builder.h b/include/perfetto/profiling/pprof_builder.h
index 4227a8c..7e26f51 100644
--- a/include/perfetto/profiling/pprof_builder.h
+++ b/include/perfetto/profiling/pprof_builder.h
@@ -27,9 +27,11 @@
 class TraceProcessor;
 }
 
-namespace trace_to_text {
-
+namespace profiling {
 class Symbolizer;
+}
+
+namespace trace_to_text {
 
 struct SerializedProfile {
   uint64_t pid;
@@ -38,13 +40,13 @@
 
 bool TraceToPprof(trace_processor::TraceProcessor*,
                   std::vector<SerializedProfile>* output,
-                  Symbolizer* symbolizer,
+                  profiling::Symbolizer* symbolizer,
                   uint64_t pid = 0,
                   const std::vector<uint64_t>& timestamps = {});
 
 bool TraceToPprof(std::istream* input,
                   std::vector<SerializedProfile>* output,
-                  Symbolizer* symbolizer,
+                  profiling::Symbolizer* symbolizer,
                   uint64_t pid = 0,
                   const std::vector<uint64_t>& timestamps = {});
 
diff --git a/src/profiling/symbolizer/BUILD.gn b/src/profiling/symbolizer/BUILD.gn
new file mode 100644
index 0000000..3bbc385
--- /dev/null
+++ b/src/profiling/symbolizer/BUILD.gn
@@ -0,0 +1,48 @@
+# 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("../../../gn/perfetto.gni")
+
+source_set("symbolizer") {
+  public_deps = [
+    "../../../include/perfetto/ext/base",
+  ]
+  deps = [
+    "../../../gn:default_deps",
+  ]
+  sources = [
+    "local_symbolizer.cc",
+    "local_symbolizer.h",
+    "symbolizer.cc",
+    "symbolizer.h",
+  ]
+}
+
+source_set("symbolize_database") {
+  public_deps = [
+    ":symbolizer",
+    "../../../include/perfetto/ext/base",
+  ]
+  deps = [
+    "../../../gn:default_deps",
+    "../../../include/perfetto/protozero",
+    "../../../include/perfetto/trace_processor:trace_processor",
+    "../../../protos/perfetto/trace:zero",
+    "../../../protos/perfetto/trace/profiling:zero",
+  ]
+  sources = [
+    "symbolize_database.cc",
+    "symbolize_database.h",
+  ]
+}
diff --git a/tools/trace_to_text/local_symbolizer.cc b/src/profiling/symbolizer/local_symbolizer.cc
similarity index 98%
rename from tools/trace_to_text/local_symbolizer.cc
rename to src/profiling/symbolizer/local_symbolizer.cc
index 3daa0be..1874df1 100644
--- a/tools/trace_to_text/local_symbolizer.cc
+++ b/src/profiling/symbolizer/local_symbolizer.cc
@@ -20,7 +20,7 @@
 // This translation unit is built only on Linux. See //gn/BUILD.gn.
 #if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
 
-#include "tools/trace_to_text/local_symbolizer.h"
+#include "src/profiling/symbolizer/local_symbolizer.h"
 
 #include "perfetto/ext/base/string_splitter.h"
 #include "perfetto/ext/base/string_utils.h"
@@ -35,7 +35,7 @@
 #include <unistd.h>
 
 namespace perfetto {
-namespace trace_to_text {
+namespace profiling {
 
 namespace {
 
@@ -60,7 +60,6 @@
   return lines;
 }
 
-
 struct Elf32 {
   using Ehdr = Elf32_Ehdr;
   using Shdr = Elf32_Shdr;
@@ -402,7 +401,7 @@
 
 LocalSymbolizer::~LocalSymbolizer() = default;
 
-}  // namespace trace_to_text
+}  // namespace profiling
 }  // namespace perfetto
 
 #endif  // PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
diff --git a/tools/trace_to_text/local_symbolizer.h b/src/profiling/symbolizer/local_symbolizer.h
similarity index 90%
rename from tools/trace_to_text/local_symbolizer.h
rename to src/profiling/symbolizer/local_symbolizer.h
index e1eef9e..eb3a717 100644
--- a/tools/trace_to_text/local_symbolizer.h
+++ b/src/profiling/symbolizer/local_symbolizer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef TOOLS_TRACE_TO_TEXT_LOCAL_SYMBOLIZER_H_
-#define TOOLS_TRACE_TO_TEXT_LOCAL_SYMBOLIZER_H_
+#ifndef SRC_PROFILING_SYMBOLIZER_LOCAL_SYMBOLIZER_H_
+#define SRC_PROFILING_SYMBOLIZER_LOCAL_SYMBOLIZER_H_
 
 #include <map>
 #include <string>
@@ -23,10 +23,10 @@
 
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/pipe.h"
-#include "perfetto/profiling/symbolizer.h"
+#include "src/profiling/symbolizer/symbolizer.h"
 
 namespace perfetto {
-namespace trace_to_text {
+namespace profiling {
 
 class LocalBinaryFinder {
  public:
@@ -93,7 +93,7 @@
   LocalBinaryFinder finder_;
 };
 
-}  // namespace trace_to_text
+}  // namespace profiling
 }  // namespace perfetto
 
-#endif  // TOOLS_TRACE_TO_TEXT_LOCAL_SYMBOLIZER_H_
+#endif  // SRC_PROFILING_SYMBOLIZER_LOCAL_SYMBOLIZER_H_
diff --git a/src/profiling/symbolizer/symbolize_database.cc b/src/profiling/symbolizer/symbolize_database.cc
new file mode 100644
index 0000000..39e09a4
--- /dev/null
+++ b/src/profiling/symbolizer/symbolize_database.cc
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#include "src/profiling/symbolizer/symbolize_database.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/logging.h"
+
+#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "perfetto/trace_processor/trace_processor.h"
+
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+namespace profiling {
+
+namespace {
+using Iterator = trace_processor::TraceProcessor::Iterator;
+
+constexpr const char* kQueryUnsymbolized =
+    "select spm.name, spm.build_id, spf.rel_pc "
+    "from stack_profile_frame spf "
+    "join stack_profile_mapping spm "
+    "on spf.mapping = spm.id "
+    "where spm.build_id != '' and spf.symbol_set_id == 0";
+
+using NameAndBuildIdPair = std::pair<std::string, std::string>;
+
+std::string FromHex(const char* str, size_t size) {
+  if (size % 2) {
+    PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
+    return "";
+  }
+  std::string result(size / 2, '\0');
+  for (size_t i = 0; i < size; i += 2) {
+    char hex_byte[3];
+    hex_byte[0] = str[i];
+    hex_byte[1] = str[i + 1];
+    hex_byte[2] = '\0';
+    char* end;
+    long int byte = strtol(hex_byte, &end, 16);
+    if (*end != '\0') {
+      PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
+      return "";
+    }
+    result[i / 2] = static_cast<char>(byte);
+  }
+  return result;
+}
+
+std::string FromHex(const std::string& str) {
+  return FromHex(str.c_str(), str.size());
+}
+
+std::map<NameAndBuildIdPair, std::vector<uint64_t>> GetUnsymbolizedFrames(
+    trace_processor::TraceProcessor* tp) {
+  std::map<std::pair<std::string, std::string>, std::vector<uint64_t>> res;
+  Iterator it = tp->ExecuteQuery(kQueryUnsymbolized);
+  while (it.Next()) {
+    auto name_and_buildid =
+        std::make_pair(it.Get(0).string_value, FromHex(it.Get(1).string_value));
+    int64_t rel_pc = it.Get(2).long_value;
+    res[name_and_buildid].emplace_back(rel_pc);
+  }
+  if (!it.Status().ok()) {
+    PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+                            it.Status().message().c_str());
+    return {};
+  }
+  return res;
+}
+}  // namespace
+
+void SymbolizeDatabase(trace_processor::TraceProcessor* tp,
+                       Symbolizer* symbolizer,
+                       std::function<void(const std::string&)> callback) {
+  PERFETTO_CHECK(symbolizer);
+  auto unsymbolized = GetUnsymbolizedFrames(tp);
+  for (auto it = unsymbolized.cbegin(); it != unsymbolized.cend(); ++it) {
+    const auto& name_and_buildid = it->first;
+    const std::vector<uint64_t>& rel_pcs = it->second;
+    auto res = symbolizer->Symbolize(name_and_buildid.first,
+                                     name_and_buildid.second, rel_pcs);
+    if (res.empty())
+      continue;
+
+    protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket> packet;
+    auto* module_symbols = packet->set_module_symbols();
+    module_symbols->set_path(name_and_buildid.first);
+    module_symbols->set_build_id(name_and_buildid.second);
+    PERFETTO_DCHECK(res.size() == rel_pcs.size());
+    for (size_t i = 0; i < res.size(); ++i) {
+      auto* address_symbols = module_symbols->add_address_symbols();
+      address_symbols->set_address(rel_pcs[i]);
+      for (const SymbolizedFrame& frame : res[i]) {
+        auto* line = address_symbols->add_lines();
+        line->set_function_name(frame.function_name);
+        line->set_source_file_name(frame.file_name);
+        line->set_line_number(frame.line);
+      }
+    }
+    callback(packet.SerializeAsString());
+  }
+}
+
+}  // namespace profiling
+}  // namespace perfetto
diff --git a/src/profiling/symbolizer/symbolize_database.h b/src/profiling/symbolizer/symbolize_database.h
new file mode 100644
index 0000000..6c9ab1b
--- /dev/null
+++ b/src/profiling/symbolizer/symbolize_database.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_PROFILING_SYMBOLIZER_SYMBOLIZE_DATABASE_H_
+#define SRC_PROFILING_SYMBOLIZER_SYMBOLIZE_DATABASE_H_
+
+#include "src/profiling/symbolizer/symbolizer.h"
+
+#include <functional>
+#include <string>
+
+namespace perfetto {
+namespace trace_processor {
+class TraceProcessor;
+}
+namespace profiling {
+// Generate ModuleSymbol protos for all unsymbolized frames in the database.
+// Wrap them in proto-encoded TracePackets messages and call callback.
+void SymbolizeDatabase(trace_processor::TraceProcessor* tp,
+                       Symbolizer* symbolizer,
+                       std::function<void(const std::string&)> callback);
+}  // namespace profiling
+}  // namespace perfetto
+
+#endif  // SRC_PROFILING_SYMBOLIZER_SYMBOLIZE_DATABASE_H_
diff --git a/tools/trace_to_text/symbolizer.cc b/src/profiling/symbolizer/symbolizer.cc
similarity index 87%
rename from tools/trace_to_text/symbolizer.cc
rename to src/profiling/symbolizer/symbolizer.cc
index 1cd83cb..0aa5d8b 100644
--- a/tools/trace_to_text/symbolizer.cc
+++ b/src/profiling/symbolizer/symbolizer.cc
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#include "perfetto/profiling/symbolizer.h"
+#include "src/profiling/symbolizer/symbolizer.h"
 
 namespace perfetto {
-namespace trace_to_text {
+namespace profiling {
 
 Symbolizer::~Symbolizer() = default;
 
-}  // namespace trace_to_text
+}  // namespace profiling
 }  // namespace perfetto
diff --git a/include/perfetto/profiling/symbolizer.h b/src/profiling/symbolizer/symbolizer.h
similarity index 80%
rename from include/perfetto/profiling/symbolizer.h
rename to src/profiling/symbolizer/symbolizer.h
index 2a5a79e..ff4ee50 100644
--- a/include/perfetto/profiling/symbolizer.h
+++ b/src/profiling/symbolizer/symbolizer.h
@@ -14,17 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef INCLUDE_PERFETTO_PROFILING_SYMBOLIZER_H_
-#define INCLUDE_PERFETTO_PROFILING_SYMBOLIZER_H_
+#ifndef SRC_PROFILING_SYMBOLIZER_SYMBOLIZER_H_
+#define SRC_PROFILING_SYMBOLIZER_SYMBOLIZER_H_
 
 #include <map>
 #include <string>
 #include <vector>
 
-// TODO(135923303): do not depend on anything in this file as it will be
-// removed as part of fixing b/135923303.
 namespace perfetto {
-namespace trace_to_text {
+namespace profiling {
 
 struct SymbolizedFrame {
   std::string function_name;
@@ -46,7 +44,7 @@
   virtual ~Symbolizer();
 };
 
-}  // namespace trace_to_text
+}  // namespace profiling
 }  // namespace perfetto
 
-#endif  // INCLUDE_PERFETTO_PROFILING_SYMBOLIZER_H_
+#endif  // SRC_PROFILING_SYMBOLIZER_SYMBOLIZER_H_
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index 4b2044c..41c844d 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -38,7 +38,6 @@
 
 source_set("utils") {
   deps = [
-    ":symbolizer",
     "../../gn:default_deps",
     "../../include/perfetto/profiling:deobfuscator",
     "../../include/perfetto/protozero",
@@ -47,12 +46,13 @@
     "../../protos/perfetto/trace/interned_data:zero",
     "../../protos/perfetto/trace/profiling:zero",
     "../../src/profiling:deobfuscator",
+    "../../src/profiling/symbolizer",
+    "../../src/profiling/symbolizer:symbolize_database",
   ]
   public_deps = [
     "../../gn:zlib",
     "../../include/perfetto/ext/base",
     "../../include/perfetto/profiling:deobfuscator",
-    "../../include/perfetto/profiling:symbolizer",
   ]
   sources = [
     "utils.cc",
@@ -60,45 +60,21 @@
   ]
 }
 
-source_set("local_symbolizer") {
-  public_deps = [
-    "../../include/perfetto/ext/base",
-    "../../include/perfetto/profiling:symbolizer",
-  ]
-  deps = [
-    ":symbolizer",
-    ":utils",
-    "../../gn:default_deps",
-    "../../include/perfetto/protozero",
-  ]
-  sources = [
-    "local_symbolizer.cc",
-    "local_symbolizer.h",
-  ]
-}
-
-source_set("symbolizer") {
-  deps = [
-    "../../gn:default_deps",
-    "../../include/perfetto/profiling:symbolizer",
-  ]
-  sources = [
-    "symbolizer.cc",
-  ]
-}
-
 source_set("pprofbuilder") {
+  public_deps = [
+    "../../include/perfetto/profiling:pprof_builder",
+  ]
   deps = [
-    ":symbolizer",
     ":utils",
     "../../gn:default_deps",
     "../../include/perfetto/base",
-    "../../include/perfetto/profiling:symbolizer",
     "../../include/perfetto/protozero",
     "../../include/perfetto/trace_processor",
     "../../protos/perfetto/trace:zero",
     "../../protos/perfetto/trace/profiling:zero",
     "../../protos/third_party/pprof:zero",
+    "../../src/profiling/symbolizer",
+    "../../src/profiling/symbolizer:symbolize_database",
   ]
   sources = [
     "pprof_builder.cc",
@@ -117,7 +93,6 @@
 # executable) and by the "lite" version (the WASM module for the UI).
 source_set("common") {
   deps = [
-    ":local_symbolizer",
     ":pprofbuilder",
     ":utils",
     "../../gn:default_deps",
@@ -126,6 +101,8 @@
     "../../include/perfetto/profiling:deobfuscator",
     "../../include/perfetto/protozero",
     "../../protos/perfetto/trace:zero",
+    "../../src/profiling/symbolizer",
+    "../../src/profiling/symbolizer:symbolize_database",
     "../../src/trace_processor:lib",
   ]
   sources = [
diff --git a/tools/trace_to_text/pprof_builder.cc b/tools/trace_to_text/pprof_builder.cc
index 77dc8615..1b1014d 100644
--- a/tools/trace_to_text/pprof_builder.cc
+++ b/tools/trace_to_text/pprof_builder.cc
@@ -31,11 +31,13 @@
 #include "perfetto/base/time.h"
 #include "perfetto/ext/base/string_utils.h"
 #include "perfetto/ext/base/utils.h"
-#include "perfetto/profiling/symbolizer.h"
 #include "perfetto/protozero/packed_repeated_fields.h"
 #include "perfetto/protozero/scattered_heap_buffer.h"
 #include "perfetto/trace_processor/trace_processor.h"
 
+#include "src/profiling/symbolizer/symbolize_database.h"
+#include "src/profiling/symbolizer/symbolizer.h"
+
 #include "protos/perfetto/trace/trace.pbzero.h"
 #include "protos/perfetto/trace/trace_packet.pbzero.h"
 #include "protos/third_party/pprof/profile.pbzero.h"
@@ -497,7 +499,7 @@
 
 bool TraceToPprof(std::istream* input,
                   std::vector<SerializedProfile>* output,
-                  Symbolizer* symbolizer,
+                  profiling::Symbolizer* symbolizer,
                   uint64_t pid,
                   const std::vector<uint64_t>& timestamps) {
   trace_processor::Config config;
@@ -513,26 +515,27 @@
 
 bool TraceToPprof(trace_processor::TraceProcessor* tp,
                   std::vector<SerializedProfile>* output,
-                  Symbolizer* symbolizer,
+                  profiling::Symbolizer* symbolizer,
                   uint64_t pid,
                   const std::vector<uint64_t>& timestamps) {
   if (symbolizer) {
-    SymbolizeDatabase(tp, symbolizer, [&tp](const std::string& packet_proto) {
-      std::unique_ptr<uint8_t[]> buf(new uint8_t[11 + packet_proto.size()]);
-      uint8_t* wptr = &buf[0];
-      *(wptr++) =
-          MakeTagLengthDelimited(protos::pbzero::Trace::kPacketFieldNumber);
-      wptr = WriteVarInt(packet_proto.size(), wptr);
-      memcpy(wptr, packet_proto.data(), packet_proto.size());
-      wptr += packet_proto.size();
-      size_t buf_size = static_cast<size_t>(wptr - &buf[0]);
-      auto status = tp->Parse(std::move(buf), buf_size);
-      if (!status.ok()) {
-        PERFETTO_DFATAL_OR_ELOG("Failed to parse: %s",
-                                status.message().c_str());
-        return;
-      }
-    });
+    profiling::SymbolizeDatabase(
+        tp, symbolizer, [&tp](const std::string& packet_proto) {
+          std::unique_ptr<uint8_t[]> buf(new uint8_t[11 + packet_proto.size()]);
+          uint8_t* wptr = &buf[0];
+          *(wptr++) =
+              MakeTagLengthDelimited(protos::pbzero::Trace::kPacketFieldNumber);
+          wptr = WriteVarInt(packet_proto.size(), wptr);
+          memcpy(wptr, packet_proto.data(), packet_proto.size());
+          wptr += packet_proto.size();
+          size_t buf_size = static_cast<size_t>(wptr - &buf[0]);
+          auto status = tp->Parse(std::move(buf), buf_size);
+          if (!status.ok()) {
+            PERFETTO_DFATAL_OR_ELOG("Failed to parse: %s",
+                                    status.message().c_str());
+            return;
+          }
+        });
   }
 
   tp->NotifyEndOfFile();
diff --git a/tools/trace_to_text/symbolize_profile.cc b/tools/trace_to_text/symbolize_profile.cc
index b354572..7cf1e10 100644
--- a/tools/trace_to_text/symbolize_profile.cc
+++ b/tools/trace_to_text/symbolize_profile.cc
@@ -19,11 +19,13 @@
 #include <vector>
 
 #include "perfetto/base/logging.h"
-#include "perfetto/profiling/symbolizer.h"
 #include "perfetto/trace_processor/trace_processor.h"
 
+#include "src/profiling/symbolizer/symbolize_database.h"
+#include "src/profiling/symbolizer/symbolizer.h"
+
 #if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
-#include "tools/trace_to_text/local_symbolizer.h"
+#include "src/profiling/symbolizer/local_symbolizer.h"
 #endif
 
 #include "protos/perfetto/trace/trace.pbzero.h"
@@ -36,11 +38,11 @@
 // Ingest profile, and emit a symbolization table for each sequence. This can
 // be prepended to the profile to attach the symbol information.
 int SymbolizeProfile(std::istream* input, std::ostream* output) {
-  std::unique_ptr<Symbolizer> symbolizer;
+  std::unique_ptr<profiling::Symbolizer> symbolizer;
   auto binary_path = GetPerfettoBinaryPath();
   if (!binary_path.empty()) {
 #if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
-    symbolizer.reset(new LocalSymbolizer(GetPerfettoBinaryPath()));
+    symbolizer.reset(new profiling::LocalSymbolizer(GetPerfettoBinaryPath()));
 #else
     PERFETTO_FATAL("This build does not support local symbolization.");
 #endif
diff --git a/tools/trace_to_text/trace_to_profile.cc b/tools/trace_to_text/trace_to_profile.cc
index 4f5f1ec..ae9a2a5 100644
--- a/tools/trace_to_text/trace_to_profile.cc
+++ b/tools/trace_to_text/trace_to_profile.cc
@@ -22,7 +22,7 @@
 #include "perfetto/base/build_config.h"
 
 #if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
-#include "tools/trace_to_text/local_symbolizer.h"
+#include "src/profiling/symbolizer/local_symbolizer.h"
 #endif
 #include "tools/trace_to_text/utils.h"
 
@@ -31,7 +31,7 @@
 #include "perfetto/ext/base/temp_file.h"
 #include "perfetto/ext/base/utils.h"
 #include "perfetto/profiling/pprof_builder.h"
-#include "perfetto/profiling/symbolizer.h"
+#include "src/profiling/symbolizer/symbolizer.h"
 
 namespace {
 
@@ -53,11 +53,11 @@
                    std::ostream* output,
                    uint64_t pid,
                    std::vector<uint64_t> timestamps) {
-  std::unique_ptr<Symbolizer> symbolizer;
+  std::unique_ptr<profiling::Symbolizer> symbolizer;
   auto binary_path = GetPerfettoBinaryPath();
   if (!binary_path.empty()) {
 #if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
-    symbolizer.reset(new LocalSymbolizer(GetPerfettoBinaryPath()));
+    symbolizer.reset(new profiling::LocalSymbolizer(GetPerfettoBinaryPath()));
 #else
     PERFETTO_ELOG(
         "This build does not support local symbolization. "
diff --git a/tools/trace_to_text/utils.cc b/tools/trace_to_text/utils.cc
index 7b9b358..efc05f5 100644
--- a/tools/trace_to_text/utils.cc
+++ b/tools/trace_to_text/utils.cc
@@ -40,61 +40,9 @@
 
 using Iterator = trace_processor::TraceProcessor::Iterator;
 
-constexpr const char* kQueryUnsymbolized =
-    "select spm.name, spm.build_id, spf.rel_pc "
-    "from stack_profile_frame spf "
-    "join stack_profile_mapping spm "
-    "on spf.mapping = spm.id "
-    "where spm.build_id != '' and spf.symbol_set_id == 0";
 
 constexpr size_t kCompressionBufferSize = 500 * 1024;
 
-std::string FromHex(const char* str, size_t size) {
-  if (size % 2) {
-    PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
-    return "";
-  }
-  std::string result(size / 2, '\0');
-  for (size_t i = 0; i < size; i += 2) {
-    char hex_byte[3];
-    hex_byte[0] = str[i];
-    hex_byte[1] = str[i + 1];
-    hex_byte[2] = '\0';
-    char* end;
-    long int byte = strtol(hex_byte, &end, 16);
-    if (*end != '\0') {
-      PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
-      return "";
-    }
-    result[i / 2] = static_cast<char>(byte);
-  }
-  return result;
-}
-
-std::string FromHex(const std::string& str) {
-  return FromHex(str.c_str(), str.size());
-}
-
-using NameAndBuildIdPair = std::pair<std::string, std::string>;
-
-std::map<NameAndBuildIdPair, std::vector<uint64_t>> GetUnsymbolizedFrames(
-    trace_processor::TraceProcessor* tp) {
-  std::map<std::pair<std::string, std::string>, std::vector<uint64_t>> res;
-  Iterator it = tp->ExecuteQuery(kQueryUnsymbolized);
-  while (it.Next()) {
-    auto name_and_buildid =
-        std::make_pair(it.Get(0).string_value, FromHex(it.Get(1).string_value));
-    int64_t rel_pc = it.Get(2).long_value;
-    res[name_and_buildid].emplace_back(rel_pc);
-  }
-  if (!it.Status().ok()) {
-    PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
-                            it.Status().message().c_str());
-    return {};
-  }
-  return res;
-}
-
 std::map<std::string, std::set<std::string>> GetHeapGraphClasses(
     trace_processor::TraceProcessor* tp) {
   std::map<std::string, std::set<std::string>> res;
@@ -242,37 +190,6 @@
   return true;
 }
 
-void SymbolizeDatabase(trace_processor::TraceProcessor* tp,
-                       Symbolizer* symbolizer,
-                       std::function<void(const std::string&)> callback) {
-  PERFETTO_CHECK(symbolizer);
-  auto unsymbolized = GetUnsymbolizedFrames(tp);
-  for (auto it = unsymbolized.cbegin(); it != unsymbolized.cend(); ++it) {
-    const auto& name_and_buildid = it->first;
-    const std::vector<uint64_t>& rel_pcs = it->second;
-    auto res = symbolizer->Symbolize(name_and_buildid.first,
-                                     name_and_buildid.second, rel_pcs);
-    if (res.empty())
-      continue;
-
-    protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket> packet;
-    auto* module_symbols = packet->set_module_symbols();
-    module_symbols->set_path(name_and_buildid.first);
-    module_symbols->set_build_id(name_and_buildid.second);
-    PERFETTO_DCHECK(res.size() == rel_pcs.size());
-    for (size_t i = 0; i < res.size(); ++i) {
-      auto* address_symbols = module_symbols->add_address_symbols();
-      address_symbols->set_address(rel_pcs[i]);
-      for (const SymbolizedFrame& frame : res[i]) {
-        auto* line = address_symbols->add_lines();
-        line->set_function_name(frame.function_name);
-        line->set_source_file_name(frame.file_name);
-        line->set_line_number(frame.line);
-      }
-    }
-    callback(packet.SerializeAsString());
-  }
-}
 
 void DeobfuscateDatabase(
     trace_processor::TraceProcessor* tp,
diff --git a/tools/trace_to_text/utils.h b/tools/trace_to_text/utils.h
index b2e2c0d..46c86f9 100644
--- a/tools/trace_to_text/utils.h
+++ b/tools/trace_to_text/utils.h
@@ -32,7 +32,6 @@
 #include "perfetto/ext/base/optional.h"
 #include "perfetto/ext/base/paged_memory.h"
 #include "perfetto/profiling/deobfuscator.h"
-#include "perfetto/profiling/symbolizer.h"
 
 namespace perfetto {
 
@@ -65,12 +64,6 @@
 
 void WriteTracePacket(const std::string& str, std::ostream* output);
 
-// Generate ModuleSymbol protos for all unsymbolized frames in the database.
-// Wrap them in proto-encoded TracePackets messages and call callback.
-void SymbolizeDatabase(trace_processor::TraceProcessor* tp,
-                       Symbolizer* symbolizer,
-                       std::function<void(const std::string&)> callback);
-
 // Generate ObfuscationMapping protos for all obfuscated java names in the
 // database.
 // Wrap them in proto-encoded TracePackets messages and call callback.