1/** 2 * \file 3 * \brief functionality to spawn domains 4 */ 5 6/* 7 * Copyright (c) 2014 ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdio.h> 16#include <string.h> 17 18#include <barrelfish/barrelfish.h> 19#include <barrelfish/dispatch.h> // for disp_name() 20#include <spawndomain/spawndomain.h> 21 22#include <if/octopus_defs.h> 23#include <if/octopus_defs.h> 24#include <if/monitor_defs.h> 25#include <octopus/getset.h> // for oct_read TODO 26#include <octopus/trigger.h> // for NOP_TRIGGER 27 28#include "spawn.h" 29 30struct symval { 31 char *name; 32 genvaddr_t addr; 33}; 34 35uint32_t symval_count; 36 37struct symval *symvals; 38 39/** 40 * \brief obtains the number of OpenMP symbols of the ELF file 41 * 42 * \param ret_count returns the number of symbols 43 * 44 * \returns SYS_ERR_OK on success 45 * errval on failure 46 */ 47errval_t spawn_symval_count(uint32_t *ret_count) 48{ 49 if (!symvals) { 50 errval_t err; 51 52 err = spawn_symval_cache_init(1); 53 if (err_is_fail(err)) { 54 return err; 55 } 56 } 57 58 if (ret_count) { 59 *ret_count = symval_count; 60 } 61 return SYS_ERR_OK; 62} 63 64/** 65 * \brief initializes the symbol value cache for faster lookups 66 * 67 * \param lazy do a lazy initialization i.e. only allocate memory for the 68 * symbols but do not load them 69 * 70 * \returns SYS_ERR_OK on success 71 * errval on error 72 */ 73errval_t spawn_symval_cache_init(uint8_t lazy) 74{ 75 errval_t err; 76 77 genvaddr_t count = 0; 78 err = spawn_symval_lookup_idx(0, NULL, &count); 79 if (err_is_fail(err)) { 80 return err; 81 } 82 83 symval_count = count; 84 85 if (count > 0) { 86 symvals = calloc(count + 1, sizeof(struct symval)); 87 if (symvals == NULL) { 88 return LIB_ERR_MALLOC_FAIL; 89 } 90 } 91 92 if (lazy) { 93 return SYS_ERR_OK; 94 } 95 96 for (uint32_t i = 1; i <= count; ++i) { 97 err = spawn_symval_lookup_idx(i, &symvals[i].name, &symvals[i].addr); 98 if (err_is_fail(err)) { 99 return err; 100 } 101 } 102 103 return SYS_ERR_OK; 104} 105 106/** 107 * \brief looks up the symbol based on its name and adds it to the cache 108 * 109 * \param name the name of the symbol to query 110 * \param ret_idx returns the symbol index 111 * \param ret_addr returns the address of the symbol 112 * 113 * \returns SYS_ERR_OK on success 114 * errval on failure 115 */ 116errval_t spawn_symval_lookup_name(char *name, 117 uint32_t *ret_idx, 118 genvaddr_t *ret_addr) 119{ 120 errval_t err; 121 122 if (!symvals) { 123 err = spawn_symval_cache_init(1); 124 if (err_is_fail(err)) { 125 return err; 126 } 127 } 128 129 for (uint32_t i = 1; i <= symval_count; ++i) { 130 if (symvals[i].addr == 0) { 131 err = spawn_symval_lookup_idx(i, &symvals[i].name, &symvals[i].addr); 132 if (err_is_fail(err)) { 133 return err; 134 } 135 } 136 if (strcmp(name, symvals[i].name) == 0) { 137 if (ret_idx) { 138 *ret_idx = i; 139 } 140 if (ret_addr) { 141 *ret_addr = symvals[i].addr; 142 } 143 return SYS_ERR_OK; 144 } 145 } 146 // todo: errval 147 return -1; 148} 149 150/** 151 * \brief looks up the symbol information based on its address 152 * 153 * \param addr the address to lookup 154 * \param ret_idx returns the symbol index 155 * \param ret_name returns the symbol name 156 * 157 * \returns SYS_ERR_OK on success 158 * errval on error 159 */ 160errval_t spawn_symval_lookup_addr(genvaddr_t addr, 161 uint32_t *ret_idx, 162 char **ret_name) 163{ 164 errval_t err; 165 166 if (!symvals) { 167 err = spawn_symval_cache_init(1); 168 if (err_is_fail(err)) { 169 return err; 170 } 171 } 172 173 for (uint32_t i = 1; i <= symval_count; ++i) { 174 if (symvals[i].addr == 0) { 175 err = spawn_symval_lookup_idx(i, &symvals[i].name, &symvals[i].addr); 176 if (err_is_fail(err)) { 177 return err; 178 } 179 } 180 if (symvals[i].addr == addr) { 181 if (ret_idx) { 182 *ret_idx = i; 183 } 184 if (ret_name) { 185 *ret_name = symvals[i].name; 186 } 187 188 return SYS_ERR_OK; 189 } 190 } 191 192 // TODO: errval 193 return -1; 194} 195 196/** 197 * \brief looks up the symbol by a given index 198 * 199 * \param idx the index of the symbol to look up 200 * \param ret_name returns the name of the symbol 201 * \param ret_addr returns the address of the symbol 202 * 203 * \returns SYS_ERR_OK on success 204 * errval on failure 205 */ 206errval_t spawn_symval_lookup_idx(uint32_t idx, 207 char **ret_name, 208 genvaddr_t *ret_addr) 209{ 210 if (symvals) { 211 if (symvals[idx].addr != 0) { 212 if (ret_name) { 213 *ret_name = symvals[idx].name; 214 } 215 if (ret_addr) { 216 *ret_addr = symvals[idx].addr; 217 } 218 } 219 } 220 221 return spawn_symval_lookup(disp_name(), idx, ret_name, ret_addr); 222} 223 224/** 225 * \brief executes a lookup query on octopus to obtain the symbol 226 * 227 * \param binary name of the binary to query 228 * \param idx index of the symbol to query 229 * \param ret_name returns the name of the symbol 230 * \param ret_addr returns the address of the symbol 231 * 232 * \return 233 */ 234errval_t spawn_symval_lookup(const char *binary, 235 uint32_t idx, 236 char **ret_name, 237 genvaddr_t *ret_addr) 238{ 239 errval_t err; 240 241 size_t len; 242 243 len = snprintf(NULL, 0, "%s.omp.%"PRIu32, binary, idx); 244 char *omp_entry = malloc(len+1); 245 if (omp_entry == NULL) { 246 return LIB_ERR_MALLOC_FAIL; 247 } 248 snprintf(omp_entry, len+1, "%s.omp.%"PRIu32, binary, idx); 249 250 struct octopus_binding *r = get_octopus_binding(); 251 if (r == NULL) { 252 return LIB_ERR_NAMESERVICE_NOT_BOUND; 253 } 254 255 // transform to lower case 256 for (int i = 0; i < len; ++i) { 257 if (omp_entry[i] >= 'A' && omp_entry[i] <= 'Z') { 258 omp_entry[i] -= ('A' - 'a'); 259 } 260 } 261 262 struct octopus_get_response__rx_args reply; 263 err = r->rpc_tx_vtbl.get(r, omp_entry, NOP_TRIGGER, 264 reply.output, &reply.tid, &reply.error_code); 265 if (err_is_fail(err)) { 266 goto out; 267 } 268 err = reply.error_code; 269 if (err_is_fail(err)) { 270 if (err_no(err) == OCT_ERR_NO_RECORD) { 271 err = err_push(err, LIB_ERR_NAMESERVICE_UNKNOWN_NAME); 272 } 273 goto out; 274 } 275 276 uint64_t addr = 0; 277 char *symname = NULL; 278 err = oct_read(reply.output, "_ { sym: %s, addr: %d }", &symname, &addr); 279 if (err_is_fail(err) || symname == NULL) { 280 err = err_push(err, LIB_ERR_NAMESERVICE_INVALID_NAME); 281 goto out; 282 } 283 if (ret_addr != NULL) { 284 *ret_addr = addr; 285 } 286 if (ret_name != NULL) { 287 *ret_name = strdup(symname); 288 } 289 290 out: 291 free(omp_entry); 292 return err; 293} 294 295/** 296 * \brief registers a found symbol with octopus for later retrieval 297 * 298 * \param binary the name of the binary 299 * \param idx index of the symbol to insert 300 * \param symname name of the symbol to insert 301 * \param address address of the sybol to insert 302 * 303 * \returns SYS_ERR_OK on success 304 * errval on error 305 */ 306errval_t spawn_symval_register(const char *binary, 307 uint32_t idx, 308 const char *symname, 309 genvaddr_t address) 310{ 311 312 errval_t err = SYS_ERR_OK; 313 314 struct octopus_binding *r = get_octopus_binding(); 315 if (r == NULL) { 316 return LIB_ERR_NAMESERVICE_NOT_BOUND; 317 } 318 319 if (symname[0] == '_') { 320 symname++; 321 } 322 // Format record 323 static const char* format = "%s.omp.%u { sym: %s, addr: %d }"; 324 size_t len = snprintf(NULL, 0, format, binary, idx, symname, address); 325 char* record = malloc(len + 1); 326 if (record == NULL) { 327 return LIB_ERR_MALLOC_FAIL; 328 } 329 snprintf(record, len + 1, format, binary, idx, symname, address); 330 // transform to lower case 331 for (int i = 0; i < len; ++i) { 332 if (record[i] >= 'A' && record[i] <= 'Z') { 333 record[i] -= ('A' - 'a'); 334 } 335 } 336 337 octopus_trigger_id_t tid; 338 errval_t error_code; 339 err = r->rpc_tx_vtbl.set(r, record, 0, NOP_TRIGGER, 340 0, NULL, &tid, &error_code); 341 if (err_is_fail(err)) { 342 goto out; 343 } 344 err = error_code; 345 346out: 347 free(record); 348 return err; 349} 350 351