Print this page
6066 dis: support for System/370, System/390, and z/Architecture ELF bins
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
6070 libdisasm: attach/detach arch ops should be optional
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
6069 libdisasm: instrlen arch op should have a sane default
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.com>
6068 libdisasm: previnstr arch op should have a sane default
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Dan McDonald <danmcd@omniti.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 ↓ 44 lines elided ↑ open up ↑
  45   45   * include support for disassembly of the native architecture.
  46   46   * The regular shared library should include support for all
  47   47   * architectures.
  48   48   */
  49   49  #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
  50   50  extern dis_arch_t dis_arch_i386;
  51   51  #endif
  52   52  #if !defined(DIS_STANDALONE) || defined(__sparc)
  53   53  extern dis_arch_t dis_arch_sparc;
  54   54  #endif
       55 +#if !defined(DIS_STANDALONE) || defined(__s390) || defined(__s390x)
       56 +extern dis_arch_t dis_arch_s390;
       57 +#endif
  55   58  
  56   59  static dis_arch_t *dis_archs[] = {
  57   60  #if !defined(DIS_STANDALONE) || defined(__i386) || defined(__amd64)
  58   61          &dis_arch_i386,
  59   62  #endif
  60   63  #if !defined(DIS_STANDALONE) || defined(__sparc)
  61   64          &dis_arch_sparc,
  62   65  #endif
       66 +#if !defined(DIS_STANDALONE) || defined(__s390) || defined(__s390x)
       67 +        &dis_arch_s390,
       68 +#endif
  63   69          NULL
  64   70  };
  65   71  
  66   72  /*
  67   73   * For the standalone library, we need to link against mdb's malloc/free.
  68   74   * Otherwise, use the standard malloc/free.
  69   75   */
  70   76  #ifdef DIS_STANDALONE
  71   77  void *
  72   78  dis_zalloc(size_t bytes)
↓ open down ↓ 63 lines elided ↑ open up ↑
 136  142  
 137  143  void
 138  144  dis_flags_clear(dis_handle_t *dhp, int f)
 139  145  {
 140  146          dhp->dh_flags &= ~f;
 141  147  }
 142  148  
 143  149  void
 144  150  dis_handle_destroy(dis_handle_t *dhp)
 145  151  {
 146      -        dhp->dh_arch->da_handle_detach(dhp);
      152 +        if (dhp->dh_arch->da_handle_detach != NULL)
      153 +                dhp->dh_arch->da_handle_detach(dhp);
      154 +
 147  155          dis_free(dhp, sizeof (dis_handle_t));
 148  156  }
 149  157  
 150  158  dis_handle_t *
 151  159  dis_handle_create(int flags, void *data, dis_lookup_f lookup_func,
 152  160      dis_read_f read_func)
 153  161  {
 154  162          dis_handle_t *dhp;
 155  163          dis_arch_t *arch = NULL;
 156  164          int i;
↓ open down ↓ 17 lines elided ↑ open up ↑
 174  182          dhp->dh_arch = arch;
 175  183          dhp->dh_lookup = lookup_func;
 176  184          dhp->dh_read = read_func;
 177  185          dhp->dh_flags = flags;
 178  186          dhp->dh_data = data;
 179  187  
 180  188          /*
 181  189           * Allow the architecture-specific code to allocate
 182  190           * its private data.
 183  191           */
 184      -        if (arch->da_handle_attach(dhp) != 0) {
      192 +        if (arch->da_handle_attach != NULL &&
      193 +            arch->da_handle_attach(dhp) != 0) {
 185  194                  dis_free(dhp, sizeof (dis_handle_t));
 186  195                  /* dis errno already set */
 187  196                  return (NULL);
 188  197          }
 189  198  
 190  199          return (dhp);
 191  200  }
 192  201  
 193  202  int
 194  203  dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
 195  204  {
 196  205          return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
 197  206  }
 198  207  
      208 +/*
      209 + * On some instruction sets (e.g., x86), we have no choice except to
      210 + * disassemble everything from the start of the symbol, and stop when we
      211 + * have reached our instruction address.  If we're not in the middle of a
      212 + * known symbol, then we return the same address to indicate failure.
      213 + */
      214 +static uint64_t
      215 +dis_generic_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
      216 +{
      217 +        uint64_t *hist, addr, start;
      218 +        int cur, nseen;
      219 +        uint64_t res = pc;
      220 +
      221 +        if (n <= 0)
      222 +                return (pc);
      223 +
      224 +        if (dhp->dh_lookup(dhp->dh_data, pc, NULL, 0, &start, NULL) != 0 ||
      225 +            start == pc)
      226 +                return (res);
      227 +
      228 +        hist = dis_zalloc(sizeof (uint64_t) * n);
      229 +
      230 +        for (cur = 0, nseen = 0, addr = start; addr < pc; addr = dhp->dh_addr) {
      231 +                hist[cur] = addr;
      232 +                cur = (cur + 1) % n;
      233 +                nseen++;
      234 +
      235 +                /* if we cannot make forward progress, give up */
      236 +                if (dis_disassemble(dhp, addr, NULL, 0) != 0)
      237 +                        goto done;
      238 +        }
      239 +
      240 +        if (addr != pc) {
      241 +                /*
      242 +                 * We scanned past %pc, but didn't find an instruction that
      243 +                 * started at %pc.  This means that either the caller specified
      244 +                 * an invalid address, or we ran into something other than code
      245 +                 * during our scan.  Virtually any combination of bytes can be
      246 +                 * construed as a valid Intel instruction, so any non-code bytes
      247 +                 * we encounter will have thrown off the scan.
      248 +                 */
      249 +                goto done;
      250 +        }
      251 +
      252 +        res = hist[(cur + n - MIN(n, nseen)) % n];
      253 +
      254 +done:
      255 +        dis_free(hist, sizeof (uint64_t) * n);
      256 +        return (res);
      257 +}
      258 +
      259 +/*
      260 + * Return the nth previous instruction's address.  Return the same address
      261 + * to indicate failure.
      262 + */
 199  263  uint64_t
 200  264  dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
 201  265  {
      266 +        if (dhp->dh_arch->da_previnstr == NULL)
      267 +                return (dis_generic_previnstr(dhp, pc, n));
      268 +
 202  269          return (dhp->dh_arch->da_previnstr(dhp, pc, n));
 203  270  }
 204  271  
 205  272  int
 206  273  dis_min_instrlen(dis_handle_t *dhp)
 207  274  {
 208  275          return (dhp->dh_arch->da_min_instrlen(dhp));
 209  276  }
 210  277  
 211  278  int
 212  279  dis_max_instrlen(dis_handle_t *dhp)
 213  280  {
 214  281          return (dhp->dh_arch->da_max_instrlen(dhp));
 215  282  }
 216  283  
      284 +static int
      285 +dis_generic_instrlen(dis_handle_t *dhp, uint64_t pc)
      286 +{
      287 +        if (dis_disassemble(dhp, pc, NULL, 0) != 0)
      288 +                return (-1);
      289 +
      290 +        return (dhp->dh_addr - pc);
      291 +}
      292 +
 217  293  int
 218  294  dis_instrlen(dis_handle_t *dhp, uint64_t pc)
 219  295  {
      296 +        if (dhp->dh_arch->da_instrlen == NULL)
      297 +                return (dis_generic_instrlen(dhp, pc));
      298 +
 220  299          return (dhp->dh_arch->da_instrlen(dhp, pc));
 221  300  }
 222  301  
 223  302  int
 224  303  dis_vsnprintf(char *restrict s, size_t n, const char *restrict format,
 225  304      va_list args)
 226  305  {
 227  306  #ifdef DIS_STANDALONE
 228  307          return (mdb_iob_vsnprintf(s, n, format, args));
 229  308  #else
↓ open down ↓ 15 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX