The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / src / node_win32_etw_provider.cc @ 6f92da2d

History | View | Annotate | Download (6.13 KB)

1 35a1421e Igor Zinkovsky
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node_dtrace.h"
23
#include "node_win32_etw_provider.h"
24
#include "node_etw_provider.h"
25 66f64ae0 Scott Blomquist
#include "node_win32_etw_provider-inl.h"
26 35a1421e Igor Zinkovsky
27
namespace node {
28
29 6caf012d Fedor Indutny
using v8::V8;
30
using v8::JitCodeEvent;
31
32 35a1421e Igor Zinkovsky
HMODULE advapi;
33
REGHANDLE node_provider;
34
EventRegisterFunc event_register;
35
EventUnregisterFunc event_unregister;
36
EventWriteFunc event_write;
37
int events_enabled;
38 66f64ae0 Scott Blomquist
static uv_async_t dispatch_etw_events_change_async;
39
40
struct v8tags {
41
  char prefix[32 - sizeof(size_t)];
42
  size_t prelen;
43
};
44
45
// The v8 CODE_ADDED event name has a prefix indicating the type of event.
46
// Many of these are internal to v8.
47
// The trace_codes array specifies which types are written.
48
struct v8tags trace_codes[] = {
49
#define MAKE_V8TAG(s) { s, sizeof(s) - 1 }
50
  MAKE_V8TAG("LazyCompile:"),
51
  MAKE_V8TAG("Script:"),
52
  MAKE_V8TAG("Function:"),
53
  MAKE_V8TAG("RegExp:"),
54
  MAKE_V8TAG("Eval:")
55
#undef MAKE_V8TAG
56
};
57
58
/* Below are some code prefixes which are not being written.
59
 *    "Builtin:"
60
 *    "Stub:"
61
 *    "CallIC:"
62
 *    "LoadIC:"
63
 *    "KeyedLoadIC:"
64
 *    "StoreIC:"
65
 *    "KeyedStoreIC:"
66
 *    "CallPreMonomorphic:"
67
 *    "CallInitialize:"
68
 *    "CallMiss:"
69
 *    "CallMegamorphic:"
70
 */
71
72
// v8 sometimes puts a '*' or '~' in front of the name.
73
#define V8_MARKER1 '*'
74
#define V8_MARKER2 '~'
75
76
77
// If prefix is not in filtered list return -1,
78
// else return length of prefix and marker.
79
int FilterCodeEvents(const char* name, size_t len) {
80
  for (int i = 0; i < ARRAY_SIZE(trace_codes); i++) {
81
    size_t prelen = trace_codes[i].prelen;
82
    if (prelen < len) {
83
      if (strncmp(name, trace_codes[i].prefix, prelen) == 0) {
84
        if (name[prelen] == V8_MARKER1 || name[prelen] == V8_MARKER2)
85
          prelen++;
86
        return prelen;
87
      }
88
    }
89
  }
90
  return -1;
91
}
92
93
94
// callback from V8 module passes symbol and address info for stack walk
95
void CodeAddressNotification(const JitCodeEvent* jevent) {
96
  int pre_offset = 0;
97
  if (NODE_V8SYMBOL_ENABLED()) {
98
    switch (jevent->type) {
99
    case JitCodeEvent::CODE_ADDED:
100
      pre_offset = FilterCodeEvents(jevent->name.str, jevent->name.len);
101
      if (pre_offset >= 0) {
102
        // skip over prefix and marker
103
        NODE_V8SYMBOL_ADD(jevent->name.str + pre_offset,
104
                          jevent->name.len - pre_offset,
105
                          jevent->code_start,
106
                          jevent->code_len);
107
      }
108
      break;
109
    case JitCodeEvent::CODE_REMOVED:
110
      NODE_V8SYMBOL_REMOVE(jevent->code_start, 0);
111
      break;
112
    case JitCodeEvent::CODE_MOVED:
113
      NODE_V8SYMBOL_MOVE(jevent->code_start, jevent->new_code_start);
114
      break;
115
    default:
116
      break;
117
    }
118
  }
119
}
120
121
122
// Call v8 to enable or disable code event callbacks.
123
// Must be on default thread to do this.
124
// Note: It is possible to call v8 from ETW thread, but then
125
//       event callbacks are received in the same thread. Attempts
126
//       to write ETW events in this thread will fail.
127
void etw_events_change_async(uv_async_t* handle, int status) {
128
  if (events_enabled > 0) {
129
    NODE_V8SYMBOL_RESET();
130
    V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
131
                               CodeAddressNotification);
132
  } else {
133
    V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
134
  }
135
}
136
137 35a1421e Igor Zinkovsky
138
// This callback is called by ETW when consumers of our provider
139
// are enabled or disabled.
140
// The callback is dispatched on ETW thread.
141 66f64ae0 Scott Blomquist
// Before calling into V8 to enable code events, switch to default thread.
142 35a1421e Igor Zinkovsky
void NTAPI etw_events_enable_callback(
143
  LPCGUID SourceId,
144
  ULONG IsEnabled,
145
  UCHAR Level,
146
  ULONGLONG MatchAnyKeyword,
147
  ULONGLONG MatchAllKeywords,
148
  PEVENT_FILTER_DESCRIPTOR FilterData,
149
  PVOID CallbackContext) {
150
  if (IsEnabled) {
151
    events_enabled++;
152 66f64ae0 Scott Blomquist
    if (events_enabled == 1) {
153
      uv_async_send(&dispatch_etw_events_change_async);
154
    }
155 35a1421e Igor Zinkovsky
  } else {
156
    events_enabled--;
157 66f64ae0 Scott Blomquist
    if (events_enabled == 0) {
158
      uv_async_send(&dispatch_etw_events_change_async);
159
    }
160 35a1421e Igor Zinkovsky
  }
161
}
162
163
164
void init_etw() {
165
  events_enabled = 0;
166
167
  advapi = LoadLibrary("advapi32.dll");
168
  if (advapi) {
169
    event_register = (EventRegisterFunc)
170
      GetProcAddress(advapi, "EventRegister");
171
    event_unregister = (EventUnregisterFunc)
172
      GetProcAddress(advapi, "EventUnregister");
173
    event_write = (EventWriteFunc)GetProcAddress(advapi, "EventWrite");
174
175 66f64ae0 Scott Blomquist
    // create async object used to invoke main thread from callback
176
    uv_async_init(uv_default_loop(),
177 4d68daea Ben Noordhuis
                  &dispatch_etw_events_change_async,
178
                  etw_events_change_async);
179
    uv_unref(reinterpret_cast<uv_handle_t*>(&dispatch_etw_events_change_async));
180 66f64ae0 Scott Blomquist
181 8e29ce9f Fedor Indutny
    if (event_register) {
182 35a1421e Igor Zinkovsky
      DWORD status = event_register(&NODE_ETW_PROVIDER,
183
                                    etw_events_enable_callback,
184
                                    NULL,
185
                                    &node_provider);
186
      assert(status == ERROR_SUCCESS);
187
    }
188
  }
189
}
190
191
192
void shutdown_etw() {
193
  if (advapi && event_unregister && node_provider) {
194
    event_unregister(node_provider);
195
    node_provider = 0;
196
  }
197
198
  events_enabled = 0;
199 66f64ae0 Scott Blomquist
  V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
200 35a1421e Igor Zinkovsky
201
  if (advapi) {
202
    FreeLibrary(advapi);
203
    advapi = NULL;
204
  }
205
}
206 4d68daea Ben Noordhuis
}