1 /* QNX Neutrino specific low level interface, for the remote server
3 Copyright (C) 2009-2014 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "gdbthread.h"
29 #include <sys/procfs.h>
32 #include <sys/iomgr.h>
33 #include <sys/neutrino.h>
36 extern int using_threads;
37 int using_threads = 1;
39 const struct target_desc *nto_tdesc;
42 nto_trace (const char *fmt, ...)
46 if (debug_threads == 0)
48 fprintf (stderr, "nto:");
49 va_start (arg_list, fmt);
50 vfprintf (stderr, fmt, arg_list);
54 #define TRACE nto_trace
56 /* Structure holding neutrino specific information about
61 char nto_procfs_path[PATH_MAX];
64 int exit_signo; /* For tracking exit status. */
67 static struct nto_inferior nto_inferior;
70 init_nto_inferior (struct nto_inferior *nto_inferior)
72 memset (nto_inferior, 0, sizeof (struct nto_inferior));
73 nto_inferior->ctl_fd = -1;
74 nto_inferior->pid = -1;
80 if (nto_inferior.ctl_fd != -1)
82 nto_trace ("Closing fd\n");
83 close (nto_inferior.ctl_fd);
84 init_nto_inferior (&nto_inferior);
88 /* Set current thread. Return 1 on success, 0 otherwise. */
91 nto_set_thread (ptid_t ptid)
95 TRACE ("%s pid: %d tid: %ld\n", __func__, ptid_get_pid (ptid),
97 if (nto_inferior.ctl_fd != -1
98 && !ptid_equal (ptid, null_ptid)
99 && !ptid_equal (ptid, minus_one_ptid))
101 pthread_t tid = ptid_get_lwp (ptid);
103 if (EOK == devctl (nto_inferior.ctl_fd, DCMD_PROC_CURTHREAD, &tid,
107 TRACE ("%s: Error: failed to set current thread\n", __func__);
112 /* This function will determine all alive threads. Note that we do not list
113 dead but unjoined threads even though they are still in the process' thread
116 NTO_INFERIOR must not be NULL. */
119 nto_find_new_threads (struct nto_inferior *nto_inferior)
123 TRACE ("%s pid:%d\n", __func__, nto_inferior->pid);
125 if (nto_inferior->ctl_fd == -1)
128 for (tid = 1;; ++tid)
130 procfs_status status;
135 err = devctl (nto_inferior->ctl_fd, DCMD_PROC_TIDSTATUS, &status,
138 if (err != EOK || status.tid == 0)
141 /* All threads in between are gone. */
142 while (tid != status.tid || status.state == STATE_DEAD)
144 struct thread_info *ti;
146 ptid = ptid_build (nto_inferior->pid, tid, 0);
147 ti = find_thread_ptid (ptid);
150 TRACE ("Removing thread %d\n", tid);
153 if (tid == status.tid)
158 if (status.state != STATE_DEAD)
160 TRACE ("Adding thread %d\n", tid);
161 ptid = ptid_build (nto_inferior->pid, tid, 0);
162 if (!find_thread_ptid (ptid))
163 add_thread (ptid, NULL);
168 /* Given pid, open procfs path. */
171 do_attach (pid_t pid)
173 procfs_status status;
174 struct sigevent event;
176 if (nto_inferior.ctl_fd != -1)
178 close (nto_inferior.ctl_fd);
179 init_nto_inferior (&nto_inferior);
181 xsnprintf (nto_inferior.nto_procfs_path, PATH_MAX - 1, "/proc/%d/as", pid);
182 nto_inferior.ctl_fd = open (nto_inferior.nto_procfs_path, O_RDWR);
183 if (nto_inferior.ctl_fd == -1)
185 TRACE ("Failed to open %s\n", nto_inferior.nto_procfs_path);
186 init_nto_inferior (&nto_inferior);
189 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0)
195 nto_inferior.pid = pid;
196 /* Define a sigevent for process stopped notification. */
197 event.sigev_notify = SIGEV_SIGNAL_THREAD;
198 event.sigev_signo = SIGUSR1;
199 event.sigev_code = 0;
200 event.sigev_value.sival_ptr = NULL;
201 event.sigev_priority = -1;
202 devctl (nto_inferior.ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0);
204 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
206 && (status.flags & _DEBUG_FLAG_STOPPED))
209 struct process_info *proc;
212 ptid = ptid_build (status.pid, status.tid, 0);
213 the_low_target.arch_setup ();
214 proc = add_process (status.pid, 1);
215 proc->tdesc = nto_tdesc;
216 TRACE ("Adding thread: pid=%d tid=%ld\n", status.pid,
217 ptid_get_lwp (ptid));
218 nto_find_new_threads (&nto_inferior);
229 /* Read or write LEN bytes from/to inferior's MEMADDR memory address
230 into gdbservers's MYADDR buffer. Return number of bytes actually
234 nto_xfer_memory (off_t memaddr, unsigned char *myaddr, int len,
239 if (lseek (nto_inferior.ctl_fd, memaddr, SEEK_SET) == memaddr)
242 nbytes = write (nto_inferior.ctl_fd, myaddr, len);
244 nbytes = read (nto_inferior.ctl_fd, myaddr, len);
251 TRACE ("Error in %s : errno=%d (%s)\n", __func__, e, strerror (e));
256 /* Insert or remove breakpoint or watchpoint at address ADDR.
257 TYPE can be one of Neutrino breakpoint types. SIZE must be 0 for
258 inserting the point, -1 for removing it.
260 Return 0 on success, 1 otherwise. */
263 nto_breakpoint (CORE_ADDR addr, int type, int size)
270 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0)
276 /* Read auxiliary vector from inferior's initial stack into gdbserver's
277 MYADDR buffer, up to LEN bytes.
279 Return number of bytes read. */
282 nto_read_auxv_from_initial_stack (CORE_ADDR initial_stack,
283 unsigned char *myaddr,
288 unsigned int len_read = 0;
290 /* Skip over argc, argv and envp... Comment from ldd.c:
292 The startup frame is set-up so that we have:
297 envp1 <----- void *frame + (argc + 2) * sizeof(char *)
302 argc <------ void * frame
304 On entry to ldd, frame gives the address of argc on the stack. */
305 if (nto_xfer_memory (initial_stack, (unsigned char *)&anint,
306 sizeof (anint), 0) != sizeof (anint))
309 /* Size of pointer is assumed to be 4 bytes (32 bit arch. ) */
310 data_ofs += (anint + 2) * sizeof (void *); /* + 2 comes from argc itself and
311 NULL terminating pointer in
314 /* Now loop over env table: */
315 while (nto_xfer_memory (initial_stack + data_ofs,
316 (unsigned char *)&anint, sizeof (anint), 0)
319 data_ofs += sizeof (anint);
323 initial_stack += data_ofs;
325 memset (myaddr, 0, len);
326 while (len_read <= len - sizeof (auxv_t))
328 auxv_t *auxv = (auxv_t *)myaddr;
330 /* Search backwards until we have read AT_PHDR (num. 3),
331 AT_PHENT (num 4), AT_PHNUM (num 5) */
332 if (nto_xfer_memory (initial_stack, (unsigned char *)auxv,
333 sizeof (auxv_t), 0) == sizeof (auxv_t))
335 if (auxv->a_type != AT_NULL)
338 len_read += sizeof (auxv_t);
340 if (auxv->a_type == AT_PHNUM) /* That's all we need. */
342 initial_stack += sizeof (auxv_t);
347 TRACE ("auxv: len_read: %d\n", len_read);
351 /* Start inferior specified by PROGRAM passing arguments ALLARGS. */
354 nto_create_inferior (char *program, char **allargs)
356 struct inheritance inherit;
360 TRACE ("%s %s\n", __func__, program);
361 /* Clear any pending SIGUSR1's but keep the behavior the same. */
362 signal (SIGUSR1, signal (SIGUSR1, SIG_IGN));
365 sigaddset (&set, SIGUSR1);
366 sigprocmask (SIG_UNBLOCK, &set, NULL);
368 memset (&inherit, 0, sizeof (inherit));
369 inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
370 inherit.pgroup = SPAWN_NEWPGROUP;
371 pid = spawnp (program, 0, NULL, &inherit, allargs, 0);
372 sigprocmask (SIG_BLOCK, &set, NULL);
377 if (do_attach (pid) != pid)
383 /* Attach to process PID. */
386 nto_attach (unsigned long pid)
388 TRACE ("%s %ld\n", __func__, pid);
389 if (do_attach (pid) != pid)
390 error ("Unable to attach to %ld\n", pid);
394 /* Send signal to process PID. */
399 TRACE ("%s %d\n", __func__, pid);
405 /* Detach from process PID. */
410 TRACE ("%s %d\n", __func__, pid);
416 nto_mourn (struct process_info *process)
418 remove_process (process);
421 /* Check if the given thread is alive.
423 Return 1 if alive, 0 otherwise. */
426 nto_thread_alive (ptid_t ptid)
430 TRACE ("%s pid:%d tid:%d\n", __func__, ptid_get_pid (ptid),
431 ptid_get_lwp (ptid));
432 if (SignalKill (0, ptid_get_pid (ptid), ptid_get_lwp (ptid),
437 TRACE ("%s: %s\n", __func__, res ? "yes" : "no");
441 /* Resume inferior's execution. */
444 nto_resume (struct thread_resume *resume_info, size_t n)
446 /* We can only work in all-stop mode. */
447 procfs_status status;
451 TRACE ("%s\n", __func__);
452 /* Workaround for aliasing rules violation. */
453 sigset_t *run_fault = (sigset_t *) (void *) &run.fault;
455 nto_set_thread (resume_info->thread);
457 run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE;
458 if (resume_info->kind == resume_step)
459 run.flags |= _DEBUG_RUN_STEP;
460 run.flags |= _DEBUG_RUN_ARM;
462 sigemptyset (run_fault);
463 sigaddset (run_fault, FLTBPT);
464 sigaddset (run_fault, FLTTRACE);
465 sigaddset (run_fault, FLTILL);
466 sigaddset (run_fault, FLTPRIV);
467 sigaddset (run_fault, FLTBOUNDS);
468 sigaddset (run_fault, FLTIOVF);
469 sigaddset (run_fault, FLTIZDIV);
470 sigaddset (run_fault, FLTFPE);
471 sigaddset (run_fault, FLTPAGE);
472 sigaddset (run_fault, FLTSTACK);
473 sigaddset (run_fault, FLTACCESS);
475 sigemptyset (&run.trace);
476 if (resume_info->sig)
480 devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
482 signal_to_pass = resume_info->sig;
483 if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED))
485 if (signal_to_pass != status.info.si_signo)
487 kill (status.pid, signal_to_pass);
488 run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG;
490 else /* Let it kill the program without telling us. */
491 sigdelset (&run.trace, signal_to_pass);
495 run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
497 sigfillset (&run.trace);
499 regcache_invalidate ();
501 err = devctl (nto_inferior.ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0);
503 TRACE ("Error: %d \"%s\"\n", err, strerror (err));
506 /* Wait for inferior's event.
508 Return ptid of thread that caused the event. */
511 nto_wait (ptid_t ptid,
512 struct target_waitstatus *ourstatus, int target_options)
516 procfs_status status;
517 const int trace_mask = (_DEBUG_FLAG_TRACE_EXEC | _DEBUG_FLAG_TRACE_RD
518 | _DEBUG_FLAG_TRACE_WR | _DEBUG_FLAG_TRACE_MODIFY);
520 TRACE ("%s\n", __func__);
522 ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
525 sigaddset (&set, SIGUSR1);
527 devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0);
528 while (!(status.flags & _DEBUG_FLAG_ISTOP))
530 sigwaitinfo (&set, &info);
531 devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status),
534 nto_find_new_threads (&nto_inferior);
536 if (status.flags & _DEBUG_FLAG_SSTEP)
539 ourstatus->kind = TARGET_WAITKIND_STOPPED;
540 ourstatus->value.sig = GDB_SIGNAL_TRAP;
542 /* Was it a breakpoint? */
543 else if (status.flags & trace_mask)
546 ourstatus->kind = TARGET_WAITKIND_STOPPED;
547 ourstatus->value.sig = GDB_SIGNAL_TRAP;
549 else if (status.flags & _DEBUG_FLAG_ISTOP)
554 case _DEBUG_WHY_SIGNALLED:
555 TRACE (" SIGNALLED\n");
556 ourstatus->kind = TARGET_WAITKIND_STOPPED;
557 ourstatus->value.sig =
558 gdb_signal_from_host (status.info.si_signo);
559 nto_inferior.exit_signo = ourstatus->value.sig;
561 case _DEBUG_WHY_FAULTED:
562 TRACE (" FAULTED\n");
563 ourstatus->kind = TARGET_WAITKIND_STOPPED;
564 if (status.info.si_signo == SIGTRAP)
566 ourstatus->value.sig = 0;
567 nto_inferior.exit_signo = 0;
571 ourstatus->value.sig =
572 gdb_signal_from_host (status.info.si_signo);
573 nto_inferior.exit_signo = ourstatus->value.sig;
577 case _DEBUG_WHY_TERMINATED:
581 TRACE (" TERMINATED\n");
582 waitpid (ptid_get_pid (ptid), &waitval, WNOHANG);
583 if (nto_inferior.exit_signo)
585 /* Abnormal death. */
586 ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
587 ourstatus->value.sig = nto_inferior.exit_signo;
592 ourstatus->kind = TARGET_WAITKIND_EXITED;
593 ourstatus->value.integer = WEXITSTATUS (waitval);
595 nto_inferior.exit_signo = 0;
599 case _DEBUG_WHY_REQUESTED:
600 TRACE ("REQUESTED\n");
601 /* We are assuming a requested stop is due to a SIGINT. */
602 ourstatus->kind = TARGET_WAITKIND_STOPPED;
603 ourstatus->value.sig = GDB_SIGNAL_INT;
604 nto_inferior.exit_signo = 0;
609 return ptid_build (status.pid, status.tid, 0);
612 /* Fetch inferior's registers for currently selected thread (CURRENT_INFERIOR).
613 If REGNO is -1, fetch all registers, or REGNO register only otherwise. */
616 nto_fetch_registers (struct regcache *regcache, int regno)
622 TRACE ("%s (regno=%d)\n", __func__, regno);
623 if (regno >= the_low_target.num_regs)
626 if (current_inferior == NULL)
628 TRACE ("current_inferior is NULL\n");
631 ptid = thread_to_gdb_id (current_inferior);
632 if (!nto_set_thread (ptid))
635 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_GETGREG, &greg, sizeof (greg),
638 if (regno == -1) /* All registers. */
640 for (regno = 0; regno != the_low_target.num_regs; ++regno)
642 const unsigned int registeroffset
643 = the_low_target.register_offset (regno);
644 supply_register (regcache, regno,
645 ((char *)&greg) + registeroffset);
650 const unsigned int registeroffset
651 = the_low_target.register_offset (regno);
652 if (registeroffset == -1)
654 supply_register (regcache, regno, ((char *)&greg) + registeroffset);
658 TRACE ("ERROR reading registers from inferior.\n");
661 /* Store registers for currently selected thread (CURRENT_INFERIOR).
662 We always store all registers, regardless of REGNO. */
665 nto_store_registers (struct regcache *regcache, int regno)
671 TRACE ("%s (regno:%d)\n", __func__, regno);
673 if (current_inferior == NULL)
675 TRACE ("current_inferior is NULL\n");
678 ptid = thread_to_gdb_id (current_inferior);
679 if (!nto_set_thread (ptid))
682 memset (&greg, 0, sizeof (greg));
683 for (regno = 0; regno != the_low_target.num_regs; ++regno)
685 const unsigned int regoffset
686 = the_low_target.register_offset (regno);
687 collect_register (regcache, regno, ((char *)&greg) + regoffset);
689 err = devctl (nto_inferior.ctl_fd, DCMD_PROC_SETGREG, &greg, sizeof (greg),
692 TRACE ("Error: setting registers.\n");
695 /* Read LEN bytes from inferior's memory address MEMADDR into
696 gdbserver's MYADDR buffer.
698 Return 0 on success -1 otherwise. */
701 nto_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
703 TRACE ("%s memaddr:0x%08lx, len:%d\n", __func__, memaddr, len);
705 if (nto_xfer_memory (memaddr, myaddr, len, 0) != len)
707 TRACE ("Failed to read memory\n");
714 /* Write LEN bytes from gdbserver's buffer MYADDR into inferior's
715 memory at address MEMADDR.
717 Return 0 on success -1 otherwise. */
720 nto_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
724 TRACE ("%s memaddr: 0x%08llx len: %d\n", __func__, memaddr, len);
725 if ((len_written = nto_xfer_memory (memaddr, (unsigned char *)myaddr, len,
729 TRACE ("Wanted to write: %d but written: %d\n", len, len_written);
736 /* Stop inferior. We always stop all threads. */
739 nto_request_interrupt (void)
741 TRACE ("%s\n", __func__);
742 nto_set_thread (ptid_build (nto_inferior.pid, 1, 0));
743 if (EOK != devctl (nto_inferior.ctl_fd, DCMD_PROC_STOP, NULL, 0, 0))
744 TRACE ("Error stopping inferior.\n");
747 /* Read auxiliary vector from inferior's memory into gdbserver's buffer
748 MYADDR. We always read whole auxv.
750 Return number of bytes stored in MYADDR buffer, 0 if OFFSET > 0
754 nto_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
757 CORE_ADDR initial_stack;
758 procfs_info procinfo;
760 TRACE ("%s\n", __func__);
764 err = devctl (nto_inferior.ctl_fd, DCMD_PROC_INFO, &procinfo,
769 initial_stack = procinfo.initial_stack;
771 return nto_read_auxv_from_initial_stack (initial_stack, myaddr, len);
775 nto_supports_z_point_type (char z_type)
781 case Z_PACKET_WRITE_WP:
782 case Z_PACKET_READ_WP:
783 case Z_PACKET_ACCESS_WP:
790 /* Insert {break/watch}point at address ADDR. SIZE is not used. */
793 nto_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
794 int size, struct raw_breakpoint *bp)
796 int wtype = _DEBUG_BREAK_HW; /* Always request HW. */
798 TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, len);
801 case raw_bkpt_type_sw:
802 wtype = _DEBUG_BREAK_EXEC;
804 case raw_bkpt_type_hw:
805 wtype |= _DEBUG_BREAK_EXEC;
807 case raw_bkpt_type_write_wp:
808 wtype |= _DEBUG_BREAK_RW;
810 case raw_bkpt_type_read_wp:
811 wtype |= _DEBUG_BREAK_RD;
813 case raw_bkpt_type_access_wp:
814 wtype |= _DEBUG_BREAK_RW;
817 return 1; /* Not supported. */
819 return nto_breakpoint (addr, wtype, 0);
822 /* Remove {break/watch}point at address ADDR. SIZE is not used. */
825 nto_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
826 int size, struct raw_breakpoint *bp)
828 int wtype = _DEBUG_BREAK_HW; /* Always request HW. */
830 TRACE ("%s type:%c addr: 0x%08lx len:%d\n", __func__, (int)type, addr, len);
833 case raw_bkpt_type_sw:
834 wtype = _DEBUG_BREAK_EXEC;
836 case raw_bkpt_type_hw:
837 wtype |= _DEBUG_BREAK_EXEC;
839 case raw_bkpt_type_write_wp:
840 wtype |= _DEBUG_BREAK_RW;
842 case raw_bkpt_type_read_wp:
843 wtype |= _DEBUG_BREAK_RD;
845 case raw_bkpt_type_access_wp:
846 wtype |= _DEBUG_BREAK_RW;
849 return 1; /* Not supported. */
851 return nto_breakpoint (addr, wtype, -1);
854 /* Check if the reason of stop for current thread (CURRENT_INFERIOR) is
857 Return 1 if stopped by watchpoint, 0 otherwise. */
860 nto_stopped_by_watchpoint (void)
864 TRACE ("%s\n", __func__);
865 if (nto_inferior.ctl_fd != -1 && current_inferior != NULL)
869 ptid = thread_to_gdb_id (current_inferior);
870 if (nto_set_thread (ptid))
872 const int watchmask = _DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR
873 | _DEBUG_FLAG_TRACE_MODIFY;
874 procfs_status status;
877 err = devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
879 if (err == EOK && (status.flags & watchmask))
883 TRACE ("%s: %s\n", __func__, ret ? "yes" : "no");
887 /* Get instruction pointer for CURRENT_INFERIOR thread.
889 Return inferior's instruction pointer value, or 0 on error. */
892 nto_stopped_data_address (void)
894 CORE_ADDR ret = (CORE_ADDR)0;
896 TRACE ("%s\n", __func__);
897 if (nto_inferior.ctl_fd != -1 && current_inferior != NULL)
901 ptid = thread_to_gdb_id (current_inferior);
903 if (nto_set_thread (ptid))
905 procfs_status status;
907 if (devctl (nto_inferior.ctl_fd, DCMD_PROC_STATUS, &status,
908 sizeof (status), 0) == EOK)
912 TRACE ("%s: 0x%08lx\n", __func__, ret);
916 /* We do not currently support non-stop. */
919 nto_supports_non_stop (void)
921 TRACE ("%s\n", __func__);
927 static struct target_ops nto_target_ops = {
939 NULL, /* prepare_to_access_memory */
940 NULL, /* done_accessing_memory */
943 NULL, /* nto_look_up_symbols */
944 nto_request_interrupt,
946 nto_supports_z_point_type,
949 nto_stopped_by_watchpoint,
950 nto_stopped_data_address,
951 NULL, /* nto_read_offsets */
952 NULL, /* thread_db_set_tls_address */
954 hostio_last_error_from_errno,
955 NULL, /* nto_qxfer_osdata */
956 NULL, /* xfer_siginfo */
957 nto_supports_non_stop,
959 NULL /* start_non_stop */
963 /* Global function called by server.c. Initializes QNX Neutrino
967 initialize_low (void)
971 TRACE ("%s\n", __func__);
972 set_target_ops (&nto_target_ops);
973 set_breakpoint_data (the_low_target.breakpoint,
974 the_low_target.breakpoint_len);
976 /* We use SIGUSR1 to gain control after we block waiting for a process.
977 We use sigwaitevent to wait. */
979 sigaddset (&set, SIGUSR1);
980 sigprocmask (SIG_BLOCK, &set, NULL);