198b9484cSchristos /* Tracing support for CGEN-based simulators. 2*88241920Schristos Copyright (C) 1996-2024 Free Software Foundation, Inc. 398b9484cSchristos Contributed by Cygnus Support. 498b9484cSchristos 598b9484cSchristos This file is part of GDB, the GNU debugger. 698b9484cSchristos 798b9484cSchristos This program is free software; you can redistribute it and/or modify 898b9484cSchristos it under the terms of the GNU General Public License as published by 998b9484cSchristos the Free Software Foundation; either version 3 of the License, or 1098b9484cSchristos (at your option) any later version. 1198b9484cSchristos 1298b9484cSchristos This program is distributed in the hope that it will be useful, 1398b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1498b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1598b9484cSchristos GNU General Public License for more details. 1698b9484cSchristos 1798b9484cSchristos You should have received a copy of the GNU General Public License 1898b9484cSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 1998b9484cSchristos 204b169a6bSchristos /* This must come before any other includes. */ 214b169a6bSchristos #include "defs.h" 224b169a6bSchristos 2398b9484cSchristos #include <errno.h> 244b169a6bSchristos #include <stdarg.h> 254b169a6bSchristos #include <stdlib.h> 264b169a6bSchristos 2798b9484cSchristos #include "bfd.h" 284b169a6bSchristos #include "diagnostics.h" 294b169a6bSchristos #include "dis-asm.h" 304b169a6bSchristos 3198b9484cSchristos #include "sim-main.h" 3298b9484cSchristos #include "sim-fpu.h" 334b169a6bSchristos #include "sim/callback.h" 3498b9484cSchristos 3598b9484cSchristos #ifndef SIZE_INSTRUCTION 3698b9484cSchristos #define SIZE_INSTRUCTION 16 3798b9484cSchristos #endif 3898b9484cSchristos 3998b9484cSchristos #ifndef SIZE_LOCATION 4098b9484cSchristos #define SIZE_LOCATION 20 4198b9484cSchristos #endif 4298b9484cSchristos 4398b9484cSchristos #ifndef SIZE_PC 4498b9484cSchristos #define SIZE_PC 6 4598b9484cSchristos #endif 4698b9484cSchristos 4798b9484cSchristos #ifndef SIZE_LINE_NUMBER 4898b9484cSchristos #define SIZE_LINE_NUMBER 4 4998b9484cSchristos #endif 5098b9484cSchristos 5198b9484cSchristos #ifndef SIZE_CYCLE_COUNT 5298b9484cSchristos #define SIZE_CYCLE_COUNT 2 5398b9484cSchristos #endif 5498b9484cSchristos 5598b9484cSchristos #ifndef SIZE_TOTAL_CYCLE_COUNT 5698b9484cSchristos #define SIZE_TOTAL_CYCLE_COUNT 9 5798b9484cSchristos #endif 5898b9484cSchristos 5998b9484cSchristos #ifndef SIZE_TRACE_BUF 6098b9484cSchristos #define SIZE_TRACE_BUF 1024 6198b9484cSchristos #endif 6298b9484cSchristos 6398b9484cSchristos /* Text is queued in TRACE_BUF because we want to output the insn's cycle 6498b9484cSchristos count first but that isn't known until after the insn has executed. 6598b9484cSchristos This also handles the queueing of trace results, TRACE_RESULT may be 6698b9484cSchristos called multiple times for one insn. */ 6798b9484cSchristos static char trace_buf[SIZE_TRACE_BUF]; 6898b9484cSchristos /* If NULL, output to stdout directly. */ 6998b9484cSchristos static char *bufptr; 7098b9484cSchristos 7198b9484cSchristos /* Non-zero if this is the first insn in a set of parallel insns. */ 7298b9484cSchristos static int first_insn_p; 7398b9484cSchristos 74212397c6Schristos /* For communication between cgen_trace_insn and cgen_trace_result. */ 7598b9484cSchristos static int printed_result_p; 7698b9484cSchristos 7798b9484cSchristos /* Insn and its extracted fields. 78212397c6Schristos Set by cgen_trace_insn, used by cgen_trace_insn_fini. 7998b9484cSchristos ??? Move to SIM_CPU to support heterogeneous multi-cpu case. */ 8098b9484cSchristos static const struct cgen_insn *current_insn; 8198b9484cSchristos static const struct argbuf *current_abuf; 8298b9484cSchristos 8398b9484cSchristos void 84212397c6Schristos cgen_trace_insn_init (SIM_CPU *cpu, int first_p) 8598b9484cSchristos { 8698b9484cSchristos bufptr = trace_buf; 8798b9484cSchristos *bufptr = 0; 8898b9484cSchristos first_insn_p = first_p; 8998b9484cSchristos 90212397c6Schristos /* Set to NULL so cgen_trace_insn_fini can know if cgen_trace_insn was 91212397c6Schristos called. */ 9298b9484cSchristos current_insn = NULL; 9398b9484cSchristos current_abuf = NULL; 9498b9484cSchristos } 9598b9484cSchristos 9698b9484cSchristos void 97212397c6Schristos cgen_trace_insn_fini (SIM_CPU *cpu, const struct argbuf *abuf, int last_p) 9898b9484cSchristos { 9998b9484cSchristos SIM_DESC sd = CPU_STATE (cpu); 10098b9484cSchristos 10198b9484cSchristos /* Was insn traced? It might not be if trace ranges are in effect. */ 10298b9484cSchristos if (current_insn == NULL) 10398b9484cSchristos return; 10498b9484cSchristos 10598b9484cSchristos /* The first thing printed is current and total cycle counts. */ 10698b9484cSchristos 10798b9484cSchristos if (PROFILE_MODEL_P (cpu) 10898b9484cSchristos && ARGBUF_PROFILE_P (current_abuf)) 10998b9484cSchristos { 11098b9484cSchristos unsigned long total = PROFILE_MODEL_TOTAL_CYCLES (CPU_PROFILE_DATA (cpu)); 11198b9484cSchristos unsigned long this_insn = PROFILE_MODEL_CUR_INSN_CYCLES (CPU_PROFILE_DATA (cpu)); 11298b9484cSchristos 11398b9484cSchristos if (last_p) 11498b9484cSchristos { 11598b9484cSchristos trace_printf (sd, cpu, "%-*ld %-*ld ", 11698b9484cSchristos SIZE_CYCLE_COUNT, this_insn, 11798b9484cSchristos SIZE_TOTAL_CYCLE_COUNT, total); 11898b9484cSchristos } 11998b9484cSchristos else 12098b9484cSchristos { 12198b9484cSchristos trace_printf (sd, cpu, "%-*ld %-*s ", 12298b9484cSchristos SIZE_CYCLE_COUNT, this_insn, 12398b9484cSchristos SIZE_TOTAL_CYCLE_COUNT, "---"); 12498b9484cSchristos } 12598b9484cSchristos } 12698b9484cSchristos 12798b9484cSchristos /* Print the disassembled insn. */ 12898b9484cSchristos 12998b9484cSchristos trace_printf (sd, cpu, "%s", TRACE_PREFIX (CPU_TRACE_DATA (cpu))); 13098b9484cSchristos 13198b9484cSchristos #if 0 13298b9484cSchristos /* Print insn results. */ 13398b9484cSchristos { 13498b9484cSchristos const CGEN_OPINST *opinst = CGEN_INSN_OPERANDS (current_insn); 13598b9484cSchristos 13698b9484cSchristos if (opinst) 13798b9484cSchristos { 13898b9484cSchristos int i; 13998b9484cSchristos int indices[MAX_OPERAND_INSTANCES]; 14098b9484cSchristos 14198b9484cSchristos /* Fetch the operands used by the insn. */ 14298b9484cSchristos /* FIXME: Add fn ptr to CGEN_CPU_DESC. */ 14398b9484cSchristos CGEN_SYM (get_insn_operands) (CPU_CPU_DESC (cpu), current_insn, 14498b9484cSchristos 0, CGEN_FIELDS_BITSIZE (&insn_fields), 14598b9484cSchristos indices); 14698b9484cSchristos 14798b9484cSchristos for (i = 0; 14898b9484cSchristos CGEN_OPINST_TYPE (opinst) != CGEN_OPINST_END; 14998b9484cSchristos ++i, ++opinst) 15098b9484cSchristos { 15198b9484cSchristos if (CGEN_OPINST_TYPE (opinst) == CGEN_OPINST_OUTPUT) 152212397c6Schristos cgen_trace_result (cpu, current_insn, opinst, indices[i]); 15398b9484cSchristos } 15498b9484cSchristos } 15598b9484cSchristos } 15698b9484cSchristos #endif 15798b9484cSchristos 15898b9484cSchristos /* Print anything else requested. */ 15998b9484cSchristos 16098b9484cSchristos if (*trace_buf) 16198b9484cSchristos trace_printf (sd, cpu, " %s\n", trace_buf); 16298b9484cSchristos else 16398b9484cSchristos trace_printf (sd, cpu, "\n"); 16498b9484cSchristos } 16598b9484cSchristos 16698b9484cSchristos void 167212397c6Schristos cgen_trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode, 16898b9484cSchristos const struct argbuf *abuf, IADDR pc) 16998b9484cSchristos { 17098b9484cSchristos char disasm_buf[50]; 17198b9484cSchristos 17298b9484cSchristos printed_result_p = 0; 17398b9484cSchristos current_insn = opcode; 17498b9484cSchristos current_abuf = abuf; 17598b9484cSchristos 17698b9484cSchristos if (CGEN_INSN_VIRTUAL_P (opcode)) 17798b9484cSchristos { 17898b9484cSchristos trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, 0, 1794b169a6bSchristos NULL, 0, "%s", CGEN_INSN_NAME (opcode)); 18098b9484cSchristos return; 18198b9484cSchristos } 18298b9484cSchristos 18398b9484cSchristos CPU_DISASSEMBLER (cpu) (cpu, opcode, abuf, pc, disasm_buf); 18498b9484cSchristos trace_prefix (CPU_STATE (cpu), cpu, NULL_CIA, pc, TRACE_LINENUM_P (cpu), 18598b9484cSchristos NULL, 0, 18698b9484cSchristos "%s%-*s", 18798b9484cSchristos first_insn_p ? " " : "|", 18898b9484cSchristos SIZE_INSTRUCTION, disasm_buf); 18998b9484cSchristos } 19098b9484cSchristos 19198b9484cSchristos void 1924b169a6bSchristos cgen_trace_extract (SIM_CPU *cpu, IADDR pc, const char *name, ...) 19398b9484cSchristos { 19498b9484cSchristos va_list args; 19598b9484cSchristos int printed_one_p = 0; 1964b169a6bSchristos const char *fmt; 19798b9484cSchristos 19898b9484cSchristos va_start (args, name); 19998b9484cSchristos 20098b9484cSchristos trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*lx: %s ", 20198b9484cSchristos SIZE_PC, (unsigned long) pc, name); 20298b9484cSchristos 20398b9484cSchristos do { 20498b9484cSchristos int type,ival; 20598b9484cSchristos 2064b169a6bSchristos fmt = va_arg (args, const char *); 20798b9484cSchristos 20898b9484cSchristos if (fmt) 20998b9484cSchristos { 21098b9484cSchristos if (printed_one_p) 21198b9484cSchristos trace_printf (CPU_STATE (cpu), cpu, ", "); 21298b9484cSchristos printed_one_p = 1; 21398b9484cSchristos type = va_arg (args, int); 21498b9484cSchristos switch (type) 21598b9484cSchristos { 21698b9484cSchristos case 'x' : 21798b9484cSchristos ival = va_arg (args, int); 2184b169a6bSchristos DIAGNOSTIC_PUSH 2194b169a6bSchristos DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL 22098b9484cSchristos trace_printf (CPU_STATE (cpu), cpu, fmt, ival); 2214b169a6bSchristos DIAGNOSTIC_POP 22298b9484cSchristos break; 22398b9484cSchristos default : 22498b9484cSchristos abort (); 22598b9484cSchristos } 22698b9484cSchristos } 22798b9484cSchristos } while (fmt); 22898b9484cSchristos 22998b9484cSchristos va_end (args); 23098b9484cSchristos trace_printf (CPU_STATE (cpu), cpu, "\n"); 23198b9484cSchristos } 23298b9484cSchristos 23398b9484cSchristos void 2344b169a6bSchristos cgen_trace_result (SIM_CPU *cpu, const char *name, int type, ...) 23598b9484cSchristos { 23698b9484cSchristos va_list args; 23798b9484cSchristos 23898b9484cSchristos va_start (args, type); 23998b9484cSchristos if (printed_result_p) 24098b9484cSchristos cgen_trace_printf (cpu, ", "); 24198b9484cSchristos 24298b9484cSchristos switch (type) 24398b9484cSchristos { 24498b9484cSchristos case 'x' : 24598b9484cSchristos default : 24698b9484cSchristos cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int)); 24798b9484cSchristos break; 24898b9484cSchristos case 'f': 24998b9484cSchristos { 25098b9484cSchristos DI di; 25198b9484cSchristos sim_fpu f; 25298b9484cSchristos 25398b9484cSchristos /* this is separated from previous line for sunos cc */ 25498b9484cSchristos di = va_arg (args, DI); 25598b9484cSchristos sim_fpu_64to (&f, di); 25698b9484cSchristos 25798b9484cSchristos cgen_trace_printf (cpu, "%s <- ", name); 25898b9484cSchristos sim_fpu_printn_fpu (&f, (sim_fpu_print_func *) cgen_trace_printf, 4, cpu); 25998b9484cSchristos break; 26098b9484cSchristos } 26198b9484cSchristos case 'D' : 26298b9484cSchristos { 26398b9484cSchristos DI di; 26498b9484cSchristos /* this is separated from previous line for sunos cc */ 26598b9484cSchristos di = va_arg (args, DI); 26698b9484cSchristos cgen_trace_printf (cpu, "%s <- 0x%x%08x", name, 26798b9484cSchristos GETHIDI(di), GETLODI (di)); 26898b9484cSchristos break; 26998b9484cSchristos } 27098b9484cSchristos } 27198b9484cSchristos 27298b9484cSchristos printed_result_p = 1; 27398b9484cSchristos va_end (args); 27498b9484cSchristos } 27598b9484cSchristos 27698b9484cSchristos /* Print trace output to BUFPTR if active, otherwise print normally. 27798b9484cSchristos This is only for tracing semantic code. */ 27898b9484cSchristos 27998b9484cSchristos void 2804b169a6bSchristos cgen_trace_printf (SIM_CPU *cpu, const char *fmt, ...) 28198b9484cSchristos { 28298b9484cSchristos va_list args; 28398b9484cSchristos 28498b9484cSchristos va_start (args, fmt); 28598b9484cSchristos 28698b9484cSchristos if (bufptr == NULL) 28798b9484cSchristos { 28898b9484cSchristos if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL) 28998b9484cSchristos (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered) 29098b9484cSchristos (STATE_CALLBACK (CPU_STATE (cpu)), fmt, args); 29198b9484cSchristos else 29298b9484cSchristos vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args); 29398b9484cSchristos } 29498b9484cSchristos else 29598b9484cSchristos { 29698b9484cSchristos vsprintf (bufptr, fmt, args); 29798b9484cSchristos bufptr += strlen (bufptr); 29898b9484cSchristos /* ??? Need version of SIM_ASSERT that is always enabled. */ 29998b9484cSchristos if (bufptr - trace_buf > SIZE_TRACE_BUF) 30098b9484cSchristos abort (); 30198b9484cSchristos } 30298b9484cSchristos 30398b9484cSchristos va_end (args); 30498b9484cSchristos } 30598b9484cSchristos 30698b9484cSchristos /* Disassembly support. */ 30798b9484cSchristos 30898b9484cSchristos /* sprintf to a "stream" */ 30998b9484cSchristos 31098b9484cSchristos int 31103467a24Schristos sim_disasm_sprintf (SFILE *f, const char *format, ...) 31298b9484cSchristos { 31398b9484cSchristos int n; 31498b9484cSchristos va_list args; 31598b9484cSchristos 31603467a24Schristos va_start (args, format); 31798b9484cSchristos vsprintf (f->current, format, args); 31898b9484cSchristos f->current += n = strlen (f->current); 31998b9484cSchristos va_end (args); 32098b9484cSchristos return n; 32198b9484cSchristos } 32298b9484cSchristos 3234b169a6bSchristos /* sprintf to a "stream" with styling. */ 3244b169a6bSchristos 3254b169a6bSchristos int 3264b169a6bSchristos sim_disasm_styled_sprintf (SFILE *f, enum disassembler_style style, 3274b169a6bSchristos const char *format, ...) 3284b169a6bSchristos { 3294b169a6bSchristos int n; 3304b169a6bSchristos va_list args; 3314b169a6bSchristos 3324b169a6bSchristos va_start (args, format); 3334b169a6bSchristos vsprintf (f->current, format, args); 3344b169a6bSchristos f->current += n = strlen (f->current); 3354b169a6bSchristos va_end (args); 3364b169a6bSchristos return n; 3374b169a6bSchristos } 3384b169a6bSchristos 33998b9484cSchristos /* Memory read support for an opcodes disassembler. */ 34098b9484cSchristos 34198b9484cSchristos int 34298b9484cSchristos sim_disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, 34398b9484cSchristos struct disassemble_info *info) 34498b9484cSchristos { 34598b9484cSchristos SIM_CPU *cpu = (SIM_CPU *) info->application_data; 34698b9484cSchristos SIM_DESC sd = CPU_STATE (cpu); 34798b9484cSchristos unsigned length_read; 34898b9484cSchristos 34998b9484cSchristos length_read = sim_core_read_buffer (sd, cpu, read_map, myaddr, memaddr, 35098b9484cSchristos length); 35198b9484cSchristos if (length_read != length) 35298b9484cSchristos return EIO; 35398b9484cSchristos return 0; 35498b9484cSchristos } 35598b9484cSchristos 35698b9484cSchristos /* Memory error support for an opcodes disassembler. */ 35798b9484cSchristos 35898b9484cSchristos void 35998b9484cSchristos sim_disasm_perror_memory (int status, bfd_vma memaddr, 36098b9484cSchristos struct disassemble_info *info) 36198b9484cSchristos { 36298b9484cSchristos if (status != EIO) 36398b9484cSchristos /* Can't happen. */ 36498b9484cSchristos info->fprintf_func (info->stream, "Unknown error %d.", status); 36598b9484cSchristos else 36698b9484cSchristos /* Actually, address between memaddr and memaddr + len was 36798b9484cSchristos out of bounds. */ 36898b9484cSchristos info->fprintf_func (info->stream, 3694b169a6bSchristos "Address 0x%" PRIx64 " is out of bounds.", 3704b169a6bSchristos (uint64_t) memaddr); 37198b9484cSchristos } 37298b9484cSchristos 37398b9484cSchristos /* Disassemble using the CGEN opcode table. 37498b9484cSchristos ??? While executing an instruction, the insn has been decoded and all its 37598b9484cSchristos fields have been extracted. It is certainly possible to do the disassembly 37698b9484cSchristos with that data. This seems simpler, but maybe in the future the already 37798b9484cSchristos extracted fields will be used. */ 37898b9484cSchristos 37998b9484cSchristos void 38098b9484cSchristos sim_cgen_disassemble_insn (SIM_CPU *cpu, const CGEN_INSN *insn, 38198b9484cSchristos const ARGBUF *abuf, IADDR pc, char *buf) 38298b9484cSchristos { 38398b9484cSchristos unsigned int length; 38498b9484cSchristos unsigned int base_length; 38598b9484cSchristos unsigned long insn_value; 38698b9484cSchristos struct disassemble_info disasm_info; 38798b9484cSchristos SFILE sfile; 38898b9484cSchristos union { 3894b169a6bSchristos uint8_t bytes[CGEN_MAX_INSN_SIZE]; 3904b169a6bSchristos uint16_t shorts[8]; 3914b169a6bSchristos uint32_t words[4]; 39298b9484cSchristos } insn_buf; 39398b9484cSchristos SIM_DESC sd = CPU_STATE (cpu); 39498b9484cSchristos CGEN_CPU_DESC cd = CPU_CPU_DESC (cpu); 39598b9484cSchristos CGEN_EXTRACT_INFO ex_info; 39698b9484cSchristos CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd)); 39798b9484cSchristos int insn_bit_length = CGEN_INSN_BITSIZE (insn); 39898b9484cSchristos int insn_length = insn_bit_length / 8; 39998b9484cSchristos 40098b9484cSchristos sfile.buffer = sfile.current = buf; 40198b9484cSchristos INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile, 4024b169a6bSchristos (fprintf_ftype) sim_disasm_sprintf, 4034b169a6bSchristos (fprintf_styled_ftype) sim_disasm_styled_sprintf); 40498b9484cSchristos disasm_info.endian = 40598b9484cSchristos (bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG 40698b9484cSchristos : bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE 40798b9484cSchristos : BFD_ENDIAN_UNKNOWN); 40898b9484cSchristos 40998b9484cSchristos length = sim_core_read_buffer (sd, cpu, read_map, &insn_buf, pc, 41098b9484cSchristos insn_length); 41198b9484cSchristos 41298b9484cSchristos if (length != insn_length) 41398b9484cSchristos { 4144b169a6bSchristos sim_io_error (sd, "unable to read address %" PRIxTA, pc); 41598b9484cSchristos } 41698b9484cSchristos 41798b9484cSchristos /* If the entire insn will fit into an integer, then do it. Otherwise, just 41898b9484cSchristos use the bits of the base_insn. */ 41998b9484cSchristos if (insn_bit_length <= 32) 42098b9484cSchristos base_length = insn_bit_length; 42198b9484cSchristos else 42298b9484cSchristos base_length = min (cd->base_insn_bitsize, insn_bit_length); 42398b9484cSchristos switch (base_length) 42498b9484cSchristos { 42598b9484cSchristos case 0 : return; /* fake insn, typically "compile" (aka "invalid") */ 42698b9484cSchristos case 8 : insn_value = insn_buf.bytes[0]; break; 42798b9484cSchristos case 16 : insn_value = T2H_2 (insn_buf.shorts[0]); break; 42898b9484cSchristos case 32 : insn_value = T2H_4 (insn_buf.words[0]); break; 42998b9484cSchristos default: abort (); 43098b9484cSchristos } 43198b9484cSchristos 43298b9484cSchristos disasm_info.buffer_vma = pc; 43398b9484cSchristos disasm_info.buffer = insn_buf.bytes; 43498b9484cSchristos disasm_info.buffer_length = length; 43598b9484cSchristos 4364b169a6bSchristos ex_info.dis_info = &disasm_info; 43798b9484cSchristos ex_info.valid = (1 << length) - 1; 43898b9484cSchristos ex_info.insn_bytes = insn_buf.bytes; 43998b9484cSchristos 44098b9484cSchristos length = (*CGEN_EXTRACT_FN (cd, insn)) (cd, insn, &ex_info, insn_value, fields, pc); 44198b9484cSchristos /* Result of extract fn is in bits. */ 44298b9484cSchristos /* ??? This assumes that each instruction has a fixed length (and thus 44398b9484cSchristos for insns with multiple versions of variable lengths they would each 44498b9484cSchristos have their own table entry). */ 44598b9484cSchristos if (length == insn_bit_length) 44698b9484cSchristos { 44798b9484cSchristos (*CGEN_PRINT_FN (cd, insn)) (cd, &disasm_info, insn, fields, pc, length); 44898b9484cSchristos } 44998b9484cSchristos else 45098b9484cSchristos { 45198b9484cSchristos /* This shouldn't happen, but aborting is too drastic. */ 45298b9484cSchristos strcpy (buf, "***unknown***"); 45398b9484cSchristos } 45498b9484cSchristos } 455