nextstep-nat-watchpoint.c [plain text]
#include "nextstep-nat-dyld.h"
#include "nextstep-nat-inferior.h"
#include "nextstep-nat-mutils.h"
#include "nextstep-nat-sigthread.h"
#include "nextstep-nat-threads.h"
#include "nextstep-xdep.h"
#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"
extern next_inferior_status *next_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 void
retire_memory_page_dictionary (void)
{
memory_page_dictionary.page_count = (LONGEST) - 1;
}
static int
write_protect_page (int pid, CORE_ADDR page_start)
{
vm_address_t r_start;
vm_size_t r_size;
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;
kret = vm_region (next_status->task, &r_start, &r_size,
VM_REGION_BASIC_INFO, (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 = vm_protect (next_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 = vm_protect (next_status->task, page_start, 4096, 0, original_permissions);
}
void
next_mach_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
next_mach_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;
}
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;
}
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
next_mach_can_use_hw_watchpoint (enum bptype type, int cnt, enum bptype ot)
{
return (type == bp_hardware_watchpoint);
}
int
next_mach_range_profitable_for_hw_watchpoint (int pid, CORE_ADDR start, LONGEST len)
{
#if 0
int range_is_stack_based;
int range_is_accessible;
CORE_ADDR page_start;
int page_size;
int page;
LONGEST range_size_in_pages;
range_is_stack_based = 0;
range_is_accessible = 1;
errno = 0;
page_size = sysconf (_SC_PAGE_SIZE);
if (errno || (page_size <= 0))
{
errno = 0;
return 0;
}
page_start = (start / page_size) * page_size;
range_size_in_pages = len / (LONGEST) page_size;
for (page = 0; page < range_size_in_pages; page++, page_start += page_size)
{
int tt_status;
int page_permissions;
errno = 0;
tt_status = call_ttrace (TT_PROC_GET_MPROTECT,
pid,
(TTRACE_ARG_TYPE) page_start,
TT_NIL,
(TTRACE_ARG_TYPE) & page_permissions);
if (errno || (tt_status < 0))
{
errno = 0;
range_is_accessible = 0;
break;
}
}
return (!range_is_stack_based && range_is_accessible);
#endif
return 1;
}
static int
get_dictionary_bucket_of_page (CORE_ADDR page_start)
{
int 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 next_mach_insert_watchpoint (CORE_ADDR addr, size_t len, int type)
{
return hppa_insert_hw_watchpoint (PIDGET (inferior_ptid), addr, len, type);
}
int next_mach_remove_watchpoint (CORE_ADDR addr, size_t len, int type)
{
return hppa_remove_hw_watchpoint (PIDGET (inferior_ptid), addr, len, type);
}
int next_mach_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_nextstep_nat_watchpoint (void)
{
memory_page_dictionary.page_count = (LONGEST) - 1;
memory_page_dictionary.page_protections_allowed = 1;
}