2020 #include <mach/mach_vm.h>
2121 #include <mach/machine.h>
2222 #include <libproc.h>
23- #endif
23+ #include <sys/proc.h>
24+ #include <sys/sysctl.h>
25+ #endif
2426
2527#include <errno.h>
2628#include <fcntl.h>
3133#include <string.h>
3234#include <sys/mman.h>
3335#include <sys/param.h>
34- #include <sys/proc.h>
3536#include <sys/stat.h>
36- #include <sys/sysctl.h>
3737#include <sys/types.h>
3838#include <unistd.h>
3939
@@ -166,6 +166,7 @@ static mach_port_t pid_to_task(pid_t pid) {
166166 result = task_for_pid (mach_task_self (), pid , & task );
167167 if (result != KERN_SUCCESS ) {
168168 printf ("Call to task_for_pid failed on PID %d: %s" , pid , mach_error_string (result ));
169+ PyErr_SetString (PyExc_PermissionError , "Cannot get task for PID" );
169170 return 0 ;
170171 }
171172 return task ;
@@ -189,7 +190,7 @@ static void* get_py_runtime(pid_t pid) {
189190 void * result_address = NULL ;
190191 while (mach_vm_region (
191192 proc_ref , & address , & size , VM_REGION_BASIC_INFO_64 ,
192- (vm_region_info_t )& region_info , // cppcheck-suppress [uninitvar]
193+ (vm_region_info_t )& region_info ,
193194 & count , & object_name ) == KERN_SUCCESS ) {
194195
195196 int path_len = proc_regionfilename (pid , address , map_filename , MAXPATHLEN );
@@ -224,6 +225,55 @@ static void* get_py_runtime(pid_t pid) {
224225
225226
226227#ifdef __linux__
228+ unsigned long
229+ find_python_map_start_address (pid_t pid , char * result_filename ) {
230+ char maps_file_path [64 ];
231+ sprintf (maps_file_path , "/proc/%d/maps" , pid );
232+
233+ FILE * maps_file = fopen (maps_file_path , "r" );
234+ if (maps_file == NULL ) {
235+ PyErr_SetFromErrno (PyExc_OSError );
236+ return 0 ;
237+ }
238+
239+ int match_found = 0 ;
240+
241+ char line [256 ];
242+ char map_filename [256 ];
243+ unsigned long result_address = 0 ;
244+ while (fgets (line , sizeof (line ), maps_file ) != NULL ) {
245+ unsigned long start_address = 0 ;
246+ sscanf (line , "%lx-%*x %*s %*s %*s %*s %s" , & start_address , map_filename );
247+ char * filename = strrchr (map_filename , '/' );
248+ if (filename != NULL ) {
249+ filename ++ ; // Move past the '/'
250+ } else {
251+ filename = map_filename ; // No path, use the whole string
252+ }
253+
254+ // Check if the filename starts with "python" or "libpython"
255+ if (!match_found && strncmp (filename , "python" , 6 ) == 0 ) {
256+ match_found = 1 ;
257+ result_address = start_address ;
258+ strcpy (result_filename , map_filename );
259+ }
260+ if (strncmp (filename , "libpython" , 9 ) == 0 ) {
261+ match_found = 1 ;
262+ result_address = start_address ;
263+ strcpy (result_filename , map_filename );
264+ break ;
265+ }
266+ }
267+
268+ fclose (maps_file );
269+
270+ if (!match_found ) {
271+ map_filename [0 ] = '\0' ;
272+ }
273+
274+ return result_address ;
275+ }
276+
227277void *
228278get_py_runtime (pid_t pid ) {
229279
@@ -279,54 +329,7 @@ get_py_runtime(pid_t pid) {
279329 return result ;
280330}
281331
282- unsigned long
283- find_python_map_start_address (pid_t pid , char * result_filename ) {
284- char maps_file_path [64 ];
285- sprintf (maps_file_path , "/proc/%d/maps" , pid );
286-
287- FILE * maps_file = fopen (maps_file_path , "r" );
288- if (maps_file == NULL ) {
289- PyErr_SetFromErrno (PyExc_OSError );
290- return 0 ;
291- }
292-
293- int match_found = 0 ;
294-
295- char line [256 ];
296- char map_filename [256 ];
297- unsigned long result_address = 0 ;
298- while (fgets (line , sizeof (line ), maps_file ) != NULL ) {
299- unsigned long start_address = 0 ;
300- sscanf (line , "%lx-%*x %*s %*s %*s %*s %s" , & start_address , map_filename );
301- char * filename = strrchr (map_filename , '/' );
302- if (filename != NULL ) {
303- filename ++ ; // Move past the '/'
304- } else {
305- filename = map_filename ; // No path, use the whole string
306- }
307332
308- // Check if the filename starts with "python" or "libpython"
309- if (!match_found && strncmp (filename , "python" , 6 ) == 0 ) {
310- match_found = 1 ;
311- result_address = start_address ;
312- strcpy (result_filename , map_filename );
313- }
314- if (strncmp (filename , "libpython" , 9 ) == 0 ) {
315- match_found = 1 ;
316- result_address = start_address ;
317- strcpy (result_filename , map_filename );
318- break ;
319- }
320- }
321-
322- fclose (maps_file );
323-
324- if (!match_found ) {
325- map_filename [0 ] = '\0' ;
326- }
327-
328- return result_address ;
329- }
330333#endif
331334
332335ssize_t
@@ -363,7 +366,7 @@ read_memory(pid_t pid, void* remote_address, ssize_t size, void* local_address)
363366 return -1 ;
364367 }
365368 total_bytes_read = size ;
366- #else
369+ #else
367370 return -1 ;
368371#endif
369372 return total_bytes_read ;
@@ -391,8 +394,8 @@ read_string(pid_t pid, _Py_DebugOffsets *debug_offsets, void* address, char* buf
391394
392395static PyObject *
393396get_stack_trace (PyObject * self , PyObject * args ) {
394- #ifndef HAVE_PROCESS_VM_READV
395- PyErr_SetString (PyExc_RuntimeError , "process_vm_readv not available on this platform" );
397+ #if (!defined( __linux__ ) && !defined( __APPLE__ )) || (defined( __linux__ ) && ! HAVE_PROCESS_VM_READV )
398+ PyErr_SetString (PyExc_RuntimeError , "get_strac_trace is not supported on this platform" );
396399 return NULL ;
397400#endif
398401 int pid ;
@@ -403,7 +406,9 @@ get_stack_trace(PyObject* self, PyObject* args) {
403406
404407 void * runtime_start_address = get_py_runtime (pid );
405408 if (runtime_start_address == NULL ) {
406- PyErr_SetString (PyExc_RuntimeError , "Failed to get .PyRuntime address" );
409+ if (!PyErr_Occurred ()) {
410+ PyErr_SetString (PyExc_RuntimeError , "Failed to get .PyRuntime address" );
411+ }
407412 return NULL ;
408413 }
409414
0 commit comments