/* The function finds the saved locations and applies the register state as well. */ HIDDEN int dwarf_find_save_locs (struct dwarf_cursor *c) { dwarf_state_record_t sr; dwarf_reg_state_t *rs, rs_copy; struct dwarf_rs_cache *cache; int ret = 0; intrmask_t saved_mask; if (c->as->caching_policy == UNW_CACHE_NONE) return uncached_dwarf_find_save_locs (c); cache = get_rs_cache(c->as, &saved_mask); rs = rs_lookup(cache, c); if (rs) { c->ret_addr_column = rs->ret_addr_column; c->use_prev_instr = ! rs->signal_frame; } else { if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 || (ret = create_state_record_for (c, &sr, c->ip)) < 0) { put_rs_cache (c->as, cache, &saved_mask); put_unwind_info (c, &c->pi); return ret; } rs = rs_new (cache, c); memcpy(rs, &sr.rs_current, offsetof(struct dwarf_reg_state, ip)); cache->buckets[c->prev_rs].hint = rs - cache->buckets; c->hint = rs->hint; c->prev_rs = rs - cache->buckets; put_unwind_info (c, &c->pi); } memcpy (&rs_copy, rs, sizeof (rs_copy)); put_rs_cache (c->as, cache, &saved_mask); tdep_reuse_frame (c, &rs_copy); if ((ret = apply_reg_state (c, &rs_copy)) < 0) return ret; return 0; }
/* * NAME: parse_grammar() * DESCRIPTION: check the grammar, return a pre-processed version */ string *parse_grammar(string *gram) { char buffer[STRINGSZ]; hashtab *ruletab, *strtab; rschunk *rschunks; rlchunk *rlchunks; rule *rgxlist, *strlist, *estrlist, *prodlist, *tmplist, *rr, *rrl; int token, ruleno, nrgx, nstr, nestr, nprod; ssizet glen; unsigned int buflen; bool nomatch; rulesym **rs; rule *rl, **r; long size; unsigned int len; # if MAX_STRLEN > 0xffffffL if (gram->len > 0xffffffL) { error("Grammar string too large"); } # endif /* initialize */ ruletab = ht_new(PARSERULTABSZ, PARSERULHASHSZ, FALSE); strtab = ht_new(PARSERULTABSZ, PARSERULHASHSZ, FALSE); rschunks = (rschunk *) NULL; rlchunks = (rlchunk *) NULL; rgxlist = strlist = estrlist = prodlist = tmplist = (rule *) NULL; nrgx = nstr = nestr = nprod = 0; size = 17 + 8; /* size of header + start rule */ glen = gram->len; nomatch = FALSE; token = gramtok(gram, &glen, buffer, &buflen); for (ruleno = 1; ; ruleno++) { switch (token) { case TOK_TOKSYM: /* * token rule definition */ r = (rule **) ht_lookup(ruletab, buffer, TRUE); if (*r != (rule *) NULL) { if ((*r)->type == RULE_UNKNOWN) { /* replace unknown rule */ rl = *r; rl->type = RULE_REGEXP; size += 4; nrgx++; if (rl->alt != (rule *) NULL) { rl->alt->next = rl->next; } else { tmplist = rl->next; } if (rl->next != (rule *) NULL) { rl->next->alt = rl->alt; } rl->alt = (rule *) NULL; rl->next = rgxlist; rgxlist = rl; } else if ((*r)->type == RULE_REGEXP) { /* new alternative regexp */ rl = rl_new(&rlchunks, RULE_REGEXP); *((*r)->last) = rl; (*r)->last = &rl->alt; } else { sprintf(buffer, "Rule %d previously defined as production rule", ruleno); goto err; } } else { /* new rule */ rl = rl_new(&rlchunks, RULE_REGEXP); str_ref(rl->symb = str_new(buffer, (long) buflen)); rl->chain.name = rl->symb->text; rl->chain.next = (hte *) *r; *r = rl; size += 4; nrgx++; rl->next = rgxlist; rgxlist = rl; } switch (gramtok(gram, &glen, buffer, &buflen)) { case TOK_REGEXP: str_ref(rl->u.rgx = str_new(buffer, (long) buflen)); (*r)->num++; (*r)->len += buflen; size += buflen + 1; break; case TOK_BADREGEXP: sprintf(buffer, "Rule %d: malformed regular expression", ruleno); goto err; case TOK_TOOBIGRGX: sprintf(buffer, "Rule %d: regular expression too large", ruleno); goto err; case TOK_SYMBOL: if (buflen == 7 && strcmp(buffer, "nomatch") == 0) { if (nomatch) { sprintf(buffer, "Rule %d: extra nomatch rule", ruleno); goto err; } nomatch = TRUE; rl->u.rgx = (string *) NULL; break; } /* fall through */ default: sprintf(buffer, "Rule %d: regular expression expected", ruleno); goto err; } /* next token */ token = gramtok(gram, &glen, buffer, &buflen); break; case TOK_PRODSYM: /* * production rule definition */ r = (rule **) ht_lookup(ruletab, buffer, TRUE); if (*r != (rule *) NULL) { if ((*r)->type == RULE_UNKNOWN) { /* replace unknown rule */ rl = *r; rl->type = RULE_PROD; size += 4; nprod++; if (rl->alt != (rule *) NULL) { rl->alt->next = rl->next; } else { tmplist = rl->next; } if (rl->next != (rule *) NULL) { rl->next->alt = rl->alt; } rl->alt = (rule *) NULL; rl->next = prodlist; prodlist = rl; } else if ((*r)->type == RULE_PROD) { /* new alternative production */ rl = rl_new(&rlchunks, RULE_PROD); *((*r)->last) = rl; (*r)->last = &rl->alt; } else { sprintf(buffer, "Rule %d previously defined as token rule", ruleno); goto err; } } else { /* new rule */ rl = rl_new(&rlchunks, RULE_PROD); str_ref(rl->symb = str_new(buffer, (long) buflen)); rl->chain.name = rl->symb->text; rl->chain.next = (hte *) *r; *r = rl; size += 4; nprod++; rl->next = prodlist; prodlist = rl; } rr = *r; rrl = rl; rs = &rl->u.syms; len = 0; for (;;) { switch (token = gramtok(gram, &glen, buffer, &buflen)) { case TOK_SYMBOL: /* * symbol */ r = (rule **) ht_lookup(ruletab, buffer, TRUE); if (*r == (rule *) NULL) { /* new unknown rule */ rl = rl_new(&rlchunks, RULE_UNKNOWN); str_ref(rl->symb = str_new(buffer, (long) buflen)); rl->chain.name = rl->symb->text; rl->chain.next = (hte *) *r; *r = rl; rl->next = tmplist; if (tmplist != (rule *) NULL) { tmplist->alt = rl; } tmplist = rl; } else { /* previously known rule */ rl = *r; } *rs = rs_new(&rschunks, rl); rs = &(*rs)->next; len += 2; continue; case TOK_STRING: case TOK_ESTRING: /* * string */ r = (rule **) ht_lookup(strtab, buffer, FALSE); while (*r != (rule *) NULL) { if ((*r)->symb->len == buflen && memcmp((*r)->symb->text, buffer, buflen) == 0) { break; } r = (rule **) &(*r)->chain.next; } if (*r == (rule *) NULL) { /* new string rule */ rl = rl_new(&rlchunks, RULE_STRING); str_ref(rl->symb = str_new(buffer, (long) buflen)); rl->chain.name = rl->symb->text; rl->chain.next = (hte *) *r; *r = rl; if (token == TOK_STRING) { size += 4; nstr++; rl->len = gram->len - glen - buflen - 1; rl->next = strlist; strlist = rl; } else { size += 3 + buflen; nestr++; rl->next = estrlist; estrlist = rl; } } else { /* existing string rule */ rl = *r; } *rs = rs_new(&rschunks, rl); rs = &(*rs)->next; len += 2; continue; case TOK_QUEST: /* * ? function */ if (gramtok(gram, &glen, buffer, &buflen) != TOK_SYMBOL) { sprintf(buffer, "Rule %d: function name expected", ruleno); goto err; } str_ref(rrl->func = str_new(buffer, (long) buflen)); len += buflen + 1; token = gramtok(gram, &glen, buffer, &buflen); /* fall through */ default: break; } break; } if (len > 255) { sprintf(buffer, "Rule %d is too long", ruleno); goto err; } rr->num++; rr->len += len; size += len + 2; break; case TOK_NULL: /* * end of grammar */ if (tmplist != (rule *) NULL) { sprintf(buffer, "Undefined symbol %s", tmplist->symb->text); goto err; } if (rgxlist == (rule *) NULL) { strcpy(buffer, "No tokens"); goto err; } if (prodlist == (rule *) NULL) { strcpy(buffer, "No starting rule"); goto err; } if (size > (long) USHRT_MAX) { strcpy(buffer, "Grammar too large"); goto err; } gram = make_grammar(rgxlist, strlist, estrlist, prodlist, nrgx, nstr, nestr, nprod, size); rs_clear(rschunks); rl_clear(rlchunks); ht_del(strtab); ht_del(ruletab); return gram; case TOK_ERROR: sprintf(buffer, "Rule %d: bad token", ruleno); goto err; case TOK_BADREGEXP: sprintf(buffer, "Rule %d: malformed regular expression", ruleno); goto err; case TOK_TOOBIGRGX: sprintf(buffer, "Rule %d: regular expression too large", ruleno); goto err; case TOK_BADSTRING: sprintf(buffer, "Rule %d: malformed string constant", ruleno); goto err; case TOK_TOOBIGSTR: sprintf(buffer, "Rule %d: string too long", ruleno); goto err; case TOK_TOOBIGSYM: sprintf(buffer, "Rule %d: symbol too long", ruleno); goto err; default: sprintf(buffer, "Rule %d: unexpected token", ruleno); goto err; } } err: rs_clear(rschunks); rl_clear(rlchunks); ht_del(strtab); ht_del(ruletab); error(buffer); return NULL; }