1/****************************************************************************
2**
3** Copyright (C) 2021 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtTest module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#ifndef QEMULATIONDETECTOR_P_H
30#define QEMULATIONDETECTOR_P_H
31
32//
33// W A R N I N G
34// -------------
35//
36// This file is not part of the Qt API. It exists purely as an
37// implementation detail. This header file may change from version to
38// version without notice, or even be removed.
39//
40// We mean it.
41//
42
43#include <QtCore/qglobal.h>
44
45#if defined(Q_OS_LINUX) && defined(Q_PROCESSOR_ARM)
46#define SHOULD_CHECK_ARM_ON_X86
47
48#include <QFileInfo>
49
50#if QT_CONFIG(process) && QT_CONFIG(regularexpression)
51#include <QProcess>
52#include <QRegularExpression>
53#endif
54
55#endif
56
57QT_BEGIN_NAMESPACE
58
59// Helper functions for detecting if running emulated
60namespace QTestPrivate {
61
62#ifdef SHOULD_CHECK_ARM_ON_X86
63static bool isX86SpecificFileAvailable(void);
64static bool isReportedArchitectureX86(void);
65#endif
66
67/*
68 * Check if we are running Arm binary on x86 machine.
69 *
70 * Currently this is only able to check on Linux. If not able to
71 * detect, return false.
72 */
73[[maybe_unused]] static bool isRunningArmOnX86()
74{
75#ifdef SHOULD_CHECK_ARM_ON_X86
76 if (isX86SpecificFileAvailable())
77 return true;
78
79 if (isReportedArchitectureX86())
80 return true;
81#endif
82 return false;
83}
84
85#ifdef SHOULD_CHECK_ARM_ON_X86
86/*
87 * Check if we can find a file that's only available on x86
88 */
89static bool isX86SpecificFileAvailable()
90{
91 // MTRR (Memory Type Range Registers) are a feature of the x86 architecture
92 // and /proc/mtrr is only present (on Linux) for that family.
93 // However, it's an optional kernel feature, so the absence of the file is
94 // not sufficient to conclude we're on real hardware.
95 QFileInfo mtrr("/proc/mtrr");
96 if (mtrr.exists())
97 return true;
98 return false;
99}
100
101/*
102 * Check if architecture reported by the OS is x86
103 */
104static bool isReportedArchitectureX86(void)
105{
106#if QT_CONFIG(process) && QT_CONFIG(regularexpression)
107 QProcess unamer;
108 QString machineString;
109
110 // Using syscall "uname" is not possible since that would be captured by
111 // QEMU and result would be the architecture being emulated (e.g. armv7l).
112 // By using QProcess we get the architecture used by the host.
113 unamer.start("uname -a");
114 if (!unamer.waitForFinished()) {
115 return false;
116 }
117 machineString = unamer.readAll();
118
119 // Is our current host cpu x86?
120 if (machineString.contains(QRegularExpression("i386|i686|x86"))) {
121 return true;
122 }
123#endif
124
125 return false;
126}
127#endif // SHOULD_CHECK_ARM_ON_X86
128
129} // QTestPrivate namespace
130
131QT_END_NAMESPACE
132
133#endif
134
135