VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dbg/dbgmodnm.cpp@ 39335

最後變更 在這個檔案從39335是 39083,由 vboxsync 提交於 13 年 前

IPRT: -Wunused-parameter.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 19.2 KB
 
1/* $Id: dbgmodnm.cpp 39083 2011-10-22 00:28:46Z vboxsync $ */
2/** @file
3 * IPRT - Debug Map Reader For NM Like Mapfiles.
4 */
5
6/*
7 * Copyright (C) 2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/dbg.h>
32#include "internal/iprt.h"
33
34#include <iprt/err.h>
35#include <iprt/ctype.h>
36#include <iprt/mem.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include "internal/dbgmod.h"
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/**
46 * Instance data.
47 */
48typedef struct RTDBGMODNM
49{
50 /** The debug container containing doing the real work. */
51 RTDBGMOD hCnt;
52} RTDBGMODNM;
53/** Pointer to instance data NM map reader. */
54typedef RTDBGMODNM *PRTDBGMODNM;
55
56
57
58/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
59static DECLCALLBACK(int) rtDbgModNm_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
60 PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
61{
62 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
63 return RTDbgModLineByAddr(pThis->hCnt, iSeg, off, poffDisp, pLineInfo);
64}
65
66
67/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
68static DECLCALLBACK(int) rtDbgModNm_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
69{
70 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
71 return RTDbgModLineByOrdinal(pThis->hCnt, iOrdinal, pLineInfo);
72}
73
74
75/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
76static DECLCALLBACK(uint32_t) rtDbgModNm_LineCount(PRTDBGMODINT pMod)
77{
78 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
79 return RTDbgModLineCount(pThis->hCnt);
80}
81
82
83/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
84static DECLCALLBACK(int) rtDbgModNm_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
85 uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
86{
87 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
88 Assert(!pszFile[cchFile]); NOREF(cchFile);
89 return RTDbgModLineAdd(pThis->hCnt, pszFile, uLineNo, iSeg, off, piOrdinal);
90}
91
92
93/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
94static DECLCALLBACK(int) rtDbgModNm_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
95 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
96{
97 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
98 return RTDbgModSymbolByAddr(pThis->hCnt, iSeg, off, poffDisp, pSymInfo);
99}
100
101
102/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
103static DECLCALLBACK(int) rtDbgModNm_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
104 PRTDBGSYMBOL pSymInfo)
105{
106 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
107 Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
108 return RTDbgModSymbolByName(pThis->hCnt, pszSymbol, pSymInfo);
109}
110
111
112/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
113static DECLCALLBACK(int) rtDbgModNm_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
114{
115 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
116 return RTDbgModSymbolByOrdinal(pThis->hCnt, iOrdinal, pSymInfo);
117}
118
119
120/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
121static DECLCALLBACK(uint32_t) rtDbgModNm_SymbolCount(PRTDBGMODINT pMod)
122{
123 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
124 return RTDbgModSymbolCount(pThis->hCnt);
125}
126
127
128/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
129static DECLCALLBACK(int) rtDbgModNm_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
130 RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
131 uint32_t *piOrdinal)
132{
133 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
134 Assert(!pszSymbol[cchSymbol]); NOREF(cchSymbol);
135 return RTDbgModSymbolAdd(pThis->hCnt, pszSymbol, iSeg, off, cb, fFlags, piOrdinal);
136}
137
138
139/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
140static DECLCALLBACK(int) rtDbgModNm_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
141{
142 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
143 return RTDbgModSegmentByIndex(pThis->hCnt, iSeg, pSegInfo);
144}
145
146
147/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
148static DECLCALLBACK(RTDBGSEGIDX) rtDbgModNm_SegmentCount(PRTDBGMODINT pMod)
149{
150 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
151 return RTDbgModSegmentCount(pThis->hCnt);
152}
153
154
155/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
156static DECLCALLBACK(int) rtDbgModNm_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
157 size_t cchName, uint32_t fFlags, PRTDBGSEGIDX piSeg)
158{
159 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
160 Assert(!pszName[cchName]); NOREF(cchName);
161 return RTDbgModSegmentAdd(pThis->hCnt, uRva, cb, pszName, fFlags, piSeg);
162}
163
164
165/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
166static DECLCALLBACK(RTUINTPTR) rtDbgModNm_ImageSize(PRTDBGMODINT pMod)
167{
168 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
169 return RTDbgModImageSize(pThis->hCnt);
170}
171
172
173/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
174static DECLCALLBACK(RTDBGSEGIDX) rtDbgModNm_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
175{
176 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
177 return RTDbgModRvaToSegOff(pThis->hCnt, uRva, poffSeg);
178}
179
180
181/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
182static DECLCALLBACK(int) rtDbgModNm_Close(PRTDBGMODINT pMod)
183{
184 PRTDBGMODNM pThis = (PRTDBGMODNM)pMod->pvDbgPriv;
185 RTDbgModRelease(pThis->hCnt);
186 pThis->hCnt = NIL_RTDBGMOD;
187 RTMemFree(pThis);
188 return VINF_SUCCESS;
189}
190
191
192/**
193 * Scans a NM-like map file.
194 *
195 * This implements both passes to avoid code duplication.
196 *
197 * @returns IPRT status code.
198 * @param pThis The instance data.
199 * @param pStrm The stream.
200 * @param fAddSymbols false in the first pass, true in the second.
201 */
202static int rtDbgModNmScanFile(PRTDBGMODNM pThis, PRTSTREAM pStrm, bool fAddSymbols)
203{
204 /*
205 * Try parse the stream.
206 */
207 RTUINTPTR SegZeroRva = fAddSymbols ? RTDbgModSegmentRva(pThis->hCnt, 0/*iSeg*/) : 0;
208 char szSym[RTDBG_SYMBOL_NAME_LENGTH] = "";
209 size_t cchMod = 0;
210 size_t offSym = 0;
211 unsigned cchAddr = 0;
212 uint64_t u64Low = UINT64_MAX;
213 uint64_t u64High = 0;
214 char szLine[512];
215 int rc;
216 while (RT_SUCCESS(rc = RTStrmGetLine(pStrm, szLine, sizeof(szLine))))
217 {
218 char chType;
219 if (RT_C_IS_XDIGIT(szLine[0]))
220 {
221 /*
222 * This is really what C was made for, string parsing.
223 */
224 /* The the symbol value (address). */
225 uint64_t u64Addr;
226 char *psz;
227 rc = RTStrToUInt64Ex(szLine, &psz, 16, &u64Addr);
228 if (rc != VWRN_TRAILING_CHARS)
229 return VERR_DBG_NOT_NM_MAP_FILE;
230
231 /* Check the address width. */
232 if (cchAddr == 0)
233 cchAddr = psz == &szLine[8] ? 8 : 16;
234 if (psz != &szLine[cchAddr])
235 return VERR_DBG_NOT_NM_MAP_FILE;
236
237 /* Get the type and check for single space before symbol. */
238 chType = szLine[cchAddr + 1];
239 if ( RT_C_IS_BLANK(chType)
240 || !RT_C_IS_BLANK(szLine[cchAddr + 2])
241 || RT_C_IS_BLANK(szLine[cchAddr + 3]))
242 return VERR_DBG_NOT_NM_MAP_FILE;
243
244 /* Find the end of the symbol name. */
245 char *pszName = &szLine[cchAddr + 3];
246 char *pszNameEnd = pszName;
247 char ch;
248 while ((ch = *pszNameEnd) != '\0' && !RT_C_IS_SPACE(ch))
249 pszNameEnd++;
250
251 /* Any module name (linux /proc/kallsyms) following in brackets? */
252 char *pszModName = pszNameEnd;
253 char *pszModNameEnd = pszModName;
254 if (*pszModName)
255 {
256 *pszModName++ = '\0';
257 pszModNameEnd = pszModName = RTStrStripL(pszModName);
258 if (*pszModName != '\0')
259 {
260 if (*pszModName != '[')
261 return VERR_DBG_NOT_LINUX_KALLSYMS;
262 pszModNameEnd = ++pszModName;
263 while ((ch = *pszModNameEnd) != '\0' && ch != ']')
264 pszModNameEnd++;
265 if (ch != ']')
266 return VERR_DBG_NOT_LINUX_KALLSYMS;
267 char *pszEnd = pszModNameEnd + 1;
268 if ((size_t)(pszModNameEnd - pszModName) >= 128) /* lazy bird */
269 return VERR_DBG_NOT_LINUX_KALLSYMS;
270 *pszModNameEnd = '\0';
271 if (*pszEnd)
272 pszEnd = RTStrStripL(pszEnd);
273 if (*pszEnd)
274 return VERR_DBG_NOT_LINUX_KALLSYMS;
275 }
276 }
277
278 /*
279 * Did the module change? Then update the symbol prefix.
280 */
281 if ( cchMod != (size_t)(pszModNameEnd - pszModName)
282 || memcmp(pszModName, szSym, cchMod))
283 {
284 cchMod = pszModNameEnd - pszModName;
285 if (cchMod == 0)
286 offSym = 0;
287 else
288 {
289 memcpy(szSym, pszModName, cchMod);
290 szSym[cchMod] = '.';
291 offSym = cchMod + 1;
292 }
293 szSym[offSym] = '\0';
294 }
295
296 /*
297 * Validate the type and add the symbol if it's a type we care for.
298 */
299 uint32_t fFlags = 0;
300 RTDBGSEGIDX iSegSym = 0;
301 switch (chType)
302 {
303 /* absolute */
304 case 'a':
305 case '?': /* /proc/kallsyms */
306 iSegSym = RTDBGSEGIDX_ABS;
307 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
308 break;
309 case 'A':
310 iSegSym = RTDBGSEGIDX_ABS;
311 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
312 break;
313
314 case 'b':
315 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
316 break;
317 case 'B':
318 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
319 break;
320
321 case 'c':
322 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_COMMON;
323 break;
324 case 'C':
325 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_COMMON;
326 break;
327
328 case 'd':
329 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
330 break;
331 case 'D':
332 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
333 break;
334
335 case 'g':
336 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
337 break;
338 case 'G':
339 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
340 break;
341
342 case 'i':
343 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
344 break;
345 case 'I':
346 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
347 break;
348
349 case 'r':
350 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_CONST;
351 break;
352 case 'R':
353 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_CONST;
354 break;
355
356 case 's':
357 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
358 break;
359 case 'S':
360 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
361 break;
362
363 case 't':
364 /// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_TEXT;
365 break;
366 case 'T':
367 /// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_TEXT;
368 break;
369
370 case 'w':
371 /// @todo fFlags |= RTDBG_SYM_FLAGS_WEAK | RTDBG_SYM_FLAGS_LOCAL; //???
372 break;
373 case 'W':
374 /// @todo fFlags |= RTDBG_SYM_FLAGS_WEAK | RTDBG_SYM_FLAGS_PUBLIC;
375 break;
376
377 case 'N': /* debug */
378 case 'n':
379 case '-': /* stabs */
380 case 'u': /* undefined (/proc/kallsyms) */
381 case 'U':
382 case 'v': /* weakext */
383 case 'V':
384 iSegSym = NIL_RTDBGSEGIDX;
385 break;
386
387 default:
388 return VERR_DBG_NOT_NM_MAP_FILE;
389 }
390
391 if (iSegSym != NIL_RTDBGSEGIDX)
392 {
393 if (fAddSymbols)
394 {
395 size_t cchName = pszNameEnd - pszName;
396 if (cchName >= sizeof(szSym) - offSym)
397 cchName = sizeof(szSym) - offSym - 1;
398 memcpy(&szSym[offSym], pszName, cchName + 1);
399 if (iSegSym == 0)
400 rc = RTDbgModSymbolAdd(pThis->hCnt, szSym, iSegSym, u64Addr - SegZeroRva, 0/*cb*/, fFlags, NULL);
401 else
402 rc = RTDbgModSymbolAdd(pThis->hCnt, szSym, iSegSym, u64Addr, 0/*cb*/, fFlags, NULL);
403 if ( RT_FAILURE(rc)
404 && rc != VERR_DBG_DUPLICATE_SYMBOL
405 && rc != VERR_DBG_ADDRESS_CONFLICT) /* (don't be too strict) */
406 return rc;
407 }
408
409 /* Track segment span. */
410 if (iSegSym == 0)
411 {
412 if (u64Low > u64Addr)
413 u64Low = u64Addr;
414 if (u64High < u64Addr)
415 u64High = u64Addr;
416 }
417 }
418 }
419 else
420 {
421 /*
422 * This is either a blank line or a symbol without an address.
423 */
424 RTStrStripR(szLine);
425 if (szLine[0])
426 {
427 size_t cch = strlen(szLine);
428 if (cchAddr == 0)
429 cchAddr = cch < 16+3 || szLine[8+1] != ' ' ? 8 : 16;
430 if (cch < cchAddr+3+1)
431 return VERR_DBG_NOT_NM_MAP_FILE;
432 chType = szLine[cchAddr + 1];
433 if ( chType != 'U'
434 && chType != 'w')
435 return VERR_DBG_NOT_NM_MAP_FILE;
436 char *pszType = RTStrStripL(szLine);
437 if (pszType != &szLine[cchAddr + 1])
438 return VERR_DBG_NOT_NM_MAP_FILE;
439 if (!RT_C_IS_BLANK(szLine[cchAddr + 2]))
440 return VERR_DBG_NOT_NM_MAP_FILE;
441 }
442 /* else: blank - ignored */
443 }
444 }
445
446 /*
447 * The final segment.
448 */
449 if (rc == VERR_EOF)
450 {
451 if (fAddSymbols)
452 rc = VINF_SUCCESS;
453 else
454 {
455 if ( u64Low != UINT64_MAX
456 || u64High != 0)
457 rc = RTDbgModSegmentAdd(pThis->hCnt, u64Low, u64High - u64Low + 1, "main", 0, NULL);
458 else /* No sensible symbols... throw an error instead? */
459 rc = RTDbgModSegmentAdd(pThis->hCnt, 0, 0, "main", 0, NULL);
460 }
461 }
462
463 return rc;
464}
465
466
467/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
468static DECLCALLBACK(int) rtDbgModNm_TryOpen(PRTDBGMODINT pMod)
469{
470 /*
471 * Fend off images.
472 */
473 if ( !pMod->pszDbgFile
474 || pMod->pImgVt)
475 return VERR_DBG_NO_MATCHING_INTERPRETER;
476
477 /*
478 * Try open the file and create an instance.
479 */
480 PRTSTREAM pStrm;
481 int rc = RTStrmOpen(pMod->pszDbgFile, "r", &pStrm);
482 if (RT_SUCCESS(rc))
483 {
484 PRTDBGMODNM pThis = (PRTDBGMODNM)RTMemAlloc(sizeof(*pThis));
485 if (pThis)
486 {
487 rc = RTDbgModCreate(&pThis->hCnt, pMod->pszName, 0 /*cbSeg*/, 0 /*fFlags*/);
488 if (RT_SUCCESS(rc))
489 {
490 /*
491 * Scan the file twice, first to figure the segment
492 * sizes, then to add the symbol.
493 */
494 rc = rtDbgModNmScanFile(pThis, pStrm, false /*fAddSymbols*/);
495 if (RT_SUCCESS(rc))
496 rc = RTStrmRewind(pStrm);
497 if (RT_SUCCESS(rc))
498 rc = rtDbgModNmScanFile(pThis, pStrm, true /*fAddSymbols*/);
499 if (RT_SUCCESS(rc))
500 {
501 RTStrmClose(pStrm);
502 pMod->pvDbgPriv = pThis;
503 return rc;
504 }
505 }
506 RTDbgModRelease(pThis->hCnt);
507 }
508 else
509 rc = VERR_NO_MEMORY;
510 RTStrmClose(pStrm);
511 }
512 return rc;
513}
514
515
516
517/** Virtual function table for the NM-like map file reader. */
518DECL_HIDDEN_CONST(RTDBGMODVTDBG) const g_rtDbgModVtDbgNm =
519{
520 /*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
521 /*.fSupports = */ RT_DBGTYPE_MAP,
522 /*.pszName = */ "nm",
523 /*.pfnTryOpen = */ rtDbgModNm_TryOpen,
524 /*.pfnClose = */ rtDbgModNm_Close,
525
526 /*.pfnRvaToSegOff = */ rtDbgModNm_RvaToSegOff,
527 /*.pfnImageSize = */ rtDbgModNm_ImageSize,
528
529 /*.pfnSegmentAdd = */ rtDbgModNm_SegmentAdd,
530 /*.pfnSegmentCount = */ rtDbgModNm_SegmentCount,
531 /*.pfnSegmentByIndex = */ rtDbgModNm_SegmentByIndex,
532
533 /*.pfnSymbolAdd = */ rtDbgModNm_SymbolAdd,
534 /*.pfnSymbolCount = */ rtDbgModNm_SymbolCount,
535 /*.pfnSymbolByOrdinal = */ rtDbgModNm_SymbolByOrdinal,
536 /*.pfnSymbolByName = */ rtDbgModNm_SymbolByName,
537 /*.pfnSymbolByAddr = */ rtDbgModNm_SymbolByAddr,
538
539 /*.pfnLineAdd = */ rtDbgModNm_LineAdd,
540 /*.pfnLineCount = */ rtDbgModNm_LineCount,
541 /*.pfnLineByOrdinal = */ rtDbgModNm_LineByOrdinal,
542 /*.pfnLineByAddr = */ rtDbgModNm_LineByAddr,
543
544 /*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
545};
546
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette