• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h"
18 
19 #include <stdlib.h>
20 #include <cctype>
21 #include <cstdint>
22 #include <cstring>
23 #include <string_view>
24 
25 #include "perfetto/base/status.h"
26 #include "perfetto/trace_processor/basic_types.h"
27 #include "protos/perfetto/trace_processor/stack.pbzero.h"
28 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
29 #include "src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.h"
30 #include "src/trace_processor/sqlite/sqlite_utils.h"
31 #include "src/trace_processor/storage/trace_storage.h"
32 #include "src/trace_processor/types/trace_processor_context.h"
33 #include "src/trace_processor/util/status_macros.h"
34 
35 namespace perfetto {
36 namespace trace_processor {
37 namespace {
38 
39 // __intrinsic_strip_hex(name STRING, min_repeated_digits LONG)
40 //
41 //   Replaces hexadecimal sequences (with at least one digit) in a string with
42 //   "<num>" based on specified criteria.
43 struct StripHexFunction : public SqlFunction {
44   static constexpr char kFunctionName[] = "__intrinsic_strip_hex";
45   using Context = void;
46 
Runperfetto::trace_processor::__anon599900070111::StripHexFunction47   static base::Status Run(void* cxt,
48                           size_t argc,
49                           sqlite3_value** argv,
50                           SqlValue& out,
51                           Destructors& destructors) {
52     base::Status status = RunImpl(cxt, argc, argv, out, destructors);
53     if (!status.ok()) {
54       return base::ErrStatus("%s: %s", kFunctionName, status.message().c_str());
55     }
56     return status;
57   }
58 
StripHexperfetto::trace_processor::__anon599900070111::StripHexFunction59   static std::string StripHex(std::string input, int64_t min_repeated_digits) {
60     std::string result;
61     result.reserve(input.length());
62     for (size_t i = 0; i < input.length();) {
63       bool replace_hex = false;
64       if ((input[i] == 'x' || input[i] == 'X') && i >= 1 &&
65           input[i - 1] == '0') {
66         // Case 1: Special prefixes (0x, 0X) for hex sequence found
67         result += input[i++];
68         // Always try to replace hex after 0x, regardless if they contain digits
69         // or not
70         replace_hex = true;
71       } else if (!isalnum(input[i])) {
72         // Case 2: Non alpha numeric prefix for hex sequence found
73         result += input[i++];
74       } else if (i == 0 && isxdigit(input[i])) {
75         // Case 3: Start of input is hex digit, continue to check hex sequence
76       } else if (isdigit(input[i])) {
77         // Case 4: A digit is found, consider replacing the sequence
78       } else {
79         // Case 5: No potential prefix for hex digits found
80         result += input[i++];
81         continue;
82       }
83 
84       size_t hex_start = i;
85       for (; i < input.length() && isxdigit(input[i]); i++) {
86         if (isdigit(input[i])) {
87           replace_hex = true;
88         }
89       }
90       result += replace_hex && (i - hex_start >=
91                                 static_cast<size_t>(min_repeated_digits))
92                     ? "<num>"
93                     : input.substr(hex_start, i - hex_start);
94     }
95     return result;
96   }
97 
RunImplperfetto::trace_processor::__anon599900070111::StripHexFunction98   static base::Status RunImpl(void*,
99                               size_t argc,
100                               sqlite3_value** argv,
101                               SqlValue& out,
102                               Destructors& destructors) {
103     if (argc != 2) {
104       return base::ErrStatus(
105           "%s; Invalid number of arguments: expected 2, actual %zu",
106           kFunctionName, argc);
107     }
108     std::optional<std::string> first_arg = sqlite::utils::SqlValueToString(
109         sqlite::utils::SqliteValueToSqlValue(argv[0]));
110     if (!first_arg.has_value()) {
111       return base::ErrStatus("Invalid name argument for %s expected string",
112                              kFunctionName);
113     }
114     const std::string& input = first_arg.value();
115 
116     SqlValue second_arg = sqlite::utils::SqliteValueToSqlValue(argv[1]);
117     if (second_arg.type != SqlValue::Type::kLong) {
118       return base::ErrStatus(
119           "Invalid min_repeated_digits argument for %s expected integer",
120           kFunctionName);
121     }
122 
123     const int64_t min_repeated_digits = second_arg.AsLong();
124     if (min_repeated_digits < 0) {
125       return base::ErrStatus(
126           "Invalid min_repeated_digits argument for %s expected positive "
127           "integer",
128           kFunctionName);
129     }
130 
131     std::string result = StripHex(input, min_repeated_digits);
132     char* result_cstr = static_cast<char*>(malloc(result.length() + 1));
133     memcpy(result_cstr, result.c_str(), result.length() + 1);
134     out = SqlValue::String(result_cstr);
135     destructors.string_destructor = free;
136     return base::OkStatus();
137   }
138 };
139 
140 }  // namespace
141 
RegisterStripHexFunction(PerfettoSqlEngine * engine,TraceProcessorContext * context)142 base::Status RegisterStripHexFunction(PerfettoSqlEngine* engine,
143                                       TraceProcessorContext* context) {
144   return engine->RegisterStaticFunction<StripHexFunction>(
145       StripHexFunction::kFunctionName, 2, context->storage.get());
146 }
147 
SqlStripHex(std::string input,int64_t min_repeated_digits)148 std::string SqlStripHex(std::string input, int64_t min_repeated_digits) {
149   return StripHexFunction::StripHex(input, min_repeated_digits);
150 }
151 
152 }  // namespace trace_processor
153 }  // namespace perfetto
154