1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2018 Jason King
  14  */
  15 
  16 #include <stdlib.h>
  17 #include <string.h>
  18 #include <errno.h>
  19 #include <pthread.h>
  20 #include <sys/debug.h>
  21 #include "demangle-sys.h"
  22 #include "demangle_int.h"
  23 
  24 #define DEMANGLE_DEBUG  "DEMANGLE_DEBUG"
  25 
  26 static pthread_once_t debug_once = PTHREAD_ONCE_INIT;
  27 volatile boolean_t demangle_debug;
  28 
  29 static sysdem_lang_t
  30 detect_lang(const char *str)
  31 {
  32         size_t n = strlen(str);
  33 
  34         if (n < 3 || str[0] != '_')
  35                 return (SYSDEM_LANG_AUTO);
  36 
  37         switch (str[1]) {
  38         case 'Z':
  39                 return (SYSDEM_LANG_CPP);
  40 
  41         case '_':
  42                 break;
  43 
  44         default:
  45                 return (SYSDEM_LANG_AUTO);
  46         }
  47 
  48         /* why they use ___Z sometimes is puzzling... *sigh* */
  49         if (str[2] == '_' && str[3] == 'Z')
  50                 return (SYSDEM_LANG_CPP);
  51 
  52         return (SYSDEM_LANG_AUTO);
  53 }
  54 
  55 static void
  56 check_debug(void)
  57 {
  58         if (getenv(DEMANGLE_DEBUG))
  59                 demangle_debug = B_TRUE;
  60 }
  61 
  62 char *
  63 sysdemangle(const char *str, sysdem_lang_t lang, sysdem_ops_t *ops)
  64 {
  65         VERIFY0(pthread_once(&debug_once, check_debug));
  66 
  67         if (ops == NULL)
  68                 ops = sysdem_ops_default;
  69 
  70         if (lang == SYSDEM_LANG_AUTO) {
  71                 lang = detect_lang(str);
  72                 if (lang == SYSDEM_LANG_AUTO) {
  73                         errno = ENOTSUP;
  74                         return (NULL);
  75                 }
  76         }
  77 
  78         switch (lang) {
  79         case SYSDEM_LANG_AUTO:
  80                 break;
  81         case SYSDEM_LANG_CPP:
  82                 return (cpp_demangle(str, ops));
  83         }
  84 
  85         errno = ENOTSUP;
  86         return (NULL);
  87 }