PDA

View Full Version : استفاده از رهنمودهای کامپایلر



حمیدرضاصادقیان
پنج شنبه 29 شهریور 1386, 12:32 عصر
سلام دوستان. میخواستم ببینم از رهنمود {+D$} چطور میتوانم در برنامه استفاده کنم.
ونتیجه دیباگ اونو کجا میتونم ببینم.

m-khorsandi
پنج شنبه 29 شهریور 1386, 14:23 عصر
What access violations are and how to prevent AVs (http://barnamenevis.org/forum/showthread.php?t=64481)

حمیدرضاصادقیان
پنج شنبه 29 شهریور 1386, 23:19 عصر
اقای خورسندی عزیز اتفاقا همین مقاله رو خوندم و برام سوال پیش اومد. واضح توضیح نداده بودین که چطور میشه debug های مربوط به فرم رو خوند.در مورد map file توضیح داده بودین. من فعالش کردم .برنامه رو کامپایل کردم ولی در هنگام رخ دادن AV در mapfile چیزی مشاهده نکردم.اگه میشه این قسمت رو بیشتر توضیح بدین ممنون میشم.

m-khorsandi
جمعه 30 شهریور 1386, 17:08 عصر
شما map file رو بر روی Detailed تنظیم کنید و آدرسی که از AV دریافت میکنید رو در mapfile جستجو کنید، در ضمن mapfile هنگام کامپایل برنامه ساخته میشه و بعد از اون در حین اجرای برنامه تغییری نمیکنه.
سعی میکنم تو یکی-دو روز آینده بیشتر توضیح بدم.

حمیدرضاصادقیان
جمعه 30 شهریور 1386, 21:01 عصر
ممنون میشم .درمورد پارامتر {+D$} هم توضیحی بدین.و نحوه استفاده از اون.
باتشکر.

حمیدرضاصادقیان
یک شنبه 01 مهر 1386, 15:02 عصر
آقای خرسندی عزیز بی صبرانه منتظر توضیحات ارزنده شما هستم.

m-khorsandi
دوشنبه 02 مهر 1386, 11:20 صبح
تبدیل آدرس AV در دلفی


این امکان وجود دارد که آدرس دریافتی از یک Access Violation که حین اجرای برنامه پیش می‌آید را به نام یونیت، نام تابع و شماره خط در سورس کد تبدیل کرد. این کار با یک Detailed map file که در زمان کامپایل برنامه ایجاد می‌شود، قابل انجام است.

ایجاد یک map file‌:
ابتدا لازم است که یک map file به روش زیر برای پروژه ایجاد کنیم:
1- مطمئن باشید که سوئیچ Code Optimization که در منوی Project -> Options در تب Compiler هست، غیر فعال باشد.
2- از منوی Project -> Options در تب Linker سوییچ map file را برروی Detailed تنظیم کنید.
3- حالا برنامه را با Project -> Build All دوباره Build کنید. یک map file با نام پروژه ساخته می‌شود، مثلا اگر نام پروژه Project.exe باشد map fileیی با نام project.map خواهیم داشت.


تبدیل آدرس AV :
حالا اگر یک AV دریافت کنید، میتوانید با استفاده از روش زیر آن را تبدیل به نام یونیت، نام تابع و شماره خط در سورس کد کنید:

1- به Project -> Options -> Linker -> Image base مقدار $1000 را اضافه کنید (هر دو مقدار هگزادسیمال‌اند)، حاصل به شکل زیر خواهد بود:

Offset = Linker | Memory sized | Image Base value + $1000

و چون مقدار پیش‌فرض Image base معمولاً $00400000 هست، مقدار نهایی برابر با $00401000 خواهد بود.

حالا Offset را از آدرس دریافتی از AV کم کنید، به شکل زیر:

Map file address = Access Violation address – offset

برای مثال، اگر آدرس AV مقدار $00437575 را داشته باشد، پس خواهیم داشت :


Offset = $400000 + $1000 = $401000 و
Map file address = $00437575 - $401000 = $36575


2- Map file را با یک ادیتور متنی(فرضاً Notepad) باز کنید، با IDE دلفی هم می‌توانید این کار را بکنید(map file یک فایل متنی است).


3- پیدا کردن نام یونیت :
داخل map file بخشی که شامل نام یونیتهاست تحت عنوان "Detailed map of segment" را پیدا کنید، معمولاً در بالای فایل قرار دارد. این بخش شامل لیست segment، آدرس شروع، طول و سایر اطلاعات و نام یونیت هست که براساس آدرس مرتب شده اند.
برای پیدا کردن نام یونیت در جایی که AV روی داده، آدرس map file را با استفاده از آدرس شروع و اندازه در لیست پیدا کنید. برای مثال، اگر آدرس map file از AV برابر با $36575 باشد، نام یونیت Unit1 خواهد بود.
مثال :

http://i6.tinypic.com/53tp74g.jpg

نکته : Unit1 در محدوده‌ی آدرسی $35184 تا $365CC قرار دارد، چگونه این محدوده‌ی آدرسی بدست می‌آید:

طول -> $00001448
آدرس شروع -> $00035184

اگر آدرس شروع را با طول جمع کنیم، محدوده آدرسی Unit1 بدست می‌آید، یعنی در نهایت ما دو عدد داریم که محدوده‌ی یونیت را مشخص می‌کند. سپس می‌توان با یک عملیات ریاضی ساده! متوجه شد که آیا آدرس دریافتی از خطای AV در این محدود قرار دارد یا خیر، تا از این طریق نام یونیت را پیدا کنیم.
طول + آدرس شروع = محدوده
4- پیدا کردن نام تابع :
در map file در بخش مختلف فهرست توابع وجود دارد. یکی در جایی که توابع بر اساس نام آنها مرتب شده‌اند و 'Publics by name' نام دارد و دیگری که بر اساس آدرس مرتب شده است و 'Publics by value' نام دارد. هر دو لیست شامل آدرس تابع و نام تابع است. برای پیدا کردن نام تابع هنگامی که AV روی می‌دهد از بخش 'Public by name' استفاده کنید و آدرس را در آن لیست جستجو کنید. ممکن است آدرس دقیقاً مطابق با آدرسی که از AV دریافت کرده‌اید و روی آن محاسبه انجام داده‌اید در map file نباشد، دلیل آن هم این است که خطا می‌تواند در هر جایی از تابع روی داده باشد. اما شما نزدیکترین آدرس که از آدرس AV کوچکتر باشد را بیابید.

آدرس خطای دریافتی از AV برابر است با $00437575 :

Map file address = $00437575 - $401000 = $36575

0001:0003642C TForm1.Button9Click
0001:00036484 TForm1.Button10Click
0001:00036564 TForm1.Button11Click
0001:0003657C Finalization
0001:000365C4 Unit1


5- پیدا کردن شماره خط:
در انتهای map file بخشی برای هر یونیت کامپایل شده شامل شماره خط، Segment و آدرس شروع وجود خواهد داشت که بر اساس آدرس خط مرتب شده‌اند. هر چهار شماره خط در یک خط در map file قرار دارد. در این مرحله، بخشی که مربوط به یونیت مورد نظر است را پیدا کنید(نام یونیت را در مرحله سوم پیدا کرده‌اید)، سپس برای پیدا کردن شماره خطی که AV در آن روی داده، نزدیکترین آدرس که از آدرس AV کوچکتر باشد را جستجو کنید.
برای مثال، اگر AV آدرس $36575 را برگرداند، شماره خط با توجه به مثال زیر 367 خواهد بود:


http://i9.tinypic.com/5x6pil0.jpg



نکته:
مرحله‌ی اول که تغییر مقدار Image base هست را با دلفی 5 انجام دادم، ولی متاسفانه با پیغام خطایی مانع ادامه‌ی کار شد. اگر شما هم چنین مشکلی را دارید می‌توانید مقدار Image base را تغییر ندهید و در عوض این مقدار را در مرحله‌ی 1 (تبدیل آدرس AV) جزء محاسبات بیاورید:

Map file address = AV address - $400000 - $1000 = Result