1 /*
2 * Copyright (C) 2020 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 "berberis/base/config_globals.h"
18
19 #include <bitset>
20 #include <cerrno>
21 #include <cstdint>
22 #include <cstdlib> // strtoull
23 #include <string>
24
25 #include "berberis/base/logging.h"
26 #include "berberis/base/strings.h"
27
28 namespace berberis {
29
30 namespace {
31
ToString(ConfigFlag flag)32 std::string ToString(ConfigFlag flag) {
33 switch (flag) {
34 case kVerboseTranslation:
35 return "verbose-translation";
36 case kAccurateSigsegv:
37 return "accurate-sigsegv";
38 case kTopByteIgnore:
39 return "top-byte-ignore";
40 case kDisableRegMap:
41 return "disable-reg-map";
42 case kEnableDisjointRegionsTranslation:
43 return "enable-disjoint-regions-translation";
44 case kDisableIntrinsicInlining:
45 return "disable-intrinsic-inlining";
46 case kMergeProfilesForSameModeRegions:
47 return "merge-profiles-for-same-mode-regions";
48 case kPrintTranslatedAddrs:
49 return "print-translated-addrs";
50 case kPrintIRs:
51 return "print-irs";
52 case kPrintCodePoolSize:
53 return "print-code-pool-size";
54 case kLocalExperiment:
55 return "local-experiment";
56 case kPlatformCustomCPUCapability:
57 return "platform-custom-cpu-capability";
58 case kNumConfigFlags:
59 break;
60 }
61 return "<unknown-config-flag>";
62 }
63
MakeConfigFlagsSet()64 std::bitset<kNumConfigFlags> MakeConfigFlagsSet() {
65 ConfigStr var("BERBERIS_FLAGS", "ro.berberis.flags");
66 std::bitset<kNumConfigFlags> flags_set;
67 if (!var.get()) {
68 return flags_set;
69 }
70 auto token_vector = Split(var.get(), ",");
71 for (const auto& token : token_vector) {
72 bool found = false;
73 for (int flag = 0; flag < kNumConfigFlags; flag++) {
74 if (token == ToString(ConfigFlag(flag))) {
75 flags_set.set(flag);
76 found = true;
77 break;
78 }
79 }
80 if (!found) {
81 ALOGW("Unrecognized config flag '%s' - ignoring", token.c_str());
82 }
83 }
84 return flags_set;
85 }
86
ParseAddr(const char * addr_cstr)87 uintptr_t ParseAddr(const char* addr_cstr) {
88 if (!addr_cstr) {
89 return 0;
90 }
91 char* end_ptr = nullptr;
92 errno = 0;
93 uintptr_t addr = static_cast<uintptr_t>(strtoull(addr_cstr, &end_ptr, 16));
94
95 // Warning: setting errno on failure is implementation defined. So we also use extra heuristics.
96 if (errno != 0 || (*end_ptr != '\n' && *end_ptr != '\0')) {
97 ALOGE("Cannot convert \"%s\" to integer: %s\n",
98 addr_cstr,
99 errno != 0 ? strerror(errno) : "unexpected end of string");
100 return 0;
101 }
102 return addr;
103 }
104
105 } // namespace
106
GetTracingConfig()107 const char* GetTracingConfig() {
108 static ConfigStr var("BERBERIS_TRACING", "berberis.tracing");
109 return var.get();
110 }
111
GetTranslationModeConfig()112 const char* GetTranslationModeConfig() {
113 static ConfigStr var("BERBERIS_MODE", "berberis.mode");
114 return var.get();
115 }
116
GetProfilingConfig()117 const char* GetProfilingConfig() {
118 static ConfigStr var("BERBERIS_PROFILING", "berberis.profiling");
119 return var.get();
120 }
121
GetEntryPointOverride()122 uintptr_t GetEntryPointOverride() {
123 static ConfigStr var("BERBERIS_ENTRY_POINT", "berberis.entry_point");
124 static uintptr_t entry_point = ParseAddr(var.get());
125 return entry_point;
126 }
127
IsConfigFlagSet(ConfigFlag flag)128 bool IsConfigFlagSet(ConfigFlag flag) {
129 static auto flags_set = MakeConfigFlagsSet();
130 return flags_set.test(flag);
131 }
132
133 } // namespace berberis
134