Skip to content

Commit b2e61c3

Browse files
authored
Merge pull request #4170 from Sonicadvance1/gdbserver_work
GdbServer: Minor work
2 parents 649a494 + 357cc04 commit b2e61c3

File tree

7 files changed

+785
-481
lines changed

7 files changed

+785
-481
lines changed

FEXCore/Source/Interface/Context/Context.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,6 @@ class ContextImpl final : public FEXCore::Context::Context {
378378
IR::AOTIRCaptureCache IRCaptureCache;
379379
fextl::unique_ptr<FEXCore::CodeSerialize::CodeObjectSerializeService> CodeObjectCacheService;
380380

381-
bool StartPaused = false;
382381
bool IsMemoryShared = false;
383382
bool SupportsHardwareTSO = false;
384383
bool AtomicTSOEmulationEnabled = true;

FEXCore/Source/Interface/Core/Core.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,6 @@ bool ContextImpl::InitCore() {
354354
if (Config.GdbServer) {
355355
// If gdbserver is enabled then this needs to be enabled.
356356
Config.NeedsPendingInterruptFaultCheck = true;
357-
// FEX needs to start paused when gdb is enabled.
358-
StartPaused = true;
359357
}
360358

361359
return true;
@@ -878,7 +876,7 @@ void ContextImpl::ExecutionThread(FEXCore::Core::InternalThreadState* Thread) {
878876
// Now notify the thread that we are initialized
879877
Thread->ThreadWaiting.NotifyAll();
880878

881-
if (StartPaused || Thread->StartPaused) {
879+
if (Thread->StartPaused) {
882880
// Parent thread doesn't need to wait to run
883881
Thread->StartRunning.Wait();
884882
}

Source/Tools/LinuxEmulation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_compile_options(-fno-operator-names)
33
set (SRCS
44
VDSO_Emulation.cpp
55
Thunks.cpp
6+
GdbServer/Info.cpp
67
LinuxSyscalls/GdbServer.cpp
78
LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp
89
LinuxSyscalls/FaultSafeUserMemAccess.cpp
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// SPDX-License-Identifier: MIT
2+
/*
3+
$info$
4+
tags: glue|gdbserver
5+
desc: Provides a gdb interface to the guest state
6+
$end_info$
7+
*/
8+
9+
#include "GdbServer/Info.h"
10+
11+
#include <Common/StringUtil.h>
12+
13+
#include <FEXCore/Core/CoreState.h>
14+
#include <FEXCore/Core/X86Enums.h>
15+
#include <FEXCore/fextl/fmt.h>
16+
#include <FEXCore/fextl/sstream.h>
17+
#include <FEXCore/Utils/CompilerDefs.h>
18+
#include <FEXCore/Utils/FileLoading.h>
19+
#include <FEXCore/Utils/LogManager.h>
20+
21+
#include <array>
22+
#include <string_view>
23+
24+
namespace FEX::GDB::Info {
25+
constexpr std::array<std::string_view, 22> FlagNames = {
26+
"CF", "", "PF", "", "AF", "", "ZF", "SF", "TF", "IF", "DF", "OF", "IOPL", "", "NT", "", "RF", "VM", "AC", "VIF", "VIP", "ID",
27+
};
28+
29+
const std::string_view& GetFlagName(unsigned Bit) {
30+
LOGMAN_THROW_A_FMT(Bit < 22, "Bit position too large");
31+
return FlagNames[Bit];
32+
}
33+
34+
std::string_view GetGRegName(unsigned Reg) {
35+
switch (Reg) {
36+
case FEXCore::X86State::REG_RAX: return "rax";
37+
case FEXCore::X86State::REG_RBX: return "rbx";
38+
case FEXCore::X86State::REG_RCX: return "rcx";
39+
case FEXCore::X86State::REG_RDX: return "rdx";
40+
case FEXCore::X86State::REG_RSP: return "rsp";
41+
case FEXCore::X86State::REG_RBP: return "rbp";
42+
case FEXCore::X86State::REG_RSI: return "rsi";
43+
case FEXCore::X86State::REG_RDI: return "rdi";
44+
case FEXCore::X86State::REG_R8: return "r8";
45+
case FEXCore::X86State::REG_R9: return "r9";
46+
case FEXCore::X86State::REG_R10: return "r10";
47+
case FEXCore::X86State::REG_R11: return "r11";
48+
case FEXCore::X86State::REG_R12: return "r12";
49+
case FEXCore::X86State::REG_R13: return "r13";
50+
case FEXCore::X86State::REG_R14: return "r14";
51+
case FEXCore::X86State::REG_R15: return "r15";
52+
default: FEX_UNREACHABLE;
53+
}
54+
}
55+
56+
fextl::string GetThreadName(uint32_t PID, uint32_t ThreadID) {
57+
const auto ThreadFile = fextl::fmt::format("/proc/{}/task/{}/comm", PID, ThreadID);
58+
fextl::string ThreadName;
59+
FEXCore::FileLoading::LoadFile(ThreadName, ThreadFile);
60+
// Trim out the potential newline, breaks GDB if it exists.
61+
FEX::StringUtil::trim(ThreadName);
62+
return ThreadName;
63+
}
64+
65+
fextl::string BuildOSXML() {
66+
fextl::ostringstream xml;
67+
68+
xml << "<?xml version='1.0'?>\n";
69+
70+
xml << "<!DOCTYPE target SYSTEM \"osdata.dtd\">\n";
71+
xml << "<osdata type=\"processes\">";
72+
// XXX
73+
xml << "</osdata>";
74+
75+
xml << std::flush;
76+
77+
return xml.str();
78+
}
79+
80+
fextl::string BuildTargetXML() {
81+
fextl::ostringstream xml;
82+
83+
xml << "<?xml version='1.0'?>\n";
84+
xml << "<!DOCTYPE target SYSTEM 'gdb-target.dtd'>\n";
85+
xml << "<target>\n";
86+
xml << "<architecture>i386:x86-64</architecture>\n";
87+
xml << "<osabi>GNU/Linux</osabi>\n";
88+
xml << "<feature name='org.gnu.gdb.i386.core'>\n";
89+
90+
xml << "<flags id='fex_eflags' size='4'>\n";
91+
// flags register
92+
for (int i = 0; i < 22; i++) {
93+
auto name = GDB::Info::GetFlagName(i);
94+
if (name.empty()) {
95+
continue;
96+
}
97+
xml << "\t<field name='" << name << "' start='" << i << "' end='" << i << "' />\n";
98+
}
99+
xml << "</flags>\n";
100+
101+
int32_t TargetSize {};
102+
auto reg = [&](std::string_view name, std::string_view type, int size) {
103+
TargetSize += size;
104+
xml << "<reg name='" << name << "' bitsize='" << size << "' type='" << type << "' />" << std::endl;
105+
};
106+
107+
// Register ordering.
108+
// We want to just memcpy our x86 state to gdb, so we tell it the ordering.
109+
110+
// GPRs
111+
for (uint32_t i = 0; i < FEXCore::Core::CPUState::NUM_GPRS; i++) {
112+
reg(GDB::Info::GetGRegName(i), "int64", 64);
113+
}
114+
115+
reg("rip", "code_ptr", 64);
116+
117+
reg("eflags", "fex_eflags", 32);
118+
119+
// Fake registers which GDB requires, but we don't support;
120+
// We stick them past the end of our cpu state.
121+
122+
// non-userspace segment registers
123+
reg("cs", "int32", 32);
124+
reg("ss", "int32", 32);
125+
reg("ds", "int32", 32);
126+
reg("es", "int32", 32);
127+
128+
reg("fs", "int32", 32);
129+
reg("gs", "int32", 32);
130+
131+
// x87 stack
132+
for (int i = 0; i < 8; i++) {
133+
reg(fextl::fmt::format("st{}", i), "i387_ext", 80);
134+
}
135+
136+
// x87 control
137+
reg("fctrl", "int32", 32);
138+
reg("fstat", "int32", 32);
139+
reg("ftag", "int32", 32);
140+
reg("fiseg", "int32", 32);
141+
reg("fioff", "int32", 32);
142+
reg("foseg", "int32", 32);
143+
reg("fooff", "int32", 32);
144+
reg("fop", "int32", 32);
145+
146+
147+
xml << "</feature>\n";
148+
xml << "<feature name='org.gnu.gdb.i386.sse'>\n";
149+
xml <<
150+
R"(<vector id="v4f" type="ieee_single" count="4"/>
151+
<vector id="v2d" type="ieee_double" count="2"/>
152+
<vector id="v16i8" type="int8" count="16"/>
153+
<vector id="v8i16" type="int16" count="8"/>
154+
<vector id="v4i32" type="int32" count="4"/>
155+
<vector id="v2i64" type="int64" count="2"/>
156+
<union id="vec128">
157+
<field name="v4_float" type="v4f"/>
158+
<field name="v2_double" type="v2d"/>
159+
<field name="v16_int8" type="v16i8"/>
160+
<field name="v8_int16" type="v8i16"/>
161+
<field name="v4_int32" type="v4i32"/>
162+
<field name="v2_int64" type="v2i64"/>
163+
<field name="uint128" type="uint128"/>
164+
</union>
165+
)";
166+
167+
// SSE regs
168+
for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) {
169+
reg(fextl::fmt::format("xmm{}", i), "vec128", 128);
170+
}
171+
172+
reg("mxcsr", "int", 32);
173+
174+
xml << "</feature>\n";
175+
176+
xml << "<feature name='org.gnu.gdb.i386.avx'>";
177+
xml <<
178+
R"(<vector id="v4f" type="ieee_single" count="4"/>
179+
<vector id="v2d" type="ieee_double" count="2"/>
180+
<vector id="v16i8" type="int8" count="16"/>
181+
<vector id="v8i16" type="int16" count="8"/>
182+
<vector id="v4i32" type="int32" count="4"/>
183+
<vector id="v2i64" type="int64" count="2"/>
184+
<union id="vec128">
185+
<field name="v4_float" type="v4f"/>
186+
<field name="v2_double" type="v2d"/>
187+
<field name="v16_int8" type="v16i8"/>
188+
<field name="v8_int16" type="v8i16"/>
189+
<field name="v4_int32" type="v4i32"/>
190+
<field name="v2_int64" type="v2i64"/>
191+
<field name="uint128" type="uint128"/>
192+
</union>
193+
)";
194+
for (size_t i = 0; i < FEXCore::Core::CPUState::NUM_XMMS; i++) {
195+
reg(fmt::format("ymm{}h", i), "vec128", 128);
196+
}
197+
xml << "</feature>\n";
198+
199+
xml << "</target>";
200+
xml << std::flush;
201+
202+
return xml.str();
203+
}
204+
205+
} // namespace FEX::GDB::Info
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: MIT
2+
/*
3+
$info$
4+
tags: glue|gdbserver
5+
desc: Provides a gdb interface to the guest state
6+
$end_info$
7+
*/
8+
#pragma once
9+
10+
#include <FEXCore/fextl/string.h>
11+
12+
#include <cstdint>
13+
#include <string_view>
14+
15+
namespace FEXCore::X86State {
16+
enum X86Reg : uint32_t;
17+
}
18+
19+
namespace FEX::GDB::Info {
20+
/**
21+
* @brief Returns textual name of bit location from EFLAGs register.
22+
*
23+
* @param Bit Which bit of EFLAG to query
24+
*/
25+
const std::string_view& GetFlagName(unsigned Bit);
26+
27+
/**
28+
* @brief Returns the textual name of a GPR register
29+
*
30+
* @param Reg Index of the register to fetch
31+
*/
32+
std::string_view GetGRegName(unsigned Reg);
33+
34+
/**
35+
* @brief Fetches the thread's name
36+
*
37+
* @param PID The program id of the application
38+
* @param ThreadID The thread id of the program
39+
*/
40+
fextl::string GetThreadName(uint32_t PID, uint32_t ThreadID);
41+
42+
/**
43+
* @brief Returns the GDB specific construct of OS describing XML.
44+
*/
45+
fextl::string BuildOSXML();
46+
47+
/**
48+
* @brief Returns the GDB specific construct of target describing XML.
49+
*/
50+
fextl::string BuildTargetXML();
51+
} // namespace FEX::GDB::Info

0 commit comments

Comments
 (0)