Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2013, Josef 'Jeff' Sipek <jeffpc@josefsipek.net>

  25  */
  26 
  27 #include <mdb/mdb_modapi.h>
  28 #include <mdb/mdb_ctf.h>
  29 
  30 #include <sys/types.h>
  31 #include <sys/regset.h>
  32 #include <sys/stack.h>
  33 #include <sys/thread.h>
  34 #include <sys/modctl.h>
  35 #include <assert.h>
  36 
  37 #include "findstack.h"
  38 #include "thread.h"
  39 #include "sobj.h"
  40 






  41 int findstack_debug_on = 0;
  42 
  43 /*
  44  * "sp" is a kernel VA.
  45  */
  46 static int
  47 print_stack(uintptr_t sp, uintptr_t pc, uintptr_t addr,
  48     int argc, const mdb_arg_t *argv, int free_state)
  49 {
  50         int showargs = 0, count, err;

  51 
  52         count = mdb_getopts(argc, argv,
  53             'v', MDB_OPT_SETBITS, TRUE, &showargs, NULL);
  54         argc -= count;
  55         argv += count;
  56 
  57         if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING))
  58                 return (DCMD_USAGE);
  59 
  60         mdb_printf("stack pointer for thread %p%s: %p\n",
  61             addr, (free_state ? " (TS_FREE)" : ""), sp);


  62         if (pc != 0)
  63                 mdb_printf("[ %0?lr %a() ]\n", sp, pc);
  64 
  65         mdb_inc_indent(2);
  66         mdb_set_dot(sp);
  67 
  68         if (argc == 1)
  69                 err = mdb_eval(argv->a_un.a_str);
  70         else if (showargs)
  71                 err = mdb_eval("<.$C");
  72         else
  73                 err = mdb_eval("<.$C0");
  74 
  75         mdb_dec_indent(2);
  76 
  77         return ((err == -1) ? DCMD_ABORT : DCMD_OK);
  78 }
  79 
  80 int
  81 findstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)


  91         if ((retval = stacks_findstack(addr, &fsi, 1)) != DCMD_OK ||
  92             fsi.fsi_failed)
  93                 return (retval);
  94 
  95         return (print_stack(fsi.fsi_sp, fsi.fsi_pc, addr,
  96             argc, argv, fsi.fsi_tstate == TS_FREE));
  97 }
  98 
  99 /*ARGSUSED*/
 100 int
 101 findstack_debug(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *av)
 102 {
 103         findstack_debug_on ^= 1;
 104 
 105         mdb_printf("findstack: debugging is now %s\n",
 106             findstack_debug_on ? "on" : "off");
 107 
 108         return (DCMD_OK);
 109 }
 110 


 111 static void
 112 uppercase(char *p)
 113 {
 114         for (; *p != '\0'; p++) {
 115                 if (*p >= 'a' && *p <= 'z')
 116                         *p += 'A' - 'a';
 117         }
 118 }
 119 
 120 static void
 121 sobj_to_text(uintptr_t addr, char *out, size_t out_sz)
 122 {
 123         sobj_ops_to_text(addr, out, out_sz);
 124         uppercase(out);
 125 }
 126 
 127 #define SOBJ_ALL        1
 128 
 129 static int
 130 text_to_sobj(const char *text, uintptr_t *out)


 180 
 181 /* Maximum stack depth reported in stacks */
 182 #define STACKS_MAX_DEPTH        254
 183 
 184 typedef struct stacks_info {
 185         size_t          si_count;       /* total stacks_entry_ts (incl dups) */
 186         size_t          si_entries;     /* # entries in hash table */
 187         stacks_entry_t  **si_hash;      /* hash table */
 188         findstack_info_t si_fsi;        /* transient callback state */
 189 } stacks_info_t;
 190 
 191 /* global state cached between invocations */
 192 #define STACKS_STATE_CLEAN      0
 193 #define STACKS_STATE_DIRTY      1
 194 #define STACKS_STATE_DONE       2
 195 static uint_t stacks_state = STACKS_STATE_CLEAN;
 196 static stacks_entry_t **stacks_hash;
 197 static stacks_entry_t **stacks_array;
 198 static size_t stacks_array_size;
 199 
 200 size_t
 201 stacks_hash_entry(stacks_entry_t *sep)
 202 {
 203         size_t depth = sep->se_depth;
 204         uintptr_t *stack = sep->se_stack;
 205 
 206         uint64_t total = depth;
 207 
 208         while (depth > 0) {
 209                 total += *stack;
 210                 stack++; depth--;
 211         }
 212 
 213         return (total % STACKS_HSIZE);
 214 }
 215 
 216 /*
 217  * This is used to both compare stacks for equality and to sort the final
 218  * list of unique stacks.  forsort specifies the latter behavior, which
 219  * additionally:
 220  *      compares se_count, and
 221  *      sorts the stacks by text function name.
 222  *
 223  * The equality test is independent of se_count, and doesn't care about
 224  * relative ordering, so we don't do the extra work of looking up symbols
 225  * for the stack addresses.
 226  */
 227 int
 228 stacks_entry_comp_impl(stacks_entry_t *l, stacks_entry_t *r,
 229     uint_t forsort)
 230 {
 231         int idx;
 232 
 233         int depth = MIN(l->se_depth, r->se_depth);
 234 
 235         /* no matter what, panic stacks come last. */
 236         if (l->se_panic > r->se_panic)
 237                 return (1);
 238         if (l->se_panic < r->se_panic)
 239                 return (-1);
 240 
 241         if (forsort) {
 242                 /* put large counts earlier */
 243                 if (l->se_count > r->se_count)
 244                         return (-1);
 245                 if (l->se_count < r->se_count)
 246                         return (1);
 247         }


 281         }
 282 
 283         if (l->se_overflow > r->se_overflow)
 284                 return (-1);
 285         if (l->se_overflow < r->se_overflow)
 286                 return (1);
 287 
 288         if (l->se_depth > r->se_depth)
 289                 return (1);
 290         if (l->se_depth < r->se_depth)
 291                 return (-1);
 292 
 293         if (l->se_sobj_ops > r->se_sobj_ops)
 294                 return (1);
 295         if (l->se_sobj_ops < r->se_sobj_ops)
 296                 return (-1);
 297 
 298         return (0);
 299 }
 300 
 301 int
 302 stacks_entry_comp(const void *l_arg, const void *r_arg)
 303 {
 304         stacks_entry_t * const *lp = l_arg;
 305         stacks_entry_t * const *rp = r_arg;
 306 
 307         return (stacks_entry_comp_impl(*lp, *rp, 1));
 308 }
 309 
 310 void
 311 stacks_cleanup(int force)
 312 {
 313         int idx = 0;
 314         stacks_entry_t *cur, *next;
 315 
 316         if (stacks_state == STACKS_STATE_CLEAN)
 317                 return;
 318 
 319         if (!force && stacks_state == STACKS_STATE_DONE)
 320                 return;
 321 


 351                                         mdb_free(next,
 352                                             STACKS_ENTRY_SIZE(next->se_depth));
 353                                 }
 354                                 stacks_array[idx] = NULL;
 355                                 mdb_free(cur, STACKS_ENTRY_SIZE(cur->se_depth));
 356                         }
 357                 }
 358                 mdb_free(stacks_array,
 359                     stacks_array_size * sizeof (*stacks_array));
 360         }
 361 
 362         stacks_findstack_cleanup();
 363 
 364         stacks_array_size = 0;
 365         stacks_state = STACKS_STATE_CLEAN;
 366         stacks_hash = NULL;
 367         stacks_array = NULL;
 368 }
 369 
 370 /*ARGSUSED*/
 371 int
 372 stacks_thread_cb(uintptr_t addr, const void *ignored, void *cbarg)
 373 {
 374         stacks_info_t *sip = cbarg;
 375         findstack_info_t *fsip = &sip->si_fsi;
 376 
 377         stacks_entry_t **sepp, *nsep, *sep;
 378         int idx;
 379         size_t depth;
 380 
 381         if (stacks_findstack(addr, fsip, 0) != DCMD_OK &&
 382             fsip->fsi_failed == FSI_FAIL_BADTHREAD) {
 383                 mdb_warn("couldn't read thread at %p\n", addr);
 384                 return (WALK_NEXT);
 385         }
 386 
 387         sip->si_count++;
 388 
 389         depth = fsip->fsi_depth;
 390         nsep = mdb_zalloc(STACKS_ENTRY_SIZE(depth), UM_SLEEP);
 391         nsep->se_thread = addr;


 404         for (sepp = &sip->si_hash[stacks_hash_entry(nsep)];
 405             (sep = *sepp) != NULL;
 406             sepp = &sep->se_next) {
 407 
 408                 if (stacks_entry_comp_impl(sep, nsep, 0) != 0)
 409                         continue;
 410 
 411                 nsep->se_dup = sep->se_dup;
 412                 sep->se_dup = nsep;
 413                 sep->se_count++;
 414                 return (WALK_NEXT);
 415         }
 416 
 417         nsep->se_next = NULL;
 418         *sepp = nsep;
 419         sip->si_entries++;
 420 
 421         return (WALK_NEXT);
 422 }
 423 
 424 int
 425 stacks_run_tlist(mdb_pipe_t *tlist, stacks_info_t *si)
 426 {
 427         size_t idx;
 428         size_t found = 0;
 429         int ret;
 430 
 431         for (idx = 0; idx < tlist->pipe_len; idx++) {
 432                 uintptr_t addr = tlist->pipe_data[idx];
 433 
 434                 found++;
 435 
 436                 ret = stacks_thread_cb(addr, NULL, si);
 437                 if (ret == WALK_DONE)
 438                         break;
 439                 if (ret != WALK_NEXT)
 440                         return (-1);
 441         }
 442 
 443         if (found)
 444                 return (0);
 445         return (-1);
 446 }
 447 
 448 int
 449 stacks_run(int verbose, mdb_pipe_t *tlist)
 450 {
 451         stacks_info_t si;
 452         findstack_info_t *fsip = &si.si_fsi;
 453         size_t idx;
 454         stacks_entry_t **cur;
 455 
 456         bzero(&si, sizeof (si));
 457 
 458         stacks_state = STACKS_STATE_DIRTY;
 459 
 460         stacks_hash = si.si_hash =
 461             mdb_zalloc(STACKS_HSIZE * sizeof (*si.si_hash), UM_SLEEP);
 462         si.si_entries = 0;
 463         si.si_count = 0;
 464 
 465         fsip->fsi_max_depth = STACKS_MAX_DEPTH;
 466         fsip->fsi_stack =
 467             mdb_alloc(fsip->fsi_max_depth * sizeof (*fsip->fsi_stack),
 468             UM_SLEEP | UM_GC);




   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2013, Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  25  * Copyright 2018 Joyent, Inc.
  26  */
  27 
  28 #include <mdb/mdb_modapi.h>
  29 #include <mdb/mdb_ctf.h>
  30 
  31 #include <sys/types.h>
  32 #include <sys/regset.h>
  33 #include <sys/stack.h>
  34 #include <sys/thread.h>
  35 #include <sys/modctl.h>
  36 #include <assert.h>
  37 
  38 #include "findstack.h"
  39 #include "thread.h"
  40 #include "sobj.h"
  41 
  42 /*
  43  * Parts of this file are shared between targets, but this section is only
  44  * used for KVM and KMDB.
  45  */
  46 #ifdef _KERNEL
  47 
  48 int findstack_debug_on = 0;
  49 
  50 /*
  51  * "sp" is a kernel VA.
  52  */
  53 static int
  54 print_stack(uintptr_t sp, uintptr_t pc, uintptr_t addr,
  55     int argc, const mdb_arg_t *argv, int free_state)
  56 {
  57         int showargs = 0, count, err;
  58         char tdesc[128] = "";
  59 
  60         count = mdb_getopts(argc, argv,
  61             'v', MDB_OPT_SETBITS, TRUE, &showargs, NULL);
  62         argc -= count;
  63         argv += count;
  64 
  65         if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING))
  66                 return (DCMD_USAGE);
  67 
  68         (void) thread_getdesc(addr, B_TRUE, tdesc, sizeof (tdesc));
  69 
  70         mdb_printf("stack pointer for thread %p%s (%s): %p\n",
  71             addr, (free_state ? " (TS_FREE)" : ""), tdesc, sp);
  72         if (pc != 0)
  73                 mdb_printf("[ %0?lr %a() ]\n", sp, pc);
  74 
  75         mdb_inc_indent(2);
  76         mdb_set_dot(sp);
  77 
  78         if (argc == 1)
  79                 err = mdb_eval(argv->a_un.a_str);
  80         else if (showargs)
  81                 err = mdb_eval("<.$C");
  82         else
  83                 err = mdb_eval("<.$C0");
  84 
  85         mdb_dec_indent(2);
  86 
  87         return ((err == -1) ? DCMD_ABORT : DCMD_OK);
  88 }
  89 
  90 int
  91 findstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)


 101         if ((retval = stacks_findstack(addr, &fsi, 1)) != DCMD_OK ||
 102             fsi.fsi_failed)
 103                 return (retval);
 104 
 105         return (print_stack(fsi.fsi_sp, fsi.fsi_pc, addr,
 106             argc, argv, fsi.fsi_tstate == TS_FREE));
 107 }
 108 
 109 /*ARGSUSED*/
 110 int
 111 findstack_debug(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *av)
 112 {
 113         findstack_debug_on ^= 1;
 114 
 115         mdb_printf("findstack: debugging is now %s\n",
 116             findstack_debug_on ? "on" : "off");
 117 
 118         return (DCMD_OK);
 119 }
 120 
 121 #endif /* _KERNEL */
 122 
 123 static void
 124 uppercase(char *p)
 125 {
 126         for (; *p != '\0'; p++) {
 127                 if (*p >= 'a' && *p <= 'z')
 128                         *p += 'A' - 'a';
 129         }
 130 }
 131 
 132 static void
 133 sobj_to_text(uintptr_t addr, char *out, size_t out_sz)
 134 {
 135         sobj_ops_to_text(addr, out, out_sz);
 136         uppercase(out);
 137 }
 138 
 139 #define SOBJ_ALL        1
 140 
 141 static int
 142 text_to_sobj(const char *text, uintptr_t *out)


 192 
 193 /* Maximum stack depth reported in stacks */
 194 #define STACKS_MAX_DEPTH        254
 195 
 196 typedef struct stacks_info {
 197         size_t          si_count;       /* total stacks_entry_ts (incl dups) */
 198         size_t          si_entries;     /* # entries in hash table */
 199         stacks_entry_t  **si_hash;      /* hash table */
 200         findstack_info_t si_fsi;        /* transient callback state */
 201 } stacks_info_t;
 202 
 203 /* global state cached between invocations */
 204 #define STACKS_STATE_CLEAN      0
 205 #define STACKS_STATE_DIRTY      1
 206 #define STACKS_STATE_DONE       2
 207 static uint_t stacks_state = STACKS_STATE_CLEAN;
 208 static stacks_entry_t **stacks_hash;
 209 static stacks_entry_t **stacks_array;
 210 static size_t stacks_array_size;
 211 
 212 static size_t
 213 stacks_hash_entry(stacks_entry_t *sep)
 214 {
 215         size_t depth = sep->se_depth;
 216         uintptr_t *stack = sep->se_stack;
 217 
 218         uint64_t total = depth;
 219 
 220         while (depth > 0) {
 221                 total += *stack;
 222                 stack++; depth--;
 223         }
 224 
 225         return (total % STACKS_HSIZE);
 226 }
 227 
 228 /*
 229  * This is used to both compare stacks for equality and to sort the final
 230  * list of unique stacks.  forsort specifies the latter behavior, which
 231  * additionally:
 232  *      compares se_count, and
 233  *      sorts the stacks by text function name.
 234  *
 235  * The equality test is independent of se_count, and doesn't care about
 236  * relative ordering, so we don't do the extra work of looking up symbols
 237  * for the stack addresses.
 238  */
 239 static int
 240 stacks_entry_comp_impl(stacks_entry_t *l, stacks_entry_t *r,
 241     uint_t forsort)
 242 {
 243         int idx;
 244 
 245         int depth = MIN(l->se_depth, r->se_depth);
 246 
 247         /* no matter what, panic stacks come last. */
 248         if (l->se_panic > r->se_panic)
 249                 return (1);
 250         if (l->se_panic < r->se_panic)
 251                 return (-1);
 252 
 253         if (forsort) {
 254                 /* put large counts earlier */
 255                 if (l->se_count > r->se_count)
 256                         return (-1);
 257                 if (l->se_count < r->se_count)
 258                         return (1);
 259         }


 293         }
 294 
 295         if (l->se_overflow > r->se_overflow)
 296                 return (-1);
 297         if (l->se_overflow < r->se_overflow)
 298                 return (1);
 299 
 300         if (l->se_depth > r->se_depth)
 301                 return (1);
 302         if (l->se_depth < r->se_depth)
 303                 return (-1);
 304 
 305         if (l->se_sobj_ops > r->se_sobj_ops)
 306                 return (1);
 307         if (l->se_sobj_ops < r->se_sobj_ops)
 308                 return (-1);
 309 
 310         return (0);
 311 }
 312 
 313 static int
 314 stacks_entry_comp(const void *l_arg, const void *r_arg)
 315 {
 316         stacks_entry_t * const *lp = l_arg;
 317         stacks_entry_t * const *rp = r_arg;
 318 
 319         return (stacks_entry_comp_impl(*lp, *rp, 1));
 320 }
 321 
 322 void
 323 stacks_cleanup(int force)
 324 {
 325         int idx = 0;
 326         stacks_entry_t *cur, *next;
 327 
 328         if (stacks_state == STACKS_STATE_CLEAN)
 329                 return;
 330 
 331         if (!force && stacks_state == STACKS_STATE_DONE)
 332                 return;
 333 


 363                                         mdb_free(next,
 364                                             STACKS_ENTRY_SIZE(next->se_depth));
 365                                 }
 366                                 stacks_array[idx] = NULL;
 367                                 mdb_free(cur, STACKS_ENTRY_SIZE(cur->se_depth));
 368                         }
 369                 }
 370                 mdb_free(stacks_array,
 371                     stacks_array_size * sizeof (*stacks_array));
 372         }
 373 
 374         stacks_findstack_cleanup();
 375 
 376         stacks_array_size = 0;
 377         stacks_state = STACKS_STATE_CLEAN;
 378         stacks_hash = NULL;
 379         stacks_array = NULL;
 380 }
 381 
 382 /*ARGSUSED*/
 383 static int
 384 stacks_thread_cb(uintptr_t addr, const void *ignored, void *cbarg)
 385 {
 386         stacks_info_t *sip = cbarg;
 387         findstack_info_t *fsip = &sip->si_fsi;
 388 
 389         stacks_entry_t **sepp, *nsep, *sep;
 390         int idx;
 391         size_t depth;
 392 
 393         if (stacks_findstack(addr, fsip, 0) != DCMD_OK &&
 394             fsip->fsi_failed == FSI_FAIL_BADTHREAD) {
 395                 mdb_warn("couldn't read thread at %p\n", addr);
 396                 return (WALK_NEXT);
 397         }
 398 
 399         sip->si_count++;
 400 
 401         depth = fsip->fsi_depth;
 402         nsep = mdb_zalloc(STACKS_ENTRY_SIZE(depth), UM_SLEEP);
 403         nsep->se_thread = addr;


 416         for (sepp = &sip->si_hash[stacks_hash_entry(nsep)];
 417             (sep = *sepp) != NULL;
 418             sepp = &sep->se_next) {
 419 
 420                 if (stacks_entry_comp_impl(sep, nsep, 0) != 0)
 421                         continue;
 422 
 423                 nsep->se_dup = sep->se_dup;
 424                 sep->se_dup = nsep;
 425                 sep->se_count++;
 426                 return (WALK_NEXT);
 427         }
 428 
 429         nsep->se_next = NULL;
 430         *sepp = nsep;
 431         sip->si_entries++;
 432 
 433         return (WALK_NEXT);
 434 }
 435 
 436 static int
 437 stacks_run_tlist(mdb_pipe_t *tlist, stacks_info_t *si)
 438 {
 439         size_t idx;
 440         size_t found = 0;
 441         int ret;
 442 
 443         for (idx = 0; idx < tlist->pipe_len; idx++) {
 444                 uintptr_t addr = tlist->pipe_data[idx];
 445 
 446                 found++;
 447 
 448                 ret = stacks_thread_cb(addr, NULL, si);
 449                 if (ret == WALK_DONE)
 450                         break;
 451                 if (ret != WALK_NEXT)
 452                         return (-1);
 453         }
 454 
 455         if (found)
 456                 return (0);
 457         return (-1);
 458 }
 459 
 460 static int
 461 stacks_run(int verbose, mdb_pipe_t *tlist)
 462 {
 463         stacks_info_t si;
 464         findstack_info_t *fsip = &si.si_fsi;
 465         size_t idx;
 466         stacks_entry_t **cur;
 467 
 468         bzero(&si, sizeof (si));
 469 
 470         stacks_state = STACKS_STATE_DIRTY;
 471 
 472         stacks_hash = si.si_hash =
 473             mdb_zalloc(STACKS_HSIZE * sizeof (*si.si_hash), UM_SLEEP);
 474         si.si_entries = 0;
 475         si.si_count = 0;
 476 
 477         fsip->fsi_max_depth = STACKS_MAX_DEPTH;
 478         fsip->fsi_stack =
 479             mdb_alloc(fsip->fsi_max_depth * sizeof (*fsip->fsi_stack),
 480             UM_SLEEP | UM_GC);