1 1.1 christos # Copyright (C) 2023-2024 Free Software Foundation, Inc. 2 1.1 christos 3 1.1 christos # This program is free software; you can redistribute it and/or modify 4 1.1 christos # it under the terms of the GNU General Public License as published by 5 1.1 christos # the Free Software Foundation; either version 3 of the License, or 6 1.1 christos # (at your option) any later version. 7 1.1 christos # 8 1.1 christos # This program is distributed in the hope that it will be useful, 9 1.1 christos # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 1.1 christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 1.1 christos # GNU General Public License for more details. 12 1.1 christos # 13 1.1 christos # You should have received a copy of the GNU General Public License 14 1.1 christos # along with this program. If not, see <http://www.gnu.org/licenses/>. 15 1.1 christos 16 1.1 christos load_lib gdb-python.exp 17 1.1 christos 18 1.1 christos require allow_python_tests 19 1.1 christos 20 1.1 christos standard_testfile 21 1.1 christos 22 1.1 christos if {[build_executable "failed to prepare" ${testfile} ${srcfile}]} { 23 1.1 christos return -1 24 1.1 christos } 25 1.1 christos 26 1.1 christos # Remove debug information from BINFILE and place it into 27 1.1 christos # BINFILE.debug. 28 1.1 christos if {[gdb_gnu_strip_debug $binfile]} { 29 1.1 christos unsupported "cannot produce separate debug info files" 30 1.1 christos return -1 31 1.1 christos } 32 1.1 christos 33 1.1 christos set remote_python_file \ 34 1.1 christos [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] 35 1.1 christos 36 1.1 christos set debug_filename ${binfile}.debug 37 1.1 christos set hidden_filename ${binfile}.hidden 38 1.1 christos 39 1.1 christos # Start GDB. 40 1.1 christos clean_restart 41 1.1 christos 42 1.1 christos # Some initial sanity checks; initially, we can find the debug information 43 1.1 christos # (this will use the .gnu_debuglink), then after we move the debug 44 1.1 christos # information, reload the executable, now the debug can't be found. 45 1.1 christos with_test_prefix "initial checks" { 46 1.1 christos # Load BINFILE, we should find the separate debug information. 47 1.1 christos gdb_file_cmd $binfile 48 1.1 christos gdb_assert {$gdb_file_cmd_debug_info == "debug"} \ 49 1.1 christos "debug info is found" 50 1.1 christos 51 1.1 christos # Rename the debug information file, re-load BINFILE, GDB should fail 52 1.1 christos # to find the debug information 53 1.1 christos remote_exec build "mv $debug_filename $hidden_filename" 54 1.1 christos gdb_file_cmd $binfile 55 1.1 christos gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \ 56 1.1 christos "debug info no longer found" 57 1.1 christos } 58 1.1 christos 59 1.1 christos # Load the Python script into GDB. 60 1.1 christos gdb_test "source $remote_python_file" "^Success" \ 61 1.1 christos "source python script" 62 1.1 christos 63 1.1 christos # Setup the separate debug info directory. This isn't actually needed until 64 1.1 christos # some of the later tests, but might as well get this done now. 65 1.1 christos set debug_directory [standard_output_file "debug-dir"] 66 1.1 christos remote_exec build "mkdir -p $debug_directory" 67 1.1 christos gdb_test_no_output "set debug-file-directory $debug_directory" \ 68 1.1 christos "set debug-file-directory" 69 1.1 christos 70 1.1 christos # Initially the missing debug handler we install is in a mode where it 71 1.1 christos # returns None, indicating that it can't help locate the debug information. 72 1.1 christos # Check this works as expected. 73 1.1 christos with_test_prefix "handler returning None" { 74 1.1 christos gdb_test_no_output \ 75 1.1 christos "python gdb.missing_debug.register_handler(None, handler_obj)" \ 76 1.1 christos "register the initial handler" 77 1.1 christos 78 1.1 christos gdb_file_cmd $binfile 79 1.1 christos gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \ 80 1.1 christos "debug info not found" 81 1.1 christos 82 1.1 christos # Check the handler was only called once. 83 1.1 christos gdb_test "python print(handler_obj.call_count)" "^1" \ 84 1.1 christos "check handler was only called once" 85 1.1 christos } 86 1.1 christos 87 1.1 christos # Now configure the handler to move the debug file back to the 88 1.1 christos # .gnu_debuglink location and then return True, this will cause GDB to 89 1.1 christos # recheck, at which point it should find the debug info. 90 1.1 christos with_test_prefix "handler in gnu_debuglink mode" { 91 1.1 christos gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \ 92 1.1 christos \"$hidden_filename\", \ 93 1.1 christos \"$debug_filename\")" \ 94 1.1 christos "confirgure handler" 95 1.1 christos gdb_file_cmd $binfile 96 1.1 christos gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found" 97 1.1 christos 98 1.1 christos # Check the handler was only called once. 99 1.1 christos gdb_test "python print(handler_obj.call_count)" "^1" \ 100 1.1 christos "check handler was only called once" 101 1.1 christos } 102 1.1 christos 103 1.1 christos # Setup a directory structure based on the build-id of BINFILE, but don't 104 1.1 christos # move the debug information into place just yet. 105 1.1 christos # 106 1.1 christos # Instead, configure the handler to move the debug info into the build-id 107 1.1 christos # directory. 108 1.1 christos # 109 1.1 christos # Reload BINFILE, at which point the handler will move the debug info into 110 1.1 christos # the build-id directory and return True, GDB will then recheck for the 111 1.1 christos # debug information, and should find it. 112 1.1 christos with_test_prefix "handler in build-id mode" { 113 1.1 christos # Move the debug file out of the way once more. 114 1.1 christos remote_exec build "mv $debug_filename $hidden_filename" 115 1.1 christos 116 1.1 christos # Create the build-id based directory in which the debug information 117 1.1 christos # will be placed. 118 1.1 christos set build_id_filename \ 119 1.1 christos $debug_directory/[build_id_debug_filename_get $binfile] 120 1.1 christos remote_exec build "mkdir -p [file dirname $build_id_filename]" 121 1.1 christos 122 1.1 christos # Configure the handler to move the debug info into the build-id dir. 123 1.1 christos gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \ 124 1.1 christos \"$hidden_filename\", \ 125 1.1 christos \"$build_id_filename\")" \ 126 1.1 christos "confirgure handler" 127 1.1 christos 128 1.1 christos # Reload the binary and check the debug information is found. 129 1.1 christos gdb_file_cmd $binfile 130 1.1 christos gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found" 131 1.1 christos 132 1.1 christos # Check the handler was only called once. 133 1.1 christos gdb_test "python print(handler_obj.call_count)" "^1" \ 134 1.1 christos "check handler was only called once" 135 1.1 christos } 136 1.1 christos 137 1.1 christos # Move the debug information back to a hidden location and configure the 138 1.1 christos # handler to return the filename of the hidden debug info location. GDB 139 1.1 christos # should immediately use this file as the debug information. 140 1.1 christos with_test_prefix "handler returning a string" { 141 1.1 christos remote_exec build "mv $build_id_filename $hidden_filename" 142 1.1 christos 143 1.1 christos # Configure the handler return a filename string. 144 1.1 christos gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_STRING, \ 145 1.1 christos \"$hidden_filename\")" \ 146 1.1 christos "confirgure handler" 147 1.1 christos 148 1.1 christos # Reload the binary and check the debug information is found. 149 1.1 christos gdb_file_cmd $binfile 150 1.1 christos gdb_assert {$gdb_file_cmd_debug_info == "debug"} "debug info found" 151 1.1 christos 152 1.1 christos # Check the handler was only called once. 153 1.1 christos gdb_test "python print(handler_obj.call_count)" "^1" \ 154 1.1 christos "check handler was only called once" 155 1.1 christos } 156 1.1 christos 157 1.1 christos # Register another global handler, this one raises an exception. Reload the 158 1.1 christos # debug information, the bad handler should be invoked first, which raises 159 1.1 christos # an excetption, at which point GDB should skip further Python handlers. 160 1.1 christos with_test_prefix "handler raises an exception" { 161 1.1 christos gdb_test_no_output \ 162 1.1 christos "python gdb.missing_debug.register_handler(None, rhandler)" 163 1.1 christos 164 1.1 christos foreach_with_prefix exception_type {gdb.GdbError TypeError} { 165 1.1 christos gdb_test_no_output \ 166 1.1 christos "python rhandler.exception_type = $exception_type" 167 1.1 christos 168 1.1 christos gdb_file_cmd $binfile 169 1.1 christos gdb_assert {$gdb_file_cmd_debug_info == "nodebug"} \ 170 1.1 christos "debug info not found" 171 1.1 christos 172 1.1 christos set re [string_to_regexp \ 173 1.1 christos "Python Exception <class '$exception_type'>: message"] 174 1.1 christos gdb_assert {[regexp $re $gdb_file_cmd_msg]} \ 175 1.1 christos "check for exception in file command output" 176 1.1 christos 177 1.1 christos # Our original handler is still registered, but should not have been 178 1.1 christos # called again (as the exception occurs first). 179 1.1 christos gdb_test "python print(handler_obj.call_count)" "^1" \ 180 1.1 christos "check good handler hasn't been called again" 181 1.1 christos } 182 1.1 christos } 183 1.1 christos 184 1.1 christos gdb_test "info missing-debug-handlers" \ 185 1.1 christos [multi_line \ 186 1.1 christos "Global:" \ 187 1.1 christos " exception_handler" \ 188 1.1 christos " handler"] \ 189 1.1 christos "check both handlers are visible" 190 1.1 christos 191 1.1 christos # Re-start GDB. 192 1.1 christos clean_restart 193 1.1 christos 194 1.1 christos # Load the Python script into GDB. 195 1.1 christos gdb_test "source $remote_python_file" "^Success" \ 196 1.1 christos "source python script for bad handler name checks" 197 1.1 christos 198 1.1 christos # Attempt to register a missing-debug-handler with NAME. The expectation is 199 1.1 christos # that this should fail as NAME contains some invalid characters. 200 1.1 christos proc check_bad_name {name} { 201 1.1 christos set name_re [string_to_regexp $name] 202 1.1 christos set re \ 203 1.1 christos [multi_line \ 204 1.1 christos "ValueError.*: invalid character '.' in handler name: $name_re" \ 205 1.1 christos "Error occurred in Python.*"] 206 1.1 christos 207 1.1 christos gdb_test "python register(\"$name\")" $re \ 208 1.1 christos "check that '$name' is not accepted" 209 1.1 christos } 210 1.1 christos 211 1.1 christos # We don't attempt to be exhaustive here, just check a few random examples 212 1.1 christos # of invalid names. 213 1.1 christos check_bad_name "!! Bad Name" 214 1.1 christos check_bad_name "Bad Name" 215 1.1 christos check_bad_name "(Bad Name)" 216 1.1 christos check_bad_name "Bad \[Name\]" 217 1.1 christos check_bad_name "Bad,Name" 218 1.1 christos check_bad_name "Bad;Name" 219 1.1 christos 220 1.1 christos # Check that there are no handlers registered. 221 1.1 christos gdb_test_no_output "info missing-debug-handlers" \ 222 1.1 christos "check no handlers are registered" 223 1.1 christos 224 1.1 christos # Check we can use the enable/disable commands where there are no handlers 225 1.1 christos # registered. 226 1.1 christos gdb_test "enable missing-debug-handler foo" \ 227 1.1 christos "^0 missing debug handlers enabled" 228 1.1 christos gdb_test "disable missing-debug-handler foo" \ 229 1.1 christos "^0 missing debug handlers disabled" 230 1.1 christos 231 1.1 christos # Grab the current program space object, used for registering handler later. 232 1.1 christos gdb_test_no_output "python pspace = gdb.selected_inferior().progspace" 233 1.1 christos 234 1.1 christos # Now register some handlers. 235 1.1 christos foreach hspec {{\"Foo\" None} 236 1.1 christos {\"-bar\" None} 237 1.1 christos {\"baz-\" pspace} 238 1.1 christos {\"abc-def\" pspace}} { 239 1.1 christos lassign $hspec name locus 240 1.1 christos gdb_test "python register($name, $locus)" 241 1.1 christos } 242 1.1 christos 243 1.1 christos with_test_prefix "all handlers enabled" { 244 1.1 christos gdb_test "info missing-debug-handlers" \ 245 1.1 christos [multi_line \ 246 1.1 christos "Current Progspace:" \ 247 1.1 christos " abc-def" \ 248 1.1 christos " baz-" \ 249 1.1 christos "Global:" \ 250 1.1 christos " -bar" \ 251 1.1 christos " Foo"] 252 1.1 christos 253 1.1 christos gdb_file_cmd $binfile 254 1.1 christos gdb_test "python print(handler_call_log)" \ 255 1.1 christos [string_to_regexp {['abc-def', 'baz-', '-bar', 'Foo']}] 256 1.1 christos gdb_test_no_output "python handler_call_log = \[\]" \ 257 1.1 christos "reset call log" 258 1.1 christos } 259 1.1 christos 260 1.1 christos with_test_prefix "disable 'baz-'" { 261 1.1 christos gdb_test "disable missing-debug-handler progspace baz-" \ 262 1.1 christos "^1 missing debug handler disabled" 263 1.1 christos 264 1.1 christos gdb_test "info missing-debug-handlers" \ 265 1.1 christos [multi_line \ 266 1.1 christos "Progspace \[^\r\n\]+:" \ 267 1.1 christos " abc-def" \ 268 1.1 christos " baz- \\\[disabled\\\]" \ 269 1.1 christos "Global:" \ 270 1.1 christos " -bar" \ 271 1.1 christos " Foo"] 272 1.1 christos 273 1.1 christos gdb_file_cmd $binfile 274 1.1 christos gdb_test "python print(handler_call_log)" \ 275 1.1 christos [string_to_regexp {['abc-def', '-bar', 'Foo']}] 276 1.1 christos gdb_test_no_output "python handler_call_log = \[\]" \ 277 1.1 christos "reset call log" 278 1.1 christos } 279 1.1 christos 280 1.1 christos with_test_prefix "disable 'Foo'" { 281 1.1 christos gdb_test "disable missing-debug-handler .* Foo" \ 282 1.1 christos "^1 missing debug handler disabled" 283 1.1 christos 284 1.1 christos gdb_test "info missing-debug-handlers" \ 285 1.1 christos [multi_line \ 286 1.1 christos "Progspace \[^\r\n\]+:" \ 287 1.1 christos " abc-def" \ 288 1.1 christos " baz- \\\[disabled\\\]" \ 289 1.1 christos "Global:" \ 290 1.1 christos " -bar" \ 291 1.1 christos " Foo \\\[disabled\\\]"] 292 1.1 christos 293 1.1 christos gdb_file_cmd $binfile 294 1.1 christos gdb_test "python print(handler_call_log)" \ 295 1.1 christos [string_to_regexp {['abc-def', '-bar']}] 296 1.1 christos gdb_test_no_output "python handler_call_log = \[\]" \ 297 1.1 christos "reset call log" 298 1.1 christos } 299 1.1 christos 300 1.1 christos with_test_prefix "disable everything" { 301 1.1 christos gdb_test "disable missing-debug-handler .* .*" \ 302 1.1 christos "^2 missing debug handlers disabled" 303 1.1 christos 304 1.1 christos gdb_test "info missing-debug-handlers" \ 305 1.1 christos [multi_line \ 306 1.1 christos "Progspace \[^\r\n\]+:" \ 307 1.1 christos " abc-def \\\[disabled\\\]" \ 308 1.1 christos " baz- \\\[disabled\\\]" \ 309 1.1 christos "Global:" \ 310 1.1 christos " -bar \\\[disabled\\\]" \ 311 1.1 christos " Foo \\\[disabled\\\]"] 312 1.1 christos 313 1.1 christos gdb_file_cmd $binfile 314 1.1 christos gdb_test "python print(handler_call_log)" \ 315 1.1 christos [string_to_regexp {[]}] 316 1.1 christos gdb_test_no_output "python handler_call_log = \[\]" \ 317 1.1 christos "reset call log" 318 1.1 christos } 319 1.1 christos 320 1.1 christos with_test_prefix "enable 'abc-def'" { 321 1.1 christos set re [string_to_regexp $binfile] 322 1.1 christos 323 1.1 christos gdb_test "enable missing-debug-handler \"$re\" abc-def" \ 324 1.1 christos "^1 missing debug handler enabled" \ 325 1.1 christos "enable missing-debug-handler" 326 1.1 christos 327 1.1 christos gdb_test "info missing-debug-handlers" \ 328 1.1 christos [multi_line \ 329 1.1 christos "Progspace \[^\r\n\]+:" \ 330 1.1 christos " abc-def" \ 331 1.1 christos " baz- \\\[disabled\\\]" \ 332 1.1 christos "Global:" \ 333 1.1 christos " -bar \\\[disabled\\\]" \ 334 1.1 christos " Foo \\\[disabled\\\]"] 335 1.1 christos 336 1.1 christos gdb_file_cmd $binfile 337 1.1 christos gdb_test "python print(handler_call_log)" \ 338 1.1 christos [string_to_regexp {['abc-def']}] 339 1.1 christos gdb_test_no_output "python handler_call_log = \[\]" \ 340 1.1 christos "reset call log" 341 1.1 christos } 342 1.1 christos 343 1.1 christos with_test_prefix "enable global handlers" { 344 1.1 christos set re [string_to_regexp $binfile] 345 1.1 christos 346 1.1 christos gdb_test "enable missing-debug-handler global" \ 347 1.1 christos "^2 missing debug handlers enabled" 348 1.1 christos 349 1.1 christos gdb_test "info missing-debug-handlers" \ 350 1.1 christos [multi_line \ 351 1.1 christos "Progspace \[^\r\n\]+:" \ 352 1.1 christos " abc-def" \ 353 1.1 christos " baz- \\\[disabled\\\]" \ 354 1.1 christos "Global:" \ 355 1.1 christos " -bar" \ 356 1.1 christos " Foo"] 357 1.1 christos 358 1.1 christos gdb_file_cmd $binfile 359 1.1 christos gdb_test "python print(handler_call_log)" \ 360 1.1 christos [string_to_regexp {['abc-def', '-bar', 'Foo']}] 361 1.1 christos gdb_test_no_output "python handler_call_log = \[\]" \ 362 1.1 christos "reset call log" 363 1.1 christos } 364 1.1 christos 365 1.1 christos # Add handler_obj to the global handler list, and configure it to 366 1.1 christos # return False. We should call all of the program space specific 367 1.1 christos # handlers (which return None), and then call handler_obj from the 368 1.1 christos # global list, which returns False, at which point we shouldn't call 369 1.1 christos # anyone else. 370 1.1 christos with_test_prefix "return False handler in progspace list" { 371 1.1 christos gdb_test "enable missing-debug-handler progspace" \ 372 1.1 christos "^1 missing debug handler enabled" 373 1.1 christos 374 1.1 christos gdb_test_no_output \ 375 1.1 christos "python gdb.missing_debug.register_handler(None, handler_obj)" \ 376 1.1 christos "register the initial handler" 377 1.1 christos 378 1.1 christos gdb_test "info missing-debug-handlers" \ 379 1.1 christos [multi_line \ 380 1.1 christos "Progspace \[^\r\n\]+:" \ 381 1.1 christos " abc-def" \ 382 1.1 christos " baz-" \ 383 1.1 christos "Global:" \ 384 1.1 christos " handler" \ 385 1.1 christos " -bar" \ 386 1.1 christos " Foo"] 387 1.1 christos 388 1.1 christos gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_FALSE)" \ 389 1.1 christos "confirgure handler" 390 1.1 christos 391 1.1 christos gdb_file_cmd $binfile 392 1.1 christos gdb_test "python print(handler_call_log)" \ 393 1.1 christos [string_to_regexp {['abc-def', 'baz-', 'handler']}] 394 1.1 christos gdb_test_no_output "python handler_call_log = \[\]" \ 395 1.1 christos "reset call log" 396 1.1 christos } 397 1.1 christos 398 1.1 christos # Now add handler_obj to the current program space's handler list. We 399 1.1 christos # use the same handler object here, that's fine. We should only see a 400 1.1 christos # call to the first handler object in the call log. 401 1.1 christos with_test_prefix "return False handler in global list" { 402 1.1 christos gdb_test_no_output \ 403 1.1 christos "python gdb.missing_debug.register_handler(pspace, handler_obj)" \ 404 1.1 christos "register the initial handler" 405 1.1 christos 406 1.1 christos gdb_test "info missing-debug-handlers" \ 407 1.1 christos [multi_line \ 408 1.1 christos "Progspace \[^\r\n\]+:" \ 409 1.1 christos " handler" \ 410 1.1 christos " abc-def" \ 411 1.1 christos " baz-" \ 412 1.1 christos "Global:" \ 413 1.1 christos " handler" \ 414 1.1 christos " -bar" \ 415 1.1 christos " Foo"] 416 1.1 christos 417 1.1 christos gdb_file_cmd $binfile 418 1.1 christos gdb_test "python print(handler_call_log)" \ 419 1.1 christos [string_to_regexp {['handler']}] 420 1.1 christos gdb_test_no_output "python handler_call_log = \[\]" \ 421 1.1 christos "reset call log" 422 1.1 christos } 423 1.1 christos 424 1.1 christos with_test_prefix "check handler replacement" { 425 1.1 christos # First, check we can have the same name appear in both program 426 1.1 christos # space and global lists without giving an error. 427 1.1 christos gdb_test_no_output "python register(\"Foo\", pspace)" 428 1.1 christos 429 1.1 christos gdb_test "info missing-debug-handlers" \ 430 1.1 christos [multi_line \ 431 1.1 christos "Progspace \[^\r\n\]+:" \ 432 1.1 christos " Foo" \ 433 1.1 christos " handler" \ 434 1.1 christos " abc-def" \ 435 1.1 christos " baz-" \ 436 1.1 christos "Global:" \ 437 1.1 christos " handler" \ 438 1.1 christos " -bar" \ 439 1.1 christos " Foo"] 440 1.1 christos 441 1.1 christos # Now check that we get an error if we try to add a handler with 442 1.1 christos # the same name. 443 1.1 christos gdb_test "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"))" \ 444 1.1 christos [multi_line \ 445 1.1 christos "RuntimeError.*: Handler Foo already exists\\." \ 446 1.1 christos "Error occurred in Python.*"] 447 1.1 christos 448 1.1 christos gdb_test "python gdb.missing_debug.register_handler(handler=log_handler(\"Foo\"), locus=pspace)" \ 449 1.1 christos [multi_line \ 450 1.1 christos "RuntimeError.*: Handler Foo already exists\\." \ 451 1.1 christos "Error occurred in Python.*"] 452 1.1 christos 453 1.1 christos # And now try again, but this time with 'replace=True', we 454 1.1 christos # shouldn't get an error in this case. 455 1.1 christos gdb_test_no_output \ 456 1.1 christos "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"), replace=True)" 457 1.1 christos 458 1.1 christos gdb_test_no_output \ 459 1.1 christos "python gdb.missing_debug.register_handler(handler=log_handler(\"Foo\"), locus=None, replace=True)" 460 1.1 christos 461 1.1 christos # Now disable a handler and check we still need to use 'replace=True'. 462 1.1 christos gdb_test "disable missing-debug-handler progspace Foo" \ 463 1.1 christos "^1 missing debug handler disabled" 464 1.1 christos 465 1.1 christos gdb_test "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"))" \ 466 1.1 christos [multi_line \ 467 1.1 christos "RuntimeError.*: Handler Foo already exists\\." \ 468 1.1 christos "Error occurred in Python.*"] \ 469 1.1 christos "still get an error when handler is disabled" 470 1.1 christos 471 1.1 christos gdb_test_no_output \ 472 1.1 christos "python gdb.missing_debug.register_handler(pspace, log_handler(\"Foo\"), replace=True)" \ 473 1.1 christos "can replace a disabled handler" 474 1.1 christos } 475