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