Breakpoints, ενέργειες, και watches#
Αυτό το κεφάλαιο καλύπτει τη διακοπή του αποσφαλματωτή σε συγκεκριμένο σημείο - μια γραμμή, μια υπορουτίνα, μια συνθήκη, μια αλλαγή τιμής - και τη μηχανική των hook προτροπής που σας επιτρέπει να τρέχετε αυτόματα κώδικα σε κάθε διακοπή.
Οι αναγνώστες που φτάνουν εδώ ξέρουν να εκκινούν το perl -d και να κάνουν βηματική εκτέλεση γραμμή προς γραμμή. Η επόμενη δεξιότητα είναι να μεταβαίνετε απευθείας στο ενδιαφέρον σημείο και να σταματάτε μόνο όταν το πρόβλημα πρόκειται να εκδηλωθεί.
Breakpoints σε γραμμές και σε sub#
Εντολή | Αποτέλεσμα |
|---|---|
| Breakpoint στην τρέχουσα γραμμή. |
| Breakpoint στη γραμμή LINE στο τρέχον αρχείο. |
| Υπό συνθήκη· διακοπή όταν η COND είναι αληθής. |
| Μεταξύ αρχείων· το FILE ταιριάζει με εγγραφή του |
| Υπό συνθήκη μεταξύ αρχείων. |
| Διακοπή στην πρώτη γραμμή της SUB (η SUB πρέπει να είναι μεταγλωττισμένη). |
| Breakpoint sub υπό συνθήκη. |
| Διακοπή στη sub στην οποία αναφέρεται το |
| Διακοπή αφού τελειώσει η μεταγλώττιση της SUB, πριν τρέξει το σώμα της. |
| Διακοπή την πρώτη φορά που καλείται η SUB, ακόμη και αν δεν έχει φορτωθεί. |
| Διακοπή όταν το FILE γίνεται |
| Διαγραφή breakpoint στη γραμμή LINE. |
| Διαγραφή όλων των breakpoints. |
| Απενεργοποίηση χωρίς αφαίρεση. |
| Επανενεργοποίηση. |
| Λίστα από breakpoints, ενέργειες, και watches. |
| Λίστα μόνο από breakpoints. |
Οι συνθήκες είναι σκέτες εκφράσεις, όχι if (…):
DB<1> b 237 $count > 10
DB<2> b 42 /unauthorized/i
DB<3> b validate_payload ref($obj) eq 'HASH' && keys %$obj
Τα breakpoints τοποθετούνται μόνο σε γραμμές που περιέχουν εκτελέσιμο κώδικα. Μια κενή γραμμή, ένα καθαρό σχόλιο, ή η συνέχεια προηγούμενης δήλωσης απορρίπτεται:
DB<1> b 3
Line 3 not breakable.
Μια γραμμή φέρει το πολύ ένα breakpoint και μία ενέργεια· η προσθήκη δεύτερου επανεγγράφει το πρώτο.
Πίνακας χρονισμού#
Πού στον κύκλο ζωής του προγράμματος πυροδοτείται ένα breakpoint έχει σημασία - ειδικά για κώδικα σε μπλοκ BEGIN ή αρθρώματα που γίνονται require τεμπέλικα.
Στόχος | Εντολή |
|---|---|
Διακοπή στην πρώτη δήλωση χρόνου εκτέλεσης | Προεπιλογή - ο αποσφαλματωτής ήδη σταματάει εκεί. |
Διακοπή μέσα σε μπλοκ | Εισάγετε |
Διακοπή πριν τρέξει το σώμα μιας sub (μετά τη μεταγλώττισή της) |
|
Διακοπή στην πρώτη κλήση μιας sub που δεν έχει ακόμη φορτωθεί |
|
Διακοπή όταν ένα αρχείο γίνεται |
|
Διακοπή σε συγκεκριμένη γραμμή |
|
Διακοπή σε γραμμή μόνο όταν ισχύει μια συνθήκη |
|
Το $DB::single = 1; μέσα σε μπλοκ BEGIN είναι το κόλπο για αποσφαλμάτωση κατά τη μεταγλώττιση: η εγγραφή b στην προτροπή λειτουργεί μόνο αφού τρέχει ο αποσφαλματωτής, αλλά ο κώδικας BEGIN τρέχει πριν από την πρώτη προτροπή. Ρίξτε την ανάθεση μέσα στο μπλοκ, εκκινήστε υπό -d, και ο αποσφαλματωτής σταματάει στην επόμενη γραμμή στην οποία μπορεί να σπάσει η εκτέλεση μέσα στο μπλοκ.
Η πρόσβαση στο $DB::single όταν δεν τρέχετε υπό -d αυτο-δημιουργεί το DB:: αβλαβώς - το μοτίβο είναι ασφαλές να γίνει commit.
Παράθεση και διαχείριση breakpoints#
DB<1> L
app.pl:
42: $user = User->load($id);
break if (1)
91: dispatch($req);
break if ($req->method eq 'POST')
DB<2> disable 42
DB<3> enable 42
DB<4> B 42
DB<5> B *
Τα disable / enable εναλλάσσουν ένα breakpoint χωρίς να ξεχνούν τη συνθήκη του - χρήσιμο όταν θέλετε να παρακάμψετε προσωρινά ένα «καυτό» breakpoint και να το επανοπλίσετε αργότερα.
Ενέργειες: αυτόματη εκτέλεση κώδικα σε μια γραμμή#
Μια ενέργεια τρέχει κώδικα Perl πριν εκτελεστεί η καθορισμένη γραμμή, χωρίς να σταματάει. Χρησιμοποιήστε την για παθητική παρατήρηση:
DB<1> a 42 print "entering: user_id=$user_id\n"
DB<2> a 91 warn "POST body:\n" . Dumper($body) if $req->method eq 'POST'
DB<3> L a
app.pl:
42: ...
action: print "entering: user_id=$user_id\n"
DB<4> A 42 # delete action at line 42
DB<5> A * # delete all actions
Διάταξη σε γραμμή στην οποία μπορεί να σπάσει η εκτέλεση:
Ελέγχεται η συνθήκη του breakpoint.
Εκτυπώνεται η έξοδος ίχνους (αν η ιχνηλάτηση είναι ενεργή).
Τρέχει η ενέργεια.
Εμφανίζεται η προτροπή (αν χτυπήθηκε breakpoint ή κάνετε βηματική εκτέλεση).
Εκτελείται η ίδια η γραμμή.
Ενέργειες και breakpoints συνυπάρχουν στην ίδια γραμμή - το πολύ ένα από κάθε είδος.
Watches: διακοπή σε αλλαγή τιμής#
Ένα watch αναφέρει την παλιά και τη νέα τιμή όταν μια παρακολουθούμενη έκφραση αλλάζει, και σας οδηγεί στην προτροπή:
DB<1> w $global_count
DB<2> c
Watchpoint 0: $global_count changed:
old value: 42
new value: 43
main::tick(app.pl:118): ++$global_count;
DB<3> W $global_count # delete this watch
DB<4> W * # delete all watches
Τα watches αποτιμώνται σε κάθε γραμμή στην οποία μπορεί να σπάσει η εκτέλεση. Οι εκφράσεις πρέπει να αναφέρονται σε καθολικές ή προσβάσιμα ψευδώνυμα· οι λεξιλογικές μεταβλητές my δεν παρακολουθούνται απευθείας. Όταν μια λεξιλογική έχει σημασία, χρησιμοποιήστε το Tie::Watch στον κώδικα για να εγκαταστήσετε watcher στη στιγμή του tie, ή αναθέστε μέσω ψευδωνύμου εμβέλειας πακέτου.
Τα watches προσθέτουν κόστος ανά δήλωση ανάλογο του πλήθους των watches και του κόστους κάθε έκφρασης. Κρατήστε τα στενά και αφαιρέστε τα όταν τελειώσετε.
Hooks προτροπής: εκτέλεση κώδικα σε κάθε διακοπή#
Τα < / > εγκαθιστούν κώδικα Perl που τρέχει αυτόματα πριν / μετά από κάθε προτροπή. Τα { / {{ κάνουν το ίδιο για εντολές αποσφαλματωτή:
Εντολή | Αποτέλεσμα |
|---|---|
| Κώδικας Perl πριν από κάθε προτροπή (= μετά τη γραμμή που μόλις εκτελέστηκε). |
| Προσάρτηση στη λίστα προ-προτροπής. |
| Λίστα κώδικα προ-προτροπής. |
| Διαγραφή όλου του κώδικα προ-προτροπής. |
| Κώδικας Perl μετά από κάθε προτροπή (= πριν από την επόμενη γραμμή). |
| Εντολή αποσφαλματωτή (όχι Perl) προ-προτροπής. |
| Προσάρτηση στη λίστα εντολών αποσφαλματωτή προ-προτροπής. |
Τυπική χρήση: χρονική σφραγίδα σε κάθε βήμα:
DB<1> < print "stop: ", scalar localtime, "\n"
DB<2> > print "start: ", scalar localtime, "\n"
Ή πάντα να εμφανίζεται η τρέχουσα γραμμή και μια παρακολουθούμενη μεταβλητή:
DB<1> { v
DB<2> { p $important
Πολλαπλών γραμμών: διαφύγετε το newline με \:
DB<1> < for my $f (@important_files) { \
cont: print " $f: ", (-s $f) // 'n/a', "\n"; \
cont: }
Ψευδώνυμα#
Μόνιμες συντομεύσεις εντολών μέσω =:
DB<1> = len s/^len(.*)/p length($1)/
DB<2> = quit s/^quit(\s*)/exit/
DB<3> = # list all aliases
Τα ψευδώνυμα ζουν στο %DB::alias και εφαρμόζονται στη στιγμή της αποστολής. Ορίστε τα μία φορά στο .perldb για επιμονή πέρα από τη συνεδρία.
Breakpoints μίας χρήσης#
Το c LINE ορίζει breakpoint στη γραμμή LINE, συνεχίζει, και καθαρίζει το breakpoint όταν χτυπήσει:
DB<1> c 42
Ο απλούστερος τρόπος για να πείτε «απλώς τρέξε ως τη γραμμή 42 και σταμάτα εκεί». Χωρίς χειροκίνητη ζευγαροποίηση b / B.
Διακοπή στην εισαγωγή / στην πρώτη κλήση τεμπέλικα#
Όταν μια sub ζει σε άρθρωμα που μπορεί να μην έχει ακόμη φορτωθεί, το b SUB αποτυγχάνει:
DB<1> b MyApp::Worker::dispatch
Subroutine not yet compiled.
Το b postpone περιμένει να τελειώσει η μεταγλώττιση της sub:
DB<1> b postpone MyApp::Worker::dispatch
DB<2> c
Για αρχεία που φορτώνονται με require / do, το b load διακόπτει στην πρώτη φόρτωση:
DB<1> b load /usr/share/perl5/MyApp/Worker.pm
Το όνομα αρχείου πρέπει να ταιριάζει με την πλήρη διαδρομή στο %INC, όχι μόνο με το όνομα του αρθρώματος.
Μάθετε περισσότερα#
inspecting-state - τι να κοιτάξετε όταν πυροδοτηθεί ένα breakpoint.
tracing - όταν θέλετε να παρακολουθήσετε τι συμβαίνει χωρίς διακοπή.