/*
   This file is part of Callgrind, a Valgrind skin for call graph
   profiling programs.

   Copyright (C) 2002-2004, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)

   This skin is derived from and contains lot of code from Cachegrind
   Copyright (C) 2002 Nicholas Nethercote (njn25@cam.ac.uk)

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.

   The GNU General Public License is contained in the file COPYING.
*/

#include "ct_include.h"



/*------------------------------------------------------------*/
/*--- Function specific configuration options              ---*/
/*------------------------------------------------------------*/

#define CONFIG_DEFAULT -1
#define CONFIG_FALSE   0
#define CONFIG_TRUE    1

/* Logging configuration for a function */
struct _fn_config {
    Char* name;

    Int dump_before;
    Int dump_after;
    Int zero_before;
    Int toggle_collect;

    Int skip;    /* Handle CALL to this function as JMP (= Skip)? */
    Int group;   /* don't change caller dependency inside group !=0 */

    Int separate_callers;    /* separate logging dependent on caller  */
    Int separate_recursions; /* separate logging of rec. levels       */

#if CT_ENABLE_DEBUG
    Int verbosity; /* Change debug verbosity level while in function */
#endif

    fn_config* next;
};

/* Configurations for function name prefix patterns.
 * Currently, only very limit patterns are possible:
 * Exact prefix patterns and "*::" are allowed.
 * E.g.
 *  - "abc" matches all functions starting with "abc".
 *  - "abc*::def" matches all functions starting with "abc" and
 *    starting with "def" after the first "::" separator.
 *  - "*::print(" matches C++ methods "print" in all classes
 *    without namespace. I.e. "*" doesn't match a "::".
 *
 * We build a trie from patterns, and for a given function, we
 * go down the tree and apply all non-default configurations.
 */


#define NODE_DEGREE 30

/* node of compressed trie search structure */
typedef struct _config_node config_node;
struct _config_node {
    Char* name;
    Int length;
    
    fn_config* config;
    config_node* sub_node[NODE_DEGREE];
    config_node* cpp_sep;
};

/* root of trie */
static config_node* fn_configs = 0;

static __inline__ 
fn_config* new_fnc(Char* name)
{
   fn_config* new = VG_(malloc)(sizeof(fn_config));

   new->name = VG_(strdup)(name);
   new->next = 0;

   new->dump_before  = CONFIG_DEFAULT;
   new->dump_after   = CONFIG_DEFAULT;
   new->zero_before  = CONFIG_DEFAULT;
   new->toggle_collect = CONFIG_DEFAULT;
   new->skip         = CONFIG_DEFAULT;
   new->group        = CONFIG_DEFAULT;
   new->separate_callers    = CONFIG_DEFAULT;
   new->separate_recursions = CONFIG_DEFAULT;

#if CT_ENABLE_DEBUG
   new->verbosity    = CONFIG_DEFAULT;
#endif

   CT_DEBUG(2, "  new_fnc('%s')\n", name);

   return new;
}


static fn_config* get_fnc1(fn_config** pfnc, Char* name)
{
    fn_config* fnc = *pfnc;
    while(fnc) {
	if (VG_(strcmp)(fnc->name,name) == 0) break;
	fnc = fnc->next;
    }
    if (!fnc) {
	fnc = new_fnc(name);
	fnc->next = *pfnc;
	*pfnc = fnc;
    }
    return fnc;
}


static config_node* new_config(Char* name, int length)
{
    int i;
    config_node* node = VG_(malloc)(sizeof(config_node));

    node->name   = name;
    node->length = length;
    node->config = 0;
    for(i=0;i<NODE_DEGREE;i++)
	node->sub_node[i] = 0;
    node->cpp_sep = 0;

    CT_DEBUG(2, "  new_config('%s', len %d)\n", name, length);

    return node;
}

/* Search first wildcard, with optionally appended cpp separator ("::").
 * if not found, *(return) is 0
 */
static Char* next_wild_cpp_sep(Char* n)
{
    while(*n!=0) {
	if (*n == '*') {
	    n++;
	    if (*n == ':') {
		n++;
		if (*n == ':') {
		    n++;
		}
	    }
	    return n;
	}
	n++;
    }
    return n;
}

/* Get function config for a specific name in search tree */
static fn_config* get_fnc2(config_node** pnode, Char* name, int offset)
{
    config_node* node;
    fn_config* fnc;
    Char* cpp_sep;

    CT_ASSERT(pnode != 0);
    node = *pnode;

    if (node == 0) {
	fnc = new_fnc(name);
	cpp_sep = next_wild_cpp_sep(name+offset);
	if (*cpp_sep) {
	    /* found wildcard */
	    int newOffset = cpp_sep - name;
	    node = new_config(name, offset);
	    node->config = fnc;
	    *pnode = node;
	    CT_DEBUG(3, "  get_config('%s', off %d, new %d): cpp_sep\n",
		     name, offset, newOffset);
	    /* recurse */
	    return get_fnc2( &(node->cpp_sep), cpp_sep, newOffset);
	}
	node = new_config(fnc->name, VG_(strlen)(fnc->name));
	node->config = fnc;
	*pnode = node;

	CT_DEBUG(3, "  get_config('%s', offset %d): new\n",
		 name, offset);

	return fnc;
    }
    
    if (name[offset] == 0) {
	CT_DEBUG(3, "  get_config('%s', off %d): found\n", name, offset);
	return get_fnc1(&node->config, name);
    }

    if (name[offset] == '*') {
	/* the "::" is optional in the pattern */
	offset++;
	if (name[offset] == ':') {
	    offset++;
	    if (name[offset] == ':') offset++;
	}
	CT_DEBUG(3, "  get_config('%s', off %d): cpp_sep\n", name, offset);
	return get_fnc2( &(node->cpp_sep), name+offset, 0);
    }

    /* FIXME: Should handle wildcard */
    while(offset < node->length) {
	if ((name[offset] == 0)  ||
	    ((name[offset]%NODE_DEGREE) != (node->name[offset]%NODE_DEGREE)))
	    break;
	offset++;
    }

    /* name is shorter or different as nodes name */
    if (offset < node->length) {
	config_node* new;

	/* split up this node */
	fnc = new_fnc(name);
	new = new_config(node->name, offset);

	new->sub_node[ node->name[offset]%NODE_DEGREE ] = node;
	    
	if (name[offset]==0) {
	    /* no subnode, insert into new node */
	    new->config = fnc;
	}
	else {
	    config_node* new2 = new_config(node->name, VG_(strlen)(name));
	    new->sub_node[ name[offset]%NODE_DEGREE ] = new2;
	    new2->config = fnc;
	}
	*pnode = new;

	CT_DEBUG(3, "  get_config('%s', off %d): splitted\n", name, offset);

	return fnc;
    }

    /* name and node name are congruent */
    if (name[offset] == 0) {
	CT_DEBUG(3, "  get_config('%s', off %d): found\n", name, offset);
	return get_fnc1(&node->config, name);
    }

    /* name is longer than the nodes name: append new node */
    CT_DEBUG(3, "  get_config('%s', off %d): next\n", name, offset);

    /* recurse */
    return get_fnc2( &(node->sub_node[ name[offset]%NODE_DEGREE ]),
		     name, offset);
}

/* get a function config for a given prefix name */
static fn_config* get_fnc(Char* name)
{
    return get_fnc2(&fn_configs, name, 0);
}


static void update_fn_config1(fn_node* fn, fn_config* fnc)
{
    if (fnc->dump_before != CONFIG_DEFAULT)
	fn->dump_before = (fnc->dump_before == CONFIG_TRUE);

    if (fnc->dump_after != CONFIG_DEFAULT)
	fn->dump_after = (fnc->dump_after == CONFIG_TRUE);

    if (fnc->zero_before != CONFIG_DEFAULT)
	fn->zero_before = (fnc->zero_before == CONFIG_TRUE);

    if (fnc->toggle_collect != CONFIG_DEFAULT)
	fn->toggle_collect = (fnc->toggle_collect == CONFIG_TRUE);

    if (fnc->skip != CONFIG_DEFAULT)
	fn->skip = (fnc->skip == CONFIG_TRUE);

    if (fnc->group != CONFIG_DEFAULT)
	fn->group = fnc->group;

    if (fnc->separate_callers != CONFIG_DEFAULT)
	fn->separate_callers = fnc->separate_callers;

    if (fnc->separate_recursions != CONFIG_DEFAULT)
	fn->separate_recursions = fnc->separate_recursions;

#if CT_ENABLE_DEBUG
    if (fnc->verbosity != CONFIG_DEFAULT)
	fn->verbosity = fnc->verbosity;
#endif
}

/* Search first cpp separator ("::").
 * if not found, m[return] is 0
 */
static Int next_cpp_sep(Char* n)
{
    Int p = 0;
    while(n[p]!=0) {
	if (n[p] == ':') {
	    p++;
	    if (n[p] == ':') {
		p++;
		return p;
	    }
	}
	p++;
    }
    return p;
}

static void update_fn_config2(fn_node* fn, char* name, config_node* node)
{
    fn_config* fnc;
    int len, cpp_sep_pos = -1;

    len = next_cpp_sep(name);
    if (name[len]) {
	cpp_sep_pos = len;
	while(name[len]) len++;

	CT_DEBUG(3, "  update_fn_config('%s', off %d): cpp_sep\n",
		 name, cpp_sep_pos);
    }

    while(node && (node->length <= len)) {
	fnc = node->config;
	while(fnc) {
	    if (VG_(strncmp)(fnc->name,name,node->length) == 0) break;
	    fnc = fnc->next;
	}
    
	if (fnc) {
	    CT_DEBUG(3, "  update_fn_config('%s', len %d): found\n",
		     fnc->name, node->length);

	    update_fn_config1(fn, fnc);

	    /* recurse on wildcard patterns (depth first search).
	     * Better would be to build a state machine...
	     */
	    if (node->cpp_sep && cpp_sep_pos>0)
		update_fn_config2(fn, name + cpp_sep_pos, node->cpp_sep);
	}

	if (name[node->length] == 0) break;
	node = node->sub_node[ name[node->length]%NODE_DEGREE ];
    }
}

/* Update function config according to configs of name prefixes */
void SK_(update_fn_config)(fn_node* fn)
{
    CT_DEBUG(3, "  update_fn_config('%s')\n", fn->name);
    update_fn_config2(fn, fn->name, fn_configs);
}


/*--------------------------------------------------------------------*/
/*--- Command line processing                                      ---*/
/*--------------------------------------------------------------------*/

#define UNDEFINED_CACHE     ((cache_t) { -1, -1, -1 }) 

static cache_t clo_I1_cache = UNDEFINED_CACHE;
static cache_t clo_D1_cache = UNDEFINED_CACHE;
static cache_t clo_L2_cache = UNDEFINED_CACHE;

static void parse_cache_opt ( cache_t* cache, char* orig_opt, int opt_len )
{
   int   i1, i2, i3;
   int   i;
   char *opt = VG_(strdup)(orig_opt);

   i = i1 = opt_len;

   /* Option looks like "--I1=65536,2,64".
    * Find commas, replace with NULs to make three independent 
    * strings, then extract numbers.  Yuck. */
   while (VG_(isdigit)(opt[i])) i++;
   if (',' == opt[i]) {
      opt[i++] = '\0';
      i2 = i;
   } else goto bad;
   while (VG_(isdigit)(opt[i])) i++;
   if (',' == opt[i]) {
      opt[i++] = '\0';
      i3 = i;
   } else goto bad;
   while (VG_(isdigit)(opt[i])) i++;
   if ('\0' != opt[i]) goto bad;

   cache->size      = (Int)VG_(atoll)(opt + i1);
   cache->assoc     = (Int)VG_(atoll)(opt + i2);
   cache->line_size = (Int)VG_(atoll)(opt + i3);

   VG_(free)(opt);

   return;

  bad:
   VG_(bad_option)(orig_opt);
}

static Char* getUInt(Char* s, UInt* pn)
{
    UInt n = 0;
    while((*s >='0') && (*s <='9')) {
	n = 10*n + (*s-'0');
	s++;
    }
    if (pn) *pn = n;
    return s;
}

Bool SK_(process_cmd_line_option)(Char* arg)
{
   if (0 == VG_(strcmp)(arg, "--skip-plt=yes"))
       SK_(clo).skip_plt = True;
   else if (0 == VG_(strcmp)(arg, "--skip-plt=no"))
       SK_(clo).skip_plt = False;

   else if (0 == VG_(strcmp)(arg, "--collect-jumps=yes"))
       SK_(clo).collect_jumps = True;
   else if (0 == VG_(strcmp)(arg, "--collect-jumps=no"))
       SK_(clo).collect_jumps = False;
   /* compatibility alias, deprecated option */
   else if (0 == VG_(strcmp)(arg, "--trace-jump=yes"))
       SK_(clo).collect_jumps = True;
   else if (0 == VG_(strcmp)(arg, "--trace-jump=no"))
       SK_(clo).collect_jumps = False;

   else if (0 == VG_(strcmp)(arg, "--separate-dumps=yes"))
       SK_(clo).separate_dumps = True;
   else if (0 == VG_(strcmp)(arg, "--separate-dumps=no"))
       SK_(clo).separate_dumps = False;

   else if (0 == VG_(strcmp)(arg, "--simulate-cache=yes"))
       SK_(clo).simulate_cache = True;
   else if (0 == VG_(strcmp)(arg, "--simulate-cache=no"))
       SK_(clo).simulate_cache = False;

   else if (0 == VG_(strcmp)(arg, "--collect-data=yes"))
       SK_(clo).collect_data = True;
   else if (0 == VG_(strcmp)(arg, "--collect-data=no"))
       SK_(clo).collect_data = False;

#ifdef CT_HWPREFETCH
   else if (0 == VG_(strcmp)(arg, "--simulate-hwpref=yes"))
       SK_(clo).simulate_hwpref = True;
   else if (0 == VG_(strcmp)(arg, "--simulate-hwpref=no"))
       SK_(clo).simulate_hwpref = False;
#endif

   else if (0 == VG_(strcmp)(arg, "--collect-atstart=yes"))
       SK_(clo).collect_atstart = True;
   else if (0 == VG_(strcmp)(arg, "--collect-atstart=no"))
       SK_(clo).collect_atstart = False;

   else if (0 == VG_(strcmp)(arg, "--instr-atstart=yes"))
       SK_(clo).instrument_atstart = True;
   else if (0 == VG_(strcmp)(arg, "--instr-atstart=no"))
       SK_(clo).instrument_atstart = False;

   else if (0 == VG_(strcmp)(arg, "--separate-threads=yes"))
       SK_(clo).separate_threads = True;
   else if (0 == VG_(strcmp)(arg, "--separate-threads=no"))
       SK_(clo).separate_threads = False;
   /* compatibility alias, deprecated option */
   else if (0 == VG_(strcmp)(arg, "--dump-threads=yes"))
       SK_(clo).separate_threads = True;
   else if (0 == VG_(strcmp)(arg, "--dump-threads=no"))
       SK_(clo).separate_threads = False;

   else if (0 == VG_(strcmp)(arg, "--compress-strings=yes"))
       SK_(clo).compress_strings = True;
   else if (0 == VG_(strcmp)(arg, "--compress-strings=no"))
       SK_(clo).compress_strings = False;

   else if (0 == VG_(strcmp)(arg, "--compress-mangled=yes"))
       SK_(clo).compress_mangled = True;
   else if (0 == VG_(strcmp)(arg, "--compress-mangled=no"))
       SK_(clo).compress_mangled = False;

   else if (0 == VG_(strcmp)(arg, "--compress-pos=yes"))
       SK_(clo).compress_pos = True;
   else if (0 == VG_(strcmp)(arg, "--compress-pos=no"))
       SK_(clo).compress_pos = False;

   else if (0 == VG_(strncmp)(arg, "--fn-skip=", 10)) {
       fn_config* fnc = get_fnc(arg+10);
       fnc->skip = CONFIG_TRUE;
   }

   else if (0 == VG_(strncmp)(arg, "--dump-before=", 14)) {
       fn_config* fnc = get_fnc(arg+14);
       fnc->dump_before = CONFIG_TRUE;
   }

   else if (0 == VG_(strncmp)(arg, "--zero-before=", 14)) {
       fn_config* fnc = get_fnc(arg+14);
       fnc->zero_before = CONFIG_TRUE;
   }

   else if (0 == VG_(strncmp)(arg, "--dump-after=", 13)) {
       fn_config* fnc = get_fnc(arg+13);
       fnc->dump_after = CONFIG_TRUE;
   }

   else if (0 == VG_(strncmp)(arg, "--toggle-collect=", 17)) {
       fn_config* fnc = get_fnc(arg+17);
       fnc->toggle_collect = CONFIG_TRUE;
       /* defaults to initial collection off */
       SK_(clo).collect_atstart = False;
   }

   else if (0 == VG_(strncmp)(arg, "--separate-recs=", 16))
        SK_(clo).separate_recursions = (Int)VG_(atoll)(&arg[16]);

#if CT_ENABLE_DEBUG
   else if (0 == VG_(strncmp)(arg, "--ct-verbose=", 13))
        SK_(clo).verbose = (Int)VG_(atoll)(&arg[13]);

   else if (0 == VG_(strncmp)(arg, "--ct-vstart=", 12))
        SK_(clo).verbose_start = (ULong)VG_(atoll)(&arg[12]);

   else if (0 == VG_(strncmp)(arg, "--ct-verbose", 12)) {
       UInt n;
       fn_config* fnc;
       Char* s = getUInt(arg+12, &n);
       if ((n == 0) || *s != '=') return False;
       fnc = get_fnc(s+1);
       fnc->verbosity = n;
   }
#endif

   else if (0 == VG_(strncmp)(arg, "--separate-callers=", 19))
       SK_(clo).separate_callers = (Int)VG_(atoll)(&arg[19]);

   else if (0 == VG_(strncmp)(arg, "--fn-group", 10)) {
       UInt n;
       fn_config* fnc;
       Char* s = getUInt(arg+10, &n);
       if ((n == 0) || *s != '=') return False;
       fnc = get_fnc(s+1);
       fnc->group = n;
   }

   else if (0 == VG_(strncmp)(arg, "--separate-callers", 18)) {
       UInt n;
       fn_config* fnc;
       Char* s = getUInt(arg+18, &n);
       if ((n == 0) || *s != '=') return False;
       fnc = get_fnc(s+1);
       fnc->separate_callers = n;
   }

   else if (0 == VG_(strncmp)(arg, "--separate-recs", 15)) {
       UInt n;
       fn_config* fnc;
       Char* s = getUInt(arg+15, &n);
       if ((n == 0) || *s != '=') return False;
       fnc = get_fnc(s+1);
       fnc->separate_recursions = n;
   }

   else if (0 == VG_(strncmp)(arg, "--base=", 7))
       SK_(clo).filename_base = VG_(strdup)(arg+7);

   else if (0 == VG_(strcmp)(arg, "--mangle-names=yes"))
       SK_(clo).mangle_names = True;
   else if (0 == VG_(strcmp)(arg, "--mangle-names=no"))
       SK_(clo).mangle_names = False;

   else if (0 == VG_(strcmp)(arg, "--skip-direct-rec=yes"))
       SK_(clo).skip_direct_recursion = True;
   else if (0 == VG_(strcmp)(arg, "--skip-direct-rec=no"))
       SK_(clo).skip_direct_recursion = False;

   else if (0 == VG_(strcmp)(arg, "--dump-bbs=yes"))
       SK_(clo).dump_bbs = True;
   else if (0 == VG_(strcmp)(arg, "--dump-bbs=no"))
       SK_(clo).dump_bbs = False;

   else if (0 == VG_(strcmp)(arg, "--dump-line=yes"))
       SK_(clo).dump_line = True;
   else if (0 == VG_(strcmp)(arg, "--dump-line=no"))
       SK_(clo).dump_line = False;

   else if (0 == VG_(strcmp)(arg, "--dump-instr=yes"))
       SK_(clo).dump_instr = True;
   else if (0 == VG_(strcmp)(arg, "--dump-instr=no"))
       SK_(clo).dump_instr = False;

   else if (0 == VG_(strcmp)(arg, "--dump-bb=yes"))
       SK_(clo).dump_bb = True;
   else if (0 == VG_(strcmp)(arg, "--dump-bb=no"))
       SK_(clo).dump_bb = False;

   else if (0 == VG_(strncmp)(arg, "--dump-every-bb=", 16))
        SK_(clo).dump_every_bb = (Int)VG_(atoll)(&arg[16]);


   else if (0 == VG_(strcmp)(arg, "--collect-alloc=yes"))
       SK_(clo).collect_alloc = True;
   else if (0 == VG_(strcmp)(arg, "--collect-alloc=no"))
       SK_(clo).collect_alloc = False;

   else if (0 == VG_(strcmp)(arg, "--collect-systime=yes"))
       SK_(clo).collect_systime = True;
   else if (0 == VG_(strcmp)(arg, "--collect-systime=no"))
       SK_(clo).collect_systime = False;

   /* 5 is length of "--I1=" */
   else if (0 == VG_(strncmp)(arg, "--I1=", 5))
      parse_cache_opt(&clo_I1_cache, arg,   5);
   else if (0 == VG_(strncmp)(arg, "--D1=", 5))
      parse_cache_opt(&clo_D1_cache, arg,   5);
   else if (0 == VG_(strncmp)(arg, "--L2=", 5))
      parse_cache_opt(&clo_L2_cache, arg,   5);
   else
      return False;

   return True;
}

void SK_(print_usage)(void)
{
   VG_(printf)(

"    --base=<prefix>           Prefix for profile files [" DEFAULT_DUMPNAME "]\n"
"    --simulate-cache=no|yes   Full cache simulation [yes]\n"
#if CT_HWPREFETCH
"    --simulate-hwpref=no|yes  Simulate Hardware Prefetch [no]\n"
#endif
"    --instr-atstart=no|yes    Do instrumentation at callgrind start [yes]\n"
"    --collect-atstart=no|yes  Collect at process/thread start [yes]\n"
"    --collect-jumps=no|yes    Collect jumps? [no]\n"
"    --collect-alloc=no|yes    Collect memory allocation info? [no]\n"
"    --collect-systime=no|yes  Collect system call time info? [no]\n"
#if CT_DATA
"    --collect-data=no|yes     Collect data relation of events [no]\n"
#endif
"    --skip-plt=no|yes         Ignore calls to/from PLT sections? [yes]\n"
"    --fn-skip=<function>      Ignore calls to/from function?\n"
#if CT_EXPERIMENTAL
"    --fn-group<no>=<func>     Put function into separation group <no>\n"
#endif
"    --separate-threads=no|yes Separate data per thread [no]\n"
"    --separate-recs=<n>       Separate function recursions upto level [2]\n"
"    --separate-callers=<n>    Separate functions by call chain length [0]\n"
"    --separate-recs<n>=<f>    Separate <n> recursions for function <f>\n"
"    --separate-callers<n>=<f> Separate <n> callers for function <f>\n"
"    --dump-before=<func>      Dump when entering function\n"
"    --zero-before=<func>      Zero all costs when entering function\n"
"    --dump-after=<func>       Dump when leaving function\n"
"    --toggle-collect=<func>   Toggle collection on enter/leave function\n"
"    --skip-direct-rec=no|yes  Ignore direct recursions? [yes]\n"
#if CT_EXPERIMENTAL
"    --mangle-names=no|yes     Mangle separation into names? [yes]\n"
#endif
"    --compress-strings=no|yes Compress strings in profile dump? [yes]\n"
#if CT_EXPERIMENTAL
"    --compress-events=no|yes  Compress events in profile dump? [no]\n"
#endif
"    --compress-pos=no|yes     Compress positions in profile dump? [yes]\n"
"    --dump-line=no|yes        Dump source lines of costs? [yes]\n"
"    --dump-instr=no|yes       Dump instruction address of costs? [no]\n"
#if CT_EXPERIMENTAL
"    --dump-bb=no|yes          Dump basic block address of costs? [no]\n"
"    --dump-bbs=no|yes         Dump basic block info? [no]\n"
"    --dump-skipped=no|yes     Dump info on skipped functions in calls? [no]\n"
#endif
"    --dump-every-bb=<count>   Dump every <count> basic blocks [0=never]\n"
#if CT_EXPERIMENTAL
"    --separate-dumps=no|yes   Write each dump into separate file [yes]\n"
#endif
"    --I1=<size>,<assoc>,<line_size>  set I1 cache manually\n"
"    --D1=<size>,<assoc>,<line_size>  set D1 cache manually\n"
"    --L2=<size>,<assoc>,<line_size>  set L2 cache manually\n"
"\n  see " VG_LIBDIR"/../share/doc/valgrind/ct_main.html for full documentation.\n\n"

    );
}

void SK_(print_debug_usage)(void)
{
    VG_(printf)(

#if CT_ENABLE_DEBUG
"    --ct-verbose=<level>       Verbosity of standard debug output [0]\n"
"    --ct-vstart=<BB number>    Only be verbose after basic block [0]\n"
"    --ct-verbose<level>=<func> Verbosity while in <func>\n"
#else
"    (none)\n"
#endif

    );
}


void SK_(set_clo_defaults)(void)
{
  /* Default values for command line arguments */

  /* dump options */
  SK_(clo).filename_base    = 0;
  SK_(clo).separate_dumps   = True;
  SK_(clo).compress_strings = True;
  SK_(clo).compress_mangled = False;
  SK_(clo).compress_events  = False;
  SK_(clo).compress_pos     = True;
  SK_(clo).mangle_names     = True;
  SK_(clo).dump_line        = True;
  SK_(clo).dump_instr       = False;
  SK_(clo).dump_bb          = False;
  SK_(clo).dump_bbs         = False;

  SK_(clo).dump_every_bb    = 0;

  /* Collection */
  SK_(clo).separate_threads = False;
  SK_(clo).collect_data     = False;
  SK_(clo).collect_atstart  = True;
  SK_(clo).collect_jumps    = False;
  SK_(clo).collect_alloc    = False;
  SK_(clo).collect_systime  = False;

  SK_(clo).skip_plt         = True;
  SK_(clo).separate_callers = 0;
  SK_(clo).separate_recursions = 2;
  SK_(clo).skip_direct_recursion = False;

  /* Simulation */
  SK_(clo).simulate_cache   = True;
  SK_(clo).simulate_hwpref  = False;
  SK_(clo).instrument_atstart = True;

#if CT_ENABLE_DEBUG
  SK_(clo).verbose = 0;
  SK_(clo).verbose_start = 0;
#endif
}


syntax highlighted by Code2HTML, v. 0.9.1