Error in accessing Hash key - perl

Here's my code..I am trying to create a hash lookup table and access the data from it in every loop..
#! usr/bin/perl
use warnings;
use strict;
sub bin2dec
{
return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}
while(<>)
{
if(/SIB_DBG/)
{
if(/TTRB:\s*([\da-f]+)\s([\da-f]+)\s([\da-f]+)\s([\da-f]+)/ ||
/ETRB:\s*([\da-f]+)\s([\da-f]+)\s([\da-f]+)\s([\da-f]+)/ ||
/Command\sETRB\s*([\da-f]+)\s([\da-f]+)\s([\da-f]+)\s([\da-f]+)/ )
{
print "$_ $1 $2 $3 $4\n";
my $deci1 = hex($1);
my $deci2 = hex($2);
my $deci3 = hex($3);
my $deci4 = hex($4);
my $bin = reverse sprintf("%032b",$deci4); #convert to 32 bit binary and reverse
print "\nbinary :$bin\n";
my $sub = substr($bin ,16,6); #extract required 6 bits
print "string :$sub\n";
my $type = bin2dec($sub);
my $val = $trb{"$type"};
print "TRB type: $type\n";
print "detail: $val\n";
}
}
}
my %trb = (
0 => "reserved",
32 => "transfer event",
48 => "vendor defined");
but I am getting an error even if I have declared trb .
Global symbol "%trb" requires explicit package name at script.plx line 31.
Execution of script.plx aborted due to compilation errors.
Again my input log file is like
Aug 31 15:25:53 usb3 kernel: [ 78.684054] SIB_DBG TTRB:00000000 00000000 00000000 00002401, PTR: ffff88005ff8b000
Aug 31 15:25:53 usb3 kernel: [ 78.815428] SIB_DBG ETRB: 5ff8b850 00000000 01000000 01018001

You are using the hash %trb in this line:
my $val = $trb{"$type"};
before you have declared %trb here:
my %trb = (
0 => "reserved",
32 => "transfer event",
48 => "vendor defined");
Move that declaration of %trb up above the while loop.

The hash %trb must be declared before it is used. Move its definition up to before the while statement -- after your subroutine defintion and all will be well
You appear to be more familiar with a different language, as you usually find Perl subroutines at the end of the program, but it doesn't matter either way

Related

Is it normal that two different versions of perl produce different results?

I am trying to perform some stack analysis on an MCU following the steps described here. The site links then to a Perl script that I launch as a post-build operation by meanings of a simple batch file.
The IDEA based on Eclipse uses the Perl executable at the path:
C:\..\S32DS_ARM_v2018.R1\utils\msys32\usr\bin\perl.exe
perl.exe -v gives:
This is perl 5, version 22, subversion 1 (v5.22.1) built for i686-msys-thread-multi-64int
The OS (windows) has a perl installation at
C:\Perl64\bin\perl.exe
perl.exe -v gives:
This is perl 5, version 24, subversion 3 (v5.24.3) built for MSWin32-x64-multi-thread
(with 1 registered patch, see perl -V for more detail)
I can confirm that avstak.pl (the perl script I am referring some lines above) produces different results with the former or the latter.
WHY this happens, is out of my area of expertise at the moment.
What I would like to understand is
Understand why this is happening;
Understand which perl provides the right outputs (pretty sure I suppose the 5.24.3 is the correct one);
Learning how to prevent this issue if I am going to use perl in future.
Thanks and best regards,
L.
Edit: the outcome of the script with the two different perl versions (reduced output for readability):
This one is result_5.22.1
Func Cost Frame Height
------------------------------------------------------------------------
> I2C_MasterGetTransferStatus 292 292 1
> FLEXIO_I2C_DRV_MasterStartTransfer 236 236 1
> CLOCK_DRV_Init 172 172 1
> CLOCK_SYS_SetConfiguration 172 172 1
> EDMA_DRV_ConfigScatterGatherTransfer 132 132 1
> CLOCK_SYS_SetSystemClockConfig 76 76 1
> FLEXIO_I2C_DRV_MasterInit 60 60 1
> EDMA_DRV_ConfigSingleBlockTransfer 60 60 1
> main 52 52 1
> LPI2C_DRV_MasterSetBaudRate 52 52 1
> LPI2C_DRV_MasterStartDmaTransfer 52 52 1
> FLEXIO_DRV_InitDriver 52 52 1
> I2C_MasterInit 44 44 1
> LPI2C_DRV_SlaveStartDmaTransfer 44 44 1
> CLOCK_SYS_UpdateConfiguration 44 44 1
> CLOCK_DRV_SetClockSource 44 44 1
> LPI2C_DRV_SlaveInit 44 44 1
> EDMA_DRV_Init 44 44 1
> EDMA_DRV_Deinit 36 36 1
> CLOCK_SYS_ConfigureSOSC 36 36 1
> CLOCK_SYS_ConfigureFIRC 36 36 1
vs
result_5.24.3
Func Cost Frame Height
------------------------------------------------------------------------
> main 536 52 9
I2C_MasterSendDataBlocking 484 28 8
> I2C_MasterReceiveDataBlocking 484 28 8
> I2C_MasterReceiveData 468 20 7
> I2C_MasterSendData 468 20 7
FLEXIO_I2C_DRV_MasterReceiveDataBlocking 456 28 7
FLEXIO_I2C_DRV_MasterSendDataBlocking 456 28 7
FLEXIO_I2C_DRV_MasterSendData 448 20 5
FLEXIO_I2C_DRV_MasterReceiveData 448 20 5
FLEXIO_I2C_DRV_MasterStartTransfer 428 236 4
> I2C_MasterGetTransferStatus 408 292 6
CLOCK_SYS_UpdateConfiguration 336 44 6
CLOCK_SYS_SetConfiguration 292 172 5
> CLOCK_DRV_Init 292 172 5
LPI2C_DRV_MasterReceiveDataBlocking 256 20 7
> I2C_SlaveReceiveDataBlocking 252 12 8
> I2C_SlaveSendDataBlocking 252 12 8
As you can see the hight number in the first version doesn't increase (and it should).
Cost and frame suffer the same issue I suppose.
the script is here:
#!/usr/bin/perl -w
# avstack.pl: AVR stack checker
# Copyright (C) 2013 Daniel Beer <dlbeer#gmail.com>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
# Usage
# -----
#
# This script requires that you compile your code with -fstack-usage.
# This results in GCC generating a .su file for each .o file. Once you
# have these, do:
#
# ./avstack.pl <object files>
#
# This will disassemble .o files to construct a call graph, and read
# frame size information from .su. The call graph is traced to find, for
# each function:
#
# - Call height: the maximum call height of any callee, plus 1
# (defined to be 1 for any function which has no callees).
#
# - Inherited frame: the maximum *inherited* frame of any callee, plus
# the GCC-calculated frame size of the function in question.
#
# Using these two pieces of information, we calculate a cost (estimated
# peak stack usage) for calling the function. Functions are then listed
# on stdout in decreasing order of cost.
#
# Functions which are recursive are marked with an 'R' to the left of
# them. Their cost is calculated for a single level of recursion.
#
# The peak stack usage of your entire program can usually be estimated
# as the stack cost of "main", plus the maximum stack cost of any
# interrupt handler which might execute.
use strict;
# Configuration: set these as appropriate for your architecture/project.
my $objdump = "arm-none-eabi-objdump";
my $call_cost = 4;
# First, we need to read all object and corresponding .su files. We're
# gathering a mapping of functions to callees and functions to frame
# sizes. We're just parsing at this stage -- callee name resolution
# comes later.
my %frame_size; # "func#file" -> size
my %call_graph; # "func#file" -> {callees}
my %addresses; # "addr#file" -> "func#file"
my %global_name; # "func" -> "func#file"
my %ambiguous; # "func" -> 1
foreach (#ARGV) {
# Disassemble this object file to obtain a callees. Sources in the
# call graph are named "func#file". Targets in the call graph are
# named either "offset#file" or "funcname". We also keep a list of
# the addresses and names of each function we encounter.
my $objfile = $_;
my $source;
open(DISASSEMBLY, "$objdump -dr $objfile|") ||
die "Can't disassemble $objfile";
while (<DISASSEMBLY>) {
chomp;
if (/^([0-9a-fA-F]+) <(.*)>:/) {
my $a = $1;
my $name = $2;
$source = "$name\#$objfile";
$call_graph{$source} = {};
$ambiguous{$name} = 1 if defined($global_name{$name});
$global_name{$name} = "$name\#$objfile";
$a =~ s/^0*//;
$addresses{"$a\#$objfile"} = "$name\#$objfile";
}
if (/: R_[A-Za-z0-9_]+_CALL[ \t]+(.*)/) {
my $t = $1;
if ($t eq ".text") {
$t = "\#$objfile";
} elsif ($t =~ /^\.text\+0x(.*)$/) {
$t = "$1\#$objfile";
}
$call_graph{$source}->{$t} = 1;
}
}
close(DISASSEMBLY);
# Extract frame sizes from the corresponding .su file.
if ($objfile =~ /^(.*).o$/) {
my $sufile = "$1.su";
open(SUFILE, "<$sufile") || die "Can't open $sufile";
while (<SUFILE>) {
$frame_size{"$1\#$objfile"} = $2 + $call_cost
if /^.*:([^\t ]+)[ \t]+([0-9]+)/;
}
close(SUFILE);
}
}
# In this step, we enumerate each list of callees in the call graph and
# try to resolve the symbols. We omit ones we can't resolve, but keep a
# set of them anyway.
my %unresolved;
foreach (keys %call_graph) {
my $from = $_;
my $callees = $call_graph{$from};
my %resolved;
foreach (keys %$callees) {
my $t = $_;
if (defined($addresses{$t})) {
$resolved{$addresses{$t}} = 1;
} elsif (defined($global_name{$t})) {
$resolved{$global_name{$t}} = 1;
warn "Ambiguous resolution: $t" if defined ($ambiguous{$t});
} elsif (defined($call_graph{$t})) {
$resolved{$t} = 1;
} else {
$unresolved{$t} = 1;
}
}
$call_graph{$from} = \%resolved;
}
# Create fake edges and nodes to account for dynamic behaviour.
$call_graph{"INTERRUPT"} = {};
foreach (keys %call_graph) {
$call_graph{"INTERRUPT"}->{$_} = 1 if /^__vector_/;
}
# Trace the call graph and calculate, for each function:
#
# - inherited frames: maximum inherited frame of callees, plus own
# frame size.
# - height: maximum height of callees, plus one.
# - recursion: is the function called recursively (including indirect
# recursion)?
my %has_caller;
my %visited;
my %total_cost;
my %call_depth;
sub trace {
my $f = shift;
if ($visited{$f}) {
$visited{$f} = "R" if $visited{$f} eq "?";
return;
}
$visited{$f} = "?";
my $max_depth = 0;
my $max_frame = 0;
my $targets = $call_graph{$f} || die "Unknown function: $f";
if (defined($targets)) {
foreach (keys %$targets) {
my $t = $_;
$has_caller{$t} = 1;
trace($t);
my $is = $total_cost{$t};
my $d = $call_depth{$t};
$max_frame = $is if $is > $max_frame;
$max_depth = $d if $d > $max_depth;
}
}
$call_depth{$f} = $max_depth + 1;
$total_cost{$f} = $max_frame + ($frame_size{$f} || 0);
$visited{$f} = " " if $visited{$f} eq "?";
}
foreach (keys %call_graph) { trace $_; }
# Now, print results in a nice table.
printf " %-30s %8s %8s %8s\n",
"Func", "Cost", "Frame", "Height";
print "------------------------------------";
print "------------------------------------\n";
my $max_iv = 0;
my $main = 0;
foreach (sort { $total_cost{$b} <=> $total_cost{$a} } keys %visited) {
my $name = $_;
if (/^(.*)#(.*)$/) {
$name = $1 unless $ambiguous{$name};
}
my $tag = $visited{$_};
my $cost = $total_cost{$_};
$name = $_ if $ambiguous{$name};
$tag = ">" unless $has_caller{$_};
if (/^__vector_/) {
$max_iv = $cost if $cost > $max_iv;
} elsif (/^main#/) {
$main = $cost;
}
if ($ambiguous{$name}) { $name = $_; }
printf "%s %-30s %8d %8d %8d\n", $tag, $name, $cost,
$frame_size{$_} || 0, $call_depth{$_};
}
print "\n";
print "Peak execution estimate (main + worst-case IV):\n";
printf " main = %d, worst IV = %d, total = %d\n",
$total_cost{$global_name{"main"}},
$total_cost{"INTERRUPT"},
$total_cost{$global_name{"main"}} + $total_cost{"INTERRUPT"};
print "\n";
print "The following functions were not resolved:\n";
foreach (keys %unresolved) { print " $_\n"; }
Edit2:
As Amon suggested to check, subsequent iterations of the script on the same dataset doesn't produce the same output. Values (cost/frame/height) are always the same but the order in which the functions are reported is different.

Convert a byte stored as string into bits in Perl and modify it

I am trying to perform the following using a Perl script:
extract two characters from a hexadecimal number stored as a string --> This will give a byte written as string
Convert this byte to binary (I must keep leading zeros if they exist)
change specific bits in the binary
convert back to hexadecimal
replace into the original hexadecimal number
To do so, after a long research on the internet, I came up with the following lines:
# Initialize my variable: in my function, this is passed as input
$str = '5B CD 02 01 10';
# Extract the two characters to form a Byte
$OldByte_str = substr($str,0,2);
# Convert to binary. Supposed to give '0101 1011'
$PDM_OldBits = ( "Binary: %b\n", $PDM_OldByte );
# Replace two bits.Supposed to give '01**10** 1011'
substr($PDM_OldBit,2,2)= '10';
# Convert back to Bytes. Supposed to give'6B'
$NewByte_str= sprintf("0x%x", stringdecimal(arraystring($PDM_OldBits)));
# Substitute back into the original Bytes string.
# Supposed to give: '**6B** CD 02 01 10'
substr($str,0,2)= $PDM_NewByte;
with:
sub stringdecimal {
return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}
sub arraystring {
my $string = join('', #_);
return $string;
}
However, the conversion to binary is not taking place; thus i am also not able to check the rest of the code.
As a beginner to Perl, I am asking this question here - in case someone has some hints or solutions to my problem.
strict and warnings will always give you hints when mistyping something.
use strict;
use warnings;
sub stringdecimal {
# return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
return oct("0b" . shift);
}
my $str = '5B CD 02 01 10'; #Initialize my variable:in my function, this is passed as input
my $OldByte_str = substr($str,0,2); #extract the two characters to form a Byte
my $PDM_OldBits = sprintf( "%b", hex($OldByte_str) );#Convert to binary. Supposed to give '0101 1011'
substr($PDM_OldBits,1,2)= '10'; #Replace two bits.Supposed to give '01**10** 1011'
my $NewByte_str= sprintf("%X", stringdecimal($PDM_OldBits)); #Convert back to Bytes. Supposed to give'6B'
substr($str,0,2)= $NewByte_str; #Substitute back into the original Bytes string.Supposed to give: '**6B** CD 02 01 10'
print $str, "\n";
Here's an alternative solution - using only pack() and unpack() and one call to substr() (no sprintf()). It will modify each value in the array. (If you don't want that just take out the for() loop and replace $_ with $bytes[0].)
use strict;
use warnings;
use feature('say');
my $str = '5B CD 02 01 10';
my ($orig, $bits, $hex);
my #bytes = split(/ /, $str);
for (#bytes) {
$bits = unpack('B8', chr(hex($_)));
$orig = $bits; # for 'debugging'
substr($bits, 2, 2) = '10';
say $orig . ' -> ' . $bits;
$hex = unpack('H2', pack('B8', $bits));
say $_ . ' -> ' . uc($hex);
}
Output ...
01011011 -> 01101011
5B -> 6b
11001101 -> 11101101
CD -> ed
00000010 -> 00100010
02 -> 22
00000001 -> 00100001
01 -> 21
00010000 -> 00100000
10 -> 20
Using substr($str, 0, 2); to extract the bytes of interest - aside from being unwieldy - is potentially unreliable. If there is inconsistent white spacing in the input, for example, then it could extract 'B ' instead of '5B' or ' C' instead of 'CD'. That's why I split the string in to bytes using split() instead.

Undefined subroutine &package::subroutine called at line <of script>

I am debugging this script at work - the boss says that is used to work on Solaris, but since they switched over to linux, it stopped working. I had to rewrite it with strict and warnings .
When I run it I get error:
Undefined subroutine &Logging::openLog called at /path/to/script line 27
here is script (well part of it)
1 #!/usr/local/bin/perl
2
3 unshift #INC, "/production/fo/lib";
4 use strict;
5 use warnings;
6 use Sys::Hostname;
7 use Getopt::Long qw(:config bundling auto_version);
8 use File::Path;
9
10 require "dbconfig2.pl";
11 require "logging2.pl";
12 require "hpov.pl";
13
14 # global variables
15 my $parseDate = "";
16 my #fileList = "";
17 my #transList = "";
18 my $mLogDate = "";
19 my $lHost = hostname;
20 my $corefiles_dir="/production/log/corefiles";
21 my $default_Threshold=90;
22
23 # do stuff
24
25 parseOptions();
26 Dbconfig::readconfigFile("$config");
27 Logging::openLog("$Dbconfig::prefs{logFile}","overwrite");
28 # msglog actions TODO logs, compress only, data files
29 my $check_shdw=`ls -l /etc/motd | awk '{print \$11}' | grep 'motd.shdw'`; #Check if hostname is shadow
30 $check_shdw =~ y/\n//d; #remove new line if any
31 if ( $check_shdw eq "motd.shdw" )
32 {
33 Logging::printLog("INFO","Enviroment is Shadow, triggering core files compressing");
34 if (is_folder_empty($corefiles_dir)) {
35 print "Corefile Directory is EMPTY......! \n";
36 }
37 else {
38 gzip_corefiles() ; #Execute compress core files
39 }
40 }
41
The script uses require statements to I guess call upon the routines that the script creator built.
For the purpsoe of this script - the dbconfig just slurps in a config file and breaks them down into values.
like the "$Dbconfig::prefs{logFile}" equals a logfile location /prod/logs/script.log - that's it.
#!/usr/local/bin/perl
package Dbconfig;
#use warnings;
use DBI;
use DBD::Oracle;
%prefs = "";
#$dbPrefs = "";
$raiseError = 0;
%startupItem = "";
# readconfigFile(file) - read in a configuration file.
sub readconfigFile {
my $file = shift;
if ( ! -e $file ) {
$errorTxt = "Error: $file does not exist.\n";
$raiseError = 1;
}
# read in the cfg variables
open(CFGFILE,"<","$file") or die "Cannot open $file for reading: $!\n";
while(<CFGFILE>) {
chomp; # kill newlines
s/#.*//; # ignore comments
s/^\s+//; # ignore leading whitespace
s/\s+$//; # ignore trailing whitespace
next unless length;
my($var,$value) = split(/\s*=\s*/, $_, 2);
$prefs{$var} = $value;
}
close(CFGFILE);
}
Then there is this logging package. In line 27 of the script (where the error comes in) i see an "overwrite" invocation, but don't see anything referenceing overwrite in the logging.pl package - but not really sure if it matters. the parent script does not seem to write to any log file. I am not even sure if the filehandle LOGFILE is gtting created.
#!/usr/local/bin/perl
package Logging;
use File::Copy;
use warnings;
use strict;
my $timestamp = "";
my $filestamp = "";
# openLog(logfile name) - opens a log file
sub openLog {
my $file = shift;
my $rotate = shift;
# force a rotation if it exists.
if ( -e $file && $rotate eq "rotate" ) {
print "Warning: $file exists. Rotating.\n";
rotateLog($file);
}
getTime();
open(LOGFILE,">","$file") or warn "Error: Cannot open $file for writing: $!\n";
print LOGFILE "[$timestamp] - Normal - Opening log for $file.\n";
}
# rotateLog(log file) - rotate a log.
sub rotateLog {
my $file = shift;
getTime();
openLog("$file");
print LOGFILE "[$timestamp] - Warning - Rotating $file to $file.$filestamp.log";
closeLog($file);
move($file,$file-"$filestamp.log");
openLog($file);
}
time() - grab timestamp for the log.
sub getTime {
undef $timestamp;
undef $filestamp;
($sec,$min,$hour,$mday,$mon,$year) = (localtime(time))[0,1,2,3,4,5];
$sec = sprintf("%02d",$sec);
$min = sprintf("%02d",$min);
$hour = sprintf("%02d",$hour);
$mday = sprintf("%02d",$mday);
$year = sprintf("%04d",$year +1900);
$mon = sprintf("%02d",$mon +1);
$timestamp = "$mon-$mday-$year $hour:$min:$sec";
$filestamp = "$year$mon$mday$hour$min$sec";
}
just wondering - is there a problem with logging.pl calling something from dbconfig.pl in line 27? Like can one module call a value fron another module? besides using strict and warnings, and alot of print statements I do not know what my next debugging
step is. I have not idea how to check and see that the LOGFILE filehandle is getting created - if it does not error out, I can only suppose that it is. Like is there something extra I have to do to get the modules talking to each other?
I am not a scripting king - just the only guy in my row who can even begin to understand this stuff.
Not sure if this will effect things but ....
1) Packages need to return true, normal procedure is to end the file with the line:
1;
to ensure that.
2) Theres a comment in the logger package without the leading # which would cause compilation failure:
time() - grab timestamp for the log.
3) This line:
unshift #INC, "/production/fo/lib";
is adding the directory to search path for modules, make sure your logging2.pl file is actually in that location (it propably is otherwise you would get different errors, but worth a double check)
That looks all OK then.
For some reason although require "logging2.pl" works (there'd be an error if not) the sub-routines in it aren't loaded and available. Unlike the load of DBconfig2.pl which works OK (otherwise the call to Dbconfig::readconfigFile() would fail first).
Only difference I can see is the leading space on the package command in Logging2.pl, don't think that would matter though.
Could try calling openLog without the package prefix (Logging::) to see if its been loading into main from some reason and print the contents of %INC after the require statements to make sure its been loaded correctly?

What do I do about the error "Not a HASH reference"?

I am trying to execute user created Perl script,
usage: my.pl <type> <stats> [-map <map>] <session1> [session2]
Produces statistics about the session from a Wireshark .pcap file where:
<type> is the type of data in the pcap file (wlan, ethernet or ip)
<stats> is the output file to write notable information
<session> is the pcap input file or a folder containing pcaps (recursive)
but it fails with the error below.
$perl my.pl ethernet pa.xls google.pcap
Processing pcap trace (TCP):
Not a HASH reference at folder/httpTrace.pm line 654.
Here is the debug console -
Not a HASH reference at folder/httpTrace.pm line 654. at folder/httpTrace.pm line 654
folder::httpTrace.pm::readHttp('HASH(0x2306d38)', undef) called at my.pl line 56
main::__processSession('google.pcap') called at my.pl line 35 Debugged program terminated.
httpTrace.pm: last line# 654
sub readHttp($#)
{
my ($conntable, $map) = #_;
my $http_req_id = 0;
my $pipelining = 0;
my $mapc;
my #allReq;
my #allRep;
if( defined( $map ) ) {
$mapc = $map->clone();
}
foreach my $connect ( sort { $pa->{'id'} <=> $pb->{'id'} } values( %{ $conntable } ) ) {
line 56 in my.pl:
my $stats = Pcapstats::HTTP::readHttp( \%tcp_stream, $map );
Also there map.pm & usage in my.pl as
my $map;
if( $ARGV[0] eq '-map' ) {
shift( #ARGV );
$map = Pcapstats::Map->new( shift( #ARGV ) );
}
In your file httpTrace.pm you have this line
foreach my $connect ( sort { $pa->{'id'} <=> $pb->{'id'} } values( %{ $conntable } ) ) {
and I wonder what $pa and $pb are? Unless you have set them to something elsewhere they will be undefined and will give you Use of uninitialized value errors. Either way you will not be doing a sort.
But that doesn't explain the Not a HASH reference error, which is most likely because $conntable isn't what you think it is. It won't cause an error if it is undefined because autovivication will automatically create an empty hash, so it is probably a simple string or number, or possibly an array reference.
If you want to show the code that sets $conntable then we may be able to help further.

Numeric value of string and vice versa

Is there any built-in function (like we have ord for a single character) to convert a string into its equivalent numeric value and vice versa i.e. getting back the string from the equivalent numeric value.
Apart from the approach involving split from nickisfat, there's also unpack:
use Encode qw(encode);
my $characters = 'This is my string.';
my $octets = encode 'UTF-8', $characters;
unpack 'C*', $octets
# expression returns qw(84 104 105 115 32 105 115 32 109 121 32 115 116 114 105 110 103 46)
unpack 'H*', $octets
# expression returns '54686973206973206d7920737472696e672e'
Perl is dynamically typed. So depending on the context a variable will be treated as a string or as a number. You don't need to explicitly convert.
ord will do what you want in Perl also:
perl -e '$char = "y"; print ord($char);'
You can always use perldoc to check if a function is part of perl, perldoc -f ord
Generally you don't need to convert number and string values, as every scalar automatically updates those when you use it in new context. So when you assign a number to a scalar and later use it in string context, Perl will automatically generate string representation for you.
However, some libraries rely on inspecting scalars to decided how to treat them - as number or as string (Hello, JSON:XS!) There isn't really any clean way to resolve that except to manually reassign number or string value to scalar to wipe "auto generated" part. Use some simple and fast calculation like $var += 0 to numify or $var = "$var" to stringify variables in such cases.
Just apply the builtin functions to each char in the string in turn. The below can probably be made more pretty, but will work:
#!/usr/bin/perl
use strict ;
use warnings ;
my $string = 'some text' ;
my $num = '115,111,109,101,32,116,101,120,116' ;
strToNum($string) ;
numToStr($num) ;
sub strToNum{
my $input = shift ;
local $" = ',' ;
my #result = map( ord, split(//, $input) ) ;
print "#result\n" ;
}
sub numToStr{
my $input = shift ;
local $" = '' ;
my #result = map( chr, split(/,/, $input) ) ;
print "#result\n" ;
}