summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-05-07 15:08:26 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2021-05-07 15:08:26 -0400
commit62f5fd4c9c561730bc6da0e9812da524c45462b1 (patch)
tree9ef43798178dc9110e7a1511cd1b3ef369a18f47
parent52c6df092091a3ec989607476c408cd343c549e1 (diff)
fixed enter-a-value search for >1-byte types; simplified code
-rw-r--r--base.h3
-rw-r--r--data.c24
-rw-r--r--main.c193
-rw-r--r--ui.glade6
4 files changed, 128 insertions, 98 deletions
diff --git a/base.h b/base.h
index 51274de..0884bc7 100644
--- a/base.h
+++ b/base.h
@@ -11,6 +11,7 @@
#include <assert.h>
#include <ctype.h>
#include <wctype.h>
+#include <math.h>
typedef pid_t PID;
typedef uint64_t Address;
@@ -55,7 +56,7 @@ typedef struct {
Address total_memory; // total amount of memory used by process, in bytes
Map *maps;
Address memory_view_address;
- uint32_t memory_view_items; // # of entries to show
+ unsigned memory_view_n_items; // # of entries to show
unsigned nmaps;
DataType data_type;
SearchType search_type;
diff --git a/data.c b/data.c
index 6434b4e..809b103 100644
--- a/data.c
+++ b/data.c
@@ -162,6 +162,28 @@ static bool data_from_str(char const *str, DataType type, void *value) {
return false;
}
+// returns whether or not the values are equal, or in the case of floating-point numbers,
+// approximately equal
static bool data_equal(DataType type, void const *a, void const *b) {
- return memcmp(a, b, data_type_size(type)) == 0;
+ double af, bf;
+ switch (type) {
+ case TYPE_F32:
+ af = *(float *)a, bf = *(float *)b;
+ goto floats;
+ case TYPE_F64:
+ af = *(double *)a, bf = *(double *)b;
+ goto floats;
+ floats: {
+ if (isinf(af) || isinf(bf) || isnan(af) || isnan(bf))
+ return false;
+ // special handling for small numbers
+ if (fabs(af) < 0.1 && fabs(bf) < 0.1)
+ return true;
+ double ab = af / bf;
+ double threshold = 1.1; // allow a 10% difference.
+ return ab >= (1/threshold) && ab <= threshold;
+ } break;
+ default:
+ return memcmp(a, b, data_type_size(type)) == 0;
+ }
}
diff --git a/main.c b/main.c
index 0993dea..2b93c9e 100644
--- a/main.c
+++ b/main.c
@@ -1,3 +1,7 @@
+// @TODO:
+// - set all candidates to value
+// - same/different search
+// - configure which memory to look at (see "rw-p")
#include "base.h"
#include "unicode.h"
#include "data.c"
@@ -13,57 +17,33 @@ static SearchType search_type_from_str(char const *str) {
return 0xff;
}
-static void update_memory_view(State *state) {
- if (!state->pid)
- return;
+static void update_memory_view(State *state, bool addresses_need_updating) {
GtkBuilder *builder = state->builder;
GtkListStore *store = GTK_LIST_STORE(gtk_builder_get_object(builder, "memory"));
GtkTreeModel *tree_model = GTK_TREE_MODEL(store);
- uint32_t ndisplay = state->memory_view_items;
- if (ndisplay == 0 || !state->nmaps) {
+ DataType data_type = state->data_type;
+ size_t item_size = data_type_size(data_type);
+
+ if (!state->pid) {
gtk_list_store_clear(store);
return;
}
- DataType data_type = state->data_type;
- size_t item_size = data_type_size(data_type);
- void *mem = calloc(item_size, ndisplay);
- GtkTreeIter iter;
- bool updating = // are we updating rows in the list store? (rather than adding new ones)
- gtk_tree_model_get_iter_from_string(tree_model, &iter, "0");
- if (mem) {
- if (!state->search_candidates || state->memory_view_address) {
- Address base_addr = state->memory_view_address ? state->memory_view_address : state->maps[0].lo;
- int reader = memory_reader_open(state);
- if (reader) {
- memory_read_bytes(reader, base_addr, mem, ndisplay * item_size);
- char *value = mem;
- Address addr = base_addr;
- for (uint32_t i = 0; i < ndisplay; i += 1, addr += item_size, value += item_size) {
- char index_str[32], addr_str[32], value_str[32];
- sprintf(index_str, "%" PRIu32, i);
- sprintf(addr_str, "%" PRIxADDR, addr);
- data_to_str(value, data_type, value_str, sizeof value_str);
- if (i != (Address)state->editing_memory) {
- if (updating)
- gtk_list_store_set(store, &iter, 0, index_str, 1, addr_str, 2, value_str, -1);
- else
- gtk_list_store_insert_with_values(store, &iter, -1, 0, index_str, 1, addr_str, 2, value_str, -1);
- }
- if (updating)
- updating = gtk_tree_model_iter_next(tree_model, &iter);
- }
- memory_reader_close(state, reader);
- }
- } else {
- int reader = memory_reader_open(state);
- if (reader) {
+
+ if (addresses_need_updating) {
+ gtk_list_store_clear(store);
+ if (state->pid) {
+ uint64_t *search_candidates = state->search_candidates;
+ Address address = state->memory_view_address;
+ bool show_candidates = search_candidates && !address;
+ unsigned n_items = state->memory_view_n_items;
+ if (show_candidates) {
+ // show the search candidates
uint32_t candidate_idx = 0;
- // show search candidates
uint64_t *candidates = state->search_candidates;
Address bitset_index = 0;
for (unsigned m = 0; m < state->nmaps; ++m) {
Map *map = &state->maps[m];
- for (Address i = 0; i < map->size; ) {
+ for (Address i = 0; i < map->size / item_size; ) {
if (i % 64 == 0 && candidates[bitset_index / 64] == 0) {
// this stretch of 64 has no candidates.
i += 64;
@@ -72,44 +52,59 @@ static void update_memory_view(State *state) {
if (candidates[bitset_index / 64] & MASK64(bitset_index % 64)) {
// a candidate!
Address addr = map->lo + i * item_size;
- uint64_t value = 0;
- char index_str[32], addr_str[32], value_str[32];
- sprintf(index_str, "%u", candidate_idx);
+ char idx_str[32], addr_str[32];
+ sprintf(idx_str, "%u", candidate_idx);
sprintf(addr_str, "%" PRIxADDR, addr);
- size_t nread = memory_read_bytes(reader, addr, (uint8_t *)&value, item_size);
- if (nread == item_size) {
- data_to_str(&value, data_type, value_str, sizeof value_str);
- } else {
- strcpy(value_str, "N/A");
- }
- if (i != (Address)state->editing_memory) {
- if (updating) {
- gtk_list_store_set(store, &iter, 0, index_str, 1, addr_str, 2, value_str, -1);
- } else {
- gtk_list_store_insert_with_values(store, &iter, -1, 0, index_str, 1, addr_str, 2, value_str, -1);
- }
- }
- if (updating)
- updating = gtk_tree_model_iter_next(tree_model, &iter);
+ gtk_list_store_insert_with_values(store, NULL, -1, 0, idx_str, 1, addr_str, 2, "", -1);
++candidate_idx;
- if (candidate_idx >= ndisplay) goto done;
+ if (candidate_idx >= n_items) goto done;
}
++i;
++bitset_index;
}
}
}
- done:
- memory_reader_close(state, reader);
+ done:;
+ } else {
+ if (address) {
+ // show `n_items` items starting from `address`
+ for (unsigned i = 0; i < n_items; ++i) {
+ char idx_str[32], addr_str[32];
+ Address addr = address + i * item_size;
+ sprintf(idx_str, "%u", i);
+ sprintf(addr_str, "%" PRIxADDR, addr);
+ gtk_list_store_insert_with_values(store, NULL, -1, 0, idx_str, 1, addr_str, 2, "", -1);
+ }
+ }
}
}
- if (updating) {
- // delete any extra rows
- while (gtk_list_store_remove(store, &iter));
+ }
+
+ GtkTreeIter iter;
+ if (gtk_tree_model_get_iter_first(tree_model, &iter)) {
+ int reader = memory_reader_open(state);
+ if (reader) {
+ int i = 0;
+ do {
+ if (i != state->editing_memory) {
+ gchararray addr_str = NULL;
+ gtk_tree_model_get(tree_model, &iter, 1, &addr_str, -1);
+ Address addr = 0;
+ sscanf(addr_str, "%" SCNxADDR, &addr);
+ g_free(addr_str);
+ uint64_t value = 0;
+ size_t nread = memory_read_bytes(reader, addr, (uint8_t *)&value, item_size);
+ char value_str[32];
+ if (nread == item_size)
+ data_to_str(&value, data_type, value_str, sizeof value_str);
+ else
+ strcpy(value_str, "N/A");
+ gtk_list_store_set(store, &iter, 2, value_str, -1);
+ }
+ ++i;
+ } while (gtk_tree_model_iter_next(tree_model, &iter));
}
- free(mem);
- } else {
- display_error(state, "Out of memory (trying to display %" PRIu32 " bytes of memory).", ndisplay);
+ memory_reader_close(state, reader);
}
}
@@ -148,26 +143,16 @@ G_MODULE_EXPORT void update_configuration(GtkWidget *_widget, gpointer user_data
char const *n_items_text = gtk_entry_get_text(
GTK_ENTRY(gtk_builder_get_object(builder, "memory-n-items")));
char *endp;
- bool update_memview = false;
- unsigned long n_items = strtoul(n_items_text, &endp, 10);
- if (*n_items_text && !*endp && n_items != state->memory_view_items) {
- state->memory_view_items = (uint32_t)n_items;
- update_memview = true;
- }
+ unsigned n_items = (unsigned)strtoul(n_items_text, &endp, 10);
+ if (*endp || !*n_items_text) n_items = 0;
+ if (n_items >= 1000) n_items = 999;
char const *address_text = gtk_entry_get_text(
GTK_ENTRY(gtk_builder_get_object(builder, "address")));
unsigned long address = strtoul(address_text, &endp, 16);
- // if the box is empty, this will be interpreted as 0, which is what we want.
- if (!*endp && address != state->memory_view_address) {
- state->memory_view_address = address;
- update_memview = true;
- }
+ if (*endp || !*address_text) address = 0;
+
char const *data_type_str = radio_group_get_selected(state, "type-u8");
DataType data_type = data_type_from_name(data_type_str);
- if (state->data_type != data_type) {
- state->data_type = data_type;
- update_memview = true;
- }
// update memory/disk estimates for search
GtkLabel *memory_label = GTK_LABEL(gtk_builder_get_object(builder, "required-memory"));
@@ -206,8 +191,19 @@ G_MODULE_EXPORT void update_configuration(GtkWidget *_widget, gpointer user_data
gtk_label_set_text(disk_label, "N/A");
}
- if (update_memview) {
- update_memory_view(state);
+ static bool prev_candidates;
+ static PID prev_pid;
+
+ uint64_t *search_candidates = state->search_candidates;
+ if (n_items != state->memory_view_n_items || (!!search_candidates) != prev_candidates || address != state->memory_view_address || data_type != state->data_type || state->pid != prev_pid) {
+ // we need to update the addresses in the memory view.
+ prev_candidates = !!search_candidates;
+ state->memory_view_n_items = n_items;
+ state->memory_view_address = address;
+ state->data_type = data_type;
+ prev_pid = state->pid;
+
+ update_memory_view(state, true);
}
}
@@ -283,8 +279,15 @@ G_MODULE_EXPORT void select_pid(GtkButton *_button, gpointer user_data) {
state->pid = (PID)pid_number;
close(dir);
if (update_maps(state)) {
+ if (state->nmaps) {
+ GtkEntry *address_entry = GTK_ENTRY(gtk_builder_get_object(builder, "address"));
+ Address addr = state->maps[0].lo;
+ char addr_text[32];
+ sprintf(addr_text, "%" PRIxADDR, addr);
+ gtk_entry_set_text(address_entry, addr_text);
+ }
update_configuration(NULL, state); // we need to do this to update the search resource usage estimates, etc.
- update_memory_view(state);
+ update_memory_view(state, true);
// only allow searching once a process has been selected
gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "search-box")));
}
@@ -329,7 +332,7 @@ G_MODULE_EXPORT void memory_edited(GtkCellRendererText *_renderer, char *path, c
G_MODULE_EXPORT void refresh_memory(GtkWidget *_widget, gpointer user_data) {
State *state = user_data;
update_configuration(NULL, state); // just in case they changed the number of items or something
- update_memory_view(state);
+ update_memory_view(state, false);
}
G_MODULE_EXPORT void memory_editing_started(GtkCellRenderer *_renderer, GtkCellEditable *editable, char *path, gpointer user_data) {
@@ -366,16 +369,15 @@ G_MODULE_EXPORT void search_start(GtkWidget *_widget, gpointer user_data) {
SearchType search_type = state->search_type;
DataType data_type = state->data_type;
size_t item_size = data_type_size(data_type);
- gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "pre-search")));
- gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "data-type-box")), 0);
- gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "search-common")));
- gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "steps-completed")), "0");
- gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "address")), "");
- state->memory_view_address = 0;
// state->total_memory should always be a multiple of the page size, which is definitely a multiple of 64 * 8 = 512.
assert(state->total_memory % 512 == 0);
uint64_t *candidates = state->search_candidates = malloc(state->total_memory / (8 * item_size));
if (candidates) {
+ gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "pre-search")));
+ gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(builder, "data-type-box")), 0);
+ gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "search-common")));
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "steps-completed")), "0");
+ gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(builder, "address")), "");
memset(candidates, 0xff, state->total_memory / (8 * item_size));
switch (search_type) {
case SEARCH_ENTER_VALUE:
@@ -385,6 +387,7 @@ G_MODULE_EXPORT void search_start(GtkWidget *_widget, gpointer user_data) {
gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(builder, "search-same-different")));
break;
}
+ update_configuration(NULL, state);
update_candidates(state);
} else {
display_error_nofmt(state, "Not enough memory available for search.");
@@ -486,7 +489,7 @@ G_MODULE_EXPORT void search_update(GtkWidget *_widget, gpointer user_data) {
gtk_label_set_text(steps_completed_label, text);
}
update_candidates(state);
- update_memory_view(state);
+ update_memory_view(state, true);
}
gtk_widget_set_sensitive(search_box, 1);
@@ -510,7 +513,7 @@ static gboolean frame_callback(gpointer user_data) {
GtkBuilder *builder = state->builder;
GtkToggleButton *auto_refresh = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "auto-refresh"));
if (gtk_toggle_button_get_active(auto_refresh)) {
- update_memory_view(state);
+ update_memory_view(state, false);
}
return 1;
}
@@ -532,7 +535,7 @@ static void on_activate(GtkApplication *app, gpointer user_data) {
gtk_window_set_application(window, app);
update_configuration(NULL, state);
- g_timeout_add(16, frame_callback, state);
+ g_timeout_add(200, frame_callback, state);
gtk_widget_show_all(GTK_WIDGET(window));
}
diff --git a/ui.glade b/ui.glade
index af4befc..749954d 100644
--- a/ui.glade
+++ b/ui.glade
@@ -50,7 +50,7 @@
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="tooltip-text" translatable="yes">Display this many entries in the memory view</property>
- <property name="max-length">6</property>
+ <property name="max-length">3</property>
<property name="text" translatable="yes">100</property>
<property name="input-purpose">number</property>
<signal name="activate" handler="update_configuration" swapped="no"/>
@@ -159,6 +159,9 @@
<child>
<object class="GtkCellRendererText" id="col_address">
<property name="editable">True</property>
+ <signal name="edited" handler="memory_edited" swapped="no"/>
+ <signal name="editing-canceled" handler="memory_editing_canceled" swapped="no"/>
+ <signal name="editing-started" handler="memory_editing_started" swapped="no"/>
</object>
<attributes>
<attribute name="text">1</attribute>
@@ -707,6 +710,7 @@
<object class="GtkEntry" id="current-value">
<property name="visible">True</property>
<property name="can-focus">True</property>
+ <property name="tooltip-text" translatable="yes">The current value in memory. For floating-point numbers, you don't need to get all the decimals, as long as you're within 10% of the actual value, you'll be fine.</property>
<signal name="activate" handler="search_update" swapped="no"/>
</object>
<packing>