/* * Copyright (c) 1991-2004 by Wayne C. Gramlich. * All rights reserved. */ /* Some run-time utilities for the debugger: */ #ifndef ERROR_EXPORTS_H #include "error_exports.h" #endif #ifndef FILE_DEFS_H #include "file_defs.h" #endif #ifndef HEAP_EXPORTS_H #include "heap_exports.h" #endif #ifndef LIBC_EXPORTS_H #include "libc_exports.h" #endif #ifndef LINT_H #include "lint.h" #endif #ifndef ROUTINE_INFO_DEFS_H #include "routine_info_defs.h" #endif #ifndef RUN_TIME_DEFS_H #include "run_time_defs.h" #endif #ifndef STHEADERS_H #include "stheaders.h" #endif #ifndef STR_EXPORTS_H #include "str_exports.h" #endif #ifndef UNIX_ASSERT_H #include "unix_assert.h" #endif #ifndef UNIX_CTYPE_H #include "unix_ctype.h" #endif /* #ifndef UNIX_DLFCN_H */ /* #include "unix_dlfcn.h" */ /* #endif */ #ifndef UNIX_FCNTL_H #include "unix_fcntl.h" #endif #ifndef UNIX_MEMORY_H #include "unix_memory.h" #endif #ifndef UNIX_SIGNAL_H #include "unix_signal.h" #endif #ifndef UNIX_SYS_STAT_H #include "unix_sys_stat.h" #endif #ifndef UNIX_STDLIB_H #include "unix_stdlib.h" #endif #ifndef UNIX_UNISTD_H #include "unix_unistd.h" #endif #ifndef VECTOR_DEFS_H #include "vector_defs.h" #endif LOCAL void run__time__pipe_write(Run_time, Str, int); extern Run_time run__time__global; /* * run__time__argument_read(run_time, error_str) * This routine will read in and return an argument from * "run_time->in_file". If any error occurs, "error_str" is * printed and (Str)0 is returned. */ Str run__time__argument_read( Run_time run_time, Str error_str) { Str argument; File_argument argument_error; if (run_time->error) { return (Str)0; } argument = file_argument_read(run_time->in_file, &argument_error, run_time->heap); if (argument_error == File_argument_ok) { if (run_time->echo) { (void)printf(" %s", argument); } return argument; } else { run_time->error = 1; (void)fprintf(stderr, "%s!\n", error_str); return (Str)0; } } /* * run__time__breakpoints_prepare(run_time, routine) * This routine will cause "routine" to stop at every breakpoint. */ void run__time__breakpoints_prepare( Run_time run_time, routine___object *routine) { Heap heap; routine__info__type routine_info; int size; routine_info = run__time__routine_info_get(run_time, routine); size = (vec_size(int, routine_info->line_numbers) + 7) >> 3; if (size > run_time->breakpoints_size) { heap = run_time->heap; /* * Can't free anything without walking up the stack * and fixing everything. * heap_free(heap, (void *)run_time->breakpoints_none); * heap_free(heap, (void *)run_time->breakpoints_stop); */ run_time->breakpoints_none = (char *)heap_alloc(heap, size); run_time->breakpoints_stop = (char *)heap_alloc(heap, size); (void)memset(run_time->breakpoints_none, '\0', size); (void)memset(run_time->breakpoints_stop, '\377', size); run_time->breakpoints_size = size; } } /* * run__time__chr_non_white_peek(run_time) * This routine will return the next non-white character from * "run_time->in_file". */ int run__time__chr_non_white_peek( Run_time run_time) { return file_chr_non_white_peek(run_time->in_file); } /* * run__time__env_delete(run_time, env_var_name) * This routine will delete "env_var_name" from the enviroment. * If "env_var_name" does not exist, 1 is returned; otherwise * 0 is returned. */ int run__time__env_delete( Run_time run_time, Str env_var_name) { int bytes; extern Str *environ; Str env_var; Str *env_vars; int env_var_index; int env_vars_size; int size; size = strlen(env_var_name); env_vars = environ; env_var_index = -1; env_vars_size = 0; while ((env_var = *env_vars++) != (Str)0) { if ((strncmp(env_var_name, env_var, size) == 0) && (env_var[size] = '=')) { env_var_index = env_vars_size; } env_vars_size++; } if (env_var_index < 0) { return 1; } bytes = sizeof(Str) * env_vars_size; env_vars = (Str *)heap_alloc(run_time->heap, bytes); (void)memcpy((Str)env_vars, (Str)environ, bytes); env_vars[env_var_index] = env_vars[env_vars_size-1]; env_vars[env_vars_size-1] = (Str)0; environ = env_vars; return 0; } /* * run__time__env_int_set(run_time, env_var_name, env_var_value) * This routine will set "env_var_name" to "env_var_value". */ void run__time__env_int_set( Run_time run_time, Str env_var_name, int env_var_value) { char number[20]; (void)sprintf(number, "%d", env_var_value); run__time__env_str_set(run_time, env_var_name, number); } /* * run__time__env_state_set(run_time, std_state) * This routine will set the program's state to "std_state". */ void run__time__env_state_set( Run_time run_time, Std_state std_state) { run_time->std_state = std_state; run__time__env_int_set(run_time, "STD_STATE", (int)std_state); } /* * run__time__env_str_get(run_time, env_var_name) * This will return the string value of "env_var_name". * A fatal error occurs is "env_var_name" does not exists. */ /* ARGSUSED */ Str run__time__env_str_get( Run_time run_time, Str env_var_name) { Str env_var_value; env_var_value = getenv(env_var_name); if (env_var_value == (Str)0) { (void)fprintf(stderr, "Environment variable `%s' not found!\n", env_var_name); assert_fail(); } return env_var_value; } /* * run__time__env_str_set(run_time, env_var_name, env_var_value) * This routine will set "env_var_name" to "env_var_value". */ void run__time__env_str_set( Run_time run_time, Str env_var_name, Str env_var_value) { Str env_var; Strvec strvec; strvec = run_time->strvec; strvec_erase(strvec); strvec_print(strvec, "%s=%s", env_var_name, env_var_value); env_var = strvec_str_get(strvec, run_time->heap); assert(putenv(env_var) == 0); } /* * run__time__eol_read(run_time) * This routine will read and ignore all characters up to and include * the next new-line character. */ void run__time__eol_read( Run_time run_time) { int chr; File in_file; Vec(File) stack; in_file = run_time->in_file; for (;;) { chr = file_chr_read(in_file); switch (chr) { case EOF: /* Treat end-of-file as end-of-line: */ run_time->eol_chr = chr; run_time->error = 0; stack = run_time->in_file_stack; for (;;) { if (vec_empty(File, stack)) { file_close(in_file); run_time->in_file = file_open("/dev/tty", 1, run_time->heap); return; } /* Lie about EOL chr to force a prompt. */ run_time->eol_chr = '\n'; in_file = vec_pop(File, stack); run_time->in_file = in_file; if (vec_empty(File, stack)) { return; } chr = file_chr_peek(in_file); if (chr != EOF) { return; } } /* NOTREACHED */ case '\n': if (run_time->echo) { (void)printf("\n"); } run_time->eol_chr = chr; run_time->error = 0; return; case ';': run_time->eol_chr = chr; if (!run_time->error) { if (run_time->echo) { (void)printf(";"); } return; } break; } } } /* * run__time__eol_test(run_time) * This routine will return 1 if we are at the logical end-of-line. */ int run__time__eol_test( Run_time run_time) { int chr; chr = file_chr_non_white_peek(run_time->in_file); switch (chr) { case EOF: case ';': case '\n': return 1; } return 0; } /* * run__time__int_read(run_time, error) * This routine will read an integer from "run_time". If there is * any error, "error" is printed and -1 is returned. */ int run__time__int_read( Run_time run_time, Str error) { Str number; number = run__time__argument_read(run_time, error); if (number == (Str)0) { return -1; } if (isdigit(number[0])) { return atoi(number); } else { (void)fprintf(stderr, "%s!\n", error); return -1; } } /* * run__time__line_display(run_time, routine, line_number, is_call_stack) * This routine will display the "line_number'th" line of "routine". */ void run__time__line_display( Run_time run_time, routine___object *routine, int line_number, int is_call_stack) { char file_name[2000]; Stdio in_file; int index; char line[2000]; module___object *module; Str new_file_name; routine__info__type routine_info; /* Decide whether to use generate file: */ module = routine->module; routine_info = routine->routine_info; assert(routine_info != (routine__info__type)0); if ((module->generate_boundary < 0) || (line_number <= module->generate_boundary)) { new_file_name = module->file_name; } else { new_file_name = module->generate_name; line_number -= module->generate_boundary; } if ((run_time->last_file_name != (Str)0) && !strequal(run_time->last_file_name, new_file_name)) { if (run_time->last_in_file != (Stdio)0) { (void)fclose(run_time->last_in_file); } run_time->last_in_file = (Stdio)0; run_time->last_module = module; run_time->last_file_name = (Str)0; } if (run_time->last_file_name == (Str)0) { run_time->last_file_name = new_file_name; } if (run_time->pipe_fd >= 0) { if (is_call_stack) { run__time__pipe_command(run_time, Dbxtool_cmd_callstack); run__time__pipe_string(run_time, new_file_name); run__time__pipe_integer(run_time, line_number); } else { run__time__pipe_command(run_time, Dbxtool_cmd_stopped); run__time__pipe_string(run_time, new_file_name); run__time__pipe_string(run_time, routine_info->name); run__time__pipe_integer(run_time, line_number); run__time__pipe_string(run_time, new_file_name); run__time__pipe_string(run_time, routine_info->name); run__time__pipe_integer(run_time, line_number); } return; } else { in_file = run_time->last_in_file; if (in_file == (Stdio)0) { in_file = fopen(new_file_name, "r"); if (in_file == (Stdio)0) { error_warn("Could not open %s\n", new_file_name); run_time->last_module = (module___object *)0; run_time->last_file_name = (Str)0; return; } run_time->last_in_file = in_file; } (void)fseek(in_file, 0L, 0); for (index = 1; index <= line_number; index++) { if (fgets(line, sizeof(line), in_file) == (Str)0) { error_warn("Could not find line %d in %s\n", line_number, file_name); return; } } (void)printf("%d\t", line_number); (void)fputs(line, stdout); } } /* * run__time__lower_case(text) * This routine will convert each character in "text" to lower case. */ void run__time__lower_case( Str text) { int chr; while ((chr = *text) != '\0') { *text++ = tolower(chr); } } /* * run__time__pipe_command(run_time, command) * This routine will send "command" to dbxtool if the dbxtool pipe is * open; otherwise, it will do nothing. */ void run__time__pipe_command( Run_time run_time, Dbxtool_cmd command) { if (run_time->pipe_fd >= 0) { run__time__pipe_write(run_time, (Str)&command, sizeof(command)); } } /* * run__time__pipe_initialize(run_time, pipe_fd) * This routine will initialize the pipe connection to stdtool * (alias dbxtool) using the pipe on file descriptor "pipe_fd". */ void run__time__pipe_initialize( Run_time run_time, int pipe_fd) { run_time->pipe_fd = pipe_fd; run__time__pipe_command(run_time, Dbxtool_cmd_version); run__time__pipe_integer(run_time, 3); run__time__pipe_command(run_time, Dbxtool_cmd_newinitdone); run__time__pipe_string(run_time, ""); run__time__pipe_string(run_time, ""); run__time__pipe_integer(run_time, 0); run__time__pipe_string(run_time, ""); run__time__pipe_string(run_time, ""); run__time__pipe_integer(run_time, 0); } /* * run__time__pipe_string(run_time, text) * This routine will send "text" to dbxtool via the dbxtool pipe if it * is open; otherwise it will do nothing. */ void run__time__pipe_string( Run_time run_time, Str text) { int length; if (run_time->pipe_fd >= 0) { run__time__pipe_command(run_time, Dbxtool_cmd_string); length = strlen(text) + 1; run__time__pipe_write(run_time, (Str)&length, sizeof(length)); run__time__pipe_write(run_time, text, length); } } /* * run__time__pipe_integer(run_time, integer) * This routine will send "integer" to dbxtool via the dbxtool pipe * (if it is open); otherwise, it will do nothing. */ void run__time__pipe_integer( Run_time run_time, int integer) { if (run_time->pipe_fd >= 0) { run__time__pipe_command(run_time, Dbxtool_cmd_int); run__time__pipe_write(run_time, (Str)&integer, sizeof(integer)); } } /* * run__time__pipe_write(run_time, buffer, size) * This routine will write "size" bytes of "buffer" to the dbxtool pipe. */ void run__time__pipe_write( Run_time run_time, Str buffer, int size) { if (write(run_time->pipe_fd, buffer, size) < 0) { error_fatal("Pipe write failed!\n"); } } /* * run__time__routine_info_get(run_time, routine) * This routine will get the routine information object for "routine" * using "run_time". */ routine__info__type run__time__routine_info_get( Run_time run_time, routine___object *routine) { char *breakpoints; Heap heap; routine__info__type routine_info; int size; routine_info = routine->routine_info; if (routine_info == (routine__info__type)0) { heap = run_time->heap; routine_info = routine__info__parse(routine->info, heap); routine->routine_info = routine_info; size = vec_size(int, routine_info->line_numbers); size = (size + 7) >> 3; breakpoints = (char *)heap_alloc(heap, size); (void)memset(breakpoints, 0, size); routine_info->breakpoints = breakpoints; } return routine_info; } /* * run__time__signals_disable() * This routine will disable signals. */ void run__time__signals_disable(void) { #ifdef OLD_OLD sigset_t signal_set; (void)sigemptyset(&signal_set); (void)sigaddset(&signal_set, SIGBUS); (void)sigaddset(&signal_set, SIGINT); (void)sigaddset(&signal_set, SIGSEGV); assert(sigprocmask(SIG_BLOCK, &signal_set, (sigset_t *)0) == 0); foo(); #endif /* OLD */ } /* * run__time__signals_enable() * This routine will enable signals. */ void run__time__signals_enable(void) { #ifdef OLD_OLD sigset_t signal_set; (void)sigemptyset(&signal_set); (void)sigaddset(&signal_set, SIGBUS); (void)sigaddset(&signal_set, SIGINT); (void)sigaddset(&signal_set, SIGSEGV); assert(sigprocmask(SIG_UNBLOCK, &signal_set, (sigset_t *)0) == 0); #endif /* OLD */ } /* * run__time__string_read(run_time, error_str) * This routine will read in and return an string from "in_file". * If any error occurs, "error_str" is printed and (Str)0 is returned. */ Str run__time__string_read( Run_time run_time, Str error_str) { Str string; File_string string_error; if (run_time->error) { return (Str)0; } string = file_string_read(run_time->in_file, &string_error, run_time->heap); switch (string_error) { case File_string_single_quoted: case File_string_double_quoted: if (run_time->echo) { char chr; char *pointer; pointer = string; (void)printf(" \""); while (chr = *pointer++) { if ((isprint(chr) && (chr != '"')) || (chr == ' ')) { (void)printf("%c", chr); } else { (void)printf("\\%3o", chr); } } (void)printf("\""); } return string; default: run_time->error = 1; (void)fprintf(stderr, "%s!\n", error_str); return (Str)0; } }