Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5a4205d

Browse files
committedMar 3, 2024
Implement "record btrace pt" for Windows
1 parent 41a46c4 commit 5a4205d

File tree

10 files changed

+1810
-3
lines changed

10 files changed

+1810
-3
lines changed
 

‎gdb/Makefile.in

+4-1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ LIBXXHASH = @LIBXXHASH@
208208
# Where is libipt? This will be empty if libipt was not available.
209209
LIBIPT = @LIBIPT@
210210

211+
# Where is libwinipt? This will be empty if libwinipt was not available.
212+
LIBWINIPT = @LIBWINIPT@
213+
211214
# How to find GMP and MPFR
212215
GMPLIBS = @GMPLIBS@
213216
GMPINC = @GMPINC@
@@ -661,7 +664,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(LIBCTF) $(BFD) $(ZLIB) $(ZSTD_LIBS) \
661664
$(LIBSUPPORT) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
662665
$(XM_CLIBS) $(GDBTKLIBS) $(LIBBACKTRACE_LIB) \
663666
@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ $(AMD_DBGAPI_LIBS) \
664-
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
667+
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) $(LIBWINIPT) \
665668
$(WIN32LIBS) $(LIBGNU) $(LIBGNU_EXTRA_LIBS) $(LIBICONV) \
666669
$(GMPLIBS) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
667670
$(DEBUGINFOD_LIBS) $(LIBBABELTRACE_LIB)

‎gdb/config.in

+3
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@
268268
/* Define to 1 if you have the <libunwind-ia64.h> header file. */
269269
#undef HAVE_LIBUNWIND_IA64_H
270270

271+
/* Define if you have the winipt library. */
272+
#undef HAVE_LIBWINIPT
273+
271274
/* Define if you have the xxhash library. */
272275
#undef HAVE_LIBXXHASH
273276

‎gdb/configure

+491-2
Large diffs are not rendered by default.

‎gdb/windows-nat.c

+320
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,21 @@
7676
#include "gdbsupport/symbol.h"
7777
#include "ser-event.h"
7878
#include "inf-loop.h"
79+
#include "nat/x86-cpuid.h"
7980

8081
#include "readline/readline.h"
8182
#ifdef TUI
8283
#include "tui/tui-win.h"
8384
#endif
8485

86+
#ifdef HAVE_LIBWINIPT
87+
#undef C_ASSERT
88+
#define C_ASSERT(e)
89+
extern "C" {
90+
#include <libipt.h>
91+
}
92+
#endif
93+
8594
using namespace windows_nat;
8695

8796
/* Maintain a linked list of "so" information. */
@@ -154,6 +163,8 @@ struct windows_per_inferior : public windows_process_info
154163
CORE_ADDR cygwin_load_start = 0;
155164
CORE_ADDR cygwin_load_end = 0;
156165
#endif /* __CYGWIN__ */
166+
167+
int pt_threads = 0;
157168
};
158169

159170
/* The current process. */
@@ -375,6 +386,17 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
375386

376387
bool info_proc (const char *, enum info_proc_what) override;
377388

389+
#ifdef HAVE_LIBWINIPT
390+
struct btrace_target_info *enable_btrace (thread_info *tp,
391+
const struct btrace_config *conf) override;
392+
void disable_btrace (struct btrace_target_info *tinfo) override;
393+
void teardown_btrace (struct btrace_target_info *tinfo) override;
394+
enum btrace_error read_btrace (struct btrace_data *data,
395+
struct btrace_target_info *btinfo,
396+
enum btrace_read_type type) override;
397+
const struct btrace_config *btrace_conf (const struct btrace_target_info *) override;
398+
#endif
399+
378400
private:
379401

380402
windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb,
@@ -2595,6 +2617,304 @@ windows_nat_target::info_proc (const char *args, enum info_proc_what what)
25952617
return true;
25962618
}
25972619

2620+
#ifdef HAVE_LIBWINIPT
2621+
struct handle_deleter
2622+
{
2623+
void operator() (HANDLE h) const
2624+
{
2625+
if (h != INVALID_HANDLE_VALUE)
2626+
CloseHandle (h);
2627+
}
2628+
using pointer = HANDLE;
2629+
};
2630+
2631+
using handle_up = std::unique_ptr<HANDLE, handle_deleter>;
2632+
2633+
struct sc_handle_deleter
2634+
{
2635+
void operator() (SC_HANDLE sch) const
2636+
{
2637+
CloseServiceHandle (sch);
2638+
}
2639+
using pointer = SC_HANDLE;
2640+
};
2641+
2642+
using sc_handle_up = std::unique_ptr<SC_HANDLE, sc_handle_deleter>;
2643+
2644+
static void windows_enable_ipt_service ()
2645+
{
2646+
sc_handle_up scManager
2647+
(OpenSCManager (nullptr, nullptr, SC_MANAGER_CONNECT));
2648+
if (!scManager)
2649+
{
2650+
unsigned err = (unsigned) GetLastError ();
2651+
error (_("Can't open SCM handle (error %u: %s)."),
2652+
err, strwinerror (err));
2653+
}
2654+
2655+
sc_handle_up scService
2656+
(OpenServiceW (scManager.get (), L"Ipt", SERVICE_START));
2657+
if (!scService)
2658+
{
2659+
unsigned err = (unsigned) GetLastError ();
2660+
error (_("Can't open IPT service (error %u: %s)."),
2661+
err, strwinerror (err));
2662+
}
2663+
2664+
if (!StartService (scService.get (), 0, nullptr))
2665+
{
2666+
unsigned err = (unsigned) GetLastError ();
2667+
if (err != ERROR_SERVICE_ALREADY_RUNNING)
2668+
error (_("Can't start IPT service (error %u: %s)."),
2669+
err, strwinerror (err));
2670+
}
2671+
}
2672+
2673+
static struct btrace_target_info *
2674+
windows_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
2675+
{
2676+
if (conf->format != BTRACE_FORMAT_PT)
2677+
error (_("Unknown branch trace format."));
2678+
2679+
DWORD size = conf->pt.size;
2680+
if (size < 4 * 1024)
2681+
size = 4 * 1024;
2682+
else if (size > 128 * 1024 * 1024)
2683+
size = 128 * 1024 * 1024;
2684+
2685+
if (windows_process.pt_threads == 0)
2686+
{
2687+
windows_enable_ipt_service ();
2688+
2689+
DWORD bufferVersion;
2690+
if (!GetIptBufferVersion (&bufferVersion))
2691+
error (_("Can't get IPT buffer version."));
2692+
if (bufferVersion != IPT_BUFFER_MAJOR_VERSION_CURRENT)
2693+
error (_("IPT buffer version mismatch."));
2694+
2695+
WORD traceVersion;
2696+
if (!GetIptTraceVersion (&traceVersion))
2697+
error (_("Can't get IPT trace version."));
2698+
if (traceVersion != IPT_TRACE_VERSION_CURRENT)
2699+
error (_("IPT trace version mismatch."));
2700+
2701+
int pid = ptid.pid ();
2702+
handle_up hProcess (OpenProcess (PROCESS_VM_READ, FALSE, pid));
2703+
if (!hProcess)
2704+
{
2705+
unsigned err = (unsigned) GetLastError ();
2706+
error (_("Can't open process handle (error %u: %s)."),
2707+
err, strwinerror (err));
2708+
}
2709+
2710+
DWORD index;
2711+
BitScanReverse(&index, size);
2712+
2713+
IPT_OPTIONS options;
2714+
options.AsULonglong = 0;
2715+
options.OptionVersion = 1;
2716+
options.TopaPagesPow2 = index - 12;
2717+
options.TimingSettings = IptNoTimingPackets;
2718+
options.ModeSettings = IptCtlUserModeOnly;
2719+
2720+
if (!StartProcessIptTracing (hProcess.get (), options))
2721+
error (_("Can't start trace."));
2722+
}
2723+
2724+
windows_process.pt_threads++;
2725+
2726+
std::unique_ptr<btrace_target_info> tinfo
2727+
{ gdb::make_unique<btrace_target_info> (ptid) };
2728+
2729+
tinfo->conf.format = BTRACE_FORMAT_PT;
2730+
tinfo->conf.pt.size = size;
2731+
2732+
return tinfo.release ();
2733+
}
2734+
2735+
static bool
2736+
windows_disable_btrace (struct btrace_target_info *tinfo)
2737+
{
2738+
if (tinfo->conf.format != BTRACE_FORMAT_PT)
2739+
return false;
2740+
2741+
if (--windows_process.pt_threads > 0)
2742+
return true;
2743+
2744+
int pid = tinfo->ptid.pid ();
2745+
handle_up hProcess (OpenProcess (PROCESS_VM_READ, FALSE, pid));
2746+
if (!hProcess)
2747+
return false;
2748+
2749+
if (!StopProcessIptTracing (hProcess.get ()))
2750+
return false;
2751+
2752+
return true;
2753+
}
2754+
2755+
/* Identify the cpu we're running on. */
2756+
static struct btrace_cpu
2757+
btrace_this_cpu (void)
2758+
{
2759+
struct btrace_cpu cpu;
2760+
unsigned int eax, ebx, ecx, edx;
2761+
int ok;
2762+
2763+
memset (&cpu, 0, sizeof (cpu));
2764+
2765+
ok = x86_cpuid (0, &eax, &ebx, &ecx, &edx);
2766+
if (ok != 0)
2767+
{
2768+
if (ebx == signature_INTEL_ebx && ecx == signature_INTEL_ecx
2769+
&& edx == signature_INTEL_edx)
2770+
{
2771+
unsigned int cpuid, ignore;
2772+
2773+
ok = x86_cpuid (1, &cpuid, &ignore, &ignore, &ignore);
2774+
if (ok != 0)
2775+
{
2776+
cpu.vendor = CV_INTEL;
2777+
2778+
cpu.family = (cpuid >> 8) & 0xf;
2779+
if (cpu.family == 0xf)
2780+
cpu.family += (cpuid >> 20) & 0xff;
2781+
2782+
cpu.model = (cpuid >> 4) & 0xf;
2783+
if ((cpu.family == 0x6) || ((cpu.family & 0xf) == 0xf))
2784+
cpu.model += (cpuid >> 12) & 0xf0;
2785+
}
2786+
}
2787+
else if (ebx == signature_AMD_ebx && ecx == signature_AMD_ecx
2788+
&& edx == signature_AMD_edx)
2789+
cpu.vendor = CV_AMD;
2790+
}
2791+
2792+
return cpu;
2793+
}
2794+
2795+
static enum btrace_error
2796+
windows_read_btrace (struct btrace_data *data,
2797+
struct btrace_target_info *btinfo,
2798+
enum btrace_read_type type)
2799+
{
2800+
if (btinfo->conf.format != BTRACE_FORMAT_PT)
2801+
return BTRACE_ERR_NOT_SUPPORTED;
2802+
2803+
data->format = BTRACE_FORMAT_PT;
2804+
data->variant.pt.data = nullptr;
2805+
data->variant.pt.size = 0;
2806+
data->variant.pt.config.cpu = btrace_this_cpu ();
2807+
2808+
if (type == BTRACE_READ_NEW)
2809+
type = BTRACE_READ_ALL;
2810+
2811+
if (type != BTRACE_READ_ALL)
2812+
return BTRACE_ERR_NOT_SUPPORTED;
2813+
2814+
int pid = btinfo->ptid.pid ();
2815+
handle_up hProcess (OpenProcess (PROCESS_VM_READ, FALSE, pid));
2816+
if (!hProcess)
2817+
return BTRACE_ERR_UNKNOWN;
2818+
2819+
DWORD traceSize;
2820+
if (!GetProcessIptTraceSize (hProcess.get (), &traceSize))
2821+
return BTRACE_ERR_UNKNOWN;
2822+
2823+
gdb::unique_xmalloc_ptr<unsigned char> buf
2824+
((unsigned char *) xmalloc (traceSize));
2825+
2826+
if (!GetProcessIptTrace (hProcess.get (), buf.get (), traceSize))
2827+
return BTRACE_ERR_UNKNOWN;
2828+
2829+
IPT_TRACE_DATA *pt_data = (IPT_TRACE_DATA *) buf.get ();
2830+
unsigned char *buf_end = buf.get () + traceSize;
2831+
size_t trace_offset = offsetof (IPT_TRACE_HEADER, Trace);
2832+
2833+
DWORD threadId = btinfo->ptid.lwp ();
2834+
IPT_TRACE_HEADER *pt_thread = (IPT_TRACE_HEADER *) pt_data->TraceData;
2835+
while ((unsigned char *) pt_thread + trace_offset < buf_end
2836+
&& pt_thread->Trace + pt_thread->TraceSize <= buf_end)
2837+
{
2838+
if (pt_thread->ThreadId == threadId)
2839+
{
2840+
uint32_t trace_size = pt_thread->TraceSize;
2841+
BYTE *trace_data = pt_thread->Trace;
2842+
gdb::unique_xmalloc_ptr<gdb_byte> bytes
2843+
((gdb_byte *) xmalloc (trace_size));
2844+
uint32_t start = pt_thread->RingBufferOffset;
2845+
if (start > 0)
2846+
memcpy (bytes.get () + (trace_size - start), trace_data, start);
2847+
memcpy (bytes.get (), trace_data + start, trace_size - start);
2848+
2849+
data->variant.pt.data = bytes.release ();
2850+
data->variant.pt.size = trace_size;
2851+
return BTRACE_ERR_NONE;
2852+
}
2853+
2854+
pt_thread
2855+
= (IPT_TRACE_HEADER *) (pt_thread->Trace + pt_thread->TraceSize);
2856+
}
2857+
2858+
return BTRACE_ERR_UNKNOWN;
2859+
}
2860+
2861+
static const struct btrace_config *
2862+
windows_btrace_conf (const struct btrace_target_info *btinfo)
2863+
{
2864+
return &btinfo->conf;
2865+
}
2866+
2867+
struct btrace_target_info *
2868+
windows_nat_target::enable_btrace (thread_info *tp,
2869+
const struct btrace_config *conf)
2870+
{
2871+
struct btrace_target_info *tinfo = nullptr;
2872+
ptid_t ptid = tp->ptid;
2873+
try
2874+
{
2875+
tinfo = windows_enable_btrace (ptid, conf);
2876+
}
2877+
catch (const gdb_exception_error &exception)
2878+
{
2879+
error (_("Could not enable branch tracing for %s: %s"),
2880+
target_pid_to_str (ptid).c_str (), exception.what ());
2881+
}
2882+
2883+
return tinfo;
2884+
}
2885+
2886+
void
2887+
windows_nat_target::disable_btrace (struct btrace_target_info *tinfo)
2888+
{
2889+
bool ret = windows_disable_btrace (tinfo);
2890+
delete tinfo;
2891+
2892+
if (!ret)
2893+
error (_("Could not disable branch tracing."));
2894+
}
2895+
2896+
void
2897+
windows_nat_target::teardown_btrace (struct btrace_target_info *tinfo)
2898+
{
2899+
windows_disable_btrace (tinfo);
2900+
delete tinfo;
2901+
}
2902+
2903+
enum btrace_error
2904+
windows_nat_target::read_btrace (struct btrace_data *data,
2905+
struct btrace_target_info *btinfo,
2906+
enum btrace_read_type type)
2907+
{
2908+
return windows_read_btrace (data, btinfo, type);
2909+
}
2910+
2911+
const struct btrace_config *
2912+
windows_nat_target::btrace_conf (const struct btrace_target_info *btinfo)
2913+
{
2914+
return windows_btrace_conf (btinfo);
2915+
}
2916+
#endif
2917+
25982918
/* Try to set or remove a user privilege to the current process. Return -1
25992919
if that fails, the previous setting of that privilege otherwise.
26002920

‎gdbserver/config.in

+3
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@
143143
/* Define if you have the ipt library. */
144144
#undef HAVE_LIBIPT
145145

146+
/* Define if you have the winipt library. */
147+
#undef HAVE_LIBWINIPT
148+
146149
/* Define if you have the xxhash library. */
147150
#undef HAVE_LIBXXHASH
148151

‎gdbserver/configure

+489
Large diffs are not rendered by default.

‎gdbsupport/Makefile.in

+3
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ GMSGFMT = @GMSGFMT@
254254
GREP = @GREP@
255255
HAVE_CXX11 = @HAVE_CXX11@
256256
HAVE_LIBIPT = @HAVE_LIBIPT@
257+
HAVE_LIBWINIPT = @HAVE_LIBWINIPT@
257258
HAVE_LIBXXHASH = @HAVE_LIBXXHASH@
258259
INCINTL = @INCINTL@
259260
INSTALL = @INSTALL@
@@ -269,9 +270,11 @@ LIBINTL_DEP = @LIBINTL_DEP@
269270
LIBIPT = @LIBIPT@
270271
LIBOBJS = @LIBOBJS@
271272
LIBS = @LIBS@
273+
LIBWINIPT = @LIBWINIPT@
272274
LIBXXHASH = @LIBXXHASH@
273275
LTLIBIPT = @LTLIBIPT@
274276
LTLIBOBJS = @LTLIBOBJS@
277+
LTLIBWINIPT = @LTLIBWINIPT@
275278
LTLIBXXHASH = @LTLIBXXHASH@
276279
MAINT = @MAINT@
277280
MAKEINFO = @MAKEINFO@

‎gdbsupport/common.m4

+5
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ AC_DEFUN([GDB_AC_COMMON], [
193193
AC_CHECK_MEMBERS([struct pt_insn.enabled, struct pt_insn.resynced], [], [],
194194
[#include <intel-pt.h>])
195195
LIBS=$save_LIBS
196+
197+
AC_LIB_HAVE_LINKFLAGS([winipt], [], [
198+
#include <windows.h>
199+
#include <libipt.h>
200+
], [GetIptBufferVersion (0);])
196201
fi
197202
fi
198203

‎gdbsupport/config.in

+3
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@
124124
/* Define if you have the ipt library. */
125125
#undef HAVE_LIBIPT
126126

127+
/* Define if you have the winipt library. */
128+
#undef HAVE_LIBWINIPT
129+
127130
/* Define if you have the xxhash library. */
128131
#undef HAVE_LIBXXHASH
129132

‎gdbsupport/configure

+489
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.