Whamcloud - gitweb
LU-2456 lnet: DLC Feature dynamic net config
[fs/lustre-release.git] / libcfs / libcfs / darwin / darwin-utils.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  *
34  * libcfs/libcfs/darwin/darwin-utils.c
35  *
36  * Darwin porting library
37  * Make things easy to port
38  *
39  * Author: Phil Schwan <phil@clusterfs.com>
40  */
41
42 #define DEBUG_SUBSYSTEM S_LNET
43
44 #include <mach/mach_types.h>
45 #include <string.h>
46 #include <sys/errno.h>
47 #include <sys/types.h>
48 #include <sys/fcntl.h>
49 #include <lnet/types.h>
50
51 #include <libcfs/libcfs.h>
52
53 #ifndef isspace
54 inline int
55 isspace(char c)
56 {
57         return (c == ' ' || c == '\t' || c == '\n' || c == '\12');
58 }
59 #endif
60
61 char * strpbrk(const char * cs,const char * ct)
62 {
63         const char *sc1,*sc2;
64         
65         for( sc1 = cs; *sc1 != '\0'; ++sc1) {
66                 for( sc2 = ct; *sc2 != '\0'; ++sc2) {
67                         if (*sc1 == *sc2)
68                                 return (char *) sc1;
69                 }
70         }
71         return NULL;
72 }
73
74 char * strsep(char **s, const char *ct)
75 {
76         char *sbegin = *s, *end;
77         
78         if (sbegin == NULL)
79                 return NULL;
80         end = strpbrk(sbegin, ct);
81         if (end != NULL)
82                 *end++ = '\0';
83         *s = end;
84
85         return sbegin;
86 }
87
88 size_t strnlen(const char * s, size_t count)
89 {
90         const char *sc;
91
92         for (sc = s; count-- && *sc != '\0'; ++sc)
93                 /* nothing */;
94         return sc - s;
95 }
96
97 char *
98 strstr(const char *in, const char *str)
99 {
100         char c;
101         size_t len;
102         
103         c = *str++;
104         if (!c)
105                 return (char *) in;     // Trivial empty string case
106         len = strlen(str);
107         do {
108                 char sc;
109                 do {
110                         sc = *in++;
111                         if (!sc)
112                                 return (char *) 0;
113                 } while (sc != c);
114         } while (strncmp(in, str, len) != 0);
115         return (char *) (in - 1);
116 }
117
118 char *
119 strrchr(const char *p, int ch)
120 {
121         const char *end = p + strlen(p);
122         do {
123                 if (*end == (char)ch)
124                         return (char *)end;
125         } while (--end >= p);
126         return NULL;
127 }
128
129 char *
130 ul2dstr(unsigned long address, char *buf, int len)
131 {
132         char *pos = buf + len - 1;
133
134         if (len <= 0 || !buf)
135                 return NULL;
136         *pos = 0;
137         while (address) {
138                 if (!--len) break;
139                 *--pos = address % 10 + '0';
140                 address /= 10;
141         }
142         return pos;
143 }
144
145 /*
146  * miscellaneous libcfs stuff
147  */
148
149 /*
150  * Convert server error code to client format.
151  * Linux errno.h.
152  */
153
154 /* obtained by
155  *
156  *     cc /usr/include/asm/errno.h -E -dM | grep '#define E' | sort -n -k3,3
157  *
158  */
159 enum linux_errnos {
160         LINUX_EPERM              = 1,
161         LINUX_ENOENT             = 2,
162         LINUX_ESRCH              = 3,
163         LINUX_EINTR              = 4,
164         LINUX_EIO                = 5,
165         LINUX_ENXIO              = 6,
166         LINUX_E2BIG              = 7,
167         LINUX_ENOEXEC            = 8,
168         LINUX_EBADF              = 9,
169         LINUX_ECHILD             = 10,
170         LINUX_EAGAIN             = 11,
171         LINUX_ENOMEM             = 12,
172         LINUX_EACCES             = 13,
173         LINUX_EFAULT             = 14,
174         LINUX_ENOTBLK            = 15,
175         LINUX_EBUSY              = 16,
176         LINUX_EEXIST             = 17,
177         LINUX_EXDEV              = 18,
178         LINUX_ENODEV             = 19,
179         LINUX_ENOTDIR            = 20,
180         LINUX_EISDIR             = 21,
181         LINUX_EINVAL             = 22,
182         LINUX_ENFILE             = 23,
183         LINUX_EMFILE             = 24,
184         LINUX_ENOTTY             = 25,
185         LINUX_ETXTBSY            = 26,
186         LINUX_EFBIG              = 27,
187         LINUX_ENOSPC             = 28,
188         LINUX_ESPIPE             = 29,
189         LINUX_EROFS              = 30,
190         LINUX_EMLINK             = 31,
191         LINUX_EPIPE              = 32,
192         LINUX_EDOM               = 33,
193         LINUX_ERANGE             = 34,
194         LINUX_EDEADLK            = 35,
195         LINUX_ENAMETOOLONG       = 36,
196         LINUX_ENOLCK             = 37,
197         LINUX_ENOSYS             = 38,
198         LINUX_ENOTEMPTY          = 39,
199         LINUX_ELOOP              = 40,
200         LINUX_ENOMSG             = 42,
201         LINUX_EIDRM              = 43,
202         LINUX_ECHRNG             = 44,
203         LINUX_EL2NSYNC           = 45,
204         LINUX_EL3HLT             = 46,
205         LINUX_EL3RST             = 47,
206         LINUX_ELNRNG             = 48,
207         LINUX_EUNATCH            = 49,
208         LINUX_ENOCSI             = 50,
209         LINUX_EL2HLT             = 51,
210         LINUX_EBADE              = 52,
211         LINUX_EBADR              = 53,
212         LINUX_EXFULL             = 54,
213         LINUX_ENOANO             = 55,
214         LINUX_EBADRQC            = 56,
215         LINUX_EBADSLT            = 57,
216         LINUX_EBFONT             = 59,
217         LINUX_ENOSTR             = 60,
218         LINUX_ENODATA            = 61,
219         LINUX_ETIME              = 62,
220         LINUX_ENOSR              = 63,
221         LINUX_ENONET             = 64,
222         LINUX_ENOPKG             = 65,
223         LINUX_EREMOTE            = 66,
224         LINUX_ENOLINK            = 67,
225         LINUX_EADV               = 68,
226         LINUX_ESRMNT             = 69,
227         LINUX_ECOMM              = 70,
228         LINUX_EPROTO             = 71,
229         LINUX_EMULTIHOP          = 72,
230         LINUX_EDOTDOT            = 73,
231         LINUX_EBADMSG            = 74,
232         LINUX_EOVERFLOW          = 75,
233         LINUX_ENOTUNIQ           = 76,
234         LINUX_EBADFD             = 77,
235         LINUX_EREMCHG            = 78,
236         LINUX_ELIBACC            = 79,
237         LINUX_ELIBBAD            = 80,
238         LINUX_ELIBSCN            = 81,
239         LINUX_ELIBMAX            = 82,
240         LINUX_ELIBEXEC           = 83,
241         LINUX_EILSEQ             = 84,
242         LINUX_ERESTART           = 85,
243         LINUX_ESTRPIPE           = 86,
244         LINUX_EUSERS             = 87,
245         LINUX_ENOTSOCK           = 88,
246         LINUX_EDESTADDRREQ       = 89,
247         LINUX_EMSGSIZE           = 90,
248         LINUX_EPROTOTYPE         = 91,
249         LINUX_ENOPROTOOPT        = 92,
250         LINUX_EPROTONOSUPPORT    = 93,
251         LINUX_ESOCKTNOSUPPORT    = 94,
252         LINUX_EOPNOTSUPP         = 95,
253         LINUX_EPFNOSUPPORT       = 96,
254         LINUX_EAFNOSUPPORT       = 97,
255         LINUX_EADDRINUSE         = 98,
256         LINUX_EADDRNOTAVAIL      = 99,
257         LINUX_ENETDOWN           = 100,
258         LINUX_ENETUNREACH        = 101,
259         LINUX_ENETRESET          = 102,
260         LINUX_ECONNABORTED       = 103,
261         LINUX_ECONNRESET         = 104,
262         LINUX_ENOBUFS            = 105,
263         LINUX_EISCONN            = 106,
264         LINUX_ENOTCONN           = 107,
265         LINUX_ESHUTDOWN          = 108,
266         LINUX_ETOOMANYREFS       = 109,
267         LINUX_ETIMEDOUT          = 110,
268         LINUX_ECONNREFUSED       = 111,
269         LINUX_EHOSTDOWN          = 112,
270         LINUX_EHOSTUNREACH       = 113,
271         LINUX_EALREADY           = 114,
272         LINUX_EINPROGRESS        = 115,
273         LINUX_ESTALE             = 116,
274         LINUX_EUCLEAN            = 117,
275         LINUX_ENOTNAM            = 118,
276         LINUX_ENAVAIL            = 119,
277         LINUX_EISNAM             = 120,
278         LINUX_EREMOTEIO          = 121,
279         LINUX_EDQUOT             = 122,
280         LINUX_ENOMEDIUM          = 123,
281         LINUX_EMEDIUMTYPE        = 124,
282
283         /*
284          * we don't need these, but for completeness..
285          */
286         LINUX_EDEADLOCK          = LINUX_EDEADLK,
287         LINUX_EWOULDBLOCK        = LINUX_EAGAIN
288 };
289
290 int convert_server_error(__u64 ecode)
291 {
292         int sign;
293         int code;
294
295         static int errno_xlate[] = {
296                 /* success is always success */
297                 [0]                     = 0,
298                 [LINUX_EPERM]           = EPERM,
299                 [LINUX_ENOENT]          = ENOENT,
300                 [LINUX_ESRCH]           = ESRCH,
301                 [LINUX_EINTR]           = EINTR,
302                 [LINUX_EIO]             = EIO,
303                 [LINUX_ENXIO]           = ENXIO,
304                 [LINUX_E2BIG]           = E2BIG,
305                 [LINUX_ENOEXEC]         = ENOEXEC,
306                 [LINUX_EBADF]           = EBADF,
307                 [LINUX_ECHILD]          = ECHILD,
308                 [LINUX_EAGAIN]          = EAGAIN,
309                 [LINUX_ENOMEM]          = ENOMEM,
310                 [LINUX_EACCES]          = EACCES,
311                 [LINUX_EFAULT]          = EFAULT,
312                 [LINUX_ENOTBLK]         = ENOTBLK,
313                 [LINUX_EBUSY]           = EBUSY,
314                 [LINUX_EEXIST]          = EEXIST,
315                 [LINUX_EXDEV]           = EXDEV,
316                 [LINUX_ENODEV]          = ENODEV,
317                 [LINUX_ENOTDIR]         = ENOTDIR,
318                 [LINUX_EISDIR]          = EISDIR,
319                 [LINUX_EINVAL]          = EINVAL,
320                 [LINUX_ENFILE]          = ENFILE,
321                 [LINUX_EMFILE]          = EMFILE,
322                 [LINUX_ENOTTY]          = ENOTTY,
323                 [LINUX_ETXTBSY]         = ETXTBSY,
324                 [LINUX_EFBIG]           = EFBIG,
325                 [LINUX_ENOSPC]          = ENOSPC,
326                 [LINUX_ESPIPE]          = ESPIPE,
327                 [LINUX_EROFS]           = EROFS,
328                 [LINUX_EMLINK]          = EMLINK,
329                 [LINUX_EPIPE]           = EPIPE,
330                 [LINUX_EDOM]            = EDOM,
331                 [LINUX_ERANGE]          = ERANGE,
332                 [LINUX_EDEADLK]         = EDEADLK,
333                 [LINUX_ENAMETOOLONG]    = ENAMETOOLONG,
334                 [LINUX_ENOLCK]          = ENOLCK,
335                 [LINUX_ENOSYS]          = ENOSYS,
336                 [LINUX_ENOTEMPTY]       = ENOTEMPTY,
337                 [LINUX_ELOOP]           = ELOOP,
338                 [LINUX_ENOMSG]          = ENOMSG,
339                 [LINUX_EIDRM]           = EIDRM,
340                 [LINUX_ECHRNG]          = EINVAL /* ECHRNG */,
341                 [LINUX_EL2NSYNC]        = EINVAL /* EL2NSYNC */,
342                 [LINUX_EL3HLT]          = EINVAL /* EL3HLT */,
343                 [LINUX_EL3RST]          = EINVAL /* EL3RST */,
344                 [LINUX_ELNRNG]          = EINVAL /* ELNRNG */,
345                 [LINUX_EUNATCH]         = EINVAL /* EUNATCH */,
346                 [LINUX_ENOCSI]          = EINVAL /* ENOCSI */,
347                 [LINUX_EL2HLT]          = EINVAL /* EL2HLT */,
348                 [LINUX_EBADE]           = EINVAL /* EBADE */,
349                 [LINUX_EBADR]           = EBADRPC,
350                 [LINUX_EXFULL]          = EINVAL /* EXFULL */,
351                 [LINUX_ENOANO]          = EINVAL /* ENOANO */,
352                 [LINUX_EBADRQC]         = EINVAL /* EBADRQC */,
353                 [LINUX_EBADSLT]         = EINVAL /* EBADSLT */,
354                 [LINUX_EBFONT]          = EINVAL /* EBFONT */,
355                 [LINUX_ENOSTR]          = EINVAL /* ENOSTR */,
356                 [LINUX_ENODATA]         = EINVAL /* ENODATA */,
357                 [LINUX_ETIME]           = EINVAL /* ETIME */,
358                 [LINUX_ENOSR]           = EINVAL /* ENOSR */,
359                 [LINUX_ENONET]          = EINVAL /* ENONET */,
360                 [LINUX_ENOPKG]          = EINVAL /* ENOPKG */,
361                 [LINUX_EREMOTE]         = EREMOTE,
362                 [LINUX_ENOLINK]         = EINVAL /* ENOLINK */,
363                 [LINUX_EADV]            = EINVAL /* EADV */,
364                 [LINUX_ESRMNT]          = EINVAL /* ESRMNT */,
365                 [LINUX_ECOMM]           = EINVAL /* ECOMM */,
366                 [LINUX_EPROTO]          = EPROTOTYPE,
367                 [LINUX_EMULTIHOP]       = EINVAL /* EMULTIHOP */,
368                 [LINUX_EDOTDOT]         = EINVAL /* EDOTDOT */,
369                 [LINUX_EBADMSG]         = EINVAL /* EBADMSG */,
370                 [LINUX_EOVERFLOW]       = EOVERFLOW,
371                 [LINUX_ENOTUNIQ]        = EINVAL /* ENOTUNIQ */,
372                 [LINUX_EBADFD]          = EINVAL /* EBADFD */,
373                 [LINUX_EREMCHG]         = EINVAL /* EREMCHG */,
374                 [LINUX_ELIBACC]         = EINVAL /* ELIBACC */,
375                 [LINUX_ELIBBAD]         = EINVAL /* ELIBBAD */,
376                 [LINUX_ELIBSCN]         = EINVAL /* ELIBSCN */,
377                 [LINUX_ELIBMAX]         = EINVAL /* ELIBMAX */,
378                 [LINUX_ELIBEXEC]        = EINVAL /* ELIBEXEC */,
379                 [LINUX_EILSEQ]          = EILSEQ,
380                 [LINUX_ERESTART]        = EINVAL /* because ERESTART is
381                                                   * negative in XNU */,
382                 [LINUX_ESTRPIPE]        = EINVAL /* ESTRPIPE */,
383                 [LINUX_EUSERS]          = EUSERS,
384                 [LINUX_ENOTSOCK]        = ENOTSOCK,
385                 [LINUX_EDESTADDRREQ]    = EDESTADDRREQ,
386                 [LINUX_EMSGSIZE]        = EMSGSIZE,
387                 [LINUX_EPROTOTYPE]      = EPROTOTYPE,
388                 [LINUX_ENOPROTOOPT]     = ENOPROTOOPT,
389                 [LINUX_EPROTONOSUPPORT] = EPROTONOSUPPORT,
390                 [LINUX_ESOCKTNOSUPPORT] = ESOCKTNOSUPPORT,
391                 [LINUX_EOPNOTSUPP]      = EOPNOTSUPP,
392                 [LINUX_EPFNOSUPPORT]    = EPFNOSUPPORT,
393                 [LINUX_EAFNOSUPPORT]    = EAFNOSUPPORT,
394                 [LINUX_EADDRINUSE]      = EADDRINUSE,
395                 [LINUX_EADDRNOTAVAIL]   = EADDRNOTAVAIL,
396                 [LINUX_ENETDOWN]        = ENETDOWN,
397                 [LINUX_ENETUNREACH]     = ENETUNREACH,
398                 [LINUX_ENETRESET]       = ENETRESET,
399                 [LINUX_ECONNABORTED]    = ECONNABORTED,
400                 [LINUX_ECONNRESET]      = ECONNRESET,
401                 [LINUX_ENOBUFS]         = ENOBUFS,
402                 [LINUX_EISCONN]         = EISCONN,
403                 [LINUX_ENOTCONN]        = ENOTCONN,
404                 [LINUX_ESHUTDOWN]       = ESHUTDOWN,
405                 [LINUX_ETOOMANYREFS]    = ETOOMANYREFS,
406                 [LINUX_ETIMEDOUT]       = ETIMEDOUT,
407                 [LINUX_ECONNREFUSED]    = ECONNREFUSED,
408                 [LINUX_EHOSTDOWN]       = EHOSTDOWN,
409                 [LINUX_EHOSTUNREACH]    = EHOSTUNREACH,
410                 [LINUX_EALREADY]        = EALREADY,
411                 [LINUX_EINPROGRESS]     = EINPROGRESS,
412                 [LINUX_ESTALE]          = ESTALE,
413                 [LINUX_EUCLEAN]         = EINVAL /* EUCLEAN */,
414                 [LINUX_ENOTNAM]         = EINVAL /* ENOTNAM */,
415                 [LINUX_ENAVAIL]         = EINVAL /* ENAVAIL */,
416                 [LINUX_EISNAM]          = EINVAL /* EISNAM */,
417                 [LINUX_EREMOTEIO]       = EINVAL /* EREMOTEIO */,
418                 [LINUX_EDQUOT]          = EDQUOT,
419                 [LINUX_ENOMEDIUM]       = EINVAL /* ENOMEDIUM */,
420                 [LINUX_EMEDIUMTYPE]     = EINVAL /* EMEDIUMTYPE */,
421         };
422         code = (int)ecode;
423         if (code >= 0) {
424                 sign = +1;
425         } else {
426                 sign = -1;
427                 code = -code;
428         }
429         if (code < (sizeof errno_xlate) / (sizeof errno_xlate[0])) {
430                 code = errno_xlate[code];
431                 LASSERT(code >= 0);
432         }
433         return sign * code;
434 }
435
436 enum {
437         LINUX_O_RDONLY   =           00,
438         LINUX_O_WRONLY   =           01,
439         LINUX_O_RDWR     =           02,
440         LINUX_O_CREAT    =         0100,
441         LINUX_O_EXCL     =         0200,
442         LINUX_O_NOCTTY   =         0400,
443         LINUX_O_TRUNC    =        01000,
444         LINUX_O_APPEND   =        02000,
445         LINUX_O_NONBLOCK =        04000,
446         LINUX_O_NDELAY   =             LINUX_O_NONBLOCK,
447         LINUX_O_SYNC     =       010000,
448         LINUX_O_FSYNC    =             LINUX_O_SYNC,
449         LINUX_O_ASYNC    =       020000,
450         LINUX_O_DIRECT   =       040000,
451         LINUX_O_NOFOLLOW =      0400000
452 };
453
454 static inline void obit_convert(int *cflag, int *sflag,
455                                 unsigned cmask, unsigned smask)
456 {
457         if (*cflag & cmask != 0) {
458                 *sflag |= smask;
459                 *cflag &= ~cmask;
460         }
461 }
462
463 /*
464  * convert <fcntl.h> flag from XNU client to Linux _i386_ server.
465  */
466 int convert_client_oflag(int cflag, int *result)
467 {
468         int sflag = 0;
469
470         cflag = 0;
471         obit_convert(&cflag, &sflag, O_RDONLY,   LINUX_O_RDONLY);
472         obit_convert(&cflag, &sflag, O_WRONLY,   LINUX_O_WRONLY);
473         obit_convert(&cflag, &sflag, O_RDWR,     LINUX_O_RDWR);
474         obit_convert(&cflag, &sflag, O_NONBLOCK, LINUX_O_NONBLOCK);
475         obit_convert(&cflag, &sflag, O_APPEND,   LINUX_O_APPEND);
476         obit_convert(&cflag, &sflag, O_ASYNC,    LINUX_O_ASYNC);
477         obit_convert(&cflag, &sflag, O_FSYNC,    LINUX_O_FSYNC);
478         obit_convert(&cflag, &sflag, O_NOFOLLOW, LINUX_O_NOFOLLOW);
479         obit_convert(&cflag, &sflag, O_CREAT,    LINUX_O_CREAT);
480         obit_convert(&cflag, &sflag, O_TRUNC,    LINUX_O_TRUNC);
481         obit_convert(&cflag, &sflag, O_EXCL,     LINUX_O_EXCL);
482         obit_convert(&cflag, &sflag, O_CREAT,    LINUX_O_CREAT);
483         obit_convert(&cflag, &sflag, O_NDELAY,   LINUX_O_NDELAY);
484         obit_convert(&cflag, &sflag, O_NOCTTY,   LINUX_O_NOCTTY);
485         /*
486          * Some more obscure BSD flags have no Linux counterparts:
487          *
488          * O_SHLOCK     0x0010
489          * O_EXLOCK     0x0020
490          * O_EVTONLY    0x8000
491          * O_POPUP      0x80000000
492          * O_ALERT      0x20000000
493          */
494         if (cflag == 0) {
495                 *result = sflag;
496                 return 0;
497         } else
498                 return -EINVAL;
499 }
500
501 #ifdef __DARWIN8__
502 #else /* !__DARWIN8__ */
503 extern int unix_syscall();
504 extern int unix_syscall_return();
505
506 extern int ktrsysret();
507 extern int ktrace();
508
509 extern int ast_taken();
510 extern int ast_check();
511
512 extern int trap();
513 extern int syscall_trace();
514
515 static int is_addr_in_range(void *addr, void *start, void *end)
516 {
517         return start <= addr && addr <= end;
518 }
519
520 extern void cfs_thread_agent (void);
521
522 static int is_last_frame(void *addr)
523 {
524         if (addr == NULL)
525                 return 1;
526         else if (is_addr_in_range(addr, unix_syscall, unix_syscall_return))
527                 return 1;
528         else if (is_addr_in_range(addr, ktrsysret, ktrace))
529                 return 1;
530         else if (is_addr_in_range(addr, ast_taken, ast_check))
531                 return 1;
532         else if (is_addr_in_range(addr, trap, syscall_trace))
533                 return 1;
534         else if (is_addr_in_range(addr, cfs_thread_agent, kthread_run))
535                 return 1;
536         else
537                 return 0;
538 }
539
540 static void *get_frame(int i)
541 {
542         void *result;
543
544 #define CASE(i) case (i): result = __builtin_return_address(i); break
545         switch (i + 1) {
546                 CASE(1);
547                 CASE(2);
548                 CASE(3);
549                 CASE(4);
550                 CASE(5);
551                 CASE(6);
552                 CASE(7);
553                 CASE(8);
554                 CASE(9);
555                 CASE(10);
556                 CASE(11);
557                 CASE(12);
558                 CASE(13);
559                 CASE(14);
560                 CASE(15);
561                 CASE(16);
562                 CASE(17);
563                 CASE(18);
564                 CASE(19);
565                 CASE(20);
566         default:
567                 panic("impossible frame number: %d\n", i);
568                 result = NULL;
569         }
570         return result;
571 }
572
573 void cfs_stack_trace_fill(struct cfs_stack_trace *trace)
574 {
575         int i;
576
577         memset(trace, 0, sizeof *trace);
578         for (i = 0; i < ARRAY_SIZE(trace->frame); ++ i) {
579                 void *addr;
580
581                 addr = get_frame(i);
582                 trace->frame[i] = addr;
583                 if (is_last_frame(addr))
584                         break;
585         }
586 }
587
588 void *cfs_stack_trace_frame(struct cfs_stack_trace *trace, int frame_no)
589 {
590         if (0 <= frame_no && frame_no < ARRAY_SIZE(trace->frame))
591                 return trace->frame[frame_no];
592         else
593                 return NULL;
594 }
595 #endif /* !__DARWIN8__ */