xref: /aosp_15_r20/system/extras/simpleperf/kallsyms_test.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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 <gtest/gtest.h>
18 
19 #include <android-base/test_utils.h>
20 
21 #include "get_test_data.h"
22 #include "kallsyms.h"
23 #include "test_util.h"
24 
25 using namespace simpleperf;
26 
ModulesMatch(const char * p,const char * q)27 static bool ModulesMatch(const char* p, const char* q) {
28   if (p == nullptr && q == nullptr) {
29     return true;
30   }
31   if (p != nullptr && q != nullptr) {
32     return strcmp(p, q) == 0;
33   }
34   return false;
35 }
36 
KernelSymbolsMatch(const KernelSymbol & sym1,const KernelSymbol & sym2)37 static bool KernelSymbolsMatch(const KernelSymbol& sym1, const KernelSymbol& sym2) {
38   return sym1.addr == sym2.addr && sym1.type == sym2.type && strcmp(sym1.name, sym2.name) == 0 &&
39          ModulesMatch(sym1.module, sym2.module);
40 }
41 
42 // @CddTest = 6.1/C-0-2
TEST(kallsyms,ProcessKernelSymbols)43 TEST(kallsyms, ProcessKernelSymbols) {
44   std::string data =
45       "ffffffffa005c4e4 d __warned.41698   [libsas]\n"
46       "aaaaaaaaaaaaaaaa T _text\n"
47       "cccccccccccccccc c ccccc\n";
48   KernelSymbol expected_symbol;
49   expected_symbol.addr = 0xffffffffa005c4e4ULL;
50   expected_symbol.type = 'd';
51   expected_symbol.name = "__warned.41698";
52   expected_symbol.module = "libsas";
53   ASSERT_TRUE(ProcessKernelSymbols(
54       data, std::bind(&KernelSymbolsMatch, std::placeholders::_1, expected_symbol)));
55 
56   expected_symbol.addr = 0xaaaaaaaaaaaaaaaaULL;
57   expected_symbol.type = 'T';
58   expected_symbol.name = "_text";
59   expected_symbol.module = nullptr;
60   ASSERT_TRUE(ProcessKernelSymbols(
61       data, std::bind(&KernelSymbolsMatch, std::placeholders::_1, expected_symbol)));
62 
63   expected_symbol.name = "non_existent_symbol";
64   ASSERT_FALSE(ProcessKernelSymbols(
65       data, std::bind(&KernelSymbolsMatch, std::placeholders::_1, expected_symbol)));
66 }
67 
68 // @CddTest = 6.1/C-0-2
TEST(kallsyms,ProcessKernelSymbols_ignore_arm_mapping_symbols)69 TEST(kallsyms, ProcessKernelSymbols_ignore_arm_mapping_symbols) {
70   std::string data =
71       "aaaaaaaaaaaaaaaa t $x.9 [coresight_etm4x]\n"
72       "bbbbbbbbbbbbbbbb t etm4_pm_clear [coresight_etm4x]\n";
73   bool has_normal_symbol = false;
74   bool has_arm_mapping_symbol = false;
75   auto callback = [&](const KernelSymbol& sym) {
76     if (strcmp(sym.name, "etm4_pm_clear") == 0) {
77       has_normal_symbol = true;
78     } else {
79       has_arm_mapping_symbol = true;
80     }
81     return false;
82   };
83   ProcessKernelSymbols(data, callback);
84   ASSERT_TRUE(has_normal_symbol);
85   ASSERT_FALSE(has_arm_mapping_symbol);
86 }
87 
88 #if defined(__ANDROID__)
89 // @CddTest = 6.1/C-0-2
TEST(kallsyms,GetKernelStartAddress)90 TEST(kallsyms, GetKernelStartAddress) {
91   TEST_REQUIRE_ROOT();
92   ASSERT_NE(GetKernelStartAddress(), 0u);
93 }
94 
95 // @CddTest = 6.1/C-0-2
TEST(kallsyms,LoadKernelSymbols)96 TEST(kallsyms, LoadKernelSymbols) {
97   TEST_REQUIRE_ROOT();
98   std::string kallsyms;
99   ASSERT_TRUE(LoadKernelSymbols(&kallsyms));
100 }
101 
102 // @CddTest = 6.1/C-0-2
TEST(kallsyms,print_warning)103 TEST(kallsyms, print_warning) {
104   TEST_REQUIRE_NON_ROOT();
105   const std::string warning_msg = "Access to kernel symbol addresses is restricted.";
106   CapturedStderr capture;
107 
108   // Call each function requiring kernel addresses once. Check if the warning is printed.
109   ResetKernelAddressWarning();
110   ASSERT_EQ(0, GetKernelStartAddress());
111   capture.Stop();
112   ASSERT_NE(capture.str().find(warning_msg), std::string::npos);
113 
114   capture.Reset();
115   capture.Start();
116   ResetKernelAddressWarning();
117   std::string kallsyms;
118   ASSERT_FALSE(LoadKernelSymbols(&kallsyms));
119   capture.Stop();
120   ASSERT_NE(capture.str().find(warning_msg), std::string::npos);
121 
122   capture.Reset();
123   capture.Start();
124   ResetKernelAddressWarning();
125   ASSERT_TRUE(GetLoadedModules().empty());
126   capture.Stop();
127   ASSERT_NE(capture.str().find(warning_msg), std::string::npos);
128 
129   // Call functions requiring kernel addresses more than once.
130   // Check if the kernel address warning is only printed once.
131   capture.Reset();
132   capture.Start();
133   ResetKernelAddressWarning();
134   for (int i = 0; i < 2; i++) {
135     ASSERT_EQ(0, GetKernelStartAddress());
136     ASSERT_FALSE(LoadKernelSymbols(&kallsyms));
137     ASSERT_TRUE(GetLoadedModules().empty());
138   }
139   capture.Stop();
140   std::string output = capture.str();
141   auto pos = output.find(warning_msg);
142   ASSERT_NE(pos, std::string::npos);
143   ASSERT_EQ(output.find(warning_msg, pos + warning_msg.size()), std::string::npos);
144 }
145 #endif  // defined(__ANDROID__)
146