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


 179 
 180         /*
 181          * Allow the architecture-specific code to allocate
 182          * its private data.
 183          */
 184         if (arch->da_handle_attach(dhp) != 0) {
 185                 dis_free(dhp, sizeof (dis_handle_t));
 186                 /* dis errno already set */
 187                 return (NULL);
 188         }
 189 
 190         return (dhp);
 191 }
 192 
 193 int
 194 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
 195 {
 196         return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
 197 }
 198 























































 199 uint64_t
 200 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
 201 {



 202         return (dhp->dh_arch->da_previnstr(dhp, pc, n));
 203 }
 204 
 205 int
 206 dis_min_instrlen(dis_handle_t *dhp)
 207 {
 208         return (dhp->dh_arch->da_min_instrlen(dhp));
 209 }
 210 
 211 int
 212 dis_max_instrlen(dis_handle_t *dhp)
 213 {
 214         return (dhp->dh_arch->da_max_instrlen(dhp));
 215 }
 216 
 217 int
 218 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
 219 {
 220         return (dhp->dh_arch->da_instrlen(dhp, pc));
 221 }




 179 
 180         /*
 181          * Allow the architecture-specific code to allocate
 182          * its private data.
 183          */
 184         if (arch->da_handle_attach(dhp) != 0) {
 185                 dis_free(dhp, sizeof (dis_handle_t));
 186                 /* dis errno already set */
 187                 return (NULL);
 188         }
 189 
 190         return (dhp);
 191 }
 192 
 193 int
 194 dis_disassemble(dis_handle_t *dhp, uint64_t addr, char *buf, size_t buflen)
 195 {
 196         return (dhp->dh_arch->da_disassemble(dhp, addr, buf, buflen));
 197 }
 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  */
 254 uint64_t
 255 dis_previnstr(dis_handle_t *dhp, uint64_t pc, int n)
 256 {
 257         if (dhp->dh_arch->da_previnstr == NULL)
 258                 return (dis_generic_previnstr(dhp, pc, n));
 259 
 260         return (dhp->dh_arch->da_previnstr(dhp, pc, n));
 261 }
 262 
 263 int
 264 dis_min_instrlen(dis_handle_t *dhp)
 265 {
 266         return (dhp->dh_arch->da_min_instrlen(dhp));
 267 }
 268 
 269 int
 270 dis_max_instrlen(dis_handle_t *dhp)
 271 {
 272         return (dhp->dh_arch->da_max_instrlen(dhp));
 273 }
 274 
 275 int
 276 dis_instrlen(dis_handle_t *dhp, uint64_t pc)
 277 {
 278         return (dhp->dh_arch->da_instrlen(dhp, pc));
 279 }