00001
00020 #include "opd_anon.h"
00021 #include "opd_trans.h"
00022 #include "opd_sfile.h"
00023 #include "opd_printf.h"
00024 #include "op_libiberty.h"
00025
00026 #include <limits.h>
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <string.h>
00030
00031 #define HASH_SIZE 1024
00032 #define HASH_BITS (HASH_SIZE - 1)
00033
00034
00035
00036
00037
00038
00039
00040 #define LRU_SIZE 8192
00041 #define LRU_AMOUNT (LRU_SIZE/8)
00042
00043 static struct list_head hashes[HASH_SIZE];
00044 static struct list_head lru;
00045 static size_t nr_lru;
00046
00047 static void do_lru(struct transient * trans)
00048 {
00049 size_t nr_to_kill = LRU_AMOUNT;
00050 struct list_head * pos;
00051 struct list_head * pos2;
00052 struct anon_mapping * entry;
00053
00054 list_for_each_safe(pos, pos2, &lru) {
00055 entry = list_entry(pos, struct anon_mapping, lru_list);
00056 if (trans->anon == entry)
00057 clear_trans_current(trans);
00058 if (trans->last_anon == entry)
00059 clear_trans_last(trans);
00060 sfile_clear_anon(entry);
00061 list_del(&entry->list);
00062 list_del(&entry->lru_list);
00063 --nr_lru;
00064 free(entry);
00065 if (nr_to_kill-- == 0)
00066 break;
00067 }
00068 }
00069
00070
00071 static unsigned long hash_anon(pid_t tgid, cookie_t app)
00072 {
00073 return ((app >> DCOOKIE_SHIFT) ^ (tgid >> 2)) & (HASH_SIZE - 1);
00074 }
00075
00076
00077 static void clear_anon_maps(struct transient * trans)
00078 {
00079 unsigned long hash = hash_anon(trans->tgid, trans->app_cookie);
00080 pid_t tgid = trans->tgid;
00081 cookie_t app = trans->app_cookie;
00082 struct list_head * pos;
00083 struct list_head * pos2;
00084 struct anon_mapping * entry;
00085
00086 clear_trans_current(trans);
00087
00088 list_for_each_safe(pos, pos2, &hashes[hash]) {
00089 entry = list_entry(pos, struct anon_mapping, list);
00090 if (entry->tgid == tgid && entry->app_cookie == app) {
00091 if (trans->last_anon == entry)
00092 clear_trans_last(trans);
00093 sfile_clear_anon(entry);
00094 list_del(&entry->list);
00095 list_del(&entry->lru_list);
00096 --nr_lru;
00097 free(entry);
00098 }
00099 }
00100
00101 if (vmisc) {
00102 char const * name = verbose_cookie(app);
00103 printf("Cleared anon maps for tgid %u (%s).\n", tgid, name);
00104 }
00105 }
00106
00107
00108 static void
00109 add_anon_mapping(struct transient * trans, vma_t start, vma_t end, char * name)
00110 {
00111 unsigned long hash = hash_anon(trans->tgid, trans->app_cookie);
00112 struct anon_mapping * m = xmalloc(sizeof(struct anon_mapping));
00113 m->tgid = trans->tgid;
00114 m->app_cookie = trans->app_cookie;
00115 m->start = start;
00116 m->end = end;
00117 strncpy(m->name, name, MAX_IMAGE_NAME_SIZE + 1);
00118 list_add_tail(&m->list, &hashes[hash]);
00119 list_add_tail(&m->lru_list, &lru);
00120 if (++nr_lru == LRU_SIZE)
00121 do_lru(trans);
00122 if (vmisc) {
00123 char const * name = verbose_cookie(m->app_cookie);
00124 printf("Added anon map 0x%llx-0x%llx for tgid %u (%s).\n",
00125 start, end, m->tgid, name);
00126 }
00127 }
00128
00129
00130
00131 static void get_anon_maps(struct transient * trans)
00132 {
00133 FILE * fp = NULL;
00134 char buf[PATH_MAX];
00135 vma_t start, end;
00136 int ret;
00137
00138 snprintf(buf, PATH_MAX, "/proc/%d/maps", trans->tgid);
00139 fp = fopen(buf, "r");
00140 if (!fp)
00141 return;
00142
00143 while (fgets(buf, PATH_MAX, fp) != NULL) {
00144 char tmp[MAX_IMAGE_NAME_SIZE + 1];
00145 char name[MAX_IMAGE_NAME_SIZE + 1];
00146
00147
00148
00149
00150
00151 strcpy(name, "anon");
00152 ret = sscanf(buf, "%llx-%llx %20s %20s %20s %20s %20s",
00153 &start, &end, tmp, tmp, tmp, tmp, name);
00154 if (ret < 6 || name[0] == '/')
00155 continue;
00156
00157 add_anon_mapping(trans, start, end, name);
00158 }
00159
00160 fclose(fp);
00161 }
00162
00163
00164 static int
00165 anon_match(struct transient const * trans, struct anon_mapping const * anon)
00166 {
00167 if (!anon)
00168 return 0;
00169 if (trans->tgid != anon->tgid)
00170 return 0;
00171 if (trans->app_cookie != anon->app_cookie)
00172 return 0;
00173 if (trans->pc < anon->start)
00174 return 0;
00175 return (trans->pc < anon->end);
00176 }
00177
00178
00179 struct anon_mapping * find_anon_mapping(struct transient * trans)
00180 {
00181 unsigned long hash = hash_anon(trans->tgid, trans->app_cookie);
00182 struct list_head * pos;
00183 struct anon_mapping * entry;
00184 int tried = 0;
00185
00186 if (anon_match(trans, trans->anon))
00187 return (trans->anon);
00188
00189 retry:
00190 list_for_each(pos, &hashes[hash]) {
00191 entry = list_entry(pos, struct anon_mapping, list);
00192 if (anon_match(trans, entry))
00193 goto success;
00194 }
00195
00196 if (!tried) {
00197 clear_anon_maps(trans);
00198 get_anon_maps(trans);
00199 tried = 1;
00200 goto retry;
00201 }
00202
00203 return NULL;
00204
00205 success:
00206
00207
00208
00209
00210 list_del(&entry->list);
00211 list_add(&entry->list, &hashes[hash]);
00212
00213 verbprintf(vmisc, "Found range 0x%llx-0x%llx for tgid %u, pc %llx.\n",
00214 entry->start, entry->end, (unsigned int)entry->tgid,
00215 trans->pc);
00216 return entry;
00217 }
00218
00219
00220 void anon_init(void)
00221 {
00222 size_t i;
00223
00224 for (i = 0; i < HASH_SIZE; ++i)
00225 list_init(&hashes[i]);
00226
00227 list_init(&lru);
00228 }