char * filename;
gulong start;
gulong end;
+ gulong offset;
gboolean do_offset;
BinFile * bin_file;
int count;
guint start;
guint end;
+ guint offset;
count = sscanf (
- buffer, "%x-%x %*15s %*x %*u:%*u %*u %255s", &start, &end, file);
- if (count == 3)
+ buffer, "%x-%x %*15s %x %*u:%*u %*u %255s",
+ &start, &end, &offset, file);
+ if (count == 4)
{
Map *map;
map->start = start;
map->end = end;
- map->do_offset = check_do_offset (map, pid);
+ map->offset = offset; //check_do_offset (map, pid);
map->bin_file = NULL;
static Symbol undefined;
const Symbol *result;
Map *map = process_locate_map (process, address);
+
+/* g_print ("addr: %x\n", address); */
if (!map)
{
return &undefined;
}
- /* if (map->do_offset)
- address -= map->start;
- */
+/* if (map->do_offset) */
+/* address -= map->start; */
+
+ address -= map->start;
+ address += map->offset;
if (!map->bin_file)
map->bin_file = bin_file_new (map->filename);
/* FIXME - this seems to work with prelinked binaries, but is
* it correct? IE., will normal binaries always have a preferred_addres of 0?
*/
- address -= map->start;
- address += bin_file_get_load_address (map->bin_file);
+/* address = address - map->start + map->offset + bin_file_get_load_address (map->bin_file); */
+/* address -= map->start; */
+/* address += map->offset; */
+/* address += bin_file_get_load_address (map->bin_file); */
+
+/* g_print ("%s: start: %p, load: %p\n", */
+/* map->filename, map->start, bin_file_get_load_address (map->bin_file)); */
result = bin_file_lookup_symbol (map->bin_file, address);
+
+/* g_print ("(%x) %x %x name; %s\n", address, map->start, map->offset, result->name); */
+
return result;
}
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/poll.h>
+#include <asm/unistd.h>
+#include <linux/pagemap.h>
#include "sysprof-module.h"
#define SAMPLES_PER_SECOND 50 /* must divide HZ */
-static const int cpu_profiler = 1; /* 0: page faults, 1: cpu */
+static const int cpu_profiler = 0; /* 0: page faults, 1: cpu */
static void on_timer_interrupt (void *);
trace->truncated = 0;
}
+static int
+disk_access (struct vm_area_struct *area,
+ unsigned long address)
+{
+ struct file *file = area->vm_file;
+ struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
+ struct inode *inode = mapping->host;
+ struct page *page, **hash;
+ unsigned long size, pgoff, endoff;
+ int disk_access = 1;
+
+ pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+ endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+
+ /*
+ * An external ptracer can access pages that normally aren't
+ * accessible..
+ */
+ size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if ((pgoff >= size) && (area->vm_mm == current->mm))
+ return 0;
+
+ /* The "size" of the file, as far as mmap is concerned, isn't bigger than the mapping */
+ if (size > endoff)
+ size = endoff;
+
+ /*
+ * Do we have something in the page cache already?
+ */
+ hash = page_hash(mapping, pgoff);
+
+ page = __find_get_page(mapping, pgoff, hash);
+ if (page)
+ /*
+ * Ok, found a page in the page cache, now we need to check
+ * that it's up-to-date.
+ */
+ if (Page_Uptodate(page))
+ disk_access = 0;
+
+ return disk_access;
+}
+
struct page *
hijacked_nopage (struct vm_area_struct * area,
unsigned long address,
int unused)
{
- if (current && current->pid != 0)
+ struct page *result;
+ int disk;
+
+ disk = disk_access (area, address);
+
+ printk (KERN_ALERT "disk access: %d\n", disk);
+
+ result = filemap_nopage (area, address, unused);
+
+ if (current && current->pid != 0 && disk)
{
-#if 0
generate_stack_trace (current, head);
- if (head++ == &stack_traces[N_TRACES - 1])
- head = &stack_traces[0];
- wake_up (&wait_for_trace);
-#endif
- memset (head, 0, sizeof (SysprofStackTrace));
-
- head->n_addresses = 1;
- head->pid = current->pid;
- head->addresses[0] = (void *)address;
- head->truncated = 0;
+/* head->pid = current->pid; */
+/* head->addresses[0] = (void *)address; */
+/* head->truncated = 0; */
if (area->vm_file)
{
wake_up (&wait_for_trace);
}
-
- return filemap_nopage (area, address, unused);
+
+ return result;
+}
+
+static void
+hijack_nopage (struct vm_area_struct *vma)
+{
+ if (vma->vm_ops && vma->vm_ops->nopage == filemap_nopage)
+ vma->vm_ops->nopage = hijacked_nopage;
}
static void
return;
for (vma = mm->mmap; vma != NULL; vma = vma->vm_next)
- {
- if (vma->vm_ops && vma->vm_ops->nopage == filemap_nopage)
- vma->vm_ops->nopage = hijacked_nopage;
- }
+ hijack_nopage (vma);
}
static void
}
}
+struct mmap_arg_struct {
+ unsigned long addr;
+ unsigned long len;
+ unsigned long prot;
+ unsigned long flags;
+ unsigned long fd;
+ unsigned long offset;
+};
+
+typedef asmlinkage int (* old_mmap_func) (struct mmap_arg_struct *arg);
+typedef asmlinkage long (* mmap2_func) (
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff);
+
+static mmap2_func orig_mmap2;
+static old_mmap_func orig_mmap;
+
+static void
+after_mmap (long res, unsigned long len)
+{
+ struct vm_area_struct *vma;
+ unsigned long start;
+
+ if (res == -1 || !current || current->pid == 0)
+ return;
+
+ start = res;
+
+ vma = find_vma (current->mm, start);
+
+ if (vma && vma->vm_end >= start + len)
+ hijack_nopage (vma);
+#if 0
+ else if (vma)
+ {
+ printk (KERN_ALERT "nope: vm_start: %x, vm_end: %x\n"
+ "start: %p, len: %x, start + len: %x\n",
+ vma->vm_start, vma->vm_end, start, len, start + len);
+ }
+ else
+ printk (KERN_ALERT "no vma\n");
+#endif
+
+}
+
+static long
+new_mmap2 (unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ int res = orig_mmap2 (addr, len, prot, flags, fd, pgoff);
+
+ after_mmap (res, len);
+
+ return res;
+}
+
+static int
+new_mmap (struct mmap_arg_struct *arg)
+{
+ int res = orig_mmap (arg);
+
+ after_mmap (res, arg->len);
+
+ return res;
+}
+
+void **sys_call_table = (void **)0xc0347df0;
+
+static void
+hijack_mmaps (void)
+{
+ orig_mmap2 = sys_call_table[__NR_mmap2];
+ sys_call_table[__NR_mmap2] = new_mmap2;
+
+ orig_mmap = sys_call_table[__NR_mmap];
+ sys_call_table[__NR_mmap] = new_mmap;
+}
+
+static void
+restore_mmaps (void)
+{
+ sys_call_table[__NR_mmap2] = orig_mmap2;
+ sys_call_table[__NR_mmap] = orig_mmap;
+}
+
static void
on_timer_interrupt (void *data)
{
if (exiting)
{
- clean_hijacked_nopages ();
+ if (!cpu_profiler)
+ {
+ restore_mmaps();
+
+ clean_hijacked_nopages ();
+ }
wake_up (&wait_for_exit);
return;
}
}
else
{
+#if 0
hijack_nopages (current);
+#endif
}
}
int
init_module (void)
{
+ struct task_struct *task;
trace_proc_file =
create_proc_entry ("sysprof-trace", S_IFREG | S_IRUGO, &proc_root);
trace_proc_file->read_proc = procfile_read;
trace_proc_file->proc_fops->poll = procfile_poll;
trace_proc_file->size = sizeof (SysprofStackTrace);
+
+ if (!cpu_profiler)
+ {
+ hijack_mmaps ();
+
+ for_each_process (task)
+ {
+ hijack_nopages (task);
+ }
+ }
queue_task(&timer_task, &tq_timer);