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 kLocalExperiment:
45       return "local-experiment";
46     case kPlatformCustomCPUCapability:
47       return "platform-custom-cpu-capability";
48     case kNumConfigFlags:
49       break;
50   }
51   return "<unknown-config-flag>";
52 }
53 
MakeConfigFlagsSet()54 std::bitset<kNumConfigFlags> MakeConfigFlagsSet() {
55   ConfigStr var("BERBERIS_FLAGS", "ro.berberis.flags");
56   std::bitset<kNumConfigFlags> flags_set;
57   if (!var.get()) {
58     return flags_set;
59   }
60   auto token_vector = Split(var.get(), ",");
61   for (const auto& token : token_vector) {
62     bool found = false;
63     for (int flag = 0; flag < kNumConfigFlags; flag++) {
64       if (token == ToString(ConfigFlag(flag))) {
65         flags_set.set(flag);
66         found = true;
67         break;
68       }
69     }
70     if (!found) {
71       ALOGW("Unrecognized config flag '%s' - ignoring", token.c_str());
72     }
73   }
74   return flags_set;
75 }
76 
ParseAddr(const char * addr_cstr)77 uintptr_t ParseAddr(const char* addr_cstr) {
78   if (!addr_cstr) {
79     return 0;
80   }
81   char* end_ptr = nullptr;
82   errno = 0;
83   uintptr_t addr = static_cast<uintptr_t>(strtoull(addr_cstr, &end_ptr, 16));
84 
85   // Warning: setting errno on failure is implementation defined. So we also use extra heuristics.
86   if (errno != 0 || (*end_ptr != '\n' && *end_ptr != '\0')) {
87     ALOGE("Cannot convert \"%s\" to integer: %s\n",
88           addr_cstr,
89           errno != 0 ? strerror(errno) : "unexpected end of string");
90     return 0;
91   }
92   return addr;
93 }
94 
95 }  // namespace
96 
GetTracingConfig()97 const char* GetTracingConfig() {
98   static ConfigStr var("BERBERIS_TRACING", "berberis.tracing");
99   return var.get();
100 }
101 
GetTranslationModeConfig()102 const char* GetTranslationModeConfig() {
103   static ConfigStr var("BERBERIS_MODE", "berberis.mode");
104   return var.get();
105 }
106 
GetProfilingConfig()107 const char* GetProfilingConfig() {
108   static ConfigStr var("BERBERIS_PROFILING", "berberis.profiling");
109   return var.get();
110 }
111 
GetEntryPointOverride()112 uintptr_t GetEntryPointOverride() {
113   static ConfigStr var("BERBERIS_ENTRY_POINT", "berberis.entry_point");
114   static uintptr_t entry_point = ParseAddr(var.get());
115   return entry_point;
116 }
117 
IsConfigFlagSet(ConfigFlag flag)118 bool IsConfigFlagSet(ConfigFlag flag) {
119   static auto flags_set = MakeConfigFlagsSet();
120   return flags_set.test(flag);
121 }
122 
123 }  // namespace berberis
124