জিডিবি কলুষিত স্ট্যাক ফ্রেম - কীভাবে ডিবাগ করবেন?


113

আমি নিম্নলিখিত স্ট্যাক ট্রেস আছে। এটি থেকে ডিবাগিংয়ের জন্য কার্যকর কিছু তৈরি করা সম্ভব?

Program received signal SIGSEGV, Segmentation fault.
0x00000002 in ?? ()
(gdb) bt
#0  0x00000002 in ?? ()
#1  0x00000001 in ?? ()
#2  0xbffff284 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) 

যখন আমরা একটি পাই তখন কোডটি অনুসন্ধান করা Segmentation faultআর স্ট্যাক ট্রেসটি এতটা কার্যকর না?

দ্রষ্টব্য: আমি যদি কোডটি পোস্ট করি তবে এসও বিশেষজ্ঞরা আমাকে উত্তরটি দেবেন। আমি এসও এর কাছ থেকে গাইডেন্স নিতে চাই এবং উত্তরটি নিজেই সন্ধান করতে চাই, তাই আমি কোডটি এখানে পোস্ট করছি না। দুঃক্ষিত।


সম্ভবত আপনার প্রোগ্রামটি আগাছায় ঝাঁপিয়ে পড়ে - আপনি কি স্ট্যাক পয়েন্টার থেকে কিছু উদ্ধার করতে পারেন?
কার্ল নরুম

1
আরেকটি বিষয় বিবেচনা করার বিষয় হ'ল যদি ফ্রেম পয়েন্টারটি সঠিকভাবে সেট করা থাকে। আপনি কি অপ্টিমাইজেশন ছাড়াই বিল্ডিং করছেন বা একটি পতাকা পাস করছেন -fno-omit-frame-pointer? এছাড়াও, স্মৃতি দুর্নীতির জন্য valgrindএটি যদি আপনার পক্ষে বিকল্প হয় তবে এটি আরও উপযুক্ত সরঞ্জাম হতে পারে।
-12

উত্তর:


155

এই বোগাস ঠিকানাগুলি (0x00000002 এবং এর মতো) আসলে পিসি মান, এসপি মান নয়। এখন, আপনি যখন বোগাস (খুব ছোট) পিসি ঠিকানা সহ এই ধরণের এসইজিভি পান, তখন বোগাস ফাংশন পয়েন্টারটির মাধ্যমে কল করার কারণে এটির 99% সময় আসে। নোট করুন যে সি ++ তে ভার্চুয়াল কলগুলি ফাংশন পয়েন্টারগুলির মাধ্যমে প্রয়োগ করা হয়, সুতরাং ভার্চুয়াল কলগুলির সাথে যে কোনও সমস্যা একইভাবে প্রকাশিত হতে পারে।

একটি পরোক্ষ কল নির্দেশ মাত্র স্ট্যাকের সম্মুখের কল পর পিসি push কর্মের এবং তারপর লক্ষ্য মান (এই ক্ষেত্রে বাজে), তাই যদি এই পিসি সেট করে হয় কি ঘটেছে, আপনি সহজেই নিজে স্ট্যাকের বন্ধ পিসি পপিং দ্বারা পূর্বাবস্থা করতে পারেন । 32-বিট x86 কোডে আপনি কেবল এটি করেন:

(gdb) set $pc = *(void **)$esp
(gdb) set $esp = $esp + 4

-৪-বিট x86 কোড সহ আপনার প্রয়োজন

(gdb) set $pc = *(void **)$rsp
(gdb) set $rsp = $rsp + 8

তারপরে, আপনি একটি করতে সক্ষম হবেন btএবং কোডটি আসলে কোথায় তা খুঁজে বের করতে পারবেন ।

অন্যান্য 1% সময়, ত্রুটিটি স্ট্যাকের ওভাররাইটিংয়ের কারণে হবে, সাধারণত স্ট্যাকের উপর সঞ্চিত একটি অ্যারে উপচে ফেলে। এই ক্ষেত্রে, আপনি ভালগ্রাইন্ডের মতো সরঞ্জাম ব্যবহার করে পরিস্থিতি সম্পর্কে আরও স্পষ্টতা পেতে সক্ষম হতে পারেন


5
@ জর্জ: gdb executable corefileএক্সিকিউটেবল এবং কোর ফাইলের সাথে জিডিবি খুলবে, আপনি যে পর্যায়ে করতে পারেন bt(বা উপরের উপরের কমান্ডগুলি অনুসরণ করবে bt) ...
ক্রিস ডড ২

2
@ এম কে .. এআরএম প্রত্যাবর্তনের ঠিকানার জন্য স্ট্যাকটি ব্যবহার করে না - পরিবর্তে এটি লিঙ্ক নিবন্ধ ব্যবহার করে। সুতরাং এটিতে সাধারণত এই সমস্যা হয় না, বা যদি এটি হয় তবে এটি সাধারণত অন্য কোনও স্ট্যাক দুর্নীতির কারণে ঘটে।
ক্রিস ডড

2
এমনকি এআরএম-এও, আমার মনে হয়, সমস্ত সাধারণ উদ্দেশ্য নিবন্ধক এবং এলআর তথাকথিত ফাংশনটি সম্পাদন শুরু হওয়ার আগে স্ট্যাকে সংরক্ষণ করা হয়। ফাংশনটি শেষ হয়ে গেলে, এলআরটির মান পিসিতে পপ হয় এবং ফলস্বরূপ ফাংশন ফিরে আসে। সুতরাং যদি স্ট্যাক দূষিত হয়, আমরা দেখতে পাচ্ছি যে একটি সঠিক মান পিসি সঠিক? এই ক্ষেত্রে স্ট্যাক পয়েন্টার সামঞ্জস্য হতে পারে উপযুক্ত স্ট্যাক এবং ইস্যু ডিবাগ করতে সাহায্য করবে। আপনি কি মনে করেন? প্লিজ আমাকে আপনার চিন্তাভাবনা জানাতে দিন। ধন্যবাদ.
এম কে ..

1
বোগাস মানে কি?
ড্যানি লো

5
এআরএম x86 নয় - এটির স্ট্যাক পয়েন্টারটি বলা হয় sp, না espবা rsp, এবং এর কল নির্দেশিকাটি ফিরতি ঠিকানাটি lrরেজিস্টারে সঞ্চয় করে, স্ট্যাকের উপরে রাখে না। তাই এআরএমের জন্য, কলটি পূর্বাবস্থায় ফেরাতে আপনার যা যা করা দরকার তা হ'ল set $pc = $lr। যদি $lrঅবৈধ হয় তবে আনইন্ডাইন্ড করা আপনার কাছে আরও শক্ত সমস্যা।
ক্রিস ডড 4

44

পরিস্থিতি যদি মোটামুটি সহজ হয় তবে ক্রিস ডডের উত্তরটি সবচেয়ে ভাল। দেখে মনে হচ্ছে এটি কোনও নুল পয়েন্টারের মাধ্যমে লাফিয়ে গেছে।

তবে, প্রোগ্রামটি ক্র্যাশ হওয়ার আগে পা, হাঁটু, ঘাড় এবং চোখের মধ্যেই গুলি চালানো সম্ভব — স্ট্যাকটি ওভাররোট করে ফ্রেম পয়েন্টারটিকে বিশৃঙ্খলা করিয়েছে এবং অন্যান্য খারাপ কাজ করেছে। যদি তা হয় তবে হ্যাশটি উন্মুক্ত করা আপনাকে আলু এবং মাংস দেখানোর সম্ভাবনা নেই।

আরও কার্যকর সমাধান হ'ল ডিবাগারের অধীনে প্রোগ্রামটি চালানো এবং প্রোগ্রামটি ক্র্যাশ না হওয়া পর্যন্ত কার্য সম্পাদন করা step একবার ক্র্যাশিং ফাংশন সনাক্ত হয়ে গেলে, আবার শুরু করুন এবং সেই ফাংশনটিতে পদক্ষেপ দিন এবং নির্ধারণ করুন যে এটি কোন ক্রিয়াকলাপটিকে কল বলে ক্রাশের কারণ। আপনি কোডের একক আপত্তিজনক লাইন না পাওয়া পর্যন্ত পুনরাবৃত্তি করুন। 75% সময়, ঠিক তখন সুস্পষ্ট হবে।

অন্যান্য 25% পরিস্থিতিতে, কোডের তথাকথিত আপত্তিকর লাইনটি একটি লাল রঙের হারিং। এটি (অবৈধ) শর্তে প্রতিক্রিয়া জানাবে এর আগে অনেকগুলি লাইন সেট আপ করে — সম্ভবত হাজার হাজার লাইনের আগে। যদি এটি হয় তবে নির্বাচিত সেরা কোর্সটি অনেকগুলি বিষয়ের উপর নির্ভর করে: বেশিরভাগ ক্ষেত্রে আপনার কোড সম্পর্কে ধারণা এবং এটির সাথে অভিজ্ঞতা:

  • সম্ভবত একটি ডিবাগার ওয়াচপয়েন্ট সেট করা বা ডায়াগোনস্টিকের printfসমালোচনামূলক ভেরিয়েবলগুলি সন্নিবেশ করানো হলে প্রয়োজনীয় এ-হে!
  • হতে পারে বিভিন্ন ইনপুট দিয়ে পরীক্ষার শর্ত পরিবর্তন করা ডিবাগিংয়ের চেয়ে আরও অন্তর্দৃষ্টি প্রদান করবে।
  • হতে পারে দ্বিতীয় জোড়া চোখ আপনাকে আপনার অনুমানগুলি যাচাই করতে বাধ্য করবে বা উপেক্ষা করা প্রমাণ সংগ্রহ করবে।
  • কখনও কখনও, এটি যা লাগে তা হ'ল ডিনারে যাওয়া এবং জড়ো হওয়া প্রমাণগুলির কথা চিন্তা করা।

শুভকামনা!


13
যদি দ্বিতীয় জোড়া চোখ না পাওয়া যায় তবে রাবার হাঁস বিকল্প হিসাবে ভাল প্রমাণিত।
ম্যাট

2
একটি বাফার শেষে লেখাটি এটিও করতে পারে। আপনি বাফারের শেষটি যেখানে লিখেছেন তা ক্র্যাশ হতে পারে না তবে আপনি যখন ফাংশন থেকে সরে দাঁড়ান তখন এটি মারা যায়।
ফায়াট


28

ধরে নিচ্ছি যে স্ট্যাক পয়েন্টারটি বৈধ ...

ব্যাকট্রেস থেকে এসইজিভিটি ঠিক কোথায় ঘটেছিল তা জানা অসম্ভব - আমি মনে করি প্রথম দুটি স্ট্যাক ফ্রেম সম্পূর্ণরূপে ওভাররাইট করা হয়েছে। 0xbffff284 একটি বৈধ ঠিকানার মতো বলে মনে হচ্ছে তবে পরবর্তী দুটি এটি নয়। স্ট্যাকটি ঘনিষ্ঠভাবে দেখার জন্য, আপনি নিম্নলিখিত চেষ্টা করতে পারেন:

gdb $ x / 32ga $ আরএসপি

বা একটি বৈকল্পিক (32 নম্বরটি অন্য সংখ্যার সাথে প্রতিস্থাপন করুন)। এটি ঠিকানা (ক) হিসাবে ফর্ম্যাট করে জায়ান্ট (জি) আকারের স্ট্যাক পয়েন্টার থেকে শুরু করে কয়েকটি সংখ্যক শব্দ (32) মুদ্রণ করবে। ফর্ম্যাটের আরও তথ্যের জন্য 'সহায়তা x' টাইপ করুন।

আপনার কোডটি কিছু সেন্ডিনেল 'প্রিন্টফ'-এর সাথে ইনস্ট্রুমেন্ট করা কোনও ক্ষেত্রে খারাপ ধারণা নাও হতে পারে।


অবিশ্বাস্যরূপে সহায়ক, আপনাকে ধন্যবাদ - আমার কাছে একটি স্ট্যাক ছিল যা কেবল তিনটি ফ্রেম পিছনে গিয়েছিল এবং তারপরে "ব্যাকট্র্যাস বন্ধ হয়ে গেছে: পূর্ববর্তী ফ্রেমটি এই ফ্রেমের অনুরূপ (দুর্নীতিযুক্ত স্ট্যাক?)"; আমি এর আগে কোনও সিপিইউ ব্যতিক্রম হ্যান্ডলারের কোডে ঠিক এর মতো কিছু করেছি, তবে info symbolজিডিবিতে এটি কীভাবে করা যায় তা ছাড়া অন্য কোনও স্মরণ করতে পারি না।
লন্ডার

22
32-বিট এআরএম ডিভাইসে x/256wa $sp
FWIW

2
@ ওলেন্ডার আপনি কি আমাকে বলতে পারবেন এক্স / 256wa কি? আমার এটি 64-বিট এআরএমের জন্য প্রয়োজন। সাধারণভাবে এটি সহায়ক হবে যদি আপনি এটি কী তা ব্যাখ্যা করতে পারেন।
এম কে ..

5
উত্তর অনুসারে, 'x' = মেমরির অবস্থান পরীক্ষা করুন; এটি 'ডাব্লু' = শব্দের একটি সংখ্যা প্রিন্ট করে (এই ক্ষেত্রে, 256), এবং তাদের 'এ' = ঠিকানা হিসাবে ব্যাখ্যা করে। জিএসবি ম্যানুয়ালটিতে সোর্সওয়্যার.অর্গ / জিডিবি / কর্নার / অন্লিনকসস / জিডিবি / মেমরি এইচটিএমএল# মেমোরিতে আরও তথ্য রয়েছে ।
লন্ডার

7

আপনার অন্য কয়েকটি রেজিস্টার দেখুন এটির জন্য তাদের কোনও স্ট্যাক পয়েন্টার ক্যাশে আছে কিনা। সেখান থেকে, আপনি একটি স্ট্যাক পুনরুদ্ধার করতে সক্ষম হতে পারে। এছাড়াও, যদি এটি এম্বেড করা থাকে তবে প্রায়শই স্ট্যাক একটি নির্দিষ্ট নির্দিষ্ট স্থানে সংজ্ঞায়িত করা হয়। এটি ব্যবহার করে আপনি মাঝে মাঝে একটি শালীন স্ট্যাকও পেতে পারেন। এটি সমস্তই ধরে নিয়েছে যে আপনি যখন হাইপারস্পেসে ঝাঁপিয়ে পড়েছিলেন, তখন আপনার প্রোগ্রামটি পুরো স্মৃতি ধরে রাখেনি ...


3

যদি এটি স্ট্যাক ওভাররাইট হয় তবে মানগুলি প্রোগ্রাম থেকে স্বীকৃত কিছুটির সাথে ভালভাবে মিলতে পারে।

উদাহরণস্বরূপ, আমি সবেমাত্র স্ট্যাকের দিকে তাকিয়ে দেখলাম

(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x000000000000342d in ?? ()
#2  0x0000000000000000 in ?? ()

এবং 0x342d13357, যা আমি যখন এর জন্য অ্যাপ্লিকেশন লগগুলি গ্রিপ করেছিলাম তখন নোড-আইডি হিসাবে পরিণত হয়েছিল। এটি অবিলম্বে প্রার্থীদের সাইটগুলিকে সঙ্কুচিত করতে সহায়তা করেছিল যেখানে স্ট্যাকের ওভাররাইটটি ঘটতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.