|
76 | 76 | #include "gdbsupport/symbol.h"
|
77 | 77 | #include "ser-event.h"
|
78 | 78 | #include "inf-loop.h"
|
| 79 | +#include "nat/x86-cpuid.h" |
79 | 80 |
|
80 | 81 | #include "readline/readline.h"
|
81 | 82 | #ifdef TUI
|
82 | 83 | #include "tui/tui-win.h"
|
83 | 84 | #endif
|
84 | 85 |
|
| 86 | +#ifdef HAVE_LIBWINIPT |
| 87 | +#undef C_ASSERT |
| 88 | +#define C_ASSERT(e) |
| 89 | +extern "C" { |
| 90 | +#include <libipt.h> |
| 91 | +} |
| 92 | +#endif |
| 93 | + |
85 | 94 | using namespace windows_nat;
|
86 | 95 |
|
87 | 96 | /* Maintain a linked list of "so" information. */
|
@@ -154,6 +163,8 @@ struct windows_per_inferior : public windows_process_info
|
154 | 163 | CORE_ADDR cygwin_load_start = 0;
|
155 | 164 | CORE_ADDR cygwin_load_end = 0;
|
156 | 165 | #endif /* __CYGWIN__ */
|
| 166 | + |
| 167 | + int pt_threads = 0; |
157 | 168 | };
|
158 | 169 |
|
159 | 170 | /* The current process. */
|
@@ -375,6 +386,17 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
|
375 | 386 |
|
376 | 387 | bool info_proc (const char *, enum info_proc_what) override;
|
377 | 388 |
|
| 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 | + |
378 | 400 | private:
|
379 | 401 |
|
380 | 402 | 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)
|
2595 | 2617 | return true;
|
2596 | 2618 | }
|
2597 | 2619 |
|
| 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 | + |
2598 | 2918 | /* Try to set or remove a user privilege to the current process. Return -1
|
2599 | 2919 | if that fails, the previous setting of that privilege otherwise.
|
2600 | 2920 |
|
|
0 commit comments