gh-103295: expose API for writing perf map files (#103546)

Co-authored-by: Aniket Panse <aniketpanse@fb.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
Co-authored-by: Carl Meyer <carl@oddbird.net>
This commit is contained in:
gsallam 2023-05-21 03:12:24 -07:00 committed by GitHub
parent 2e91c7e626
commit be0c106789
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 214 additions and 73 deletions

View file

@ -52,6 +52,10 @@ extern const char *PyWin_DLLVersionString;
#include <emscripten.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
/*[clinic input]
module sys
[clinic start generated code]*/
@ -2144,7 +2148,7 @@ sys_activate_stack_trampoline_impl(PyObject *module, const char *backend)
if (strcmp(backend, "perf") == 0) {
_PyPerf_Callbacks cur_cb;
_PyPerfTrampoline_GetCallbacks(&cur_cb);
if (cur_cb.init_state != _Py_perfmap_callbacks.init_state) {
if (cur_cb.write_state != _Py_perfmap_callbacks.write_state) {
if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_callbacks) < 0 ) {
PyErr_SetString(PyExc_ValueError, "can't activate perf trampoline");
return NULL;
@ -2240,6 +2244,80 @@ sys__getframemodulename_impl(PyObject *module, int depth)
}
#ifdef __cplusplus
extern "C" {
#endif
static PerfMapState perf_map_state;
PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void) {
#ifndef MS_WINDOWS
char filename[100];
pid_t pid = getpid();
// Use nofollow flag to prevent symlink attacks.
int flags = O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW | O_CLOEXEC;
snprintf(filename, sizeof(filename) - 1, "/tmp/perf-%jd.map",
(intmax_t)pid);
int fd = open(filename, flags, 0600);
if (fd == -1) {
return -1;
}
else{
perf_map_state.perf_map = fdopen(fd, "a");
if (perf_map_state.perf_map == NULL) {
close(fd);
return -1;
}
}
perf_map_state.map_lock = PyThread_allocate_lock();
if (perf_map_state.map_lock == NULL) {
fclose(perf_map_state.perf_map);
return -2;
}
#endif
return 0;
}
PyAPI_FUNC(int) PyUnstable_WritePerfMapEntry(
const void *code_addr,
unsigned int code_size,
const char *entry_name
) {
#ifndef MS_WINDOWS
if (perf_map_state.perf_map == NULL) {
int ret = PyUnstable_PerfMapState_Init();
if(ret != 0){
return ret;
}
}
PyThread_acquire_lock(perf_map_state.map_lock, 1);
fprintf(perf_map_state.perf_map, "%" PRIxPTR " %x %s\n", (uintptr_t) code_addr, code_size, entry_name);
fflush(perf_map_state.perf_map);
PyThread_release_lock(perf_map_state.map_lock);
#endif
return 0;
}
PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void) {
#ifndef MS_WINDOWS
if (perf_map_state.perf_map != NULL) {
// close the file
PyThread_acquire_lock(perf_map_state.map_lock, 1);
fclose(perf_map_state.perf_map);
PyThread_release_lock(perf_map_state.map_lock);
// clean up the lock and state
PyThread_free_lock(perf_map_state.map_lock);
perf_map_state.perf_map = NULL;
}
#endif
}
#ifdef __cplusplus
}
#endif
static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */
SYS_ADDAUDITHOOK_METHODDEF