Print this page
6068 libdisasm: previnstr arch op should have a sane default
Reviewed by: Robert Mustacchi <rm@joyent.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libdisasm/common/libdisasm.c
          +++ new/usr/src/lib/libdisasm/common/libdisasm.c
↓ open down ↓ 188 lines elided ↑ open up ↑
 189  189  
 190  190          return (dhp);
 191  191  }
 192  192  
 193  193  int
 194  194  dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
 195  195  {
 196  196          return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
 197  197  }
 198  198  
      199 +/*
      200 + * On some instruction sets (e.g., x86), we have no choice except to
      201 + * disassemble everything from the start of the symbol, and stop when we
      202 + * have reached our instruction address.  If we're not in the middle of a
      203 + * known symbol, then we return the same address to indicate failure.
      204 + */
      205 +static uint64_t
      206 +dis_generic_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
      207 +{
      208 +        uint64_t *hist, addr, start;
      209 +        int cur, nseen;
      210 +        uint64_t res = pc;
      211 +
      212 +        if (n <= 0)
      213 +                return (pc);
      214 +
      215 +        if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 ||
      216 +            start == pc)
      217 +                return (res);
      218 +
      219 +        hist = dis_zalloc(sizeof (uint64_t) * n);
      220 +
      221 +        for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) {
      222 +                hist[cur] = addr;
      223 +                cur = (cur + 1) % n;
      224 +                nseen++;
      225 +
      226 +                /* if we cannot make forward progress, give up */
      227 +                if (dis_disassemble(dhp, addr, NULL, 0) != 0)
      228 +                        goto done;
      229 +        }
      230 +
      231 +        if (addr != pc) {
      232 +                /*
      233 +                 * We scanned past %pc, but didn't find an instruction that
      234 +                 * started at %pc.  This means that either the caller specified
      235 +                 * an invalid address, or we ran into something other than code
      236 +                 * during our scan.  Virtually any combination of bytes can be
      237 +                 * construed as a valid Intel instruction, so any non-code bytes
      238 +                 * we encounter will have thrown off the scan.
      239 +                 */
      240 +                goto done;
      241 +        }
      242 +
      243 +        res = hist[(cur + n - MIN(n, nseen)) % n];
      244 +
      245 +done:
      246 +        dis_free(hist, sizeof (uint64_t) * n);
      247 +        return (res);
      248 +}
      249 +
      250 +/*
      251 + * Return the nth previous instruction's address.  Return the same address
      252 + * to indicate failure.
      253 + */
 199  254  uint64_t
 200  255  dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
 201  256  {
      257 +        if (dhp->dh_arch->da_previnstr == NULL)
      258 +                return (dis_generic_previnstr(dhp, pc, n));
      259 +
 202  260          return (dhp->dh_arch->da_previnstr(dhp, pc, n));
 203  261  }
 204  262  
 205  263  int
 206  264  dis_min_instrlen(dis_handle_t *dhp)
 207  265  {
 208  266          return (dhp->dh_arch->da_min_instrlen(dhp));
 209  267  }
 210  268  
 211  269  int
↓ open down ↓ 33 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX