Print this page
saveargs: let disasm do the lifting
3544 save-args matcher could be considerably more robust
3545 save-args matcher should accept saves maybe out-of-order
Reviewed by: Joshua M. Clulow <josh@sysmgr.org>

Split Close
Expand all
Collapse all
          --- old/usr/src/common/saveargs/saveargs.c
          +++ new/usr/src/common/saveargs/saveargs.c
↓ open down ↓ 85 lines elided ↑ open up ↑
  86   86   *     pushq    %rsi
  87   87   *     pushq    %rdx
  88   88   *     pushq    %rcx
  89   89   *     pushq    %r8
  90   90   *     pushq    %r9
  91   91   *
  92   92   * **: The space being reserved is in addition to what the current
  93   93   *     function prolog already reserves.
  94   94   *
  95   95   * We loop through the first SAVEARGS_INSN_SEQ_LEN bytes of the function
  96      - * looking for each argument saving instruction we would expect to see.  We
  97      - * loop byte-by-byte, rather than doing anything smart about insn lengths,
  98      - * only deviating from this when we know we have our insn, and can skip the
  99      - * rest of it.
       96 + * looking for each argument saving instruction we would expect to see.
 100   97   *
 101   98   * If there are odd number of arguments to a function, additional space is
 102   99   * reserved on the stack to maintain 16-byte alignment.  For example,
 103  100   *
 104  101   *     argc == 0: no argument saving.
 105  102   *     argc == 3: save 3, but space for 4 is reserved
 106  103   *     argc == 7: save 6.
 107  104   */
 108  105  
 109  106  #include <sys/sysmacros.h>
 110  107  #include <sys/types.h>
      108 +#include <libdisasm.h>
      109 +#include <string.h>
      110 +
 111  111  #include <saveargs.h>
 112  112  
 113  113  /*
 114  114   * Size of the instruction sequence arrays.  It should correspond to
 115  115   * the maximum number of arguments passed via registers.
 116  116   */
 117  117  #define INSTR_ARRAY_SIZE        6
 118  118  
 119  119  #define INSTR1(ins, off) (ins[(off)])
 120  120  #define INSTR2(ins, off) (ins[(off)] + (ins[(off) + 1] << 8))
↓ open down ↓ 34 lines elided ↑ open up ↑
 155  155   */
 156  156  static const uint32_t save_instr_sr[INSTR_ARRAY_SIZE-1] = {
 157  157          0xf8758948,     /* movq %rsi,-0x8(%rbp) */
 158  158          0xf0558948,     /* movq %rdx,-0x10(%rbp) */
 159  159          0xe84d8948,     /* movq %rcx,-0x18(%rbp) */
 160  160          0xe045894c,     /* movq %r8,-0x20(%rbp) */
 161  161          0xd84d894c      /* movq %r9,-0x28(%rbp) */
 162  162  };
 163  163  
 164  164  static const uint8_t save_fp_pushes[] = {
 165      -    0x55,       /* pushq %rbp */
 166      -    0xcc        /* int $0x3 */
      165 +        0x55,   /* pushq %rbp */
      166 +        0xcc    /* int $0x3 */
 167  167  };
 168  168  #define NUM_FP_PUSHES (sizeof (save_fp_pushes) / sizeof (save_fp_pushes[0]))
 169  169  
 170  170  static const uint32_t save_fp_movs[] = {
 171  171          0x00e58948,     /* movq %rsp,%rbp, encoding 1 */
 172  172          0x00ec8b48,     /* movq %rsp,%rbp, encoding 2 */
 173  173  };
 174  174  #define NUM_FP_MOVS (sizeof (save_fp_movs) / sizeof (save_fp_movs[0]))
 175  175  
      176 +typedef struct {
      177 +        uint8_t *data;
      178 +        size_t size;
      179 +} text_t;
      180 +
      181 +static int
      182 +do_read(void *data, uint64_t addr, void *buf, size_t len)
      183 +{
      184 +        text_t  *t = data;
      185 +
      186 +        if (addr > t->size)
      187 +                return (-1);
      188 +
      189 +        len = MIN(len, t->size - addr);
      190 +        
      191 +        (void) memcpy(buf, (char *)t->data + addr, len);
      192 +        
      193 +        return (len);
      194 +}
      195 +
      196 +/* ARGSUSED */
      197 +int
      198 +do_lookup(void *data, uint64_t addr, char *buf, size_t buflen, uint64_t *start,
      199 +    size_t *symlen)
      200 +{
      201 +        /* We don't actually need lookup info */
      202 +        return (-1);
      203 +}
      204 +
 176  205  static int
 177      -has_saved_fp(uint8_t *ins, int size)
      206 +instr_size(dis_handle_t *dhp, uint8_t *ins, unsigned int i, size_t size)
      207 +{
      208 +        text_t  t;
      209 +
      210 +        t.data = ins;
      211 +        t.size = size;
      212 +
      213 +        dis_set_data(dhp, &t);
      214 +        return (dis_instrlen(dhp, i));
      215 +}
      216 +
      217 +static boolean_t
      218 +has_saved_fp(dis_handle_t *dhp, uint8_t *ins, int size)
 178  219  {
 179      -        int i, j;
 180      -        uint32_t n;
 181      -        int found_push = 0;
      220 +        int             i, j;
      221 +        uint32_t        n;
      222 +        boolean_t       found_push = B_FALSE;
      223 +        int             sz = 0;
      224 +
      225 +        for (i = 0; i < size; i += sz) {
      226 +                if ((sz = instr_size(dhp, ins, i, size)) == -1)
      227 +                        return (B_FALSE);
      228 +
      229 +                if (found_push == B_FALSE) {
      230 +                        if (sz != 1)
      231 +                                continue;
 182  232  
 183      -        for (i = 0; i < size; i++) {
 184      -                if (found_push == 0) {
 185  233                          n = INSTR1(ins, i);
 186  234                          for (j = 0; j <= NUM_FP_PUSHES; j++)
 187  235                                  if (save_fp_pushes[j] == n) {
 188      -                                        found_push = 1;
      236 +                                        found_push = B_TRUE;
 189  237                                          break;
 190  238                                  }
 191  239                  } else {
      240 +                        if (sz != 3)
      241 +                                continue;
 192  242                          n = INSTR3(ins, i);
 193  243                          for (j = 0; j <= NUM_FP_MOVS; j++)
 194  244                                  if (save_fp_movs[j] == n)
 195      -                                        return (1);
      245 +                                        return (B_TRUE);
 196  246                  }
 197  247          }
 198  248  
 199      -        return (0);
      249 +        return (B_FALSE);
 200  250  }
 201  251  
 202  252  int
 203  253  saveargs_has_args(uint8_t *ins, size_t size, uint_t argc, int start_index)
 204  254  {
 205  255          int             i, j;
 206  256          uint32_t        n;
      257 +        uint8_t         found = 0;
      258 +        size_t          sz = 0;
      259 +        dis_handle_t    *dhp = NULL;
      260 +        int             ret = SAVEARGS_NO_ARGS;
 207  261  
 208  262          argc = MIN((start_index + argc), INSTR_ARRAY_SIZE);
 209  263  
 210      -        if (!has_saved_fp(ins, size))
      264 +        if ((dhp = dis_handle_create(DIS_X86_SIZE64, NULL, do_lookup,
      265 +            do_read)) == NULL)
 211  266                  return (SAVEARGS_NO_ARGS);
 212  267  
      268 +        if (!has_saved_fp(dhp, ins, size)) {
      269 +                dis_handle_destroy(dhp);
      270 +                return (SAVEARGS_NO_ARGS);
      271 +        }
      272 +
 213  273          /*
 214      -         * Compare against Sun Studio implementation
      274 +         * For each possible style of argument saving, walk the insn stream as
      275 +         * we've been given it, and set bit N in 'found' if we find the
      276 +         * instruction saving the Nth argument.
 215  277           */
 216      -        for (i = 4, j = 0; i <= size - 4; i++) {
 217      -                n = INSTR4(ins, i);
 218      -
 219      -                if (n == save_instr[j]) {
 220      -                        i += 3;
 221      -                        if (++j >= argc)
 222      -                                return (start_index ? SAVEARGS_STRUCT_ARGS :
 223      -                                    SAVEARGS_TRAD_ARGS);
 224      -                }
 225      -        }
 226  278  
 227  279          /*
 228      -         * Compare against GCC implementation
      280 +         * Compare against regular implementation
 229  281           */
 230      -        for (i = 4, j = argc - 1; i <= size - 4; i++) {
      282 +        found = 0;
      283 +        for (i = 0; i < size; i += sz) {
      284 +                sz = instr_size(dhp, ins, i, size);
      285 +
      286 +                if (sz == -1)
      287 +                        break;
      288 +                else if (sz != 4)
      289 +                        continue;
      290 +
 231  291                  n = INSTR4(ins, i);
 232  292  
 233      -                if (n == save_instr[j]) {
 234      -                        i += 3;
 235      -                        if (--j < start_index)
 236      -                                return (SAVEARGS_TRAD_ARGS);
      293 +                for (j = 0; j < argc; j++) {
      294 +                        if (n == save_instr[j]) {
      295 +                                found |= (1 << j);
      296 +
      297 +                                if (found == ((1 << argc) - 1)) {
      298 +                                        ret = start_index ?
      299 +                                            SAVEARGS_STRUCT_ARGS :
      300 +                                            SAVEARGS_TRAD_ARGS;
      301 +                                        goto done;
      302 +                                }
      303 +
      304 +                                break;
      305 +                        }
 237  306                  }
 238  307          }
 239  308  
 240  309          /*
 241  310           * Compare against GCC push-based implementation
 242  311           */
 243      -        for (i = 4, j = start_index; i <= size - 2; i += 1) {
 244      -                n = (i >= (8 - start_index)) ? INSTR2(ins, i) : INSTR1(ins, i);
      312 +        found = 0;
      313 +        for (i = 0; i < size; i += sz) {
      314 +                if ((sz = instr_size(dhp, ins, i, size)) == -1)
      315 +                        break;
      316 +
      317 +                for (j = start_index; j < argc; j++) {
      318 +                        if (sz == 2) /* Two byte */
      319 +                                n = INSTR2(ins, i);
      320 +                        else if (sz == 1)
      321 +                                n = INSTR1(ins, i);
      322 +                        else
      323 +                                continue;
      324 +
      325 +                        if (n == save_instr_push[j]) {
      326 +                                found |= (1 << (j - start_index));
      327 +
      328 +                                if (found == ((1 << (argc - start_index)) - 1)) {
      329 +                                        ret = SAVEARGS_TRAD_ARGS;
      330 +                                        goto done;
      331 +                                }
 245  332  
 246      -                if (n == save_instr_push[j]) {
 247      -                        if (i >= (8 - start_index))
 248      -                                i += 1;
 249      -                        if (++j >= argc)
 250      -                                return (SAVEARGS_TRAD_ARGS);
      333 +                                break;
      334 +                        }
 251  335                  }
 252  336          }
 253  337  
 254      -        /* Look for a GCC-style returned structure */
      338 +        /*
      339 +         * Look for a GCC-style returned structure.
      340 +         */
      341 +        found = 0;
 255  342          if (start_index != 0) {
 256      -                for (i = 4, j = argc - 2; i <= size - 4; i++) {
      343 +                for (i = 0; i < size; i += sz) {
      344 +                        sz = instr_size(dhp, ins, i, size);
      345 +
      346 +                        if (sz == -1)
      347 +                                break;
      348 +                        else if (sz != 4)
      349 +                                continue;
      350 +
 257  351                          n = INSTR4(ins, i);
 258  352  
 259      -                        if (n == save_instr_sr[j]) {
 260      -                                i += 3;
 261      -                                if (--j >= (argc - 1))
 262      -                                        return (SAVEARGS_TRAD_ARGS);
      353 +                        /* argc is inclusive of start_index, allow for that */
      354 +                        for (j = 0; j < (argc - start_index); j++) {
      355 +                                if (n == save_instr_sr[j]) {
      356 +                                        found |= (1 << j);
      357 +
      358 +                                        if (found ==
      359 +                                            ((1 << (argc - start_index)) - 1)) {
      360 +                                                ret = SAVEARGS_TRAD_ARGS;
      361 +                                                goto done;
      362 +                                        }
      363 +
      364 +                                        break;
      365 +                                }
 263  366                          }
 264  367                  }
 265  368          }
 266  369  
 267      -        return (SAVEARGS_NO_ARGS);
      370 +done:
      371 +        dis_handle_destroy(dhp);
      372 +        return (ret);
 268  373  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX