1 /* -*- mode: C; c-file-style: "linux" -*- */
3 /* MemProf -- memory profiler and leak detector
4 * Copyright 1999, 2000, 2001, Red Hat, Inc.
5 * Copyright 2002, Kristian Rietveld
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include <sys/types.h>
31 #include <sys/socket.h>
34 #include <sys/sysmacros.h>
36 #include <glib-object.h>
38 #include "memintercept.h"
42 #include <glib/gi18n.h>
49 static guint process_signals
[LAST_SIGNAL
] = { 0 };
51 static void mp_process_class_init (MPProcessClass
*class);
52 static void mp_process_init (MPProcess
*process
);
53 static void mp_process_finalize (GObject
*object
);
54 static void process_reinit (MPProcess
*process
);
56 #define MP_PAGE_SIZE 4096
58 /* Code to keep a queue of commands read
66 queue_compare (gconstpointer a
, gconstpointer b
)
68 const Command
*commanda
= a
;
69 const Command
*commandb
= b
;
71 return (commanda
->info
.any
.seqno
< commandb
->info
.any
.seqno
? -1 :
72 (commanda
->info
.any
.seqno
> commandb
->info
.any
.seqno
? 1 : 0));
76 queue_command (MPProcess
*process
, MIInfo
*info
, StackNode
*stack
)
78 Command
*command
= g_new (Command
, 1);
79 command
->info
= *info
;
80 command
->stack
= stack
;
82 process
->command_queue
= g_list_insert_sorted (process
->command_queue
, command
, queue_compare
);
86 unqueue_command (MPProcess
*process
, MIInfo
*info
, StackNode
**stack
)
88 Command
*command
= process
->command_queue
->data
;
91 if (command
->info
.any
.seqno
== process
->seqno
) {
92 *stack
= command
->stack
;
93 *info
= command
->info
;
95 tmp_list
= process
->command_queue
;
96 process
->command_queue
= g_list_remove_link (process
->command_queue
, tmp_list
);
98 g_list_free_1 (tmp_list
);
105 /************************************************************
107 ************************************************************/
110 block_unref (Block
*block
)
113 if (block
->refcount
== 0)
117 /************************************************************
118 * Code to map addresses to object files
119 ************************************************************/
127 compare_address (const void *symbol1
, const void *symbol2
)
129 return (((Symbol
*)symbol1
)->addr
< ((Symbol
*)symbol2
)->addr
) ?
130 -1 : ((((Symbol
*)symbol1
)->addr
== ((Symbol
*)symbol2
)->addr
) ?
135 prepare_map (Map
*map
)
137 g_return_if_fail (!map
->prepared
);
139 map
->binfile
= bin_file_new (map
->name
);
141 map
->prepared
= TRUE
;
145 process_read_maps (MPProcess
*process
)
150 snprintf (buffer
, 1023, "/proc/%d/maps", process
->pid
);
152 in
= fopen (buffer
, "r");
154 if (process
->map_list
) {
155 g_list_foreach (process
->map_list
, (GFunc
)g_free
, NULL
);
156 g_list_free (process
->map_list
);
158 process
->map_list
= NULL
;
161 while (fgets(buffer
, 1023, in
)) {
170 buffer
, "%lx-%lx %*15s %lx %*x:%*x %lu %255s",
171 &start
, &end
, &offset
, &inode
, file
);
176 map
= g_new (Map
, 1);
177 map
->prepared
= FALSE
;
179 map
->size
= end
- start
;
181 map
->offset
= offset
;
183 map
->name
= g_strdup (file
);
185 process
->map_list
= g_list_prepend (process
->map_list
, map
);
193 real_locate_map (MPProcess
*process
, guint addr
)
195 GList
*tmp_list
= process
->map_list
;
199 Map
*tmp_map
= tmp_list
->data
;
201 if ((addr
>= tmp_map
->start
) &&
202 (addr
< tmp_map
->start
+ tmp_map
->size
))
205 tmp_list
= tmp_list
->next
;
212 locate_map (MPProcess
*process
, guint addr
)
214 Map
*map
= real_locate_map (process
, addr
);
217 gpointer page_addr
= (gpointer
) (addr
- addr
% MP_PAGE_SIZE
);
218 if (g_list_find (process
->bad_pages
, page_addr
))
221 process_read_maps (process
);
223 map
= real_locate_map (process
, addr
);
226 process
->bad_pages
= g_list_prepend (process
->bad_pages
, page_addr
);
238 process_locate_symbol (MPProcess
*process
, guint addr
)
240 Map
*map
= locate_map (process
, addr
);
241 const BinSymbol
*symbol
;
249 symbol
= bin_file_lookup_symbol (map
->binfile
, addr
);
251 return bin_symbol_get_name (map
->binfile
, symbol
);
255 process_find_line (MPProcess
*process
, void *address
,
256 const char **filename
, char **functionname
,
259 char *s
= process_locate_symbol (process
, address
);
272 process_dump_stack (MPProcess
*process
, FILE *out
, StackNode
*stack
)
274 for (; stack
!= NULL
; stack
= stack
->parent
)
276 const char *filename
;
280 if (process_find_line (process
, stack
->address
,
281 &filename
, &functionname
, &line
)) {
283 fprintf(out
, "\t%s(): %s:%u\n", functionname
, filename
, line
);
285 fprintf(out
, "\t%s()\n", functionname
);
287 fprintf(out
, "\t[%p]\n", stack
->address
);
293 process_map_sections (Map
*map
, SectionFunc func
, gpointer user_data
)
295 /* FIXME: this should be reinstated */
301 for (section
= map
->abfd
->sections
; section
; section
= section
->next
) {
302 if (strcmp (section
->name
, ".bss") == 0 ||
303 strcmp (section
->name
, ".data") == 0) {
304 void *addr
= (void *)section
->vma
;
308 /* bfd_section_size() gives 0 for old versions of binutils, so peek
309 * into the internals instead. :-(
311 (*func
) (addr
, bfd_section_size (map
->abfd
, section
), user_data
);
312 // (*func) (addr, section->_cooked_size, user_data);
319 process_sections (MPProcess
*process
, SectionFunc func
, gpointer user_data
)
323 process_read_maps (process
);
325 tmp_list
= process
->map_list
;
328 Map
*map
= tmp_list
->data
;
333 process_map_sections (map
, func
, user_data
);
334 tmp_list
= tmp_list
->next
;
338 /************************************************************
339 * Communication with subprocess
340 ************************************************************/
343 get_block_table (MPProcess
*process
)
345 if (!process
->block_table
)
346 process
->block_table
= g_hash_table_new (g_direct_hash
, NULL
);
348 return process
->block_table
;
353 process_free_block (gpointer key
, gpointer value
, gpointer data
)
359 process_duplicate_block (gpointer key
, gpointer value
, gpointer data
)
361 GHashTable
*new_table
= data
;
362 Block
*block
= value
;
366 g_hash_table_insert (new_table
, key
, value
);
370 process_duplicate (MPProcess
*process
)
372 MPProcess
*new_process
= process_new (process
->server
);
374 if (process
->block_table
) {
375 GHashTable
*new_block_table
= get_block_table(new_process
);
377 g_hash_table_foreach (process
->block_table
,
378 process_duplicate_block
,
382 new_process
->bytes_used
= process
->bytes_used
;
383 new_process
->n_allocations
= process
->n_allocations
;
384 new_process
->seqno
= process
->seqno
;
386 new_process
->parent
= process
;
392 process_reinit (MPProcess
*process
)
394 process_stop_input (process
);
396 if (process
->input_channel
) {
397 g_io_channel_unref (process
->input_channel
);
398 process
->input_channel
= NULL
;
401 process
->bytes_used
= 0;
402 process
->n_allocations
= 0;
405 if (process
->map_list
) {
406 g_list_foreach (process
->map_list
, (GFunc
)g_free
, NULL
);
407 g_list_free (process
->map_list
);
409 process
->map_list
= NULL
;
412 if (process
->bad_pages
) {
413 g_list_free (process
->bad_pages
);
414 process
->bad_pages
= NULL
;
417 if (process
->block_table
) {
418 g_hash_table_foreach (process
->block_table
, process_free_block
, NULL
);
419 g_hash_table_destroy (process
->block_table
);
420 process
->block_table
= NULL
;
423 if (process
->stack_stash
) {
424 stack_stash_unref (process
->stack_stash
);
425 process
->stack_stash
= NULL
;
429 process
->command_queue
= NULL
;
433 get_stack_stash (MPProcess
*process
)
435 if (!process
->stack_stash
)
436 process
->stack_stash
= stack_stash_new (NULL
);
438 return process
->stack_stash
;
442 process_exec_reset (MPProcess
*process
)
444 process_reinit (process
);
445 g_signal_emit_by_name (process
, "reset");
449 process_command (MPProcess
*process
, MIInfo
*info
, StackNode
*stack
)
451 GHashTable
*block_table
;
454 if (info
->any
.seqno
!= process
->seqno
) {
455 queue_command (process
, info
, stack
);
463 switch (info
->operation
) {
468 g_assert_not_reached ();
472 /* Handled before, ignore */
476 info
->alloc
.old_ptr
= NULL
;
477 info
->alloc
.new_ptr
= (void *)process
->seqno
;
478 info
->alloc
.size
= 1;
481 default: /* MALLOC / REALLOC / FREE */
482 block_table
= get_block_table (process
);
484 if (info
->alloc
.old_ptr
!= NULL
) {
485 block
= g_hash_table_lookup (block_table
, info
->alloc
.old_ptr
);
487 g_warning ("Block %p not found (pid=%d)!\n", info
->alloc
.old_ptr
, process
->pid
);
488 process_dump_stack (process
, stderr
, stack
);
491 g_hash_table_remove (block_table
, info
->alloc
.old_ptr
);
492 process
->bytes_used
-= block
->size
;
495 process
->n_allocations
--;
499 /* We need to lookup before inserting, because realloc() can call malloc(), so we
500 * see the same block twice. The same problem comes upduring malloc initialization
501 * where __libc_malloc() is called twice for the same block. We could optimize
502 * things a bit by using g_hash_table_new_full() to catch the replacement when
503 * it happens and free the old block, but that would make keeping track of
504 * process->n_allocations/bytes_used a little difficult.
507 if (info
->alloc
.new_ptr
&& !g_hash_table_lookup (block_table
, info
->alloc
.new_ptr
)) {
508 block
= g_new (Block
, 1);
512 block
->addr
= info
->alloc
.new_ptr
;
513 block
->size
= info
->alloc
.size
;
514 block
->stack
= stack
;
516 process
->n_allocations
++;
517 process
->bytes_used
+= info
->alloc
.size
;
519 g_hash_table_insert (block_table
, info
->alloc
.new_ptr
, block
);
523 while (process
->command_queue
&& unqueue_command (process
, info
, &stack
))
524 process_command (process
, info
, stack
);
528 input_func (GIOChannel
*source
,
529 GIOCondition condition
,
534 MPProcess
*input_process
= data
;
535 MPProcess
*process
= NULL
;
538 memset (&info
, 0, sizeof (info
));
541 if (g_io_channel_get_flags(source
) & G_IO_FLAG_IS_READABLE
)
542 g_io_channel_read_chars (source
, (char *)&info
, sizeof(info
), &count
, NULL
);
545 g_io_channel_unref (input_process
->input_channel
);
546 input_process
->input_channel
= NULL
;
548 mp_server_remove_process (input_process
->server
, input_process
);
549 process_set_status (input_process
, MP_PROCESS_DEFUNCT
);
553 StackNode
*stack
= NULL
;
555 // fprintf (stderr, "Read size %d op 0x%x\n", count, info.operation);
557 if (info
.operation
== MI_MALLOC
||
558 info
.operation
== MI_REALLOC
||
559 info
.operation
== MI_FREE
||
560 info
.operation
== MI_TIME
) {
561 void **stack_buffer
= NULL
;
562 StackStash
*stash
= get_stack_stash (input_process
);
564 g_assert (count
>= sizeof (MIInfoAlloc
));
566 stack_buffer
= g_alloca (sizeof (void *) * info
.alloc
.stack_size
);
567 g_io_channel_read_chars (source
, (char *)stack_buffer
, sizeof(void *) * info
.alloc
.stack_size
, &count
, NULL
);
568 stack
= stack_stash_add_trace (stash
, stack_buffer
, info
.alloc
.stack_size
, -1);
570 } else if (info
.operation
== MI_EXIT
) {
571 process_set_status (input_process
, MP_PROCESS_EXITING
);
572 if (input_process
->clone_of
)
573 process_detach (input_process
);
576 process
= input_process
;
577 while (process
->clone_of
)
578 process
= process
->clone_of
;
580 process_command (process
, &info
, stack
);
583 /* if (info.any.pid != input_process->pid)
584 g_warning ("Ow! Ow! Ow: %d %d %d!", info.any.pid, input_process->pid, g_io_channel_unix_get_fd (input_process->input_channel)); */
587 } while (info
.operation
!= MI_EXIT
&& (g_io_channel_get_buffer_condition(source
) & G_IO_IN
));
593 process_stop_input (MPProcess
*process
)
595 g_return_if_fail (process
!= NULL
);
597 if (process
->input_tag
) {
598 g_source_remove (process
->input_tag
);
599 process
->input_tag
= 0;
604 process_start_input (MPProcess
*process
)
606 g_return_if_fail (process
!= NULL
);
608 if (!process
->input_tag
&& process
->input_channel
)
609 process
->input_tag
= g_io_add_watch_full (process
->input_channel
,
611 G_IO_IN
| G_IO_PRI
| G_IO_ERR
| G_IO_HUP
| G_IO_NVAL
,
612 input_func
, process
, NULL
);
616 process_clear_input (MPProcess
*process
)
618 g_return_if_fail (process
!= NULL
);
620 process
->bytes_used
= 0;
621 process
->n_allocations
= 0;
623 if (process
->map_list
) {
624 g_list_foreach (process
->map_list
, (GFunc
)g_free
, NULL
);
625 g_list_free (process
->map_list
);
627 process
->map_list
= NULL
;
630 if (process
->bad_pages
) {
631 g_list_free (process
->bad_pages
);
632 process
->bad_pages
= NULL
;
635 if (process
->block_table
) {
636 g_hash_table_foreach (process
->block_table
, process_free_block
, NULL
);
637 g_hash_table_destroy (process
->block_table
);
638 process
->block_table
= NULL
;
641 if (process
->stack_stash
) {
642 stack_stash_unref (process
->stack_stash
);
643 process
->stack_stash
= NULL
;
648 process_find_exec (char **args
)
652 if (g_file_test(args
[0], G_FILE_TEST_EXISTS
)) {
653 if (!g_path_is_absolute (args
[0]))
654 return g_strconcat ("./", args
[0], NULL
);
656 return g_strdup (args
[0]);
660 char *pathenv
= getenv ("PATH");
663 paths
= g_strsplit (pathenv
, ":", -1);
664 for (i
=0; paths
[i
]; i
++) {
665 path
= g_build_filename (paths
[i
], args
[0], NULL
);
666 if (g_file_test (path
, G_FILE_TEST_EXISTS
))
682 process_parse_exec (const char *exec_string
)
684 return g_strsplit (exec_string
, " ", -1);
688 mp_process_get_type (void)
690 static GType process_type
= 0;
693 static const GTypeInfo process_info
= {
694 sizeof (MPProcessClass
),
695 (GBaseInitFunc
) NULL
,
696 (GBaseFinalizeFunc
) NULL
,
697 (GClassInitFunc
) mp_process_class_init
,
698 NULL
, /* class_finalize */
699 NULL
, /* class_data */
702 (GInstanceInitFunc
) mp_process_init
705 process_type
= g_type_register_static (G_TYPE_OBJECT
,
714 mp_process_class_init (MPProcessClass
*class)
716 static gboolean initialized
= FALSE
;
718 GObjectClass
*o_class
= G_OBJECT_CLASS (class);
720 o_class
->finalize
= mp_process_finalize
;
723 process_signals
[STATUS_CHANGED
] =
724 g_signal_new ("status_changed",
727 G_STRUCT_OFFSET (MPProcessClass
, status_changed
),
729 g_cclosure_marshal_VOID__VOID
,
732 process_signals
[RESET
] =
733 g_signal_new ("reset",
736 G_STRUCT_OFFSET (MPProcessClass
, reset
),
738 g_cclosure_marshal_VOID__VOID
,
746 mp_process_init (MPProcess
*process
)
748 process
->status
= MP_PROCESS_INIT
;
750 process
->clone_of
= NULL
;
752 process
->bytes_used
= 0;
753 process
->n_allocations
= 0;
754 process
->block_table
= NULL
;
755 process
->stack_stash
= NULL
;
757 process
->program_name
= NULL
;
758 process
->input_channel
= NULL
;
762 process
->command_queue
= NULL
;
764 process
->follow_fork
= FALSE
;
765 process
->follow_exec
= FALSE
;
767 g_object_ref (G_OBJECT (process
));
771 mp_process_finalize (GObject
*object
)
773 MPProcess
*process
= MP_PROCESS (object
);
775 process_reinit (process
);
777 g_free (process
->program_name
);
782 process_new (MPServer
*server
)
786 process
= g_object_new (MP_TYPE_PROCESS
, NULL
);
788 process
->server
= server
;
794 process_set_follow_fork (MPProcess
*process
,
795 gboolean follow_fork
)
797 process
->follow_fork
= follow_fork
;
801 process_set_follow_exec (MPProcess
*process
,
802 gboolean follow_exec
)
804 process
->follow_exec
= follow_exec
;
808 process_run (MPProcess
*process
, const char *path
, char **args
)
810 process
->program_name
= g_strdup (path
);
813 process
->pid
= mp_server_instrument (process
->server
, path
, args
);
814 mp_server_add_process (process
->server
, process
);
816 process_set_status (process
, MP_PROCESS_STARTING
);
818 process_start_input (process
);
822 process_get_clones (MPProcess
*process
)
824 return mp_server_get_process_clones (process
->server
, process
);
828 process_set_status (MPProcess
*process
, MPProcessStatus status
)
830 if (process
->status
!= status
) {
831 process
->status
= status
;
832 g_signal_emit_by_name (process
, "status_changed", NULL
);
837 process_get_status_text (MPProcess
*process
)
841 switch (process
->status
) {
842 case MP_PROCESS_INIT
:
843 status
= _("Initial");
845 case MP_PROCESS_STARTING
:
846 status
= _("Starting");
848 case MP_PROCESS_RUNNING
:
849 status
= _("Running");
851 case MP_PROCESS_EXITING
:
852 status
= _("Exiting");
854 case MP_PROCESS_DEFUNCT
:
855 status
= _("Defunct");
857 case MP_PROCESS_DETACHED
:
858 status
= _("Defunct");
862 return g_strdup (status
);
866 process_get_cmdline (MPProcess
*process
)
874 if (process
->status
== MP_PROCESS_DEFUNCT
)
875 return g_strdup ("");
877 fname
= g_strdup_printf ("/proc/%d/cmdline", process
->pid
);
878 in
= fopen (fname
, "r");
880 g_warning ("Can't open %s\n", fname
);
881 return g_strdup ("");
885 getline (&tmp
, &n
, in
);
886 result
= g_strdup (tmp
);
895 process_detach (MPProcess
*process
)
897 if (process
->status
!= MP_PROCESS_DEFUNCT
) {
898 int fd
= g_io_channel_unix_get_fd (process
->input_channel
);
900 if (process
->status
== MP_PROCESS_EXITING
) {
902 write (fd
, &response
, 1);
904 g_io_channel_shutdown (process
->input_channel
, TRUE
, NULL
);
905 process_set_status (process
, MP_PROCESS_DETACHED
);
911 process_kill (MPProcess
*process
)
913 if (process
->status
== MP_PROCESS_EXITING
) {
914 process_detach (process
);
915 } else if (process
->status
!= MP_PROCESS_DEFUNCT
&&
916 process
->status
!= MP_PROCESS_INIT
) {
917 kill (process
->pid
, SIGTERM
);
922 MPProcessBlockForeachFunc foreach_func
;
927 block_table_foreach_func (gpointer key
,
931 BlockForeachInfo
*info
= data
;
933 info
->foreach_func (value
, info
->data
);
937 process_block_foreach (MPProcess
*process
,
938 MPProcessBlockForeachFunc foreach_func
,
941 GHashTable
*block_table
= get_block_table (process
);
942 BlockForeachInfo info
;
944 info
.foreach_func
= foreach_func
;
947 g_hash_table_foreach (block_table
, block_table_foreach_func
, &info
);
951 my_str_equal (const char *s1
, const char *s2
)
957 symbol_equal (gconstpointer s1
, gconstpointer s2
)
963 symbol_hash (gconstpointer s
)
965 const char *symbol
= s
;
967 return g_str_hash (s
);
971 symbol_copy (const char *orig
)
980 symbol_free (char *symbol
)