Εάν έχετε εγκαταστήσει στον υπολογιστή σας πρόγραμμα προστασίας από ιούςΜπορώ σαρώστε όλα τα αρχεία στον υπολογιστή σας, καθώς και κάθε αρχείο ξεχωριστά. Μπορείτε να σαρώσετε οποιοδήποτε αρχείο κάνοντας δεξί κλικ στο αρχείο και επιλέγοντας την κατάλληλη επιλογή για σάρωση του αρχείου για ιούς.

Για παράδειγμα, σε αυτό το σχήμα επισημαίνεται αρχείο my-file.elf, τότε πρέπει να κάνετε δεξί κλικ σε αυτό το αρχείο και να επιλέξετε την επιλογή στο μενού αρχείο "σάρωση με AVG". Όταν κάνετε αυτήν την επιλογή, το AVG Antivirus θα ανοίξει και θα σαρώσει το αρχείο για ιούς.


Μερικές φορές μπορεί να προκύψει σφάλμα ως αποτέλεσμα λανθασμένη εγκατάσταση λογισμικού, το οποίο μπορεί να οφείλεται σε πρόβλημα που παρουσιάστηκε κατά τη διαδικασία εγκατάστασης. Αυτό μπορεί να επηρεάσει το λειτουργικό σας σύστημα συνδέστε το αρχείο ELF με το σωστό λογισμικό εφαρμογής, επηρεάζοντας τα λεγόμενα "συσχετίσεις επέκτασης αρχείων".

Μερικές φορές απλά επανεγκατάσταση του Dolphin (εξομοιωτή)μπορεί να λύσει το πρόβλημά σας συνδέοντας σωστά το ELF με το Dolphin (εξομοιωτή). Σε άλλες περιπτώσεις, ενδέχεται να προκύψουν προβλήματα με συσχετίσεις αρχείων κακός προγραμματισμός λογισμικούπρογραμματιστή και ίσως χρειαστεί να επικοινωνήσετε με τον προγραμματιστή για περαιτέρω βοήθεια.


Συμβουλή:Δοκιμάστε να ενημερώσετε το Dolphin (εξομοιωτή) στην πιο πρόσφατη έκδοση για να βεβαιωθείτε ότι έχετε τις πιο πρόσφατες ενημερώσεις κώδικα και ενημερώσεις.


Αυτό μπορεί να φαίνεται πολύ προφανές, αλλά συχνά Το ίδιο το αρχείο ELF μπορεί να προκαλεί το πρόβλημα. Εάν λάβατε ένα αρχείο μέσω συνημμένου ηλεκτρονικού ταχυδρομείου ή το κατεβάσατε από έναν ιστότοπο και η διαδικασία λήψης διακόπηκε (όπως διακοπή ρεύματος ή άλλος λόγος), το αρχείο μπορεί να καταστραφεί. Εάν είναι δυνατόν, δοκιμάστε να λάβετε ένα νέο αντίγραφο του αρχείου ELF και προσπαθήστε να το ανοίξετε ξανά.


Προσεκτικά:Ένα κατεστραμμένο αρχείο μπορεί να προκαλέσει παράπλευρη βλάβη σε προηγούμενο ή υπάρχον κακόβουλο λογισμικό στον υπολογιστή σας, επομένως είναι σημαντικό να διατηρείτε τον υπολογιστή σας ενημερωμένο με ένα ενημερωμένο πρόγραμμα προστασίας από ιούς.


Εάν το αρχείο σας είναι ELF που σχετίζονται με το υλικό του υπολογιστή σαςγια να ανοίξετε το αρχείο που μπορεί να χρειαστείτε ενημέρωση προγραμμάτων οδήγησης συσκευώνπου σχετίζονται με αυτόν τον εξοπλισμό.

Αυτό το πρόβλημα συνήθως σχετίζεται με τύπους αρχείων πολυμέσων, τα οποία εξαρτώνται από το επιτυχές άνοιγμα του υλικού μέσα στον υπολογιστή, π.χ. κάρτα ήχου ή κάρτα βίντεο. Για παράδειγμα, εάν προσπαθείτε να ανοίξετε ένα αρχείο ήχου αλλά δεν μπορείτε να το ανοίξετε, ίσως χρειαστεί ενημέρωση προγραμμάτων οδήγησης κάρτας ήχου.


Συμβουλή:Εάν όταν προσπαθείτε να ανοίξετε ένα αρχείο ELF λαμβάνετε Μήνυμα σφάλματος αρχείου .SYS, το πρόβλημα μπορεί να είναι σχετίζεται με κατεστραμμένα ή παλιά προγράμματα οδήγησης συσκευώνπου πρέπει να ενημερωθούν. Αυτή η διαδικασία μπορεί να γίνει ευκολότερη χρησιμοποιώντας λογισμικό ενημέρωσης προγραμμάτων οδήγησης όπως το DriverDoc.


Εάν τα βήματα δεν λύσουν το πρόβλημακαι εξακολουθείτε να αντιμετωπίζετε προβλήματα με το άνοιγμα αρχείων ELF, αυτό μπορεί να οφείλεται έλλειψη διαθέσιμων πόρων συστήματος. Ορισμένες εκδόσεις αρχείων ELF ενδέχεται να απαιτούν σημαντική ποσότητα πόρων (π.χ. μνήμη/RAM, ισχύς επεξεργασίας) για να ανοίξουν σωστά στον υπολογιστή σας. Αυτό το πρόβλημα είναι αρκετά κοινό εάν χρησιμοποιείτε αρκετά παλιό υλικό υπολογιστή και ταυτόχρονα ένα πολύ νεότερο λειτουργικό σύστημα.

Αυτό το πρόβλημα μπορεί να προκύψει όταν ο υπολογιστής δυσκολεύεται να συμβαδίσει με μια εργασία, επειδή το λειτουργικό σύστημα (και άλλες υπηρεσίες που εκτελούνται στο παρασκήνιο) ενδέχεται να καταναλώστε πάρα πολλούς πόρους για να ανοίξετε ένα αρχείο ELF. Δοκιμάστε να κλείσετε όλες τις εφαρμογές στον υπολογιστή σας πριν ανοίξετε το Αρχείο παιχνιδιών Nintendo Wii. Απελευθερώνοντας όλους τους διαθέσιμους πόρους στον υπολογιστή σας, θα είστε στην καλύτερη θέση να προσπαθήσετε να ανοίξετε το αρχείο ELF.


Αν εσύ ολοκλήρωσε όλα τα βήματα που περιγράφονται παραπάνωκαι το αρχείο ELF εξακολουθεί να μην ανοίγει, ίσως χρειαστεί να το εκτελέσετε ενημέρωση εξοπλισμού. Στις περισσότερες περιπτώσεις, ακόμη και όταν χρησιμοποιείτε παλαιότερες εκδόσεις υλικού, η ισχύς επεξεργασίας μπορεί να είναι ακόμη περισσότερο από επαρκής για τις περισσότερες εφαρμογές χρηστών (εκτός αν κάνετε πολλή εργασία με ένταση CPU, όπως απόδοση 3D, οικονομική/επιστημονική μοντελοποίηση ή εντατική εργασία πολυμέσων) . Ετσι, είναι πιθανό ο υπολογιστής σας να μην έχει αρκετή μνήμη(κοινώς ονομάζεται "RAM" ή μνήμη τυχαίας πρόσβασης) για να εκτελέσετε την εργασία ανοίγματος ενός αρχείου.

Ελπίζουμε ότι σας βοηθήσαμε να επιλύσετε το πρόβλημά σας με το αρχείο ELF. Εάν δεν γνωρίζετε πού μπορείτε να κατεβάσετε μια εφαρμογή από τη λίστα μας, κάντε κλικ στον σύνδεσμο (αυτό είναι το όνομα του προγράμματος) - Θα βρείτε πιο λεπτομερείς πληροφορίες σχετικά με το πού μπορείτε να κατεβάσετε την έκδοση ασφαλούς εγκατάστασης της απαιτούμενης εφαρμογής.

Μια επίσκεψη σε αυτήν τη σελίδα θα σας βοηθήσει να απαντήσετε συγκεκριμένα σε αυτές ή παρόμοιες ερωτήσεις:

  • Πώς να ανοίξετε ένα αρχείο με επέκταση ELF;
  • Πώς να μετατρέψετε ένα αρχείο ELF σε άλλη μορφή;
  • Τι είναι η επέκταση μορφής αρχείου ELF;
  • Ποια προγράμματα υποστηρίζουν το αρχείο ELF;

Εάν, μετά την προβολή του υλικού αυτής της σελίδας, δεν έχετε λάβει ακόμη ικανοποιητική απάντηση σε καμία από τις ερωτήσεις που παρουσιάζονται παραπάνω, αυτό σημαίνει ότι οι πληροφορίες που παρουσιάζονται εδώ σχετικά με το αρχείο ELF είναι ελλιπείς. Επικοινωνήστε μαζί μας χρησιμοποιώντας τη φόρμα επικοινωνίας και γράψτε ποιες πληροφορίες δεν βρήκατε.

Τι άλλο μπορεί να προκαλέσει προβλήματα;

Μπορεί να υπάρχουν περισσότεροι λόγοι για τους οποίους δεν μπορείτε να ανοίξετε το αρχείο ELF (όχι μόνο η έλλειψη αντίστοιχης εφαρμογής).
Πρώτα- το αρχείο ELF μπορεί να είναι λανθασμένα συνδεδεμένο (μη συμβατό) με την εφαρμογή που έχει εγκατασταθεί για την υποστήριξή του. Σε αυτήν την περίπτωση, πρέπει να αλλάξετε μόνοι σας αυτή τη σύνδεση. Για να το κάνετε αυτό, κάντε δεξί κλικ στο αρχείο ELF που θέλετε να επεξεργαστείτε και κάντε κλικ στην επιλογή "Για να ανοίξω με"και μετά επιλέξτε το πρόγραμμα που εγκαταστήσατε από τη λίστα. Μετά από αυτήν την ενέργεια, τα προβλήματα με το άνοιγμα του αρχείου ELF θα πρέπει να εξαφανιστούν εντελώς.
κατα δευτερον- το αρχείο που θέλετε να ανοίξετε μπορεί απλώς να είναι κατεστραμμένο. Σε αυτήν την περίπτωση, θα ήταν καλύτερο να βρείτε μια νέα έκδοση ή να το κατεβάσετε ξανά από την ίδια πηγή (ίσως για κάποιο λόγο στην προηγούμενη συνεδρία η λήψη του αρχείου ELF δεν ολοκληρώθηκε και δεν μπορούσε να ανοίξει σωστά) .

Θέλετε να βοηθήσετε;

Εάν έχετε πρόσθετες πληροφορίες σχετικά με την επέκταση αρχείου ELF, θα είμαστε ευγνώμονες εάν τις μοιραστείτε με τους χρήστες του ιστότοπού μας. Χρησιμοποιήστε την παρακάτω φόρμα και στείλτε μας τα στοιχεία σας σχετικά με το αρχείο ELF.

Μορφή ELF

Η μορφή ELF έχει διάφορους τύπους αρχείων, τους οποίους μέχρι στιγμής έχουμε καλέσει διαφορετικά, όπως εκτελέσιμο αρχείο ή αρχείο αντικειμένου. Ωστόσο, το πρότυπο ELF διακρίνει τους ακόλουθους τύπους:

1. Αρχείο προς μετακίνηση(relocatable file) αποθήκευση οδηγιών και δεδομένων που μπορούν να συνδεθούν με άλλα αρχεία αντικειμένων. Το αποτέλεσμα μιας τέτοιας σύνδεσης μπορεί να είναι ένα εκτελέσιμο αρχείο ή ένα αρχείο κοινόχρηστου αντικειμένου.

2. Κοινόχρηστο αρχείο αντικειμένου(κοινόχρηστο αρχείο αντικειμένου) περιέχει επίσης οδηγίες και δεδομένα, αλλά μπορεί να χρησιμοποιηθεί με δύο τρόπους. Στην πρώτη περίπτωση, μπορεί να συνδεθεί με άλλα αρχεία με δυνατότητα μεταφοράς και κοινόχρηστα αρχεία αντικειμένων, με αποτέλεσμα να δημιουργηθεί ένα νέο αρχείο αντικειμένου. Στη δεύτερη περίπτωση, όταν ένα πρόγραμμα ξεκινά για εκτέλεση, το λειτουργικό σύστημα μπορεί να το συνδέσει δυναμικά με το εκτελέσιμο αρχείο του προγράμματος, με αποτέλεσμα να δημιουργηθεί μια εκτελέσιμη εικόνα του προγράμματος. Στην τελευταία περίπτωση μιλάμε για κοινόχρηστες βιβλιοθήκες.

3. Εκτελέσιμο αρχείοαποθηκεύει μια πλήρη περιγραφή που επιτρέπει στο σύστημα να δημιουργήσει μια εικόνα της διαδικασίας. Περιέχει οδηγίες, δεδομένα, περιγραφές των απαιτούμενων αρχείων κοινόχρηστων αντικειμένων και τις απαραίτητες συμβολικές πληροφορίες και πληροφορίες εντοπισμού σφαλμάτων.

Στο Σχ. Το 2.4 δείχνει τη δομή του εκτελέσιμου αρχείου, με τη βοήθεια του οποίου το λειτουργικό σύστημα μπορεί να δημιουργήσει μια εικόνα προγράμματος και να ξεκινήσει το πρόγραμμα για εκτέλεση.

Ρύζι. 2.4. Δομή ενός εκτελέσιμου αρχείου σε μορφή ELF

Η κεφαλίδα έχει μια σταθερή θέση στο αρχείο. Τα υπόλοιπα στοιχεία τοποθετούνται σύμφωνα με τις πληροφορίες που είναι αποθηκευμένες στην κεφαλίδα. Έτσι, η κεφαλίδα περιέχει μια γενική περιγραφή της δομής του αρχείου, τη θέση των μεμονωμένων στοιχείων και τα μεγέθη τους.

Εφόσον η κεφαλίδα ενός αρχείου ELF καθορίζει τη δομή του, ας το δούμε λεπτομερέστερα (Πίνακας 2.4).

Πίνακας 2.3. Πεδία κεφαλίδας ELF

Πεδίο Περιγραφή
e_ident Μια σειρά byte, καθένα από τα οποία ορίζει κάποια γενικά χαρακτηριστικά του αρχείου: μορφή αρχείου (ELF), αριθμός έκδοσης, αρχιτεκτονική συστήματος (32-bit ή 64-bit) κ.λπ.
e_type Τύπος αρχείου, καθώς η μορφή ELF υποστηρίζει πολλούς τύπους
e_machine Η αρχιτεκτονική της πλατφόρμας υλικού για την οποία δημιουργήθηκε αυτό το αρχείο. Στον πίνακα Το 2.4 δείχνει τις πιθανές τιμές αυτού του πεδίου
e_έκδοση Αριθμός έκδοσης μορφής ELF. Συνήθως ορίζεται ως EV_CURRENC (τρέχον), που σημαίνει την πιο πρόσφατη έκδοση
e_entry Η εικονική διεύθυνση στην οποία το σύστημα θα μεταφέρει τον έλεγχο μετά τη φόρτωση του προγράμματος (σημείο εισόδου)
e_phoff Θέση (μετατόπιση από την αρχή του αρχείου) του πίνακα κεφαλίδων του προγράμματος
e_shoff Θέση πίνακα κεφαλίδας ενότητας
e_ehsize Μέγεθος κεφαλίδας
e_phentsize Μέγεθος κάθε κεφαλίδας προγράμματος
e_phnum Αριθμός κεφαλίδων προγράμματος
e_shentsize Μέγεθος κάθε κεφαλίδας τμήματος (τμήμα)
e_shnum Αριθμός κεφαλίδων τμήματος (ενότητες)
e_shstrndx Θέση του τμήματος που περιέχει τον πίνακα συμβολοσειρών

Πίνακας 2.4. Τιμές πεδίου κεφαλίδας αρχείου ELF e_machine

Εννοια Πλατφόρμα υλικού
EM_M32 AT&T WE 32100
EM_SPARC Sun SPARC
EM_386 Intel 80386
EM_68K Motorola 68000
EM_88K Motorola 88000
EM_486 Intel 80486
EM_860 Intel i860
EM_MIPS MIPS RS3000 Big-Endian
EM_MIPS_RS3_LE MIPS RS3000 Little-Endian
EM_RS6000 RS6000
EM_PA_RISC PA-RISC
EM_nCUBE nCUBE
EM_VPP500 Fujitsu VPP500
EM_SPARC32PLUS Ήλιος SPARC 32+

Οι πληροφορίες που περιέχονται στον πίνακα κεφαλίδων προγράμματος λένε στον πυρήνα πώς να δημιουργήσει μια εικόνα διεργασίας από τμήματα. Τα περισσότερα τμήματα αντιγράφονται (αντιστοιχίζονται) στη μνήμη και αντιπροσωπεύουν σχετικά τμήματα της διαδικασίας καθώς εκτελείται, όπως τμήματα κώδικα ή δεδομένων.

Κάθε κεφαλίδα τμήματος προγράμματος περιγράφει ένα τμήμα και περιέχει τις ακόλουθες πληροφορίες:

Ενέργειες τύπου τμήματος και λειτουργικού συστήματος με αυτό το τμήμα

Τοποθεσία τμήματος στο αρχείο

Η αρχική διεύθυνση του τμήματος στην εικονική μνήμη διεργασίας

Μέγεθος τμήματος στο αρχείο

Μέγεθος τμήματος μνήμης

Σημαίες πρόσβασης τμήματος (εγγραφή, ανάγνωση, εκτέλεση)

Ορισμένα τμήματα είναι του τύπου LOAD, που δίνει εντολή στον πυρήνα, κατά την εκκίνηση του προγράμματος για εκτέλεση, να δημιουργήσει δομές δεδομένων που αντιστοιχούν σε αυτά τα τμήματα, που ονομάζονται περιφέρειες, που ορίζουν συνεχόμενες ενότητες της εικονικής μνήμης μιας διεργασίας και τα σχετικά χαρακτηριστικά τους. Το τμήμα, η θέση του οποίου στο αρχείο ELF υποδεικνύεται στην αντίστοιχη κεφαλίδα προγράμματος, θα αντιστοιχιστεί στη δημιουργημένη περιοχή, η εικονική διεύθυνση της αρχής της οποίας υποδεικνύεται επίσης στην κεφαλίδα του προγράμματος. Τα τμήματα αυτού του τύπου περιλαμβάνουν, για παράδειγμα, τμήματα που περιέχουν οδηγίες προγράμματος (κώδικας) και τα δεδομένα του. Εάν το μέγεθος του τμήματος είναι μικρότερο από το μέγεθος της περιοχής, ο αχρησιμοποίητος χώρος μπορεί να γεμίσει με μηδενικά. Αυτός ο μηχανισμός χρησιμοποιείται ιδιαίτερα κατά τη δημιουργία μη αρχικοποιημένων δεδομένων διεργασίας (BSS). Θα μιλήσουμε περισσότερα για τις περιοχές στο Κεφάλαιο 3.

Το τμήμα INTERP αποθηκεύει τον διερμηνέα προγράμματος. Αυτός ο τύπος τμήματος χρησιμοποιείται για προγράμματα που απαιτούν δυναμική σύνδεση. Η ουσία της δυναμικής σύνδεσης είναι ότι τα μεμονωμένα στοιχεία του εκτελέσιμου αρχείου (κοινόχρηστα αρχεία αντικειμένων) συνδέονται όχι στο στάδιο της μεταγλώττισης, αλλά στο στάδιο της εκκίνησης του προγράμματος για εκτέλεση. Το όνομα του αρχείου δηλαδή δυναμικός επεξεργαστής συνδέσμων, αποθηκεύεται σε αυτό το τμήμα. Όταν ένα πρόγραμμα εκκινείται για εκτέλεση, ο πυρήνας δημιουργεί μια εικόνα διεργασίας χρησιμοποιώντας τον καθορισμένο επεξεργαστή συνδέσμων. Έτσι, αρχικά δεν είναι το πρόγραμμα πηγής που φορτώνεται στη μνήμη, αλλά ο επεξεργαστής δυναμικής σύνδεσης. Στο επόμενο βήμα, ο επεξεργαστής δυναμικής σύνδεσης συνεργάζεται με τον πυρήνα του UNIX για να δημιουργήσει μια πλήρη εικόνα του εκτελέσιμου αρχείου. Ο δυναμικός επεξεργαστής φορτώνει τα απαραίτητα αρχεία κοινόχρηστων αντικειμένων, τα ονόματα των οποίων αποθηκεύονται σε ξεχωριστά τμήματα του εκτελέσιμου αρχείου προέλευσης και εκτελεί την απαιτούμενη τοποθέτηση και σύνδεση. Τέλος, ο έλεγχος μεταφέρεται στο αρχικό πρόγραμμα.

Τέλος, το αρχείο τελειώνει με έναν πίνακα κεφαλίδων ενότητεςή ενότητες(Ενότητα). Οι ενότητες (ενότητες) ορίζουν τμήματα ενός αρχείου που χρησιμοποιούνται για σύνδεση με άλλες μονάδες κατά τη μεταγλώττιση ή κατά τη δυναμική σύνδεση. Συνεπώς, οι επικεφαλίδες περιέχουν όλες τις απαραίτητες πληροφορίες για την περιγραφή αυτών των τμημάτων. Κατά κανόνα, οι ενότητες περιέχουν πιο λεπτομερείς πληροφορίες για τμήματα. Για παράδειγμα, ένα τμήμα κώδικα μπορεί να αποτελείται από πολλές ενότητες, όπως έναν πίνακα κατακερματισμού για την αποθήκευση ευρετηρίων συμβόλων που χρησιμοποιούνται στο πρόγραμμα, ένα τμήμα του κώδικα αρχικοποίησης του προγράμματος, έναν πίνακα σύνδεσης που χρησιμοποιείται από τον δυναμικό επεξεργαστή και μια ενότητα που περιέχει την πραγματική οδηγίες προγράμματος.

Θα επιστρέψουμε στη μορφή ELF στο Κεφάλαιο 3 όταν συζητήσουμε την οργάνωση της εικονικής μνήμης διεργασιών, αλλά προς το παρόν θα προχωρήσουμε στην επόμενη κοινή μορφή, το COFF.

Από το βιβλίο The Art of Programming for Unix συγγραφέας Raymond Eric Stephen

Από το βιβλίο Εγχειρίδιο αυτο-οδηγίας για εργασία σε υπολογιστή συγγραφέας Kolisnichenko Denis Nikolaevich

Από το βιβλίο Περίληψη, μαθήματα, δίπλωμα σε υπολογιστή συγγραφέας Balovsyak Nadezhda Vasilievna

5.2.6. Μορφή INI των Windows Πολλά προγράμματα των Microsoft Windows χρησιμοποιούν μια μορφή δεδομένων κειμένου παρόμοια με αυτή που εμφανίζεται στο Παράδειγμα 5.6. Αυτό το παράδειγμα συσχετίζει προαιρετικούς πόρους που ονομάζονται λογαριασμός, κατάλογος, numeric_id και προγραμματιστής με έργα που ονομάζονται python, sng, fetchmail και py-howto. Στην ηχογράφηση

Από το βιβλίο Το νεότερο εγχειρίδιο αυτο-οδηγίας για εργασία σε υπολογιστή συγγραφέας Beluntsov Valery

14.5.3. Μορφή κελιού Η μορφή καθορίζει πώς θα εμφανίζεται η τιμή του κελιού. Η μορφή σχετίζεται στενά με τον τύπο δεδομένων του κελιού. Τον τύπο τον ορίζεις μόνος σου. Εάν εισαγάγατε έναν αριθμό, τότε πρόκειται για έναν αριθμητικό τύπο δεδομένων. Το ίδιο το Excel προσπαθεί να προσδιορίσει τη μορφή με βάση τον τύπο δεδομένων. Για παράδειγμα, εάν εισαγάγατε κείμενο, τότε

Από το βιβλίο The Art of Programming for Unix συγγραφέας Raymond Eric Stephen

Μορφή PDF Το PDF σημαίνει φορητή μορφή εγγράφου. Αυτή η μορφή δημιουργήθηκε ειδικά για την εξάλειψη προβλημάτων με την εμφάνιση πληροφοριών σε αρχεία. Το πλεονέκτημά του είναι ότι, πρώτον, ένα έγγραφο που είναι αποθηκευμένο σε μορφή PDF θα είναι το ίδιο

Από το βιβλίο TCP/IP Architecture, Protocols, Implementation (συμπεριλαμβανομένης της έκδοσης IP 6 και της Ασφάλειας IP) από τη Faith Sydney M

Μορφή αρχείου Όταν ένας χρήστης ξεκινά να εργάζεται με ένα αρχείο, το σύστημα πρέπει να γνωρίζει σε ποια μορφή είναι γραμμένο και με ποιο πρόγραμμα πρέπει να ανοίξει. Για παράδειγμα, εάν ένα αρχείο περιέχει απλό κείμενο, τότε μπορεί να διαβαστεί σε οποιοδήποτε πρόγραμμα κειμένου

Από το βιβλίο Yandex για όλους συγγραφέας Abramzon M. G.

5.2.2. Μορφή RFC 822 Η μεταμορφοποίηση RFC 822 προέρχεται από τη μορφή κειμένου των μηνυμάτων ηλεκτρονικού ταχυδρομείου Internet. Το RFC 822 είναι το κύριο πρότυπο RFC Διαδικτύου που περιγράφει αυτήν τη μορφή (αργότερα αντικαταστάθηκε από το RFC 2822). Μορφή MIME (Πολλαπλών χρήσεων Internet Media Extension).

Από το βιβλίο Macromedia Flash Professional 8. Graphics and Animation συγγραφέας Dronov V. A.

5.2.3. Μορφή Cookie-Jar Η μορφή cookie-jar χρησιμοποιείται από το fortune(1) για τη δική του βάση δεδομένων με τυχαία εισαγωγικά. Είναι κατάλληλο για αναρτήσεις που είναι απλώς μπλοκ μη δομημένου κειμένου. Το σύμβολο χρησιμοποιείται ως διαχωριστικό εγγραφών σε αυτήν τη μορφή

Από το βιβλίο Computer Sound Processing συγγραφέας Zagumennov Alexander Petrovich

5.2.4. Μορφή ρεκόρ-βάζα Τα διαχωριστικά καρτελών μορφής cookie-jar λειτουργούν καλά με τη μορφή μεταφοράς RFC 822 για εγγραφές, σχηματίζοντας μια μορφή που ονομάζεται "record-jar" σε αυτό το βιβλίο. Μερικές φορές απαιτείται μια μορφή κειμένου που να υποστηρίζει πολλαπλές καταχωρήσεις με διαφορετικό σύνολο ρητών ονομάτων

Από το βιβλίο UNIX Operating System συγγραφέας Ρομπατσέφσκι Αντρέι Μ.

5.2.6. Μορφή INI των Windows Πολλά προγράμματα των Microsoft Windows χρησιμοποιούν μια μορφή δεδομένων κειμένου παρόμοια με αυτή που εμφανίζεται στο Παράδειγμα 5.6. Αυτό το παράδειγμα συσχετίζει προαιρετικούς πόρους που ονομάζονται λογαριασμός, κατάλογος, numeric_id και προγραμματιστής με έργα που ονομάζονται python, sng, fetchmail και py-howto. Στην ηχογράφηση

Από το βιβλίο Υπολογιστής γραφείου για γυναίκες συγγραφέας Παστερνάκ Ευγενία

19.5 Γενικευμένη μορφή URL Για να συνοψίσουμε τα παραπάνω, σημειώνουμε ότι:? Η διεύθυνση URL ξεκινά με το πρωτόκολλο πρόσβασης που χρησιμοποιείται. Για όλες τις εφαρμογές εκτός από τις διαδικτυακές ειδήσεις και το ηλεκτρονικό ταχυδρομείο, ακολουθεί το διαχωριστικό: //.? Στη συνέχεια, καθορίζεται το όνομα κεντρικού υπολογιστή του διακομιστή. Τελικά

Από το βιβλίο του συγγραφέα

3.3.1. Μορφή RSS Μπορείτε να διαβάσετε νέα του ιστότοπου με διαφορετικούς τρόπους. Ο ευκολότερος τρόπος είναι να επισκέπτεστε τον ιστότοπο από καιρό σε καιρό και να βλέπετε νέα μηνύματα. Μπορείτε να εγκαταστήσετε ένα πρόγραμμα που συνδέεται με ένα κανάλι ειδήσεων και το ίδιο λαμβάνει τίτλους ή περιλήψεις ειδήσεων, σύμφωνα με

Από το βιβλίο του συγγραφέα

Μορφή MP3 Η μορφή MP3 δημιουργήθηκε για τη διανομή αρχείων μουσικής συμπιεσμένα με τον κωδικοποιητή MPEG 1 επιπέδου 3 Επί του παρόντος, είναι η πιο δημοφιλής μορφή για τη διανομή μουσικής μέσω του Διαδικτύου, και όχι μόνο. Υποστηρίζεται από απολύτως όλα τα προγράμματα εγγραφής και επεξεργασίας ήχου, για

Από το βιβλίο του συγγραφέα

Μορφή MP3 Μια μέθοδος συμπίεσης ήχου, καθώς και μια μορφή συμπιεσμένου αρχείου ήχου που προτείνεται από τον διεθνή οργανισμό MPEG (Moving Pictures Experts Group), που βασίζεται σε αντιληπτική κωδικοποίηση ήχου. Εργαστείτε για τη δημιουργία αποτελεσματικών αλγορίθμων κωδικοποίησης

Από το βιβλίο του συγγραφέα

Μορφή ELF Η μορφή ELF έχει διάφορους τύπους αρχείων, τους οποίους μέχρι στιγμής ονομάζαμε με διαφορετικά ονόματα, όπως εκτελέσιμο αρχείο ή αρχείο αντικειμένου. Ωστόσο, το πρότυπο ELF διακρίνει τους ακόλουθους τύπους:1. Ένα αρχείο με δυνατότητα μεταφοράς που αποθηκεύει οδηγίες και δεδομένα που μπορεί να είναι

Από το βιβλίο του συγγραφέα

Μορφή αριθμών Τελικά φτάσαμε στη μορφή αριθμών. Το έχω ήδη αναφέρει περισσότερες από μία φορές, τώρα θα το αναλύσω (αν και ίσως καταλάβατε ήδη τη γενική σημασία Οι αριθμοί στο Excel μπορούν να εμφανίζονται σε διάφορες μορφές). Σε αυτή την ενότητα θα μιλήσουμε για το ποιες μορφές αριθμών υπάρχουν και πώς

Σε αυτήν την ανασκόπηση θα μιλήσουμε μόνο για την έκδοση 32-bit αυτής της μορφής, επειδή δεν χρειαζόμαστε ακόμα την έκδοση 64-bit.

Οποιοδήποτε αρχείο ELF (συμπεριλαμβανομένων των ενοτήτων αντικειμένων αυτής της μορφής) αποτελείται από τα ακόλουθα μέρη:

  • Κεφαλίδα αρχείου ELF.
  • Πίνακας ενοτήτων προγράμματος (μπορεί να απουσιάζει στις ενότητες αντικειμένων).
  • Ενότητες αρχείου ELF.
  • Πίνακας ενοτήτων (ενδέχεται να μην υπάρχει στην ενότητα εκτέλεσης).
  • Για λόγους απόδοσης, η μορφή ELF δεν χρησιμοποιεί πεδία bit. Και όλες οι δομές είναι συνήθως ευθυγραμμισμένες κατά 4 byte.

Τώρα ας δούμε τους τύπους που χρησιμοποιούνται στις κεφαλίδες αρχείων ELF:

Τώρα ας δούμε την κεφαλίδα του αρχείου:

#define EI_NIDENT 16 struct elf32_hdr ( ανυπόγραφο char e_ident; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; /* Entry point */Eff _Λέξη e_fla gs;

Ο πίνακας e_ident περιέχει πληροφορίες για το σύστημα και αποτελείται από πολλά υποπεδία.

Struct ( ανυπόγραφο char ei_magic; ανυπόγραφο char ei_class; ανυπόγραφο char ei_data; ανυπόγραφο char ei_version; ανυπόγραφο char ei_pad; )

  • ei_magic - σταθερή τιμή για όλα τα αρχεία ELF, ίση με (0x7f, "E", "L", "F")
  • ei_class - κλάση αρχείου ELF (1 - 32 bit, 2 - 64 bit που δεν λαμβάνουμε υπόψη)
  • ei_data - καθορίζει τη σειρά byte για αυτό το αρχείο (αυτή η σειρά εξαρτάται από την πλατφόρμα και μπορεί να είναι προς τα εμπρός (LSB ή 1) ή αντίστροφα (MSB ή 2)) Για επεξεργαστές Intel, επιτρέπεται μόνο η τιμή 1.
  • Το ei_version είναι ένα μάλλον άχρηστο πεδίο και αν δεν είναι ίσο με 1 (EV_CURRENT) τότε το αρχείο θεωρείται λανθασμένο.

Τα λειτουργικά συστήματα αποθηκεύουν τις πληροφορίες αναγνώρισής τους στο πεδίο ei_pad. Αυτό το πεδίο μπορεί να είναι κενό. Ούτε μας έχει σημασία.

Το πεδίο κεφαλίδας e_type μπορεί να περιέχει πολλές τιμές, για εκτελέσιμα αρχεία θα πρέπει να είναι ET_EXEC ίσο με 2

e_machine - καθορίζει τον επεξεργαστή στον οποίο μπορεί να εκτελεστεί αυτό το εκτελέσιμο αρχείο (Για εμάς, η αποδεκτή τιμή EM_386 είναι 3)

Το πεδίο e_version αντιστοιχεί στο πεδίο ei_version από την κεφαλίδα.

Το πεδίο e_entry ορίζει τη διεύθυνση έναρξης του προγράμματος, η οποία τοποθετείται στο eip πριν ξεκινήσει το πρόγραμμα.

Το πεδίο e_phoff καθορίζει τη μετατόπιση από την αρχή του αρχείου στην οποία βρίσκεται ο πίνακας ενότητας προγράμματος που χρησιμοποιείται για τη φόρτωση προγραμμάτων στη μνήμη.

Δεν θα απαριθμήσω τον σκοπό όλων των πεδίων δεν χρειάζονται όλα για τη φόρτωση. Θα περιγράψω μόνο δύο ακόμη.

Το πεδίο e_phentsize καθορίζει το μέγεθος της καταχώρισης στον πίνακα της ενότητας του προγράμματος.

Και το πεδίο e_phnum καθορίζει τον αριθμό των καταχωρήσεων στον πίνακα της ενότητας του προγράμματος.

Ο πίνακας ενοτήτων (όχι ενότητες προγράμματος) χρησιμοποιείται για τη σύνδεση προγραμμάτων. δεν θα το εξετάσουμε. Επίσης, δεν θα εξετάσουμε δυναμικά συνδεδεμένες ενότητες. Αυτό το θέμα είναι αρκετά σύνθετο και δεν είναι κατάλληλο για μια πρώτη γνωριμία. :)

Τώρα για τις ενότητες του προγράμματος. Η μορφή καταχώρισης του πίνακα ενότητας προγράμματος έχει ως εξής:

Struct elf32_phdr ( Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_memsz; Elf_3_Word p_memsz; Elf_3_Word;

Μάθετε περισσότερα για τα πεδία.

  • p_type - καθορίζει τον τύπο της ενότητας του προγράμματος. Μπορεί να πάρει πολλές τιμές, αλλά μας ενδιαφέρει μόνο μία. PT_LOAD(1). Εάν το τμήμα είναι αυτού του τύπου, τότε προορίζεται να φορτωθεί στη μνήμη.
  • p_offset - καθορίζει τη μετατόπιση στο αρχείο από το οποίο ξεκινά αυτή η ενότητα.
  • p_vaddr - ορίζει την εικονική διεύθυνση στην οποία αυτή η ενότητα θα πρέπει να φορτωθεί στη μνήμη.
  • p_paddr - ορίζει τη φυσική διεύθυνση στην οποία θα πρέπει να φορτωθεί αυτή η ενότητα. Αυτό το πεδίο είναι προαιρετικό και έχει νόημα μόνο σε ορισμένες πλατφόρμες.
  • p_filesz - καθορίζει το μέγεθος της ενότητας στο αρχείο.
  • p_memsz - καθορίζει το μέγεθος του τμήματος μνήμης. Αυτή η τιμή μπορεί να είναι μεγαλύτερη από την προηγούμενη. Το πεδίο p_flag καθορίζει τον τύπο πρόσβασης σε τμήματα στη μνήμη. Ορισμένες ενότητες μπορούν να εκτελεστούν, μερικές μπορούν να γραφτούν. Όλα είναι διαθέσιμα για ανάγνωση σε υπάρχοντα συστήματα.

Φόρτωση μορφής ELF.

Καταλάβαμε λίγο τον τίτλο. Τώρα θα δώσω έναν αλγόριθμο για τη φόρτωση ενός δυαδικού αρχείου σε μορφή ELF. Ο αλγόριθμος είναι σχηματικός και δεν πρέπει να θεωρείται ως πρόγραμμα εργασίας.

Int LoadELF (unsigned char *bin) (struct elf32_hdr *EH = (struct elf32_hdr *)bin; struct elf32_phdr *EPH; if (EH->e_ident != 0x7f || // Control MAGIC EH->e_ident != "E" EH->e_ident != EH->e_ident != EH->e_ident != ELFCLASS32 || e_ident != EV_CURRENT ||. // έκδοση EH->e_type != ET_EXEC || // πληκτρολογήστε EH->e_machine != EM_386 || // πλατφόρμα EH->e_version != EV_CURRENT) //. επιστροφή ELF_WRONG = (struct elf32_phdr *)(bin + EH->e_phnum--) (αν (EPH->p_type == PT_LOAD) memcpy (EPH->p_vaddr, bin + EPH-); >p_offset, EPH->p_filesz EPH = (struct elf32_phdr *)((unsigned char *)EPH + EH->e_phentsize)); )

Σοβαρά, αξίζει να αναλύσετε τα πεδία EPH->p_flags και να ορίσετε δικαιώματα πρόσβασης στις κατάλληλες σελίδες και η απλή αντιγραφή δεν θα λειτουργήσει εδώ, αλλά αυτό δεν σχετίζεται πλέον με τη μορφή, αλλά με την εκχώρηση μνήμης. Επομένως, δεν θα μιλήσουμε για αυτό τώρα.

Μορφή PE.

Από πολλές απόψεις είναι παρόμοιο με τη μορφή ELF, και δεν αποτελεί έκπληξη το γεγονός ότι θα πρέπει επίσης να διαθέτει ενότητες για λήψη.

Όπως όλα τα άλλα στη Microsoft:) η μορφή PE βασίζεται στη μορφή EXE. Η δομή του αρχείου είναι η εξής:

  • 00h - Κεφαλίδα EXE (δεν θα το κοιτάξω, είναι τόσο παλιά όσο το Dos. :)
  • 20h - κεφαλίδα OEM (τίποτα σημαντικό σε αυτό).
  • 3сh - μετατόπιση της πραγματικής κεφαλίδας PE στο αρχείο (dword).
  • Τραπέζι κίνησης στέλεχος?
  • στέλεχος;
  • Κεφαλίδα PE.
  • πίνακας αντικειμένων?
  • αντικείμενα αρχείου?

Το stub είναι ένα πρόγραμμα που εκτελείται σε πραγματική λειτουργία και εκτελεί ορισμένες προκαταρκτικές ενέργειες. Μπορεί να απουσιάζει, αλλά μερικές φορές μπορεί να χρειαστεί.

Μας ενδιαφέρει κάτι ελαφρώς διαφορετικό, η κεφαλίδα PE.

Η δομή του έχει ως εξής:

Struct pe_hdr ( ανυπόγραφο μακρύ pe_sign; ανυπόγραφο σύντομο pe_cputype; ανυπόγραφο σύντομο pe_objnum; ανυπόγραφο μακρύ pe_time; ανυπόγραφο μακρύ pe_cofftbl_off; ανυπόγραφο μακρύ pe_cofftbl_size; ανυπόγραφο σύντομο pe_nthdr_size_size; ανυπόγραφο μακρύ μέγεθος pe_code pe_idata_size ;

Υπάρχουν πολλά πράγματα εκεί. Αρκεί να πούμε ότι το μέγεθος αυτής της κεφαλίδας είναι 248 byte.

Και το κυριότερο είναι ότι τα περισσότερα από αυτά τα πεδία δεν χρησιμοποιούνται. (Ποιος φτιάχνει έτσι;) Όχι, έχουν, φυσικά, έναν σκοπό που είναι αρκετά γνωστός, αλλά το δοκιμαστικό μου πρόγραμμα, για παράδειγμα, περιέχει μηδενικά στα πεδία pe_code_base, pe_code_size, κ.λπ., αλλά λειτουργεί καλά. Το συμπέρασμα είναι ότι το αρχείο φορτώνεται με βάση τον πίνακα αντικειμένων. Για αυτό θα μιλήσουμε.

Ο πίνακας αντικειμένων ακολουθεί αμέσως μετά την κεφαλίδα PE. Οι καταχωρήσεις σε αυτόν τον πίνακα έχουν την ακόλουθη μορφή:

Struct pe_ohdr ( ανυπόγραφο char o_name; ανυπόγραφο μακρύ o_vsize; ανυπόγραφο μακρύ o_vaddr; ανυπόγραφο μακρύ o_psize; ανυπόγραφο μακρύ o_poff; ανυπόγραφο char o_reserved; ανυπόγραφο long o_flags; );

  • o_name - το όνομα της ενότητας, είναι απολύτως αδιάφορο για τη φόρτωση.
  • o_vsize - μέγεθος του τμήματος μνήμης.
  • o_vaddr - διεύθυνση μνήμης σε σχέση με το ImageBase.
  • o_psize - μέγεθος ενότητας στο αρχείο.
  • o_poff - μετατόπιση ενότητας στο αρχείο.
  • o_flags - σημαίες ενότητας.

Αξίζει να ρίξετε μια πιο προσεκτική ματιά στις σημαίες.

  • 00000004h - χρησιμοποιείται για κώδικα με μετατοπίσεις 16 bit
  • 00000020h - ενότητα κωδικού
  • 00000040h - αρχικοποιημένη ενότητα δεδομένων
  • 00000080h - ενότητα μη αρχικοποιημένων δεδομένων
  • 00000200h - σχόλια ή οποιοδήποτε άλλο είδος πληροφοριών
  • 00000400h - τμήμα επικάλυψης
  • 00000800h - δεν θα είναι μέρος της εικόνας του προγράμματος
  • 00001000h - γενικά δεδομένα
  • 00500000h - προεπιλεγμένη στοίχιση εκτός εάν ορίζεται διαφορετικά
  • 02000000h - μπορεί να εκφορτωθεί από τη μνήμη
  • 04000000h - δεν έχει αποθηκευτεί στην κρυφή μνήμη
  • 08000000h - χωρίς σελίδα
  • 10000000h - κοινόχρηστο
  • 20000000h - εφικτό
  • 40000000h - μπορεί να διαβαστεί
  • 80000000h - μπορείτε να γράψετε

Και πάλι, δεν θα μιλήσω για κοινόχρηστες και επικαλυπτόμενες ενότητες, μας ενδιαφέρει ο κώδικας, τα δεδομένα και τα δικαιώματα πρόσβασης.

Σε γενικές γραμμές, αυτές οι πληροφορίες είναι ήδη αρκετές για τη λήψη του δυαδικού αρχείου.

Φόρτωση μορφής PE.

int LoadPE (unsigned char *bin) ( struct elf32_hdr *PH = (struct pe_hdr *) (bin + *((unsigned long *)&bin)); // Φυσικά, ο συνδυασμός δεν είναι σαφής... απλά πάρτε το dword σε μετατόπιση 0x3c / / Και υπολογίστε τη διεύθυνση κεφαλίδας PE στην εικόνα του αρχείου struct elf32_phdr *POH if (PH == NULL || // Έλεγχος του δείκτη PH->pe_sign != 0x4550 || // PE signature ("P"; , "E", 0, 0) PH->pe_cputype != 0x14c || >pe_obj_num--) ( if ((POH->p_flags & 0x60) != 0) // είτε κωδικός είτε αρχικοποιημένο memcpy δεδομένων (PE->pe_image_base + POH->o_vaddr, bin + POH- >o_poff, POH->o_psize POH = (struct pe_ohdr *)((unsigned char *)POH + sizeof (struct pe_ohdr));

Αυτό πάλι δεν είναι ένα έτοιμο πρόγραμμα, αλλά ένας αλγόριθμος φόρτωσης.

Και πάλι, πολλά σημεία δεν καλύπτονται, καθώς ξεφεύγουν από το εύρος του θέματος.

Αλλά τώρα αξίζει να μιλήσουμε λίγο για τις υπάρχουσες δυνατότητες του συστήματος.

Χαρακτηριστικά συστήματος.

Παρά την ευελιξία των εργαλείων προστασίας που διατίθενται στους επεξεργαστές (προστασία σε επίπεδο πινάκων περιγραφής, προστασία σε επίπεδο τμήματος, προστασία σε επίπεδο σελίδας), στα υπάρχοντα συστήματα (τόσο στα Windows όσο και στο Unix) χρησιμοποιείται πλήρως μόνο η προστασία σελίδας, η οποία: αν και μπορεί να προστατεύσει τον κώδικα από την εγγραφή, αλλά δεν μπορεί να προστατεύσει τα δεδομένα από την εκτέλεση. (Ίσως αυτός είναι ο λόγος για την αφθονία των τρωτών σημείων του συστήματος;)

Όλα τα τμήματα διευθυνσιοδοτούνται από τη γραμμική διεύθυνση μηδέν και εκτείνονται μέχρι το τέλος της γραμμικής μνήμης. Η οριοθέτηση της διαδικασίας γίνεται μόνο σε επίπεδο πινάκων σελίδων.

Από αυτή την άποψη, όλες οι μονάδες συνδέονται όχι από αρχικές διευθύνσεις, αλλά με αρκετά μεγάλη μετατόπιση στο τμήμα. Στα Windows, η βασική διεύθυνση στο τμήμα είναι 0x400000, στο Unix (Linux ή FreeBSD) - 0x8048000.

Ορισμένες λειτουργίες σχετίζονται επίσης με την οργάνωση σελίδων της μνήμης.

Τα αρχεία ELF συνδέονται με τέτοιο τρόπο ώστε τα όρια και τα μεγέθη των τμημάτων να εμπίπτουν σε μπλοκ 4 kilobyte του αρχείου.

Και στη μορφή PE, παρά το γεγονός ότι η ίδια η μορφή σάς επιτρέπει να ευθυγραμμίσετε τμήματα των 512 byte, η στοίχιση των τμημάτων χρησιμοποιείται σε 4k μια μικρότερη στοίχιση στα Windows.

Τα τυπικά εργαλεία ανάπτυξης μεταγλωττίζουν το πρόγραμμά σας σε ένα αρχείο ELF (Εκτέλεση και Συνδέσιμη Μορφή) με τη δυνατότητα να περιλαμβάνει πληροφορίες εντοπισμού σφαλμάτων. Η προδιαγραφή μορφής μπορεί να διαβαστεί. Επιπλέον, κάθε αρχιτεκτονική έχει τα δικά της χαρακτηριστικά, όπως χαρακτηριστικά ARM. Ας ρίξουμε μια σύντομη ματιά σε αυτή τη μορφή.
Ένα εκτελέσιμο αρχείο σε μορφή ELF αποτελείται από τα ακόλουθα μέρη:
1. Κεφαλίδα (ELF Header)
Περιέχει γενικές πληροφορίες για το αρχείο και τα κύρια χαρακτηριστικά του.
2. Πίνακας κεφαλίδων προγράμματος
Αυτός είναι ένας πίνακας αντιστοιχίας μεταξύ των τμημάτων του αρχείου και των τμημάτων μνήμης που λέει στο πρόγραμμα εκκίνησης σε ποια περιοχή μνήμης να γράψει κάθε ενότητα.
3. Τομές
Οι ενότητες περιέχουν όλες τις πληροφορίες του αρχείου (πρόγραμμα, δεδομένα, πληροφορίες εντοπισμού σφαλμάτων κ.λπ.)
Κάθε ενότητα έχει έναν τύπο, όνομα και άλλες παραμέτρους. Η ενότητα ".text" συνήθως αποθηκεύει τον κώδικα, ".symtab" - έναν πίνακα με σύμβολα προγράμματος (ονόματα αρχείων, διαδικασίες και μεταβλητές), ".strtab" - έναν πίνακα συμβολοσειρών, ενότητες με το πρόθεμα ".debug_" - πληροφορίες εντοπισμού σφαλμάτων κ.λπ. .δ. Επιπλέον, το αρχείο πρέπει να έχει μια κενή ενότητα με ευρετήριο 0.
4. Πίνακας κεφαλίδας ενότητας
Αυτός είναι ένας πίνακας που περιέχει μια σειρά από κεφαλίδες ενοτήτων.
Η μορφή αναλύεται λεπτομερέστερα στην ενότητα Δημιουργία ELF.

Επισκόπηση ΝΑΝΟΥ

Το DWARF είναι μια τυποποιημένη μορφή πληροφοριών εντοπισμού σφαλμάτων. Μπορείτε να κατεβάσετε το πρότυπο από τον επίσημο ιστότοπο. Υπάρχει επίσης μια εξαιρετική σύντομη επισκόπηση της μορφής: Εισαγωγή στη μορφή εντοπισμού σφαλμάτων DWARF (Michael J. Eager).
Γιατί χρειάζονται πληροφορίες εντοπισμού σφαλμάτων; Επιτρέπει:
  • ορίστε σημεία διακοπής όχι σε μια φυσική διεύθυνση, αλλά στον αριθμό γραμμής στο αρχείο πηγαίου κώδικα ή στο όνομα της συνάρτησης
  • εμφάνιση και αλλαγή των τιμών των καθολικών και τοπικών μεταβλητών, καθώς και των παραμέτρων συνάρτησης
  • εμφάνιση της στοίβας κλήσεων (backtrace)
  • εκτελέστε το πρόγραμμα βήμα προς βήμα όχι σύμφωνα με μία οδηγία συναρμολόγησης, αλλά σύμφωνα με γραμμές πηγαίου κώδικα
Αυτές οι πληροφορίες αποθηκεύονται σε μια δομή δέντρου. Κάθε κόμβος δέντρου έχει έναν γονέα, μπορεί να έχει παιδιά και ονομάζεται DIE (Εισαγωγή πληροφοριών εντοπισμού σφαλμάτων). Κάθε κόμβος έχει τη δική του ετικέτα (τύπος) και μια λίστα χαρακτηριστικών (ιδιοτήτων) που περιγράφουν τον κόμβο. Τα χαρακτηριστικά μπορούν να περιέχουν οτιδήποτε, όπως δεδομένα ή συνδέσμους προς άλλους κόμβους. Επιπλέον, υπάρχουν πληροφορίες αποθηκευμένες έξω από το δέντρο.
Οι κόμβοι χωρίζονται σε δύο βασικούς τύπους: κόμβους που περιγράφουν δεδομένα και κόμβους που περιγράφουν κώδικα.
Κόμβοι που περιγράφουν δεδομένα:
  1. Τύποι δεδομένων:
    • Βασικοί τύποι δεδομένων (κόμβος με τύπο DW_TAG_base_type), όπως ο τύπος int στο C.
    • Σύνθετοι τύποι δεδομένων (δείκτες, κ.λπ.)
    • Πίνακες
    • Δομές, κλάσεις, ενώσεις, διεπαφές
  2. Αντικείμενα δεδομένων:
    • σταθερές
    • παραμέτρους λειτουργίας
    • μεταβλητές
    • και τα λοιπά.
Κάθε αντικείμενο δεδομένων έχει ένα χαρακτηριστικό DW_AT_location, το οποίο καθορίζει τον τρόπο υπολογισμού της διεύθυνσης όπου βρίσκονται τα δεδομένα. Για παράδειγμα, μια μεταβλητή μπορεί να έχει μια σταθερή διεύθυνση, να είναι σε έναν καταχωρητή ή στη στοίβα ή να είναι μέλος μιας κλάσης ή ενός αντικειμένου. Αυτή η διεύθυνση μπορεί να υπολογιστεί με αρκετά περίπλοκο τρόπο, επομένως το πρότυπο παρέχει τις λεγόμενες εκφράσεις τοποθεσίας, οι οποίες μπορούν να περιέχουν μια ακολουθία χειριστών μιας ειδικής μηχανής εσωτερικής στοίβας.
Κόμβοι που περιγράφουν τον κώδικα:
  1. Διαδικασίες (συναρτήσεις) - κόμβοι με την ετικέτα DW_TAG_υποπρόγραμμα. Οι απόγονοι κόμβοι μπορούν να περιέχουν περιγραφές μεταβλητών - παραμέτρων συνάρτησης και τοπικές μεταβλητές συνάρτησης.
  2. Μονάδα Σύνταξης. Περιέχει πληροφορίες προγράμματος και είναι ο γονέας όλων των άλλων κόμβων.
Οι πληροφορίες που περιγράφονται παραπάνω βρίσκονται στις ενότητες ".debug_info" και ".debug_abbrev".
Αλλες πληροφορίες:
  • Πληροφορίες σχετικά με τους αριθμούς γραμμών (ενότητα ".debug_line")
  • Πληροφορίες σχετικά με τις μακροεντολές (ενότητα ".debug_macinfo")
  • Πληροφορίες πλαισίου κλήσεων (ενότητα ".debug_frame")

Δημιουργία ELF

Θα δημιουργήσουμε αρχεία σε μορφή EFL χρησιμοποιώντας τη βιβλιοθήκη libelf από το πακέτο elfutils. Υπάρχει ένα καλό άρθρο στο Διαδίκτυο σχετικά με τη χρήση του libelf - LibELF by Example (δυστυχώς, περιγράφει τη δημιουργία αρχείων πολύ σύντομα) καθώς και τεκμηρίωση.
Η δημιουργία ενός αρχείου αποτελείται από διάφορα στάδια:
  1. Αρχικοποίηση συκοφαντίας
  2. Δημιουργία κεφαλίδας αρχείου (ELF Header)
  3. Δημιουργία πίνακα κεφαλίδων προγράμματος
  4. Δημιουργία Ενοτήτων
  5. Γράψτε ένα αρχείο
Ας ρίξουμε μια πιο προσεκτική ματιά στα στάδια
Αρχικοποίηση συκοφαντίας
Πρώτα θα χρειαστεί να καλέσετε τη συνάρτηση elf_version(EV_CURRENT) και να ελέγξετε το αποτέλεσμα. Εάν είναι ίσο με EV_NONE, έχει προκύψει σφάλμα και δεν μπορούν να εκτελεστούν περαιτέρω ενέργειες. Στη συνέχεια, πρέπει να δημιουργήσουμε το αρχείο που χρειαζόμαστε στο δίσκο, να πάρουμε τον περιγραφέα του και να το περάσουμε στη συνάρτηση elf_begin:
Elf * elf_begin(int fd, Elf_Cmd cmd, Elf *elf)
  • fd - περιγραφέας του αρχείου που άνοιξε πρόσφατα
  • cmd - λειτουργία (ELF_C_READ για ανάγνωση πληροφοριών, ELF_C_WRITE για γραφή ή ELF_C_RDWR για ανάγνωση/εγγραφή), πρέπει να αντιστοιχεί στη λειτουργία ανοιχτού αρχείου (ELF_C_WRITE στην περίπτωσή μας)
  • elf - απαιτείται μόνο για εργασία με αρχεία αρχειοθέτησης (.a), στην περίπτωσή μας πρέπει να περάσετε το 0
Η συνάρτηση επιστρέφει έναν δείκτη στη δημιουργημένη λαβή, ο οποίος θα χρησιμοποιηθεί σε όλες τις συναρτήσεις libelf, το 0 επιστρέφεται σε σφάλμα.
Δημιουργία τίτλου
Μια νέα κεφαλίδα αρχείου δημιουργείται από τη συνάρτηση elf32_newehdr:
Elf32_Ehdr * elf32_newehdr(Elf *elf);
  • elf - λαβή που επιστρέφεται από τη συνάρτηση elf_begin
Επιστρέφει 0 σε σφάλμα ή δείκτη στη δομή - την κεφαλίδα του αρχείου ELF:
#define EI_NIDENT 16 typedef struct ( ανυπόγραφο char e_ident; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff;Eff _Half e_ehs ize;

Μερικά από τα πεδία του συμπληρώνονται με τυπικό τρόπο, μερικά πρέπει να συμπληρώσουμε:

  • e_ident - ο πίνακας byte αναγνώρισης, έχει τους ακόλουθους δείκτες:
    • EI_MAG0, EI_MAG1, EI_MAG2, EI_MAG3 - αυτά τα 4 byte πρέπει να περιέχουν τους χαρακτήρες 0x7f,"ELF", τους οποίους η συνάρτηση elf32_newehdr έχει ήδη κάνει για εμάς
    • EI_DATA - υποδεικνύει τον τύπο των δεδομένων που κωδικοποιούνται στο αρχείο: ELFDATA2LSB ή ELFDATA2MSB. Πρέπει να εγκαταστήσετε το ELFDATA2LSB ως εξής: e_ident = ELFDATA2LSB
    • EI_VERSION - έκδοση κεφαλίδας αρχείου, που έχει ήδη οριστεί για εμάς
    • EI_PAD - μην αγγίζετε
  • e_type - τύπος αρχείου, μπορεί να είναι ET_NONE - χωρίς τύπο, ET_REL - αρχείο με δυνατότητα μετακίνησης, ET_EXEC - εκτελέσιμο αρχείο, ET_DYN - αρχείο κοινόχρηστου αντικειμένου κ.λπ. Πρέπει να ορίσουμε τον τύπο αρχείου σε ET_EXEC
  • e_machine - η αρχιτεκτονική που απαιτείται για αυτό το αρχείο, για παράδειγμα EM_386 - για την αρχιτεκτονική Intel, για ARM πρέπει να γράψουμε EM_ARM (40) εδώ - δείτε ELF για την αρχιτεκτονική ARM
  • e_version - έκδοση αρχείου, πρέπει να οριστεί σε EV_CURRENT
  • e_entry - διεύθυνση σημείου εισόδου, δεν είναι απαραίτητη για εμάς
  • e_phoff - μετατόπιση στο αρχείο κεφαλίδας προγράμματος, e_shoff - μετατόπιση της κεφαλίδας ενότητας, μη συμπληρώσετε
  • e_flags - σημαίες για συγκεκριμένο επεξεργαστή, για την αρχιτεκτονική μας (Cortex-M3) θα πρέπει να οριστούν σε 0x05000000 (έκδοση ABI 5)
  • e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum - μην αγγίζετε
  • e_shstrndx - περιέχει τον αριθμό της ενότητας στην οποία βρίσκεται ο πίνακας σειρών με κεφαλίδες ενοτήτων. Επειδή δεν έχουμε ακόμη ενότητες, θα ορίσουμε αυτόν τον αριθμό αργότερα
Δημιουργία κεφαλίδας προγράμματος
Όπως αναφέρθηκε ήδη, ο Πίνακας Κεφαλίδων Προγράμματος είναι ένας πίνακας αντιστοιχίας μεταξύ τμημάτων αρχείου και τμημάτων μνήμης, ο οποίος λέει στον φορτωτή εκκίνησης πού να γράψει κάθε ενότητα. Ο τίτλος δημιουργείται χρησιμοποιώντας τη συνάρτηση elf32_newphdr:
Elf32_Phdr * elf32_newphdr(Ξωτικό *ξωτικό, μέτρηση μεγέθους_t);
  • ξωτικό είναι το χερούλι μας
  • count - ο αριθμός των στοιχείων του πίνακα που θα δημιουργηθούν. Εφόσον θα έχουμε μόνο μία ενότητα (με κωδικό προγράμματος), η μέτρηση θα είναι ίση με 1.
Επιστρέφει 0 σε σφάλμα ή δείκτη στην κεφαλίδα του προγράμματος.
Κάθε στοιχείο στον πίνακα κεφαλίδων περιγράφεται από την ακόλουθη δομή:
TYPEDEF STRUCT (ELF32_WORD P_TYPE; ELF32_OFF P_OFFSET; ELF32_ADDR P_VADDR; ELF32_ADDR P_PADDDR; ELF32_WORD P_Filesz; ELF32_WORD P_MEMS_FLORD;
  • p_type - τύπος τμήματος (τμήμα), εδώ πρέπει να καθορίσουμε PT_LOAD - τμήμα φόρτωσης
  • p_offset - μετατοπίσεις στο αρχείο όπου ξεκινούν τα δεδομένα της ενότητας που θα φορτωθεί στη μνήμη. Για εμάς, αυτή είναι η ενότητα .text, η οποία θα βρίσκεται αμέσως μετά την κεφαλίδα του αρχείου και την κεφαλίδα του προγράμματος, μπορούμε να υπολογίσουμε τη μετατόπιση ως το άθροισμα των μηκών αυτών των κεφαλίδων. Το μήκος οποιουδήποτε τύπου μπορεί να ληφθεί χρησιμοποιώντας τη συνάρτηση elf32_fsize:
    size_t elf32_fsize (Τύπος Elf_Type, μέτρηση size_t, ανυπόγραφη int έκδοση); τύπος - εδώ η σταθερά ELF_T_xxx, θα χρειαστούμε τα μεγέθη ELF_T_EHDR και ELF_T_PHDR. count - ο αριθμός των στοιχείων του επιθυμητού τύπου, έκδοση - πρέπει να οριστεί σε EV_CURRENT
  • p_vaddr, p_paddr - εικονική και φυσική διεύθυνση στην οποία θα φορτωθούν τα περιεχόμενα της ενότητας. Δεδομένου ότι δεν έχουμε εικονικές διευθύνσεις, την ορίζουμε ίση με τη φυσική, στην απλούστερη περίπτωση - 0, γιατί εκεί θα φορτωθεί το πρόγραμμά μας.
  • p_filesz, p_memsz - μέγεθος ενότητας σε αρχείο και μνήμη. Τα έχουμε τα ίδια, αλλά επειδή δεν υπάρχει ακόμη ενότητα με τον κωδικό προγράμματος, θα τα εγκαταστήσουμε αργότερα
  • p_flags - δικαιώματα για το φορτωμένο τμήμα μνήμης. Μπορεί να είναι PF_R - ανάγνωση, PF_W - εγγραφή, PF_X - εκτέλεση ή συνδυασμός αυτών. Ορίστε το p_flags σε PF_R + PF_X
  • p_align - στοίχιση τμήματος, έχουμε 4
Δημιουργία Ενοτήτων
Αφού δημιουργήσετε τις επικεφαλίδες, μπορείτε να ξεκινήσετε τη δημιουργία ενοτήτων. Δημιουργείται μια κενή ενότητα χρησιμοποιώντας τη συνάρτηση elf_newscn:
Elf_Scn * elf_newscn(Elf *elf);
  • elf - η λαβή που επιστράφηκε νωρίτερα από τη συνάρτηση elf_begin
Η συνάρτηση επιστρέφει δείκτη στην ενότητα ή 0 σε σφάλμα.
Αφού δημιουργήσετε μια ενότητα, πρέπει να συμπληρώσετε την κεφαλίδα ενότητας και να δημιουργήσετε μια περιγραφή δεδομένων ενότητας.
Μπορούμε να λάβουμε έναν δείκτη στην κεφαλίδα ενότητας χρησιμοποιώντας τη συνάρτηση elf32_getshdr:
Elf32_Shdr * elf32_getshdr(Elf_Scn *scn);
  • Το scn είναι ένας δείκτης στην ενότητα που λάβαμε από τη συνάρτηση elf_newscn.
Η κεφαλίδα της ενότητας μοιάζει με αυτό:
typedef struct ( Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh.3_Word; sh_entsize ) Elf32_Shdr;
  • sh_name - όνομα ενότητας - μετατόπιση στον πίνακα συμβολοσειρών των κεφαλίδων ενοτήτων (section.shstrtab) - βλέπε "Πίνακες συμβολοσειρών" παρακάτω
  • sh_type - τύπος περιεχομένου ενότητας, για ενότητα με κωδικό προγράμματος πρέπει να ορίσετε SHT_PROGBITS, για ενότητες με πίνακα συμβολοσειρών - SHT_STRTAB, για πίνακα συμβόλων - SHT_SYMTAB
  • Τα sh_flags είναι σημαίες ενοτήτων που μπορούν να συνδυαστούν και από τις οποίες χρειαζόμαστε μόνο τρεις:
    • SHF_ALLOC - σημαίνει ότι η ενότητα θα φορτωθεί στη μνήμη
    • SHF_EXECINSTR - η ενότητα περιέχει εκτελέσιμο κώδικα
    • SHF_STRINGS - η ενότητα περιέχει έναν πίνακα συμβολοσειρών
    Αντίστοιχα, για την ενότητα .text με το πρόγραμμα πρέπει να ορίσετε τις σημαίες SHF_ALLOC + SHF_EXECINSTR
  • sh_addr - διεύθυνση όπου θα φορτωθεί η ενότητα στη μνήμη
  • sh_offset - μετατόπιση της ενότητας στο αρχείο - μην το αγγίζετε, η βιβλιοθήκη θα το εγκαταστήσει για εμάς
  • sh_size - μέγεθος τμήματος - μην αγγίζετε
  • sh_link - περιέχει τον αριθμό της συνδεδεμένης ενότητας που απαιτείται για τη σύνδεση της ενότητας με τον αντίστοιχο πίνακα σειρών (δείτε παρακάτω)
  • sh_info - πρόσθετες πληροφορίες ανάλογα με τον τύπο ενότητας, ρυθμισμένο σε 0
  • sh_addralign - στοίχιση διευθύνσεων, μην αγγίζετε
  • sh_entsize - εάν ένα τμήμα αποτελείται από πολλά στοιχεία του ίδιου μήκους, υποδεικνύει το μήκος ενός τέτοιου στοιχείου, μην αγγίζετε
Αφού συμπληρώσετε την κεφαλίδα, πρέπει να δημιουργήσετε έναν περιγραφέα δεδομένων ενότητας με τη συνάρτηση elf_newdata:
Elf_Data * elf_newdata(Elf_Scn *scn);
  • Το scn είναι ο δείκτης που μόλις ελήφθη στη νέα ενότητα.
Η συνάρτηση επιστρέφει 0 σε σφάλμα ή έναν δείκτη στη δομή Elf_Data που θα πρέπει να συμπληρωθεί:
typedef struct ( void* d_buf; Elf_Type d_type; size_t d_size; off_t d_off; size_t d_align; unsigned d_version; ) Elf_Data;
  • d_buf - δείκτης προς τα δεδομένα που θα εγγραφούν στην ενότητα
  • d_type - τύπος δεδομένων, το ELF_T_BYTE είναι κατάλληλο για εμάς παντού
  • d_size - μέγεθος δεδομένων
  • d_off - μετατόπιση στην ενότητα, ορίστηκε σε 0
  • d_align - alignment, μπορεί να οριστεί σε 1 - no alignment
  • d_version - έκδοση, πρέπει να οριστεί σε EV_CURRENT
Ειδικά τμήματα
Για τους σκοπούς μας, θα χρειαστεί να δημιουργήσουμε το ελάχιστο απαιτούμενο σύνολο ενοτήτων:
  • .text - ενότητα με κωδικό προγράμματος
  • .symtab - πίνακας συμβόλων αρχείου
  • Το .strtab είναι ένας πίνακας συμβολοσειρών που περιέχει τα ονόματα των συμβόλων από την ενότητα .symtab, καθώς η τελευταία δεν αποθηκεύει τα ίδια τα ονόματα, αλλά τους δείκτες τους
  • .shstrtab - πίνακας συμβολοσειρών που περιέχει ονόματα ενοτήτων
Όλες οι ενότητες δημιουργούνται όπως περιγράφεται στην προηγούμενη ενότητα, αλλά κάθε ειδική ενότητα έχει τα δικά της χαρακτηριστικά.
Ενότητα.κείμενο
Αυτή η ενότητα περιέχει εκτελέσιμο κώδικα, επομένως πρέπει να ορίσετε το sh_type σε SHT_PROGBITS, sh_flags σε SHF_EXECINSTR + SHF_ALLOC, sh_addr στη διεύθυνση όπου θα φορτωθεί αυτός ο κωδικός
Ενότητα.symtab
Η ενότητα περιέχει μια περιγραφή όλων των συμβόλων (λειτουργιών) του προγράμματος και των αρχείων στα οποία περιγράφηκαν. Αποτελείται από τα ακόλουθα στοιχεία, μήκους 16 byte το καθένα:
typedef struct ( Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; ανυπόγραφο char st_info; ανυπόγραφο char st_other; Elf32_Half st_shndx; ) Elf32_Sym;
  • st_name - όνομα συμβόλου (ευρετήριο στον πίνακα συμβολοσειρών.strtab)
  • st_value - τιμή (διεύθυνση εισαγωγής για μια συνάρτηση ή 0 για ένα αρχείο). Εφόσον το Cortex-M3 έχει ένα σύνολο εντολών Thumb-2, αυτή η διεύθυνση πρέπει να είναι περίεργη (πραγματική διεύθυνση + 1)
  • st_size - μήκος κωδικού συνάρτησης (0 για αρχείο)
  • st_info - τύπος συμβόλου και το εύρος του. Υπάρχει μια μακροεντολή για τον προσδιορισμό της τιμής αυτού του πεδίου
    #define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
    όπου b είναι το εύρος και t ο τύπος χαρακτήρα
    Το εύρος μπορεί να είναι STB_LOCAL (το σύμβολο δεν είναι ορατό από άλλα αρχεία αντικειμένων) ή STB_GLOBAL (ορατό). Για να απλοποιήσουμε τα πράγματα, χρησιμοποιούμε STB_GLOBAL.
    Τύπος συμβόλου - STT_FUNC για συνάρτηση, STT_FILE για αρχείο
  • st_other - ορίστηκε στο 0
  • st_shndx - ευρετήριο της ενότητας για την οποία έχει οριστεί το σύμβολο (ενότητα index.text) ή SHN_ABS για το αρχείο.
    Το ευρετήριο ενότητας από τον περιγραφέα scn του μπορεί να προσδιοριστεί χρησιμοποιώντας elf_ndxscn:
    size_t elf_ndxscn(Elf_Scn *scn);

Αυτή η ενότητα δημιουργείται με τον συνηθισμένο τρόπο, μόνο το sh_type χρειάζεται να οριστεί σε SHT_SYMTAB και η ενότητα index.strtab θα πρέπει να γραφτεί στο πεδίο sh_link, έτσι αυτές οι ενότητες θα συνδεθούν.
Section.strtab
Αυτή η ενότητα περιέχει τα ονόματα όλων των συμβόλων από την ενότητα .symtab. Δημιουργήθηκε σαν μια κανονική ενότητα, αλλά το sh_type πρέπει να οριστεί σε SHT_STRTAB, το sh_flag σε SHF_STRINGS, ώστε αυτή η ενότητα να γίνει πίνακας συμβολοσειρών.
Τα δεδομένα για μια ενότητα μπορούν να συλλεχθούν περνώντας μέσα από το κείμενο προέλευσης σε έναν πίνακα, ο δείκτης στον οποίο στη συνέχεια γράφεται στον περιγραφέα δεδομένων ενότητας (d_buf).
Section.shstrtab
Μια ενότητα είναι ένας πίνακας συμβολοσειρών που περιέχει τις κεφαλίδες όλων των ενοτήτων του αρχείου, συμπεριλαμβανομένης της δικής της κεφαλίδας. Δημιουργείται με τον ίδιο τρόπο όπως η ενότητα .strtab. Μετά τη δημιουργία, το ευρετήριό του πρέπει να γραφτεί στο πεδίο e_shstrndx της κεφαλίδας του αρχείου.
Τραπέζια χορδών
Οι πίνακες συμβολοσειρών περιέχουν διαδοχικές σειρές που τελειώνουν με ένα μηδενικό byte, το πρώτο byte σε αυτόν τον πίνακα πρέπει επίσης να είναι 0. Ο δείκτης μιας σειράς στον πίνακα είναι απλώς η μετατόπιση σε byte από την αρχή του πίνακα, επομένως η πρώτη σειρά "όνομα" έχει δείκτη 1, η επόμενη σειρά "var" έχει δείκτη 6.
Ευρετήριο 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \0 n a m e \0 v a r \0
Γράψτε ένα αρχείο
Έτσι, οι κεφαλίδες και οι ενότητες έχουν ήδη διαμορφωθεί, τώρα πρέπει να γραφτούν σε ένα αρχείο και να ολοκληρωθεί η εργασία με το libelf. Η εγγραφή πραγματοποιείται από τη συνάρτηση elf_update:
off_t elf_update(Elf *elf, Elf_Cmd cmd);
  • ξωτικό - λαβή
  • cmd - εντολή, πρέπει να είναι ίση με ELF_C_WRITE για να γράψετε.
Η συνάρτηση επιστρέφει -1 σε σφάλμα. Το κείμενο σφάλματος μπορεί να ληφθεί καλώντας τη συνάρτηση elf_errmsg(-1), η οποία θα επιστρέψει έναν δείκτη στη γραμμή με το σφάλμα.
Τελειώνουμε την εργασία με τη βιβλιοθήκη με τη συνάρτηση elf_end, στην οποία περνάμε τον περιγραφέα μας. Το μόνο που μένει είναι να κλείσετε το αρχείο που είχε ανοίξει προηγουμένως.
Ωστόσο, το αρχείο που δημιουργήσαμε δεν περιέχει πληροφορίες εντοπισμού σφαλμάτων, τις οποίες θα προσθέσουμε στην επόμενη ενότητα.

Δημιουργία ΝΑΝΟΥ

Θα δημιουργήσουμε πληροφορίες εντοπισμού σφαλμάτων χρησιμοποιώντας τη βιβλιοθήκη, η οποία συνοδεύεται από ένα αρχείο pdf με τεκμηρίωση (libdwarf2p.1.pdf - A Producer Library Interface to DWARF).
Η δημιουργία πληροφοριών εντοπισμού σφαλμάτων αποτελείται από τα ακόλουθα βήματα:
  1. Δημιουργία κόμβων (DIE - Εισαγωγή πληροφοριών εντοπισμού σφαλμάτων)
  2. Δημιουργία Χαρακτηριστικών Κόμβων
  3. Δημιουργία τύπων δεδομένων
  4. Δημιουργία διαδικασιών (συναρτήσεων)
Ας ρίξουμε μια πιο προσεκτική ματιά στα στάδια
Αρχικοποίηση παραγωγού libdwarf
Θα δημιουργήσουμε πληροφορίες εντοπισμού σφαλμάτων τη στιγμή της μεταγλώττισης ταυτόχρονα με τη δημιουργία των συμβόλων στην ενότητα .symtab, επομένως η βιβλιοθήκη πρέπει να προετοιμαστεί μετά την προετοιμασία του libelf, τη δημιουργία της κεφαλίδας ELF και του προγράμματος και πριν δημιουργηθούν οι ενότητες.
Για αρχικοποίηση θα χρησιμοποιήσουμε τη συνάρτηση dwarf_producer_init_c. Η βιβλιοθήκη έχει πολλές ακόμη συναρτήσεις αρχικοποίησης (dwarf_producer_init, dwarf_producer_init_b), οι οποίες διαφέρουν σε ορισμένες αποχρώσεις που περιγράφονται στην τεκμηρίωση. Κατ 'αρχήν, μπορείτε να χρησιμοποιήσετε οποιοδήποτε από αυτά.

Dwarf_P_Debug dwarf_producer_init_c(Dwarf_Unsigned flags, Dwarf_Callback_Func_c func, Dwarf_Handler errhand, Dwarf_Ptr errarg, void * user_data, Dwarf_Error *error)

  • flags - ένας συνδυασμός "ή" πολλών σταθερών που καθορίζουν ορισμένες παραμέτρους, για παράδειγμα, βάθος bit πληροφοριών, ακολουθία byte (little-endian, big-endian), μορφή μετεγκατάστασης, από τα οποία χρειαζόμαστε οπωσδήποτε DW_DLC_WRITE και DW_DLC_SYMBOLIC_RELOCATIONS
  • Το func είναι μια συνάρτηση επανάκλησης που θα καλείται κατά τη δημιουργία ενοτήτων ELF με πληροφορίες εντοπισμού σφαλμάτων. Για περισσότερες λεπτομέρειες, δείτε παρακάτω στην ενότητα "Δημιουργία ενοτήτων με πληροφορίες εντοπισμού σφαλμάτων"
  • Το errhand είναι ένας δείκτης σε μια συνάρτηση που θα καλείται όταν προκύψουν σφάλματα. Μπορείτε να στείλετε 0
  • errarg - τα δεδομένα που θα περάσουν στη συνάρτηση errhand μπορούν να οριστούν στο 0
  • user_data - τα δεδομένα που θα περάσουν στη συνάρτηση func μπορούν να οριστούν σε 0
  • error - επέστρεψε κωδικός σφάλματος
Η συνάρτηση επιστρέφει Dwarf_P_Debug - ένας περιγραφέας που χρησιμοποιείται σε όλες τις επόμενες συναρτήσεις ή -1 σε περίπτωση σφάλματος και το σφάλμα θα περιέχει τον κωδικό σφάλματος (μπορείτε να λάβετε το κείμενο του μηνύματος σφάλματος από τον κώδικά του χρησιμοποιώντας τη συνάρτηση dwarf_errmsg, περνώντας αυτόν τον κωδικό σε αυτό)
Δημιουργία κόμβων (DIE - Καταχώρηση πληροφοριών εντοπισμού σφαλμάτων)
Όπως περιγράφηκε παραπάνω, οι πληροφορίες εντοπισμού σφαλμάτων σχηματίζουν μια δομή δέντρου. Για να δημιουργήσετε έναν κόμβο αυτού του δέντρου, χρειάζεστε:
  • δημιουργήστε το χρησιμοποιώντας τη συνάρτηση dwarf_new_die
  • προσθέστε χαρακτηριστικά σε αυτό (κάθε τύπος χαρακτηριστικού προστίθεται από τη δική του συνάρτηση, η οποία θα περιγραφεί παρακάτω)
Ο κόμβος δημιουργείται χρησιμοποιώντας τη συνάρτηση dwarf_new_die:
Dwarf_P_Die dwarf_new_die(Dwarf_P_Debug dbg, Dwarf_Tag new_tag, Dwarf_P_Die γονέας, Dwarf_P_Die παιδί, Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling, Dwarf_Error *Errorf)
  • new_tag - ετικέτα κόμβου (τύπος) - σταθερή DW_TAG_xxxx, η οποία βρίσκεται στο αρχείο libdwarf.h
  • γονέας, παιδί, left_sibling, right_sibling - αντίστοιχα ο γονέας, το παιδί, ο αριστερός και ο δεξιός γείτονας του κόμβου. Δεν είναι απαραίτητο να καθορίσετε όλες αυτές τις παραμέτρους, αρκεί να ορίσετε μία και να βάλετε 0 αντί για τις υπόλοιπες, ο κόμβος θα είναι είτε ρίζας είτε απομονωμένος
  • σφάλμα - θα περιέχει τον κωδικό σφάλματος όταν παρουσιαστεί
Η συνάρτηση επιστρέφει DW_DLV_BADADDR σε περίπτωση σφάλματος ή λαβή κόμβου Dwarf_P_Die σε επιτυχία
Δημιουργία Χαρακτηριστικών Κόμβων
Για να δημιουργήσετε χαρακτηριστικά κόμβου, υπάρχει μια ολόκληρη οικογένεια συναρτήσεων dwarf_add_AT_xxxx. Μερικές φορές είναι δύσκολο να προσδιοριστεί ποια συνάρτηση χρειάζεται για να δημιουργήσει το απαιτούμενο χαρακτηριστικό, γι' αυτό έσκαψα ακόμη και τον πηγαίο κώδικα της βιβλιοθήκης αρκετές φορές. Μερικές από τις λειτουργίες θα περιγραφούν εδώ, μερικές παρακάτω στις κατάλληλες ενότητες. Όλα δέχονται μια παράμετρο ιδιοκτησίας - μια λαβή στον κόμβο στον οποίο θα προστεθεί το χαρακτηριστικό και επιστρέφουν έναν κωδικό σφάλματος στην παράμετρο σφάλματος.
Η συνάρτηση dwarf_add_AT_name προσθέτει ένα χαρακτηριστικό "όνομα" (DW_AT_name) σε έναν κόμβο. Οι περισσότεροι κόμβοι πρέπει να έχουν όνομα (για παράδειγμα, διαδικασίες, μεταβλητές, σταθερές), ορισμένοι μπορεί να μην έχουν όνομα (για παράδειγμα, Compilation Unit)
Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die ownerdie, char *name, Dwarf_Error *error)
  • όνομα - η πραγματική τιμή χαρακτηριστικού (όνομα κόμβου)

Οι συναρτήσεις dwarf_add_AT_signed_const, dwarf_add_AT_unsigned_const προσθέτουν το καθορισμένο χαρακτηριστικό και την υπογεγραμμένη (unsigned) τιμή του στον κόμβο. Τα χαρακτηριστικά με υπογραφή και χωρίς υπογραφή χρησιμοποιούνται για τον καθορισμό σταθερών τιμών, μεγεθών, αριθμών γραμμών κ.λπ. Μορφή λειτουργίας:
Dwarf_P_Attribute dwarf_add_AT_(un)signed_const(Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_Signed value, Dwarf_Error *error)
  • dbg - Ο περιγραφέας Dwarf_P_Debug λήφθηκε κατά την προετοιμασία της βιβλιοθήκης
  • attr - το χαρακτηριστικό του οποίου η τιμή έχει οριστεί - η σταθερά DW_AT_xxxx, η οποία μπορεί να βρεθεί στο αρχείο libdwarf.h
  • τιμή - τιμή χαρακτηριστικού
Επιστρέψτε το DW_DLV_BADADDR σε σφάλμα ή μια λαβή χαρακτηριστικού σε περίπτωση επιτυχίας.
Δημιουργία μονάδας μεταγλώττισης
Κάθε δέντρο πρέπει να έχει ρίζα - στην περίπτωσή μας, αυτή είναι μια μονάδα μεταγλώττισης που περιέχει πληροφορίες για το πρόγραμμα (για παράδειγμα, το όνομα του κύριου αρχείου, τη γλώσσα προγραμματισμού που χρησιμοποιείται, το όνομα του μεταγλωττιστή, την ευαισθησία πεζών-κεφαλαίων των συμβόλων ( μεταβλητές, συναρτήσεις), η κύρια συνάρτηση του προγράμματος, η διεύθυνση έναρξης, κ.λπ. κ.λπ.). Κατ 'αρχήν, δεν απαιτούνται χαρακτηριστικά. Για παράδειγμα, ας δημιουργήσουμε πληροφορίες για το κύριο αρχείο και τον μεταγλωττιστή.
Πληροφορίες για το κύριο αρχείο
Για να αποθηκεύσετε πληροφορίες σχετικά με το κύριο αρχείο, χρησιμοποιήστε το χαρακτηριστικό name (DW_AT_name), χρησιμοποιήστε τη συνάρτηση dwarf_add_AT_name όπως φαίνεται στην ενότητα "Δημιουργία χαρακτηριστικών κόμβων".
Πληροφορίες μεταγλωττιστή
Χρησιμοποιούμε τη συνάρτηση dwarf_add_AT_producer:
Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die ownerdie, char *producer_string, Dwarf_Error *error)
  • producer_string - συμβολοσειρά με κείμενο πληροφοριών
Επιστρέφει το DW_DLV_BADADDR σε σφάλμα ή μια λαβή χαρακτηριστικού σε περίπτωση επιτυχίας.
Δημιουργία κοινής καταχώρισης πληροφοριών
Συνήθως, όταν καλείται μια συνάρτηση (υπορουτίνα), οι παράμετροί της και η διεύθυνση επιστροφής ωθούνται στη στοίβα (αν και κάθε μεταγλωττιστής μπορεί να το κάνει διαφορετικά), όλα αυτά ονομάζονται Πλαίσιο Κλήσης. Το πρόγραμμα εντοπισμού σφαλμάτων χρειάζεται πληροφορίες σχετικά με τη μορφή πλαισίου για να προσδιορίσει σωστά τη διεύθυνση επιστροφής από μια συνάρτηση και να δημιουργήσει ένα backtrace - μια αλυσίδα κλήσεων συναρτήσεων που μας οδήγησαν στην τρέχουσα συνάρτηση και στις παραμέτρους αυτών των συναρτήσεων. Είναι επίσης σύνηθες να καθορίζονται καταχωρητές επεξεργαστή που είναι αποθηκευμένοι στη στοίβα. Ο κώδικας που διατηρεί χώρο στη στοίβα και αποθηκεύει καταχωρητές επεξεργαστή ονομάζεται πρόλογος συνάρτησης, ο κώδικας που επαναφέρει τους καταχωρητές και η στοίβα ονομάζεται επίλογος.
Αυτές οι πληροφορίες εξαρτώνται σε μεγάλο βαθμό από τον μεταγλωττιστή. Για παράδειγμα, ο πρόλογος και ο επίλογος δεν χρειάζεται να βρίσκονται στην αρχή και στο τέλος της λειτουργίας. Μερικές φορές χρησιμοποιείται το πλαίσιο, μερικές φορές όχι. Οι καταχωρητές επεξεργαστή μπορούν να αποθηκευτούν σε άλλους καταχωρητές κ.λπ.
Έτσι, ο εντοπισμός σφαλμάτων πρέπει να γνωρίζει πώς οι καταχωρίσεις του επεξεργαστή αλλάζουν την τιμή τους και πού θα αποθηκευτούν κατά την είσοδο στη διαδικασία. Αυτές οι πληροφορίες ονομάζονται πληροφορίες πλαισίου κλήσεων - πληροφορίες σχετικά με τη μορφή πλαισίου. Για κάθε διεύθυνση στο πρόγραμμα (που περιέχει κωδικό), υποδεικνύονται η διεύθυνση πλαισίου στη μνήμη (Canonical Frame Address - CFA) και πληροφορίες σχετικά με τους καταχωρητές επεξεργαστή, για παράδειγμα, μπορείτε να υποδείξετε ότι:
  • υπόθεση δεν σώζεται στη διαδικασία
  • το μητρώο δεν αλλάζει την τιμή του στη διαδικασία
  • ο καταχωρητής αποθηκεύεται στη στοίβα στη διεύθυνση CFA+n
  • Ο καταχωρητής αποθηκεύεται σε άλλο μητρώο
  • ο καταχωρητής αποθηκεύεται στη μνήμη σε κάποια διεύθυνση, η οποία μπορεί να υπολογιστεί με μάλλον μη προφανή τρόπο
  • και τα λοιπά.
Δεδομένου ότι οι πληροφορίες πρέπει να προσδιορίζονται για κάθε διεύθυνση στον κώδικα, είναι πολύ ογκώδεις και αποθηκεύονται σε συμπιεσμένη μορφή στην ενότητα .debug_frame. Δεδομένου ότι αλλάζει ελάχιστα από διεύθυνση σε διεύθυνση, μόνο οι αλλαγές του κωδικοποιούνται με τη μορφή οδηγιών DW_CFA_xxxx. Κάθε οδηγία υποδεικνύει μία αλλαγή, για παράδειγμα:
  • DW_CFA_set_loc - δείχνει την τρέχουσα διεύθυνση στο πρόγραμμα
  • DW_CFA_advance_loc - προωθεί τον δείκτη κατά έναν ορισμένο αριθμό byte
  • DW_CFA_def_cfa - υποδεικνύει τη διεύθυνση του πλαισίου στοίβας (αριθμητική σταθερά)
  • DW_CFA_def_cfa_register - υποδεικνύει τη διεύθυνση του πλαισίου στοίβας (λαμβάνεται από τον καταχωρητή επεξεργαστή)
  • DW_CFA_def_cfa_expression - καθορίζει τον τρόπο υπολογισμού της διεύθυνσης πλαισίου στοίβας
  • DW_CFA_same_value - υποδηλώνει ότι ο καταχωρητής δεν έχει αλλάξει
  • DW_CFA_register - υποδηλώστε ότι ο καταχωρητής είναι αποθηκευμένος σε άλλο μητρώο
  • και τα λοιπά.
Τα στοιχεία της ενότητας .debug_frame είναι εγγραφές που μπορεί να είναι δύο τύπων: Κοινή καταχώριση πληροφοριών (CIE) και καταχώριση περιγραφής πλαισίου (FDE). Το CIE περιέχει πληροφορίες που είναι κοινές σε πολλές εγγραφές FDE, σε γενικές γραμμές, περιγράφει έναν συγκεκριμένο τύπο διαδικασίας. Οι FDE περιγράφουν κάθε συγκεκριμένη διαδικασία. Κατά την εισαγωγή μιας διαδικασίας, το πρόγραμμα εντοπισμού σφαλμάτων εκτελεί πρώτα οδηγίες από το CIE και μετά από το FDE.
Ο μεταγλωττιστής μου δημιουργεί διαδικασίες όπου το CFA βρίσκεται στον καταχωρητή sp (r13). Ας δημιουργήσουμε ένα CIE για όλες τις διαδικασίες. Υπάρχει μια συνάρτηση για αυτό, dwarf_add_frame_cie:
Dwarf_Unsigned dwarf_add_frame_cie(Dwarf_P_Debug dbg, char *augmenter, Dwarf_Small code_align, Dwarf_Small data_align, Dwarf_Small ret_addr_reg, Dwarf_Ptr init_Urror_bytes, Dwarf_Ptr init_Urror_bytes, Dwarf_Ptr init_Urrorfigne_Dwarf_Bytes, Dwarf_Small;
  • Το augmenter είναι μια κωδικοποιημένη συμβολοσειρά UTF-8, η παρουσία της οποίας δείχνει ότι υπάρχουν πρόσθετες πληροφορίες που εξαρτώνται από την πλατφόρμα για το CIE ή το FDE. Βάλτε μια κενή γραμμή
  • code_align - στοίχιση κώδικα σε byte (έχουμε 2)
  • data_align - στοίχιση δεδομένων στο πλαίσιο (σύνολο -4, που σημαίνει ότι όλες οι παράμετροι παίρνουν 4 byte στη στοίβα και μεγαλώνουν στη μνήμη)
  • ret_addr_reg - ένας καταχωρητής που περιέχει τη διεύθυνση επιστροφής από τη διαδικασία (έχουμε 14)
  • init_bytes - ένας πίνακας που περιέχει οδηγίες DW_CFA_xxxx. Δυστυχώς, δεν υπάρχει βολικός τρόπος δημιουργίας αυτού του πίνακα. Μπορείτε να το δημιουργήσετε με μη αυτόματο τρόπο ή να το δείτε στο αρχείο elf που δημιουργήθηκε από τον μεταγλωττιστή C, κάτι που έκανα. Για την περίπτωσή μου περιέχει 3 byte: 0x0C, 0x0D, 0, που σημαίνει DW_CFA_def_cfa: r13 από 0 (το CFA είναι στον καταχωρητή r13, η μετατόπιση είναι 0)
  • init_bytes_len - μήκος του πίνακα init_bytes
Η συνάρτηση επιστρέφει DW_DLV_NOCOUNT σε σφάλμα ή μια λαβή CIE που θα πρέπει να χρησιμοποιείται κατά τη δημιουργία μιας FDE για κάθε διαδικασία, την οποία θα εξετάσουμε αργότερα στην ενότητα "Δημιουργία διαδικασίας FDE"
Δημιουργία τύπων δεδομένων
Για να μπορέσετε να δημιουργήσετε διαδικασίες και μεταβλητές, πρέπει πρώτα να δημιουργήσετε κόμβους που αντιστοιχούν στους τύπους δεδομένων. Υπάρχουν πολλοί τύποι δεδομένων, αλλά βασίζονται όλοι σε βασικούς τύπους (στοιχειώδεις τύπους όπως int, double, κ.λπ.), άλλοι τύποι δημιουργούνται από βασικούς.
Ο βασικός τύπος είναι ο κόμβος με την ετικέτα DW_TAG_base_type. Πρέπει να έχει τα ακόλουθα χαρακτηριστικά:
  • "όνομα" (DW_AT_name)
  • "encoding" (DW_AT_encoding) - σημαίνει τι είδους δεδομένα περιγράφουν αυτόν τον βασικό τύπο (για παράδειγμα, DW_ATE_boolean - λογικό, DW_ATE_float - κινητή υποδιαστολή, DW_ATE_signed - υπογεγραμμένος ακέραιος, DW_ATE_unsigned - unsigned ακέραιος κ.λπ.)
  • "μέγεθος" (DW_AT_byte_size - μέγεθος σε byte ή DW_AT_bit_size - μέγεθος σε bit)
Ένας κόμβος μπορεί επίσης να περιέχει άλλα προαιρετικά χαρακτηριστικά.
Για παράδειγμα, για να δημιουργήσουμε έναν υπογεγραμμένο ακέραιο τύπο βάσης 32 bit "int", θα χρειαστεί να δημιουργήσουμε έναν κόμβο με την ετικέτα DW_TAG_base_type και να ορίσουμε τα χαρακτηριστικά του DW_AT_name - "int", DW_AT_encoding - DW_ATE_signed, DW_AT_byte_size - 4.
Μόλις δημιουργηθούν οι βασικοί τύποι, μπορείτε να αντλήσετε παράγωγα από αυτούς. Τέτοιοι κόμβοι πρέπει να περιέχουν το χαρακτηριστικό DW_AT_type - μια αναφορά στον βασικό τύπο τους. Για παράδειγμα, ένας δείκτης προς int - ένας κόμβος με την ετικέτα DW_TAG_pointer_type πρέπει να περιέχει στο χαρακτηριστικό DW_AT_type έναν σύνδεσμο προς τον τύπο "int" που δημιουργήθηκε προηγουμένως.
Ένα χαρακτηριστικό με αναφορά σε άλλο κόμβο δημιουργείται από τη συνάρτηση dwarf_add_AT_reference:
Dwarf_P_Attribute dwarf_add_AT_reference(Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_P_Die otherdie, Dwarf_Error *error)
  • attr - χαρακτηριστικό, σε αυτήν την περίπτωση DW_AT_type
  • otherdie - μια λαβή στον κόμβο του τύπου που αναφέρεται
Δημιουργία Διαδικασιών
Για να δημιουργήσω διαδικασίες, πρέπει να εξηγήσω έναν ακόμη τύπο πληροφοριών εντοπισμού σφαλμάτων - Πληροφορίες αριθμού γραμμής. Χρησιμεύει για την αντιστοίχιση κάθε εντολής μηχανής σε μια συγκεκριμένη γραμμή πηγαίου κώδικα και επίσης για να επιτρέπει τον εντοπισμό σφαλμάτων γραμμή προς γραμμή του προγράμματος. Αυτές οι πληροφορίες αποθηκεύονται στην ενότητα .debug_line. Εάν είχαμε αρκετό χώρο, θα αποθηκευόταν ως μήτρα, μια γραμμή για κάθε εντολή με στήλες όπως αυτή:
  • όνομα αρχείου πηγής
  • αριθμός γραμμής σε αυτό το αρχείο
  • αριθμός στήλης στο αρχείο
  • εάν η εντολή είναι η αρχή μιας δήλωσης ή ένα μπλοκ εντολών
  • και τα λοιπά.
Ένας τέτοιος πίνακας θα ήταν πολύ μεγάλος, επομένως πρέπει να συμπιεστεί. Πρώτον, οι διπλές γραμμές διαγράφονται και, δεύτερον, δεν αποθηκεύονται οι ίδιες οι γραμμές, αλλά μόνο οι αλλαγές σε αυτές. Αυτές οι αλλαγές μοιάζουν με εντολές για μια μηχανή πεπερασμένης κατάστασης και οι ίδιες οι πληροφορίες θεωρούνται ήδη ένα πρόγραμμα που θα «εκτελεσθεί» από αυτό το μηχάνημα. Οι εντολές αυτού του προγράμματος μοιάζουν, για παράδειγμα, ως εξής: DW_LNS_advance_pc - προωθήστε τον μετρητή προγράμματος σε μια συγκεκριμένη διεύθυνση, DW_LNS_set_file - ορίστε το αρχείο στο οποίο ορίζεται η διαδικασία, DW_LNS_const_add_pc - προωθήστε τον μετρητή προγράμματος κατά πολλά byte, κ.λπ.
Η δημιουργία αυτών των πληροφοριών σε τόσο χαμηλό επίπεδο είναι δύσκολη, επομένως το libdwarf παρέχει αρκετές λειτουργίες για να διευκολύνει αυτήν την εργασία.
Είναι ακριβό να αποθηκεύσετε το όνομα αρχείου για κάθε εντολή, επομένως αντί για το όνομα, το ευρετήριό του αποθηκεύεται σε έναν ειδικό πίνακα. Για να δημιουργήσετε ένα ευρετήριο αρχείου, πρέπει να χρησιμοποιήσετε τη συνάρτηση dwarf_add_file_decl:
Dwarf_Unsigned dwarf_add_file_decl(Dwarf_P_Debug dbg, char *name, Dwarf_Unsigned dir_idx, Dwarf_Unsigned time_mod, Dwarf_Unsigned μήκος, Dwarf_Error *error)
  • όνομα - όνομα αρχείου
  • dir_idx - ευρετήριο του φακέλου στον οποίο βρίσκεται το αρχείο. Το ευρετήριο μπορεί να ληφθεί χρησιμοποιώντας τη συνάρτηση dwarf_add_directory_decl. Εάν χρησιμοποιούνται πλήρεις διαδρομές, μπορείτε να ορίσετε το 0 ως ευρετήριο φακέλου και να μην χρησιμοποιήσετε καθόλου το dwarf_add_directory_decl
  • time_mod - χρόνος τροποποίησης αρχείου, ενδέχεται να μην έχει καθοριστεί (0)
  • μήκος - μέγεθος αρχείου, επίσης προαιρετικό (0)
Η συνάρτηση θα επιστρέψει το ευρετήριο αρχείου ή DW_DLV_NOCOUNT σε σφάλμα.
Για να δημιουργήσετε πληροφορίες σχετικά με τους αριθμούς γραμμών, υπάρχουν τρεις συναρτήσεις dwarf_add_line_entry_b, dwarf_lne_set_address, dwarf_lne_end_sequence, τις οποίες θα εξετάσουμε παρακάτω.
Η δημιουργία πληροφοριών εντοπισμού σφαλμάτων για μια διαδικασία πραγματοποιείται σε διάφορα στάδια:
  • δημιουργώντας ένα σύμβολο διαδικασίας στην ενότητα .symtab
  • δημιουργία ενός κόμβου διαδικασίας με χαρακτηριστικά
  • δημιουργία μιας διαδικασίας FDE
  • δημιουργία παραμέτρων διαδικασίας
  • δημιουργία πληροφοριών αριθμού γραμμής
Δημιουργία συμβόλου διαδικασίας
Το σύμβολο της διαδικασίας δημιουργείται όπως περιγράφεται παραπάνω στην ενότητα Section.symtab. Σε αυτό, σύμβολα διαδικασιών παρεμβάλλονται με σύμβολα αρχείων στα οποία βρίσκεται ο πηγαίος κώδικας αυτών των διαδικασιών. Πρώτα δημιουργούμε ένα σύμβολο αρχείου και μετά μια διαδικασία. Αυτό καθιστά το αρχείο τρέχον και εάν η επόμενη διαδικασία είναι στο τρέχον αρχείο, το σύμβολο αρχείου δεν χρειάζεται να δημιουργηθεί ξανά.
Δημιουργία κόμβου διαδικασίας με χαρακτηριστικά
Αρχικά, δημιουργούμε έναν κόμβο χρησιμοποιώντας τη συνάρτηση dwarf_new_die (δείτε την ενότητα «Δημιουργία κόμβων»), προσδιορίζοντας το DW_TAG_υποπρόγραμμα ως ετικέτα και τη Μονάδα Σύνταξης (αν πρόκειται για καθολική διαδικασία) ή το αντίστοιχο DIE (αν είναι τοπικό) ως γονικό. Στη συνέχεια δημιουργούμε τα χαρακτηριστικά:
  • όνομα διαδικασίας (συνάρτηση dwarf_add_AT_name, βλέπε «Δημιουργία χαρακτηριστικών κόμβου»)
  • αριθμός γραμμής στο αρχείο όπου ξεκινά ο κώδικας διαδικασίας (χαρακτηριστικό DW_AT_decl_line), συνάρτηση dwarf_add_AT_unsigned_const (δείτε «Δημιουργία χαρακτηριστικών κόμβου»)
  • διεύθυνση έναρξης της διαδικασίας (χαρακτηριστικό DW_AT_low_pc), συνάρτηση dwarf_add_AT_targ_address, βλέπε παρακάτω
  • τελική διεύθυνση της διαδικασίας (χαρακτηριστικό DW_AT_high_pc), συνάρτηση dwarf_add_AT_targ_address, βλέπε παρακάτω
  • τον τύπο του αποτελέσματος που επιστρέφεται από τη διαδικασία (το χαρακτηριστικό DW_AT_type είναι ένας σύνδεσμος προς έναν τύπο που δημιουργήθηκε προηγουμένως, βλ. «Δημιουργία τύπων δεδομένων»). Εάν η διαδικασία δεν επιστρέφει τίποτα, αυτό το χαρακτηριστικό δεν χρειάζεται να δημιουργηθεί
Τα χαρακτηριστικά DW_AT_low_pc και DW_AT_high_pc πρέπει να δημιουργηθούν χρησιμοποιώντας τη συνάρτηση dwarf_add_AT_targ_address_b που έχει σχεδιαστεί ειδικά για αυτόν τον σκοπό:
Dwarf_P_Attribute dwarf_add_AT_targ_address_b(Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, *error_Error)
  • attr - χαρακτηριστικό (DW_AT_low_pc ή DW_AT_high_pc)
  • pc_value - τιμή διεύθυνσης
  • sym_index - ευρετήριο του συμβόλου της διαδικασίας στον πίνακα.symtab. Προαιρετικά, μπορεί να περάσει το 0
Η συνάρτηση θα επιστρέψει DW_DLV_BADADDR σε σφάλμα.
Δημιουργία διαδικασίας FDE
Όπως συζητήθηκε παραπάνω στην ενότητα «Δημιουργία κοινής καταχώρισης πληροφοριών», για κάθε διαδικασία πρέπει να δημιουργήσετε έναν περιγραφέα πλαισίου, το οποίο συμβαίνει σε διάφορα στάδια:
  • δημιουργία ενός νέου FDE (δείτε Δημιουργία κοινής καταχώρισης πληροφοριών)
  • την ένταξη του δημιουργημένου FDE στη γενική λίστα
  • προσθέτοντας οδηγίες στο δημιουργημένο FDE
Μπορείτε να δημιουργήσετε ένα νέο FDE χρησιμοποιώντας τη συνάρτηση dwarf_new_fde:
Dwarf_P_Fde dwarf_new_fde(Dwarf_P_Debug dbg, Dwarf_Error *error)
Η συνάρτηση θα επιστρέψει μια λαβή στο νέο FDE ή στο DW_DLV_BADADDR σε περίπτωση σφάλματος.
Μπορείτε να επισυνάψετε ένα νέο FDE στη λίστα χρησιμοποιώντας το dwarf_add_frame_fde:
Dwarf_Unsigned dwarf_add_frame_fde(Dwarf_P_Debug dbg, Dwarf_P_Fde fde, Dwarf_P_Die die, Dwarf_Unsigned cie, Dwarf_Addr virt_addr, Dwarf_Unsigned code_warm_Error*
  • fde - η λαβή που μόλις ελήφθη
  • die - Διαδικασίες DIE (δείτε Δημιουργία κόμβου διαδικασίας με χαρακτηριστικά)
  • cie - Περιγραφέας CIE (δείτε Δημιουργία κοινής καταχώρισης πληροφοριών)
  • virt_addr - η αρχική διεύθυνση της διαδικασίας μας
  • code_len - μήκος διαδικασίας σε byte
Η συνάρτηση θα επιστρέψει DW_DLV_NOCOUNT σε σφάλμα.
Μετά από όλα αυτά, μπορείτε να προσθέσετε οδηγίες DW_CFA_xxxx στο FDE μας. Αυτό γίνεται από τις συναρτήσεις dwarf_add_fde_inst και dwarf_fde_cfa_offset. Ο πρώτος προσθέτει τη δεδομένη οδηγία στη λίστα:
Dwarf_P_Fde dwarf_add_fde_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *error)
  • op - κωδικός εντολής (DW_CFA_хххх)
  • val1, val2 - παράμετροι εντολών (διαφορετικές για κάθε εντολή, βλέπε Πρότυπο, ενότητα 6.4.2 Οδηγίες πλαισίου κλήσης)
Η συνάρτηση dwarf_fde_cfa_offset προσθέτει την εντολή DW_CFA_offset:
Dwarf_P_Fde dwarf_fde_cfa_offset(Dwarf_P_Fde fde, Dwarf_Unsigned reg, Dwarf_Signed offset, Dwarf_Error *error)
  • fde - λαβή στο δημιουργημένο FDE
  • reg - μητρώο που είναι γραμμένο στο πλαίσιο
  • offset - η μετατόπισή του στο πλαίσιο (όχι σε byte, αλλά σε στοιχεία πλαισίου, βλ. Δημιουργία κοινής καταχώρισης πληροφοριών, data_align)
Για παράδειγμα, ο μεταγλωττιστής δημιουργεί μια διαδικασία της οποίας ο πρόλογος αποθηκεύει τον καταχωρητή lr (r14) στο πλαίσιο στοίβας. Το πρώτο βήμα είναι να προσθέσετε την εντολή DW_CFA_advance_loc με την πρώτη παράμετρο ίση με 1, που σημαίνει προώθηση του καταχωρητή υπολογιστή κατά 2 byte (δείτε Δημιουργία κοινής καταχώρησης πληροφοριών, code_align), και στη συνέχεια προσθέστε DW_CFA_def_cfa_offset με την παράμετρο 4 (ρυθμίζοντας τη μετατόπιση δεδομένων στο καρέ κατά 4 byte) και καλέστε τη συνάρτηση dwarf_fde_cfa_offset με την παράμετρο reg=14 offset=1, που σημαίνει εγγραφή του καταχωρητή r14 στο πλαίσιο με μετατόπιση -4 byte από το CFA.
Δημιουργία παραμέτρων διαδικασίας
Η δημιουργία παραμέτρων διαδικασίας είναι παρόμοια με τη δημιουργία συνηθισμένων μεταβλητών, βλέπε «Δημιουργία μεταβλητών και σταθερών»
Δημιουργία πληροφοριών σχετικά με αριθμούς γραμμών
Αυτές οι πληροφορίες δημιουργούνται ως εξής:
  • στην αρχή της διαδικασίας, ξεκινάμε ένα μπλοκ εντολών με τη συνάρτηση dwarf_lne_set_address
  • για κάθε γραμμή κώδικα (ή εντολή μηχανής) δημιουργούμε πληροφορίες σχετικά με τον πηγαίο κώδικα (dwarf_add_line_entry)
  • στο τέλος της διαδικασίας συμπληρώνουμε το μπλοκ εντολών με τη συνάρτηση dwarf_lne_end_sequence
Η συνάρτηση dwarf_lne_set_address ορίζει τη διεύθυνση στην οποία ξεκινά ένα μπλοκ εντολών:
Dwarf_Unsigned dwarf_lne_set_address(Dwarf_P_Debug dbg, Dwarf_Addr offs, Dwarf_Unsigned symidx, Dwarf_Error *error)
  • offs - διεύθυνση διαδικασίας (διεύθυνση της πρώτης εντολής μηχανήματος)
  • sym_idx - ευρετήριο συμβόλων (προαιρετικό, μπορείτε να καθορίσετε 0)

Η συνάρτηση dwarf_add_line_entry_b προσθέτει πληροφορίες σχετικά με τις γραμμές πηγαίου κώδικα στην ενότητα .debug_line. Καλώ αυτή τη λειτουργία για κάθε εντολή μηχανής:
Dwarf_Unsigned dwarf_add_line_entry_b(Dwarf_P_Debug dbg, Dwarf_Unsigned file_index, Dwarf_Addr code_offset, Dwarf_Unsigned lineno, Dwarf_Signed column_number, Dwarf_Bool is_be_gin_warb, Dwarf_Bool is_be_gin_war Bool is_epilogue _begin, Dwarf_Bool is_prologue_end, Dwarf_Unsigned isa, Dwarf_Unsigned discriminator, Dwarf_Error *error)
  • file_index - ευρετήριο του αρχείου πηγαίου κώδικα που ελήφθη νωρίτερα από τη συνάρτηση dwarf_add_file_decl (δείτε «Δημιουργία διαδικασιών»)
  • code_offset - διεύθυνση της τρέχουσας εντολής μηχανής
  • lineno - αριθμός γραμμής στο αρχείο πηγαίου κώδικα
  • στήλη_αριθμός - αριθμός στήλης στο αρχείο πηγαίου κώδικα
  • is_source_stmt_begin - 1 εάν η τρέχουσα εντολή είναι η πρώτη στον κώδικα στη γραμμή lineno (χρησιμοποιώ πάντα 1)
  • is_basic_block_begin - 1 εάν η τρέχουσα εντολή είναι η πρώτη στο μπλοκ εντολών (χρησιμοποιώ πάντα 0)
  • is_epilogue_begin - 1 εάν η τρέχουσα οδηγία είναι η πρώτη στον επίλογο της διαδικασίας (δεν είναι απαραίτητο, έχω πάντα 0)
  • is_prologue_end - 1 εάν η τρέχουσα εντολή είναι η τελευταία στον πρόλογο της διαδικασίας (απαιτείται!)
  • isa - αρχιτεκτονική συνόλου εντολών. Βεβαιωθείτε ότι έχετε καθορίσει το DW_ISA_ARM_thumb για το ARM Cortex M3!
  • διευκρινιστής. Μία θέση (αρχείο, γραμμή, στήλη) του πηγαίου κώδικα μπορεί να αντιστοιχεί σε διαφορετικές οδηγίες μηχανής. Σε αυτήν την περίπτωση, πρέπει να εγκατασταθούν διαφορετικοί διαχωριστές για σετ τέτοιων οδηγιών. Εάν δεν υπάρχουν τέτοιες περιπτώσεις, θα πρέπει να είναι 0
Η συνάρτηση επιστρέφει 0 (επιτυχία) ή DW_DLV_NOCOUNT (σφάλμα).
Τέλος, η συνάρτηση dwarf_lne_end_sequence ολοκληρώνει τη διαδικασία:
Dwarf_Unsigned dwarf_lne_end_sequence(Dwarf_P_Debug dbg, Dwarf_Addr address; Dwarf_Error *error)
  • διεύθυνση - διεύθυνση της τρέχουσας εντολής μηχανής
Επιστρέφει 0 (επιτυχία) ή DW_DLV_NOCOUNT (σφάλμα).
Αυτό ολοκληρώνει τη δημιουργία της διαδικασίας.
Δημιουργία μεταβλητών και σταθερών
Γενικά, οι μεταβλητές είναι αρκετά απλές. Έχουν ένα όνομα, μια θέση μνήμης (ή καταχωρητή επεξεργαστή) όπου βρίσκονται τα δεδομένα τους και τον τύπο αυτών των δεδομένων. Εάν η μεταβλητή είναι καθολική, η γονική της μονάδα πρέπει να είναι η Μονάδα μεταγλώττισης, εάν είναι τοπική, ο αντίστοιχος κόμβος (αυτό ισχύει ιδιαίτερα για τις παραμέτρους της διαδικασίας, ο γονέας τους πρέπει να είναι η ίδια η διαδικασία). Μπορείτε επίσης να καθορίσετε σε ποιο αρχείο, γραμμή και στήλη βρίσκεται η δήλωση μεταβλητής.
Στην απλούστερη περίπτωση, η τιμή μιας μεταβλητής βρίσκεται σε κάποια σταθερή διεύθυνση, αλλά πολλές μεταβλητές δημιουργούνται δυναμικά κατά την εισαγωγή μιας διαδικασίας στη στοίβα ή τον καταχωρητή, μερικές φορές ο υπολογισμός της διεύθυνσης της τιμής μπορεί να είναι αρκετά μη τετριμμένος. Το πρότυπο παρέχει έναν μηχανισμό για την περιγραφή του πού βρίσκεται η τιμή μιας μεταβλητής - παραστάσεις τοποθεσίας. Μια έκφραση διεύθυνσης είναι ένα σύνολο εντολών (σταθερές DW_OP_xxxx) για μια μηχανή στοίβας τύπου Fort, στην πραγματικότητα είναι μια ξεχωριστή γλώσσα με κλάδους, διαδικασίες και αριθμητικές πράξεις. Δεν θα εξετάσουμε αυτή τη γλώσσα στο σύνολό της, θα μας ενδιαφέρουν μόνο μερικές οδηγίες:
  • DW_OP_addr - υποδεικνύει τη διεύθυνση της μεταβλητής
  • DW_OP_fbreg - υποδεικνύει τη μετατόπιση της μεταβλητής από τον βασικό καταχωρητή (συνήθως τον δείκτη στοίβας)
  • DW_OP_reg0… DW_OP_reg31 - υποδηλώνει ότι η μεταβλητή είναι αποθηκευμένη στον αντίστοιχο καταχωρητή
Για να δημιουργήσετε μια έκφραση διεύθυνσης, πρέπει πρώτα να δημιουργήσετε μια κενή έκφραση (dwarf_new_expr), να προσθέσετε οδηγίες σε αυτήν (dwarf_add_expr_addr, dwarf_add_expr_gen, κ.λπ.) και να την προσθέσετε στον κόμβο ως τιμή του χαρακτηριστικού DW_AT_location (dwarf_add_AT_location_expression).
Η συνάρτηση για τη δημιουργία μιας έκφρασης κενής διεύθυνσης επιστρέφει τη λαβή της ή το 0 στο σφάλμα:
Dwarf_Expr dwarf_new_expr(Dwarf_P_Debug dbg, Dwarf_Error *error)
Για να προσθέσετε οδηγίες σε μια έκφραση, πρέπει να χρησιμοποιήσετε τη συνάρτηση dwarf_add_expr_gen:
Dwarf_Unsigned dwarf_add_expr_gen(Dwarf_P_Expr expr, Dwarf_Small opcode, Dwarf_Unsigned val1, Dwarf_Unsigned val2, Dwarf_Error *error)
  • opcode - κωδικός λειτουργίας, σταθερός DW_OP_хххх
  • val1, val2 - παράμετροι εντολών (βλ. Πρότυπο)

Για να ορίσετε ρητά τη διεύθυνση μιας μεταβλητής, πρέπει να χρησιμοποιηθεί η συνάρτηση dwarf_add_expr_addr αντί της προηγούμενης:
Dwarf_Unsigned dwarf_add_expr_addr(Dwarf_P_Expr expr, Dwarf_Unsigned address, Dwarf_Signed sym_index, Dwarf_Error *error)
  • Το expr είναι μια λαβή στην έκφραση διεύθυνσης στην οποία προστίθεται η εντολή
  • διεύθυνση - μεταβλητή διεύθυνση
  • sym_index - ευρετήριο του συμβόλου στον πίνακα.symtab. Προαιρετικά, μπορεί να περάσει το 0
Η συνάρτηση επιστρέφει επίσης DW_DLV_NOCOUNT σε σφάλμα.
Τέλος, μπορείτε να προσθέσετε την έκφραση διεύθυνσης που δημιουργήθηκε στον κόμβο χρησιμοποιώντας τη συνάρτηση dwarf_add_AT_location_expr:
Dwarf_P_Attribute dwarf_add_AT_location_expr(Dwarf_P_Debug dbg, Dwarf_P_Die ownerdie, Dwarf_Half attr, Dwarf_P_Expr loc_expr, Dwarf_Error *error)
  • ιδιοκτήτης - ο κόμβος στον οποίο προστίθεται η έκφραση
  • attr - χαρακτηριστικό (στην περίπτωσή μας DW_AT_location)
  • loc_expr - χειρισμός σε μια έκφραση διεύθυνσης που δημιουργήθηκε προηγουμένως
Η συνάρτηση επιστρέφει τη λαβή χαρακτηριστικού ή DW_DLV_NOCOUNT σε σφάλμα.
Οι μεταβλητές (καθώς και οι παράμετροι διαδικασίας) και οι σταθερές είναι συνηθισμένοι κόμβοι με την ετικέτα DW_TAG_variable, DW_TAG_formal_parameter και DW_TAG_const_type, αντίστοιχα. Απαιτούν τα ακόλουθα χαρακτηριστικά:
  • όνομα μεταβλητής/σταθερής (συνάρτηση dwarf_add_AT_name, βλέπε «Δημιουργία χαρακτηριστικών κόμβου»)
  • αριθμός γραμμής στο αρχείο όπου δηλώνεται η μεταβλητή (χαρακτηριστικό DW_AT_decl_line), συνάρτηση dwarf_add_AT_unsigned_const (δείτε «Δημιουργία χαρακτηριστικών κόμβου»)
  • ευρετήριο ονόματος αρχείου (ιδιότητα DW_AT_decl_file), συνάρτηση dwarf_add_AT_unsigned_const (δείτε «Δημιουργία χαρακτηριστικών κόμβου»)
  • μεταβλητός/σταθερός τύπος δεδομένων (το χαρακτηριστικό DW_AT_type είναι ένας σύνδεσμος προς έναν τύπο που δημιουργήθηκε προηγουμένως, ανατρέξτε στην ενότητα "Δημιουργία τύπων δεδομένων")
  • έκφραση διεύθυνσης (βλ. παραπάνω) - απαιτείται για μια παράμετρο μεταβλητής ή διαδικασίας
  • ή τιμή - για μια σταθερά (χαρακτηριστικό DW_AT_const_value, βλέπε «Δημιουργία χαρακτηριστικών κόμβου»)
Δημιουργία ενοτήτων με πληροφορίες εντοπισμού σφαλμάτων
Αφού δημιουργήσετε όλους τους κόμβους του δέντρου πληροφοριών εντοπισμού σφαλμάτων, μπορείτε να αρχίσετε να δημιουργείτε τμήματα ξωτικών με αυτό. Αυτό συμβαίνει σε δύο στάδια:
  • πρώτα πρέπει να καλέσουμε τη συνάρτηση dwarf_transform_to_disk_form, η οποία θα καλέσει τη συνάρτηση που γράψαμε για να δημιουργήσουμε τα απαραίτητα τμήματα ξωτικού μία φορά για κάθε ενότητα
  • για κάθε ενότητα, η συνάρτηση dwarf_get_section_bytes θα μας επιστρέψει δεδομένα που θα πρέπει να γραφτούν στην αντίστοιχη ενότητα
Λειτουργία
dwarf_transform_to_disk_form (Dwarf_P_Debug dbg, Dwarf_Error* error)
μετατρέπει τις πληροφορίες εντοπισμού σφαλμάτων που δημιουργήσαμε σε δυαδική μορφή, αλλά δεν γράφει τίποτα στο δίσκο. Θα επιστρέψει τον αριθμό των τμημάτων ξωτικών που δημιουργήθηκαν ή DW_DLV_NOCOUNT σε περίπτωση σφάλματος. Σε αυτήν την περίπτωση, για κάθε ενότητα θα καλείται η συνάρτηση επανάκλησης, την οποία περάσαμε στη συνάρτηση dwarf_producer_init_c κατά την προετοιμασία της βιβλιοθήκης. Πρέπει να γράψουμε αυτή τη συνάρτηση μόνοι μας. Οι προδιαγραφές του είναι οι εξής:
typedef int (*Dwarf_Callback_Func_c)(char* όνομα, μέγεθος int, Dwarf_Unsigned type, Dwarf_Unsigned flags, Dwarf_Unsigned link, Dwarf_Unsigned info, Dwarf_Unsigned* sect_name_index, void * error_user_detata),
  • όνομα - το όνομα του τμήματος των ξωτικών που θα δημιουργηθεί
  • μέγεθος - μέγεθος τμήματος
  • τύπος - τύπος τμήματος
  • σημαίες - σημαίες τμήματος
  • σύνδεσμος - πεδίο συνδέσμου ενότητας
  • πληροφορίες - πεδίο πληροφοριών ενότητας
  • sect_name_index - πρέπει να επιστρέψετε το ευρετήριο της ενότητας με μετεγκαταστάσεις (προαιρετικό)
  • user_data - μας μεταβιβάζεται με τον ίδιο τρόπο που τα ορίσαμε στη συνάρτηση προετοιμασίας βιβλιοθήκης
  • σφάλμα - εδώ μπορείτε να στείλετε τον κωδικό σφάλματος
Σε αυτή τη λειτουργία πρέπει:
  • δημιουργήστε μια νέα ενότητα (συνάρτηση elf_newscn, δείτε Δημιουργία Ενοτήτων)
  • δημιουργήστε μια κεφαλίδα ενότητας (συνάρτηση elf32_getshdr, ό.π.)
  • συμπληρώστε το σωστά (βλ. ό.π.). Αυτό είναι εύκολο γιατί τα πεδία κεφαλίδας ενότητας αντιστοιχούν στις παραμέτρους της συνάρτησής μας. Ορίστε τα πεδία που λείπουν sh_addr, sh_offset, sh_entsize σε 0 και sh_addralign σε 1
  • επιστρέψτε το ευρετήριο της ενότητας που δημιουργήθηκε (συνάρτηση elf_ndxscn, βλ. «Section.symtab») ή -1 στο σφάλμα (ρυθμίζοντας τον κωδικό σφάλματος σε σφάλμα)
  • Επίσης θα πρέπει να παραλείψουμε την ενότητα ".rel" (στην περίπτωσή μας), επιστρέφοντας 0 όταν επιστρέφουμε από τη συνάρτηση
Μόλις ολοκληρωθεί, η συνάρτηση dwarf_transform_to_disk_form θα επιστρέψει τον αριθμό των τμημάτων που δημιουργήθηκαν. Θα χρειαστεί να περάσουμε από κάθε ενότητα σε βρόχο από το 0, ακολουθώντας αυτά τα βήματα:
  • δημιουργήστε δεδομένα που θα εγγραφούν σε μια ενότητα χρησιμοποιώντας τη συνάρτηση dwarf_get_section_bytes:
    Dwarf_Ptr dwarf_get_section_bytes(Dwarf_P_Debug dbg, Dwarf_Signed dwarf_section, Dwarf_Signed *elf_section_index, Dwarf_Unsigned *length, Dwarf_Error* σφάλμα)
    • dwarf_section - αριθμός τμήματος. Πρέπει να βρίσκεται στην περιοχή 0..n, όπου n είναι ο αριθμός που μας επιστρέφει η συνάρτηση dwarf_transform_to_disk_form
    • elf_section_index - επιστρέφει το ευρετήριο της ενότητας στην οποία πρέπει να εγγραφούν τα δεδομένα
    • μήκος - το μήκος αυτών των δεδομένων
    • σφάλμα - δεν χρησιμοποιείται
    Η συνάρτηση επιστρέφει έναν δείκτη στα λαμβανόμενα δεδομένα ή 0 (στην περίπτωση
    όταν δεν απομένουν άλλες ενότητες για δημιουργία)
  • δημιουργήστε έναν περιγραφέα δεδομένων για την τρέχουσα ενότητα (συνάρτηση elf_newdata, βλ. Δημιουργία ενοτήτων) και συμπληρώστε τον (δείτε εκεί) ορίζοντας:
    • d_buf - ένας δείκτης στα δεδομένα που λάβαμε από την προηγούμενη συνάρτηση
    • d_size - το μέγεθος αυτών των δεδομένων (ibid.)
Ολοκλήρωση εργασιών με τη βιβλιοθήκη
Αφού σχηματιστούν οι ενότητες, μπορείτε να ολοκληρώσετε την εργασία με το libdwarf χρησιμοποιώντας τη συνάρτηση dwarf_producer_finish:
Dwarf_Unsigned dwarf_producer_finish(Dwarf_P_Debug dbg, Dwarf_Error* error)
Η συνάρτηση επιστρέφει DW_DLV_NOCOUNT σε σφάλμα.
Λάβετε υπόψη ότι η εγγραφή σε δίσκο δεν πραγματοποιείται σε αυτό το στάδιο. Η εγγραφή πρέπει να γίνει χρησιμοποιώντας τις λειτουργίες από την ενότητα "Δημιουργία ELF - Γράψιμο αρχείου".

συμπέρασμα

Αυτό είναι όλο.
Επαναλαμβάνω, η δημιουργία πληροφοριών εντοπισμού σφαλμάτων είναι ένα πολύ ευρύ θέμα, και δεν έθιξα πολλά θέματα, άροντας μόνο το πέπλο. Όσοι επιθυμούν μπορούν να εμβαθύνουν επ' αόριστον.
Αν έχετε ερωτήσεις, θα προσπαθήσω να τις απαντήσω.

Κλείσε