📄 process.c
字号:
/* -*- mode: C; c-file-style: "linux" -*- *//* MemProf -- memory profiler and leak detector * Copyright 1999, 2000, 2001, Red Hat, Inc. * Copyright 2002, Kristian Rietveld * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//*====*/#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <signal.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/sysmacros.h>#include <glib-object.h>#include <libgnome/libgnome.h>#include "memintercept.h"#include "memprof.h"#include "process.h"#include "server.h"enum { STATUS_CHANGED, RESET, LAST_SIGNAL};static guint process_signals[LAST_SIGNAL] = { 0 };static void mp_process_class_init (MPProcessClass *class);static void mp_process_init (MPProcess *process);static void mp_process_finalize (GObject *object);static void process_reinit (MPProcess *process);#define MP_PAGE_SIZE 4096/* Code to keep a queue of commands read */typedef struct { MIInfo info; StackElement *stack;} Command;static gintqueue_compare (gconstpointer a, gconstpointer b){ const Command *commanda = a; const Command *commandb = b; return (commanda->info.any.seqno < commandb->info.any.seqno ? -1 : (commanda->info.any.seqno > commandb->info.any.seqno ? 1 : 0));}static voidqueue_command (MPProcess *process, MIInfo *info, StackElement *stack){ Command *command = g_new (Command, 1); command->info = *info; command->stack = stack; process->command_queue = g_list_insert_sorted (process->command_queue, command, queue_compare);}static gbooleanunqueue_command (MPProcess *process, MIInfo *info, StackElement **stack){ Command *command = process->command_queue->data; GList *tmp_list; if (command->info.any.seqno == process->seqno) { *stack = command->stack; *info = command->info; tmp_list = process->command_queue; process->command_queue = g_list_remove_link (process->command_queue, tmp_list); g_free (command); g_list_free_1 (tmp_list); return TRUE; } else return FALSE;}/************************************************************ * Block Manipulation ************************************************************/static voidblock_unref (Block *block){ block->refcount--; if (block->refcount == 0) g_free (block);} /************************************************************ * Code to map addresses to object files ************************************************************/static gintcompare_address (const void *symbol1, const void *symbol2){ return (((Symbol *)symbol1)->addr < ((Symbol *)symbol2)->addr) ? -1 : ((((Symbol *)symbol1)->addr == ((Symbol *)symbol2)->addr) ? 0 : 1);}voidprepare_map (Map *map){ GArray *result; Symbol symbol; int i; g_return_if_fail (!map->prepared); map->prepared = TRUE; read_bfd (map); if (map->syms) { result = g_array_new (FALSE, FALSE, sizeof(Symbol)); for (i = 0; i < map->symcount; i++) { if (map->syms[i]->flags & BSF_FUNCTION) { symbol.addr = bfd_asymbol_value(map->syms[i]); symbol.size = 0; symbol.name = demangle (map, bfd_asymbol_name(map->syms[i])); g_array_append_vals (result, &symbol, 1); } } /* Sort the symbols by address */ qsort (result->data, result->len, sizeof(Symbol), compare_address); map->symbols =result; }}static voidprocess_read_maps (MPProcess *process){ gchar buffer[1024]; FILE *in; gchar perms[26]; gchar file[256]; guint start, end, major, minor, inode; snprintf (buffer, 1023, "/proc/%d/maps", process->pid); in = fopen (buffer, "r"); if (process->map_list) { g_list_foreach (process->map_list, (GFunc)g_free, NULL); g_list_free (process->map_list); process->map_list = NULL; } while (fgets(buffer, 1023, in)) { int count = sscanf (buffer, "%x-%x %15s %*x %u:%u %u %255s", &start, &end, perms, &major, &minor, &inode, file); if (count >= 6) { if (strcmp (perms, "r-xp") == 0) { Map *map; dev_t device = makedev(major, minor); map = g_new (Map, 1); map->prepared = FALSE; map->addr = start; map->size = end - start; if (count == 7) map->name = g_strdup (file); else map->name = locate_inode (device, inode); map->abfd = NULL; map->section = NULL; map->symbols = NULL; map->syms = NULL; map->symcount = 0; map->do_offset = TRUE; if (map->name) { struct stat stat1, stat2; char *progname = g_strdup_printf ("/proc/%d/exe", process->pid); if (stat (map->name, &stat1) != 0) g_warning ("Cannot stat %s: %s\n", map->name, g_strerror (errno)); else if (stat (progname, &stat2) != 0) g_warning ("Cannot stat %s: %s\n", process->program_name, g_strerror (errno)); else map->do_offset = !(stat1.st_ino == stat2.st_ino && stat1.st_dev == stat2.st_dev); g_free (progname); } process->map_list = g_list_prepend (process->map_list, map); } } } fclose (in);}static Map *real_locate_map (MPProcess *process, guint addr){ GList *tmp_list = process->map_list; while (tmp_list) { Map *tmp_map = tmp_list->data; if ((addr >= tmp_map->addr) && (addr < tmp_map->addr + tmp_map->size)) return tmp_map; tmp_list = tmp_list->next; } return NULL;}Map *locate_map (MPProcess *process, guint addr){ Map *map = real_locate_map (process, addr); if (!map) { gpointer page_addr = (gpointer) (addr - addr % MP_PAGE_SIZE); if (g_list_find (process->bad_pages, page_addr)) return NULL; process_read_maps (process); map = real_locate_map (process, addr); if (!map) { process->bad_pages = g_list_prepend (process->bad_pages, page_addr); return NULL; } } if (!map->prepared) prepare_map (map); return map;}Symbol *process_locate_symbol (MPProcess *process, guint addr){ Symbol *data; Map *map; guint first, middle, last; map = locate_map (process, addr); if (!map) return NULL; if (!map->symbols || (map->symbols->len == 0)) return NULL; if (map->do_offset) addr -= map->addr; first = 0; last = map->symbols->len - 1; middle = last; data = (Symbol *)map->symbols->data; if (addr < data[last].addr) { /* Invariant: data[first].addr <= val < data[last].addr */ while (first < last - 1) { middle = (first + last) / 2; if (addr < data[middle].addr) last = middle; else first = middle; } /* Size is not included in generic bfd data, so we * ignore it for now. (It is ELF specific) */ return &data[first];#if 0 if (addr < data[first].addr + data[first].size) return &data[first]; else return NULL;#endif } else { return &data[last];#if 0 if (addr < data[last].addr + data[last].size) return &data[last]; else return NULL;#endif }}gboolean process_find_line (MPProcess *process, void *address, const char **filename, char **functionname, unsigned int *line){ Map *map = locate_map (process, (guint)address); if (map) { bfd_vma addr = (bfd_vma)address; if (map->do_offset) addr -= map->addr; return find_line (map, addr, filename, functionname, line); } else return FALSE;}voidprocess_dump_stack (MPProcess *process, FILE *out, StackElement *stack){ for (; !STACK_ELEMENT_IS_ROOT (stack); stack = stack->parent) { const char *filename; char *functionname; unsigned int line; if (process_find_line (process, stack->address, &filename, &functionname, &line)) { if (filename) fprintf(out, "\t%s(): %s:%u\n", functionname, filename, line); else fprintf(out, "\t%s()\n", functionname); free (functionname); } else fprintf(out, "\t[%p]\n", stack->address); }}void process_sections (MPProcess *process, SectionFunc func, gpointer user_data){ GList *tmp_list; process_read_maps (process); tmp_list = process->map_list; while (tmp_list) { Map *map = tmp_list->data; if (!map->prepared) prepare_map (map); process_map_sections (map, func, user_data); tmp_list = tmp_list->next; }}/************************************************************ * Communication with subprocess ************************************************************/static voidprocess_free_block (gpointer key, gpointer value, gpointer data){ block_unref (value);}static voidprocess_duplicate_block (gpointer key, gpointer value, gpointer data){ GHashTable *new_table = data; Block *block = value; block->refcount++; g_hash_table_insert (new_table, key, value);}MPProcess *process_duplicate (MPProcess *process){ MPProcess *new_process = process_new (process->server); g_hash_table_foreach (process->block_table, process_duplicate_block, new_process->block_table); new_process->bytes_used = process->bytes_used; new_process->n_allocations = process->n_allocations; new_process->seqno = process->seqno; new_process->parent = process; return new_process;}static voidprocess_reinit (MPProcess *process){ process_stop_input (process); if (process->input_channel) { g_io_channel_unref (process->input_channel); process->input_channel = NULL; } process->bytes_used = 0; process->n_allocations = 0; process->seqno = 0; if (process->map_list) { g_list_foreach (process->map_list, (GFunc)g_free, NULL); g_list_free (process->map_list); process->map_list = NULL; } if (process->bad_pages) { g_list_free (process->bad_pages); process->bad_pages = NULL; } if (process->block_table) { g_hash_table_foreach (process->block_table, process_free_block, NULL); g_hash_table_destroy (process->block_table); process->block_table = NULL; } if (process->stack_stash) { stack_stash_free (process->stack_stash); process->stack_stash = NULL; } /* FIXME: leak */ process->command_queue = NULL;}static GHashTable *get_block_table (MPProcess *process){ if (!process->block_table) process->block_table = g_hash_table_new (g_direct_hash, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -