1/* 2 * linux/arch/arm/kernel/ptrace.c 3 * 4 * By Ross Biro 1/23/92 5 * edited by Linus Torvalds 6 * ARM modifications Copyright (C) 2000 Russell King 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12#include <linux/kernel.h> 13#include <linux/sched.h> 14#include <linux/mm.h> 15#include <linux/smp.h> 16#include <linux/ptrace.h> 17#include <linux/user.h> 18#include <linux/security.h> 19#include <linux/init.h> 20#include <linux/signal.h> 21 22#include <asm/uaccess.h> 23#include <asm/pgtable.h> 24#include <asm/system.h> 25#include <asm/traps.h> 26 27#include "ptrace.h" 28 29#define REG_PC 15 30#define REG_PSR 16 31/* 32 * does not yet catch signals sent when the child dies. 33 * in exit.c or in signal.c. 34 */ 35 36#define BREAKINST_ARM 0xe7f001f0 37#define BREAKINST_THUMB 0xde01 38 39/* 40 * this routine will get a word off of the processes privileged stack. 41 * the offset is how far from the base addr as stored in the THREAD. 42 * this routine assumes that all the privileged stacks are in our 43 * data space. 44 */ 45static inline long get_user_reg(struct task_struct *task, int offset) 46{ 47 return task_pt_regs(task)->uregs[offset]; 48} 49 50/* 51 * this routine will put a word on the processes privileged stack. 52 * the offset is how far from the base addr as stored in the THREAD. 53 * this routine assumes that all the privileged stacks are in our 54 * data space. 55 */ 56static inline int 57put_user_reg(struct task_struct *task, int offset, long data) 58{ 59 struct pt_regs newregs, *regs = task_pt_regs(task); 60 int ret = -EINVAL; 61 62 newregs = *regs; 63 newregs.uregs[offset] = data; 64 65 if (valid_user_regs(&newregs)) { 66 regs->uregs[offset] = data; 67 ret = 0; 68 } 69 70 return ret; 71} 72 73static inline int 74read_u32(struct task_struct *task, unsigned long addr, u32 *res) 75{ 76 int ret; 77 78 ret = access_process_vm(task, addr, res, sizeof(*res), 0); 79 80 return ret == sizeof(*res) ? 0 : -EIO; 81} 82 83static inline int 84read_instr(struct task_struct *task, unsigned long addr, u32 *res) 85{ 86 int ret; 87 88 if (addr & 1) { 89 u16 val; 90 ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); 91 ret = ret == sizeof(val) ? 0 : -EIO; 92 *res = val; 93 } else { 94 u32 val; 95 ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); 96 ret = ret == sizeof(val) ? 0 : -EIO; 97 *res = val; 98 } 99 return ret; 100} 101 102/* 103 * Get value of register `rn' (in the instruction) 104 */ 105static unsigned long 106ptrace_getrn(struct task_struct *child, unsigned long insn) 107{ 108 unsigned int reg = (insn >> 16) & 15; 109 unsigned long val; 110 111 val = get_user_reg(child, reg); 112 if (reg == 15) 113 val = pc_pointer(val + 8); 114 115 return val; 116} 117 118/* 119 * Get value of operand 2 (in an ALU instruction) 120 */ 121static unsigned long 122ptrace_getaluop2(struct task_struct *child, unsigned long insn) 123{ 124 unsigned long val; 125 int shift; 126 int type; 127 128 if (insn & 1 << 25) { 129 val = insn & 255; 130 shift = (insn >> 8) & 15; 131 type = 3; 132 } else { 133 val = get_user_reg (child, insn & 15); 134 135 if (insn & (1 << 4)) 136 shift = (int)get_user_reg (child, (insn >> 8) & 15); 137 else 138 shift = (insn >> 7) & 31; 139 140 type = (insn >> 5) & 3; 141 } 142 143 switch (type) { 144 case 0: val <<= shift; break; 145 case 1: val >>= shift; break; 146 case 2: 147 val = (((signed long)val) >> shift); 148 break; 149 case 3: 150 val = (val >> shift) | (val << (32 - shift)); 151 break; 152 } 153 return val; 154} 155 156/* 157 * Get value of operand 2 (in a LDR instruction) 158 */ 159static unsigned long 160ptrace_getldrop2(struct task_struct *child, unsigned long insn) 161{ 162 unsigned long val; 163 int shift; 164 int type; 165 166 val = get_user_reg(child, insn & 15); 167 shift = (insn >> 7) & 31; 168 type = (insn >> 5) & 3; 169 170 switch (type) { 171 case 0: val <<= shift; break; 172 case 1: val >>= shift; break; 173 case 2: 174 val = (((signed long)val) >> shift); 175 break; 176 case 3: 177 val = (val >> shift) | (val << (32 - shift)); 178 break; 179 } 180 return val; 181} 182 183#define OP_MASK 0x01e00000 184#define OP_AND 0x00000000 185#define OP_EOR 0x00200000 186#define OP_SUB 0x00400000 187#define OP_RSB 0x00600000 188#define OP_ADD 0x00800000 189#define OP_ADC 0x00a00000 190#define OP_SBC 0x00c00000 191#define OP_RSC 0x00e00000 192#define OP_ORR 0x01800000 193#define OP_MOV 0x01a00000 194#define OP_BIC 0x01c00000 195#define OP_MVN 0x01e00000 196 197static unsigned long 198get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) 199{ 200 u32 alt = 0; 201 202 switch (insn & 0x0e000000) { 203 case 0x00000000: 204 case 0x02000000: { 205 /* 206 * data processing 207 */ 208 long aluop1, aluop2, ccbit; 209 210 if ((insn & 0x0fffffd0) == 0x012fff10) { 211 /* 212 * bx or blx 213 */ 214 alt = get_user_reg(child, insn & 15); 215 break; 216 } 217 218 219 if ((insn & 0xf000) != 0xf000) 220 break; 221 222 aluop1 = ptrace_getrn(child, insn); 223 aluop2 = ptrace_getaluop2(child, insn); 224 ccbit = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0; 225 226 switch (insn & OP_MASK) { 227 case OP_AND: alt = aluop1 & aluop2; break; 228 case OP_EOR: alt = aluop1 ^ aluop2; break; 229 case OP_SUB: alt = aluop1 - aluop2; break; 230 case OP_RSB: alt = aluop2 - aluop1; break; 231 case OP_ADD: alt = aluop1 + aluop2; break; 232 case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; 233 case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; 234 case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; 235 case OP_ORR: alt = aluop1 | aluop2; break; 236 case OP_MOV: alt = aluop2; break; 237 case OP_BIC: alt = aluop1 & ~aluop2; break; 238 case OP_MVN: alt = ~aluop2; break; 239 } 240 break; 241 } 242 243 case 0x04000000: 244 case 0x06000000: 245 /* 246 * ldr 247 */ 248 if ((insn & 0x0010f000) == 0x0010f000) { 249 unsigned long base; 250 251 base = ptrace_getrn(child, insn); 252 if (insn & 1 << 24) { 253 long aluop2; 254 255 if (insn & 0x02000000) 256 aluop2 = ptrace_getldrop2(child, insn); 257 else 258 aluop2 = insn & 0xfff; 259 260 if (insn & 1 << 23) 261 base += aluop2; 262 else 263 base -= aluop2; 264 } 265 if (read_u32(child, base, &alt) == 0) 266 alt = pc_pointer(alt); 267 } 268 break; 269 270 case 0x08000000: 271 /* 272 * ldm 273 */ 274 if ((insn & 0x00108000) == 0x00108000) { 275 unsigned long base; 276 unsigned int nr_regs; 277 278 if (insn & (1 << 23)) { 279 nr_regs = hweight16(insn & 65535) << 2; 280 281 if (!(insn & (1 << 24))) 282 nr_regs -= 4; 283 } else { 284 if (insn & (1 << 24)) 285 nr_regs = -4; 286 else 287 nr_regs = 0; 288 } 289 290 base = ptrace_getrn(child, insn); 291 292 if (read_u32(child, base + nr_regs, &alt) == 0) 293 alt = pc_pointer(alt); 294 break; 295 } 296 break; 297 298 case 0x0a000000: { 299 /* 300 * bl or b 301 */ 302 signed long displ; 303 /* It's a branch/branch link: instead of trying to 304 * figure out whether the branch will be taken or not, 305 * we'll put a breakpoint at both locations. This is 306 * simpler, more reliable, and probably not a whole lot 307 * slower than the alternative approach of emulating the 308 * branch. 309 */ 310 displ = (insn & 0x00ffffff) << 8; 311 displ = (displ >> 6) + 8; 312 if (displ != 0 && displ != 4) 313 alt = pc + displ; 314 } 315 break; 316 } 317 318 return alt; 319} 320 321static int 322swap_insn(struct task_struct *task, unsigned long addr, 323 void *old_insn, void *new_insn, int size) 324{ 325 int ret; 326 327 ret = access_process_vm(task, addr, old_insn, size, 0); 328 if (ret == size) 329 ret = access_process_vm(task, addr, new_insn, size, 1); 330 return ret; 331} 332 333static void 334add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) 335{ 336 int nr = dbg->nsaved; 337 338 if (nr < 2) { 339 u32 new_insn = BREAKINST_ARM; 340 int res; 341 342 res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); 343 344 if (res == 4) { 345 dbg->bp[nr].address = addr; 346 dbg->nsaved += 1; 347 } 348 } else 349 printk(KERN_ERR "ptrace: too many breakpoints\n"); 350} 351 352/* 353 * Clear one breakpoint in the user program. We copy what the hardware 354 * does and use bit 0 of the address to indicate whether this is a Thumb 355 * breakpoint or an ARM breakpoint. 356 */ 357static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) 358{ 359 unsigned long addr = bp->address; 360 union debug_insn old_insn; 361 int ret; 362 363 if (addr & 1) { 364 ret = swap_insn(task, addr & ~1, &old_insn.thumb, 365 &bp->insn.thumb, 2); 366 367 if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) 368 printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " 369 "0x%08lx (0x%04x)\n", task->comm, task->pid, 370 addr, old_insn.thumb); 371 } else { 372 ret = swap_insn(task, addr & ~3, &old_insn.arm, 373 &bp->insn.arm, 4); 374 375 if (ret != 4 || old_insn.arm != BREAKINST_ARM) 376 printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " 377 "0x%08lx (0x%08x)\n", task->comm, task->pid, 378 addr, old_insn.arm); 379 } 380} 381 382void ptrace_set_bpt(struct task_struct *child) 383{ 384 struct pt_regs *regs; 385 unsigned long pc; 386 u32 insn; 387 int res; 388 389 regs = task_pt_regs(child); 390 pc = instruction_pointer(regs); 391 392 if (thumb_mode(regs)) { 393 printk(KERN_WARNING "ptrace: can't handle thumb mode\n"); 394 return; 395 } 396 397 res = read_instr(child, pc, &insn); 398 if (!res) { 399 struct debug_info *dbg = &child->thread.debug; 400 unsigned long alt; 401 402 dbg->nsaved = 0; 403 404 alt = get_branch_address(child, pc, insn); 405 if (alt) 406 add_breakpoint(child, dbg, alt); 407 408 /* 409 * Note that we ignore the result of setting the above 410 * breakpoint since it may fail. When it does, this is 411 * not so much an error, but a forewarning that we may 412 * be receiving a prefetch abort shortly. 413 * 414 * If we don't set this breakpoint here, then we can 415 * lose control of the thread during single stepping. 416 */ 417 if (!alt || predicate(insn) != PREDICATE_ALWAYS) 418 add_breakpoint(child, dbg, pc + 4); 419 } 420} 421 422/* 423 * Ensure no single-step breakpoint is pending. Returns non-zero 424 * value if child was being single-stepped. 425 */ 426void ptrace_cancel_bpt(struct task_struct *child) 427{ 428 int i, nsaved = child->thread.debug.nsaved; 429 430 child->thread.debug.nsaved = 0; 431 432 if (nsaved > 2) { 433 printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); 434 nsaved = 2; 435 } 436 437 for (i = 0; i < nsaved; i++) 438 clear_breakpoint(child, &child->thread.debug.bp[i]); 439} 440 441/* 442 * Called by kernel/ptrace.c when detaching.. 443 */ 444void ptrace_disable(struct task_struct *child) 445{ 446 single_step_disable(child); 447} 448 449/* 450 * Handle hitting a breakpoint. 451 */ 452void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) 453{ 454 siginfo_t info; 455 456 ptrace_cancel_bpt(tsk); 457 458 info.si_signo = SIGTRAP; 459 info.si_errno = 0; 460 info.si_code = TRAP_BRKPT; 461 info.si_addr = (void __user *)instruction_pointer(regs); 462 463 force_sig_info(SIGTRAP, &info, tsk); 464} 465 466static int break_trap(struct pt_regs *regs, unsigned int instr) 467{ 468 ptrace_break(current, regs); 469 return 0; 470} 471 472static struct undef_hook arm_break_hook = { 473 .instr_mask = 0x0fffffff, 474 .instr_val = 0x07f001f0, 475 .cpsr_mask = PSR_T_BIT, 476 .cpsr_val = 0, 477 .fn = break_trap, 478}; 479 480static struct undef_hook thumb_break_hook = { 481 .instr_mask = 0xffff, 482 .instr_val = 0xde01, 483 .cpsr_mask = PSR_T_BIT, 484 .cpsr_val = PSR_T_BIT, 485 .fn = break_trap, 486}; 487 488static int __init ptrace_break_init(void) 489{ 490 register_undef_hook(&arm_break_hook); 491 register_undef_hook(&thumb_break_hook); 492 return 0; 493} 494 495core_initcall(ptrace_break_init); 496 497/* 498 * Read the word at offset "off" into the "struct user". We 499 * actually access the pt_regs stored on the kernel stack. 500 */ 501static int ptrace_read_user(struct task_struct *tsk, unsigned long off, 502 unsigned long __user *ret) 503{ 504 unsigned long tmp; 505 506 if (off & 3 || off >= sizeof(struct user)) 507 return -EIO; 508 509 tmp = 0; 510 if (off < sizeof(struct pt_regs)) 511 tmp = get_user_reg(tsk, off >> 2); 512 513 return put_user(tmp, ret); 514} 515 516/* 517 * Write the word at offset "off" into "struct user". We 518 * actually access the pt_regs stored on the kernel stack. 519 */ 520static int ptrace_write_user(struct task_struct *tsk, unsigned long off, 521 unsigned long val) 522{ 523 if (off & 3 || off >= sizeof(struct user)) 524 return -EIO; 525 526 if (off >= sizeof(struct pt_regs)) 527 return 0; 528 529 return put_user_reg(tsk, off >> 2, val); 530} 531 532/* 533 * Get all user integer registers. 534 */ 535static int ptrace_getregs(struct task_struct *tsk, void __user *uregs) 536{ 537 struct pt_regs *regs = task_pt_regs(tsk); 538 539 return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; 540} 541 542/* 543 * Set all user integer registers. 544 */ 545static int ptrace_setregs(struct task_struct *tsk, void __user *uregs) 546{ 547 struct pt_regs newregs; 548 int ret; 549 550 ret = -EFAULT; 551 if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { 552 struct pt_regs *regs = task_pt_regs(tsk); 553 554 ret = -EINVAL; 555 if (valid_user_regs(&newregs)) { 556 *regs = newregs; 557 ret = 0; 558 } 559 } 560 561 return ret; 562} 563 564/* 565 * Get the child FPU state. 566 */ 567static int ptrace_getfpregs(struct task_struct *tsk, void __user *ufp) 568{ 569 return copy_to_user(ufp, &task_thread_info(tsk)->fpstate, 570 sizeof(struct user_fp)) ? -EFAULT : 0; 571} 572 573/* 574 * Set the child FPU state. 575 */ 576static int ptrace_setfpregs(struct task_struct *tsk, void __user *ufp) 577{ 578 struct thread_info *thread = task_thread_info(tsk); 579 thread->used_cp[1] = thread->used_cp[2] = 1; 580 return copy_from_user(&thread->fpstate, ufp, 581 sizeof(struct user_fp)) ? -EFAULT : 0; 582} 583 584#ifdef CONFIG_IWMMXT 585 586/* 587 * Get the child iWMMXt state. 588 */ 589static int ptrace_getwmmxregs(struct task_struct *tsk, void __user *ufp) 590{ 591 struct thread_info *thread = task_thread_info(tsk); 592 593 if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 594 return -ENODATA; 595 iwmmxt_task_disable(thread); /* force it to ram */ 596 return copy_to_user(ufp, &thread->fpstate.iwmmxt, IWMMXT_SIZE) 597 ? -EFAULT : 0; 598} 599 600/* 601 * Set the child iWMMXt state. 602 */ 603static int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp) 604{ 605 struct thread_info *thread = task_thread_info(tsk); 606 607 if (!test_ti_thread_flag(thread, TIF_USING_IWMMXT)) 608 return -EACCES; 609 iwmmxt_task_release(thread); /* force a reload */ 610 return copy_from_user(&thread->fpstate.iwmmxt, ufp, IWMMXT_SIZE) 611 ? -EFAULT : 0; 612} 613 614#endif 615 616#ifdef CONFIG_CRUNCH 617/* 618 * Get the child Crunch state. 619 */ 620static int ptrace_getcrunchregs(struct task_struct *tsk, void __user *ufp) 621{ 622 struct thread_info *thread = task_thread_info(tsk); 623 624 crunch_task_disable(thread); /* force it to ram */ 625 return copy_to_user(ufp, &thread->crunchstate, CRUNCH_SIZE) 626 ? -EFAULT : 0; 627} 628 629/* 630 * Set the child Crunch state. 631 */ 632static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp) 633{ 634 struct thread_info *thread = task_thread_info(tsk); 635 636 crunch_task_release(thread); /* force a reload */ 637 return copy_from_user(&thread->crunchstate, ufp, CRUNCH_SIZE) 638 ? -EFAULT : 0; 639} 640#endif 641 642long arch_ptrace(struct task_struct *child, long request, long addr, long data) 643{ 644 unsigned long tmp; 645 int ret; 646 647 switch (request) { 648 /* 649 * read word at location "addr" in the child process. 650 */ 651 case PTRACE_PEEKTEXT: 652 case PTRACE_PEEKDATA: 653 ret = access_process_vm(child, addr, &tmp, 654 sizeof(unsigned long), 0); 655 if (ret == sizeof(unsigned long)) 656 ret = put_user(tmp, (unsigned long __user *) data); 657 else 658 ret = -EIO; 659 break; 660 661 case PTRACE_PEEKUSR: 662 ret = ptrace_read_user(child, addr, (unsigned long __user *)data); 663 break; 664 665 /* 666 * write the word at location addr. 667 */ 668 case PTRACE_POKETEXT: 669 case PTRACE_POKEDATA: 670 ret = access_process_vm(child, addr, &data, 671 sizeof(unsigned long), 1); 672 if (ret == sizeof(unsigned long)) 673 ret = 0; 674 else 675 ret = -EIO; 676 break; 677 678 case PTRACE_POKEUSR: 679 ret = ptrace_write_user(child, addr, data); 680 break; 681 682 /* 683 * continue/restart and stop at next (return from) syscall 684 */ 685 case PTRACE_SYSCALL: 686 case PTRACE_CONT: 687 ret = -EIO; 688 if (!valid_signal(data)) 689 break; 690 if (request == PTRACE_SYSCALL) 691 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 692 else 693 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 694 child->exit_code = data; 695 single_step_disable(child); 696 wake_up_process(child); 697 ret = 0; 698 break; 699 700 /* 701 * make the child exit. Best I can do is send it a sigkill. 702 * perhaps it should be put in the status that it wants to 703 * exit. 704 */ 705 case PTRACE_KILL: 706 single_step_disable(child); 707 if (child->exit_state != EXIT_ZOMBIE) { 708 child->exit_code = SIGKILL; 709 wake_up_process(child); 710 } 711 ret = 0; 712 break; 713 714 /* 715 * execute single instruction. 716 */ 717 case PTRACE_SINGLESTEP: 718 ret = -EIO; 719 if (!valid_signal(data)) 720 break; 721 single_step_enable(child); 722 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 723 child->exit_code = data; 724 /* give it a chance to run. */ 725 wake_up_process(child); 726 ret = 0; 727 break; 728 729 case PTRACE_DETACH: 730 ret = ptrace_detach(child, data); 731 break; 732 733 case PTRACE_GETREGS: 734 ret = ptrace_getregs(child, (void __user *)data); 735 break; 736 737 case PTRACE_SETREGS: 738 ret = ptrace_setregs(child, (void __user *)data); 739 break; 740 741 case PTRACE_GETFPREGS: 742 ret = ptrace_getfpregs(child, (void __user *)data); 743 break; 744 745 case PTRACE_SETFPREGS: 746 ret = ptrace_setfpregs(child, (void __user *)data); 747 break; 748 749#ifdef CONFIG_IWMMXT 750 case PTRACE_GETWMMXREGS: 751 ret = ptrace_getwmmxregs(child, (void __user *)data); 752 break; 753 754 case PTRACE_SETWMMXREGS: 755 ret = ptrace_setwmmxregs(child, (void __user *)data); 756 break; 757#endif 758 759 case PTRACE_GET_THREAD_AREA: 760 ret = put_user(task_thread_info(child)->tp_value, 761 (unsigned long __user *) data); 762 break; 763 764 case PTRACE_SET_SYSCALL: 765 task_thread_info(child)->syscall = data; 766 ret = 0; 767 break; 768 769#ifdef CONFIG_CRUNCH 770 case PTRACE_GETCRUNCHREGS: 771 ret = ptrace_getcrunchregs(child, (void __user *)data); 772 break; 773 774 case PTRACE_SETCRUNCHREGS: 775 ret = ptrace_setcrunchregs(child, (void __user *)data); 776 break; 777#endif 778 779 default: 780 ret = ptrace_request(child, request, addr, data); 781 break; 782 } 783 784 return ret; 785} 786 787asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) 788{ 789 unsigned long ip; 790 791 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 792 return scno; 793 if (!(current->ptrace & PT_PTRACED)) 794 return scno; 795 796 /* 797 * Save IP. IP is used to denote syscall entry/exit: 798 * IP = 0 -> entry, = 1 -> exit 799 */ 800 ip = regs->ARM_ip; 801 regs->ARM_ip = why; 802 803 current_thread_info()->syscall = scno; 804 805 /* the 0x80 provides a way for the tracing parent to distinguish 806 between a syscall stop and SIGTRAP delivery */ 807 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 808 ? 0x80 : 0)); 809 /* 810 * this isn't the same as continuing with a signal, but it will do 811 * for normal use. strace only continues with a signal if the 812 * stopping signal is not SIGTRAP. -brl 813 */ 814 if (current->exit_code) { 815 send_sig(current->exit_code, current, 1); 816 current->exit_code = 0; 817 } 818 regs->ARM_ip = ip; 819 820 return current_thread_info()->syscall; 821} 822