macosx-nat-watchpoint.c [plain text]
#include "defs.h"
#include "inferior.h"
#include "target.h"
#include "symfile.h"
#include "symtab.h"
#include "objfiles.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdbthread.h"
#include "macosx-nat-watchpoint.h"
#include "macosx-nat-dyld.h"
#include "macosx-nat-inferior.h"
#include "macosx-nat-mutils.h"
#include "macosx-nat-sigthread.h"
#include "macosx-nat-threads.h"
#include "macosx-xdep.h"
#include <AvailabilityMacros.h>
#include <mach/mach_vm.h>
extern macosx_inferior_status *macosx_status;
typedef struct memory_page
{
CORE_ADDR page_start;
int reference_count;
int original_permissions;
struct memory_page *next;
struct memory_page *previous;
}
memory_page_t;
#define MEMORY_PAGE_DICTIONARY_BUCKET_COUNT 128
static struct
{
LONGEST page_count;
int page_size;
int page_protections_allowed;
memory_page_t buckets[MEMORY_PAGE_DICTIONARY_BUCKET_COUNT];
}
memory_page_dictionary;
static memory_page_t *get_dictionary_entry_of_page (int pid,
CORE_ADDR page_start);
static void remove_dictionary_entry_of_page (int pid, memory_page_t * page);
static void
require_memory_page_dictionary (void)
{
int i;
if (memory_page_dictionary.page_count >= (LONGEST) 0)
return;
memory_page_dictionary.page_count = (LONGEST) 0;
memory_page_dictionary.page_size = 4096;
for (i = 0; i < MEMORY_PAGE_DICTIONARY_BUCKET_COUNT; i++)
{
memory_page_dictionary.buckets[i].page_start = (CORE_ADDR) 0;
memory_page_dictionary.buckets[i].reference_count = 0;
memory_page_dictionary.buckets[i].next = NULL;
memory_page_dictionary.buckets[i].previous = NULL;
}
}
static int
write_protect_page (int pid, CORE_ADDR page_start)
{
mach_vm_address_t r_start;
mach_vm_size_t r_size;
mach_port_t r_object_name;
vm_region_basic_info_data_t r_data;
mach_msg_type_number_t r_info_size;
kern_return_t kret;
r_start = page_start;
r_info_size = VM_REGION_BASIC_INFO_COUNT_64;
kret = mach_vm_region (macosx_status->task, &r_start, &r_size,
VM_REGION_BASIC_INFO_64,
(vm_region_info_t) & r_data, &r_info_size,
&r_object_name);
if (kret != KERN_SUCCESS)
return -1;
if (r_start != page_start)
return -1;
if (memory_page_dictionary.page_protections_allowed)
{
kret =
mach_vm_protect (macosx_status->task, r_start, 4096, 0,
r_data.protection & ~VM_PROT_WRITE);
if (kret != KERN_SUCCESS)
return -1;
}
return r_data.protection;
}
static void
unwrite_protect_page (int pid, CORE_ADDR page_start, int original_permissions)
{
kern_return_t kret;
kret =
mach_vm_protect (macosx_status->task, page_start, 4096, 0,
original_permissions);
}
void
macosx_enable_page_protection_events (int pid)
{
int bucket;
memory_page_dictionary.page_protections_allowed = 1;
for (bucket = 0; bucket < MEMORY_PAGE_DICTIONARY_BUCKET_COUNT; bucket++)
{
memory_page_t *page;
page = memory_page_dictionary.buckets[bucket].next;
while (page != NULL)
{
page->original_permissions =
write_protect_page (pid, page->page_start);
page = page->next;
}
}
}
void
macosx_disable_page_protection_events (int pid)
{
int bucket;
for (bucket = 0; bucket < MEMORY_PAGE_DICTIONARY_BUCKET_COUNT; bucket++)
{
memory_page_t *page;
page = memory_page_dictionary.buckets[bucket].next;
while (page != NULL)
{
unwrite_protect_page (pid, page->page_start,
page->original_permissions);
page = page->next;
}
}
memory_page_dictionary.page_protections_allowed = 0;
}
static int
hppa_insert_hw_watchpoint (int pid, CORE_ADDR start, LONGEST len, int type)
{
CORE_ADDR page_start;
int dictionary_was_empty;
int page_size;
int page_id;
LONGEST range_size_in_pages;
if (type != 0)
error ("read or access hardware watchpoints not supported on HP-UX");
require_memory_page_dictionary ();
dictionary_was_empty = (memory_page_dictionary.page_count == (LONGEST) 0);
page_size = memory_page_dictionary.page_size;
page_start = (start / page_size) * page_size;
range_size_in_pages =
((LONGEST) len + (LONGEST) page_size - 1) / (LONGEST) page_size;
for (page_id = 0; page_id < range_size_in_pages;
page_id++, page_start += page_size)
{
memory_page_t *page;
page = get_dictionary_entry_of_page (pid, page_start);
page->reference_count++;
}
#if 0
if (dictionary_was_empty)
hppa_enable_syscall_events (pid);
#endif
return 1;
}
static int
hppa_remove_hw_watchpoint (int pid, CORE_ADDR start, LONGEST len,
enum bptype type)
{
CORE_ADDR page_start;
int dictionary_is_empty;
int page_size;
int page_id;
LONGEST range_size_in_pages;
if (type != 0)
error ("read or access hardware watchpoints not supported on HP-UX");
require_memory_page_dictionary ();
page_size = memory_page_dictionary.page_size;
page_start = (start / page_size) * page_size;
range_size_in_pages =
((LONGEST) len + (LONGEST) page_size - 1) / (LONGEST) page_size;
for (page_id = 0; page_id < range_size_in_pages;
page_id++, page_start += page_size)
{
memory_page_t *page;
page = get_dictionary_entry_of_page (pid, page_start);
page->reference_count--;
if (page->reference_count == 0)
remove_dictionary_entry_of_page (pid, page);
}
dictionary_is_empty = (memory_page_dictionary.page_count == (LONGEST) 0);
#if 0
if (dictionary_is_empty && memory_page_dictionary.page_protections_allowed)
hppa_disable_syscall_events (pid);
#endif
return 1;
}
int
macosx_can_use_hw_watchpoint (int type, int cnt, int ot)
{
return (type == bp_hardware_watchpoint);
}
int
macosx_region_ok_for_hw_watchpoint (CORE_ADDR start, LONGEST len)
{
return 1;
}
static int
get_dictionary_bucket_of_page (CORE_ADDR page_start)
{
CORE_ADDR hash;
hash = (page_start / memory_page_dictionary.page_size);
hash = hash % MEMORY_PAGE_DICTIONARY_BUCKET_COUNT;
return hash;
}
static memory_page_t *
get_dictionary_entry_of_page (int pid, CORE_ADDR page_start)
{
int bucket;
memory_page_t *page = NULL;
memory_page_t *previous_page = NULL;
require_memory_page_dictionary ();
bucket = get_dictionary_bucket_of_page (page_start);
page = &memory_page_dictionary.buckets[bucket];
while (page != NULL)
{
if (page->page_start == page_start)
break;
previous_page = page;
page = page->next;
}
if (page == NULL)
{
page = (memory_page_t *) xmalloc (sizeof (memory_page_t));
page->page_start = page_start;
page->reference_count = 0;
page->next = NULL;
page->previous = NULL;
page->original_permissions = write_protect_page (pid, page_start);
page->previous = previous_page;
previous_page->next = page;
memory_page_dictionary.page_count++;
}
return page;
}
static void
remove_dictionary_entry_of_page (int pid, memory_page_t * page)
{
unwrite_protect_page (pid, page->page_start, page->original_permissions);
if (page->previous != NULL)
page->previous->next = page->next;
if (page->next != NULL)
page->next->previous = page->previous;
page->page_start = (CORE_ADDR) 0;
memory_page_dictionary.page_count--;
xfree (page);
}
int
macosx_insert_watchpoint (CORE_ADDR addr, size_t len, int type)
{
return hppa_insert_hw_watchpoint (PIDGET (inferior_ptid), addr, len, type);
}
int
macosx_remove_watchpoint (CORE_ADDR addr, size_t len, int type)
{
return hppa_remove_hw_watchpoint (PIDGET (inferior_ptid), addr, len, type);
}
int macosx_stopped_by_watchpoint
(struct target_waitstatus *w, int stop_signal,
int stepped_after_stopped_by_watchpoint)
{
return
((w->kind == TARGET_WAITKIND_STOPPED)
&& (stop_signal == TARGET_EXC_BAD_ACCESS)
&& (!stepped_after_stopped_by_watchpoint)
&& bpstat_have_active_hw_watchpoints ());
}
void
_initialize_macosx_nat_watchpoint (void)
{
memory_page_dictionary.page_count = (LONGEST) - 1;
memory_page_dictionary.page_protections_allowed = 1;
}