Graphviz change edge direction - linked-list

I use graphviz on hackmd and draw a graph like this
my code is:
digraph G {
rankdir=LR
node [color=black,shape=record]
node0 [label="{<data>node 0|<next>}"]
node1 [label="{<data>node 1|<next>}"]
new_node [label="{<data>new_node|<next>}"]
null0 [shape=none, label="NULL"]
null1 [shape=none, label="NULL"]
head [shape=none, label="head"]
ptr [shape=none, label="ptr"]
indirect [shape=none]
head->ptr
indirect->node0:next [constraint=false headport=s tailport=n];
ptr->node0
node0:next:c->node1 [arrowhead=normal, arrowtail=dot, dir=both, tailclip=false];
node1:next:c -> null0 [tailclip=false, arrowtail=dot, dir=both]
new_node:next:c->null1 [arrowhead=normal, arrowtail=dot, dir=both, tailclip=false];
{rank=same; indirect node1;}
}
I want node0 and indirect on the same rank. However, when I change
{rank=same; indirect node1;} -> {rank=same; indirect node0;}
they will have error message: "Error: lost indirect node0 edge"
The actual graph I want:

Change your layout to use html style labels instead of shape=record
digraph G {
rankdir=LR
node [color=black shape=none margin=0 height=.3 ]
node0 [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="data">node 0</td><td port="next"> </td></tr></table>>]
node1 [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="data">node 1</td><td port="next"> </td></tr></table>>]
new_node [label=<<table border="0" cellborder="1" cellspacing="0"><tr><td port="data">new_node</td><td port="next"> </td></tr></table>>]
null0 [shape=none, label="NULL"]
null1 [shape=none, label="NULL"]
head [shape=none, label="head"]
ptr [shape=none, label="ptr"]
indirect [shape=none]
head->ptr
indirect->node0:next [constraint=false headport=s tailport=n];
ptr->node0
node0:next:c->node1 [arrowhead=normal, arrowtail=dot, dir=both, tailclip=false];
node1:next:c -> null0 [tailclip=false, arrowtail=dot, dir=both]
new_node:next:c->null1 [arrowhead=normal, arrowtail=dot, dir=both, tailclip=false];
{rank=same indirect node0}
}

Related

32-bit ADD on Aarch64 assembly

This is my first post here and I'm also kind of new to arm64 assembly, so I'm trying to do some arithmetic, but for example when I try to do an addition it seems to do it in 32-bit.
Here's my code:
.data
msg: .asciz "Value 1: "
msg2: .asciz "Value 2: "
result: .asciz "Result: %d\n"
fmt: .asciz "%d"
.balign 8
value1: .quad 0
.balign 8
value2: .quad 0
.balign 16
lr_value: .quad 0
.text
.global main
main:
adr x0, lr_value
str x30, [x0]
//Display message
adr x0,msg
bl printf
//Input first value
adr x0,fmt
adr x1,value1
bl scanf
//Display second message
adr x0,msg2
bl printf
//Input second value
adr x0,fmt
adr x1,value2
bl scanf
//Load first and second value
adr x1,value1
ldr x1,[x1]
adr x2,value2
ldr x2,[x2]
//Add both values on x1
add x1,x1,x2
//Show result
adr x0,result
bl printf
adr x0,lr_value
ldr x30,[x0]
mov w0,#0
ret
And here's the output:
Value 1: 2147483647
Value 2: 1
Result: -2147483648
What am I doing wrong? I've also tried multiplication and substraction
Edit: Solved it, turns out I had to use %ld instead of %d, thank you Nate Eldredge!

How to make Erlang client/server connect with arguments/nodes from config?

I'm writing a client/server System in Erlang and can't get them to connect. The nodes they should use are stored in config files, which are loaded upon starting them. They also use several distributed data structures. Problem is, I'm first starting the data structure, then the server (works fine) but when I start the client, it doesn't connect to anything and throws an exception.
Server:
-module(server).
-export([startServer/0,loopServer/7,node/0,log/0,name/0]).
-compile({no_auto_import,[node/0]}).
-import(werkzeug, [get_config_value/2,lengthSL/1,logging/2,reset_timer/3,get_config_value/2]).
-import(erlang, [append/2]).
log() ->
erlang:list_to_atom(lists:concat(["Server#", node(),".log"])).
node() ->
{ok,Config} = file:consult("configs/server.cfg"),
{ok, Node} = werkzeug:get_config_value(node,Config),
Node.
name() ->
{ok,Config} = file:consult("configs/server.cfg"),
{ok, Name} = werkzeug:get_config_value(servername,Config),
Name.
%%Startet den Server und die darin enthaltene Schleife
startServer() ->
{ok,Config} = file:consult("configs/server.cfg"),
{ok, Name} = get_config_value(servername,Config),
%%CMEM initialisieren
{ok, RemTime} = get_config_value(cmemtime,Config),
CMEM = cmem:initCMEM(RemTime, log()),
%%HBQ-Prozess erzeugen
{ok,HBQName} = get_config_value(hbqname,Config),
{ok,HBQNode} = get_config_value(node,Config),
HBQ = {HBQName,HBQNode},
{ok,Serverzeit} = get_config_value(serverzeit,Config),
%%Zeitpunkt des Timer übergeben
{ok, Timer} = timer:send_after(round(RemTime * 1000),Name,delServer),
%%Prozess registrieren, Serverschleife mit allen Infos starten, plus NNr 1
ServerPid = spawn(?MODULE, loopServer, [Name,CMEM,HBQ,Timer,Serverzeit,Config,1]),
register(Name,ServerPid),
%%HBQ initialisieren
HBQ ! {ServerPid, {request,initHBQ}},
{Config,CMEM,HBQ,ServerPid}.
loopServer(Name,CMEM,HBQ,Timer,Serverzeit,Config,NNr) ->
receive
%%Client fragt neue Nachrichten ab, dazu wird aus CMEM die aktuelle NNr für
%%den Client angefordert und mit der ClientPID an die HBQ weitergegeben
{ClientPID,getmessages} ->
NewTimer = reset_timer(Timer,Serverzeit,delServer),
ClientNNr = cmem:getClientNNr(CMEM, ClientPID),
HBQ ! {self(), {request, deliverMSG, ClientNNr, ClientPID}},
logging(log(), lists:concat(["Server: Nachricht ", NNr, " wurde zugestellt.\n"])),
loopServer(Name,CMEM,HBQ,NewTimer,Serverzeit,Config,NNr);
%%Nachricht soll in HBQ verschoben werden
{dropmessage,[INNr,Msg,TSclientout]} ->
NewTimer = reset_timer(Timer,Serverzeit,delServer),
HBQ ! {self(), {request,pushHBQ,[INNr,Msg,TSclientout]}},
receive
{reply,ok} ->
logging(log(), lists:concat(["Server: Nachricht ", INNr, " wurde in HBQ eingefuegt.\n"]))
end,
loopServer(Name,CMEM,HBQ,NewTimer,Serverzeit,Config,NNr);
%%Client fragt naechste NNr ab, diese wird dem Zustand des Server entnommen
{ClientPID,getmsgid} ->
NewTimer = reset_timer(Timer,Serverzeit,delServer),
ClientPID ! {nid, NNr},
NewNNr = NNr + 1,
logging(log(), lists:concat(["Server: Nachrichtennumer ", NNr, " an ", erlang:pid_to_list(ClientPID), "gesendet.\n"])),
loopServer(Name,CMEM,HBQ,NewTimer,Serverzeit,Config,NewNNr);
%%Server beendet sich selbst und zugleich die HBQ
delServer ->
HBQ ! {self(),{request,delHBQ}},
receive
{reply,ok} ->
logging(log(), lists:concat([lists:concat(["Server: Downtime ", werkzeug:timeMilliSecond(), " von ", name() ,"\n"])])),
ok
end
end.
Client:
-module(client).
-export([startClients/0,loopClient/4,spawnC/1,forLoop/3,mitServerVerbinden/6,configLaden/0]).
-import(werkzeug, [get_config_value/2]).
-import(timer, [apply_after/4]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Client %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%initClient
startClients() ->
Config = configLaden(),
{ok, ClientAnzahl} = werkzeug:get_config_value(clientanzahl, Config),
{ok, ServerName} = werkzeug:get_config_value(servername, Config),
{ok, ServerNode} = werkzeug:get_config_value(servernode, Config),
ServerPid = {ServerName,ServerNode},
forLoop(ClientAnzahl, fun client:spawnC/1, ServerPid).
%%Hilfsfunktion fuer for-Schleife: Zaehlt runter,
%%ruft Funktion auf und gibt Ergebnisse als Liste zurueck
forLoop(Clients, Spawn, SPid) -> forLoop(Clients, Spawn, SPid, []).
forLoop(0, _Spawn, _SPid, ClientListe) -> ClientListe;
forLoop(Clients, Spawn, SPid, ClientListe) ->
ClientListeNew = ClientListe ++ [Spawn(SPid)],
ClientsNew = Clients - 1,
forLoop(ClientsNew, Spawn, SPid, ClientListeNew).
%%Neuen ClientProzess erzeugen
spawnC(ServerPid) ->
Config = configLaden(),
{ok, Lebenszeit} = werkzeug:get_config_value(lebenszeit, Config),
{ok, Cookie} = werkzeug:get_config_value(cookie, Config),
{ok, ServerNode} = werkzeug:get_config_value(servernode, Config),
{ok, Wartezeit} = werkzeug:get_config_value(wartezeit, Config),
ClientPid = erlang:spawn(?MODULE, mitServerVerbinden, [ServerPid, [], [], Wartezeit, ServerNode, Cookie]),
timer:kill_after(Lebenszeit, ClientPid),
ClientPid.
%%mit Server Verbinden
mitServerVerbinden(ServerPid,Datei,NNummern,Wartezeit,ServerNode,Cookie) ->
erlang:set_cookie(ServerNode,Cookie),
pong = net_adm:ping(ServerNode),
loopClient(ServerPid,NNummern,Wartezeit,Datei).
%%loopClient
loopClient(ServerPid,NNummern,Wartezeit,Datei) ->
%%Client wird zum Redakteur
{NNummernNew, WartezeitNew, DateiNew} = nachrichtenSenden(5,ServerPid,NNummern,Wartezeit,Datei),
%%Client wird zum Leser
nachrichtenLesen(false, NNummernNew, ServerPid,DateiNew),
%%Methode ruft sich selbst wieder auf
loopClient(ServerPid, NNummernNew, WartezeitNew,DateiNew).
configLaden() ->
{ok, Config} = file:consult("configs/client.cfg"),
Config.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Redakteur %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%Nachricht soll vergessen werden
nachrichtenSenden(0,ServerPid,NNummern,Wartezeit,Datei) ->
%%Naechste NNr beim Server anfragen
ServerPid ! {self(),getmsgid},
receive
%%Server sendet NNr
{nid,NNr} ->
%%Logeintrag
werkzeug:logging(Datei,lists:concat([NNr, "te Nachricht um ", werkzeug:timeMilliSecond(), " vergessen zu senden. ******\n"]))
end,
WartezeitNew = wartezeitBerechnen(Wartezeit),
%%Rückgabewerte: Liste mit Nachrichtennummern fuer leser, neue Wartezeit, Logfile
{NNummern,WartezeitNew,Datei};
%%Nachrichtennummer anfragen und erhalten, Nachricht schreiben
nachrichtenSenden(NachrichtenVorVergessen,ServerPid,NNummern,Wartezeit,Datei) ->
Config = configLaden(),
{ok, ServerNode} = werkzeug:get_config_value(servernode, Config),
%%Naechste NNr beim Server anfragen
ServerPid ! {self(),getmsgid},
receive
%%Server sendet NNr
{nid,NNr} ->
%%Nachricht schreiben
Nachricht = nachrichtSchreiben(NNr),
%%NNr zur Liste hinzufuegen fuer Leser
NNummernNew = NNummern ++[NNr],
timer:sleep(Wartezeit),
%%Nachricht an Server senden
ServerPid ! {dropmessage,[NNr,Nachricht,erlang:now()]},
%%Logeintrag schreiben
werkzeug:logging(Datei,lists:concat([Nachricht, " gesendet"])),
%%Neue Wartezeit berechnen
WartezeitNew = wartezeitBerechnen(Wartezeit),
%%Zaehler dekrementieren
NachrichtenVorVergessenNew = NachrichtenVorVergessen -1,
%%Methode neu aufrufen
nachrichtenSenden(ServerPid,NNummernNew,WartezeitNew,NachrichtenVorVergessenNew,Datei)
end.
%%nachrichtSchreiben
nachrichtSchreiben(NNr) ->
Config = configLaden(),
{ok, Rechner} = werkzeug:get_config_value(rechner, Config),
{ok, Praktikumsgruppe} = werkzeug:get_config_value(praktikumsgruppe, Config),
{ok, Teamnummer} = werkzeug:get_config_value(teamnummer, Config),
lists:concat(["client#",Rechner, "_", Praktikumsgruppe, "_", Teamnummer, ": ", integer_to_list(NNr), "_te Nachricht. Sendezeit: ", werkzeug:timeMilliSecond()]).
%%Hilfsmethode: Intervall darf nicht kleiner als zwei Sekunden werden
minimumTime() -> 2000.
%%Berechnet das neue Zeitintervall, um die Haelfte groesser oder
%%kleiner als die alte Zeit, solange sie groesser gleich 2 Sekunden ist
wartezeitBerechnen(Wartezeit) ->
GroesserKleiner = werkzeug:bool_rand(),
HaelfteZeit = trunc(max(Wartezeit * 0.5, minimumTime())),
if
GroesserKleiner ->
Wartezeit + HaelfteZeit;
true ->
max(Wartezeit - HaelfteZeit, minimumTime())
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Leser %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
nachrichtenLesen(true,NNummern,ServerPid,Datei) -> ok;
nachrichtenLesen(false,NNummern,ServerPid,Datei) ->
ServerPid ! {self(),getmessages},
receive
{reply,Message,Terminated} ->
nachrichtInLogSchreiben(Message,NNummern,Datei),
nachrichtenLesen(Terminated,NNummern,ServerPid,Datei)
end.
nachrichtInLogSchreiben([NNr,Msg,TSclientout,TShbqin,TSdlqin,TSdlqout],NNummern,Datei) ->
Now = erlang:timestamp(),
DLQInTrue = werkzeug:validTS(TSdlqin),
DLQOutTrue = werkzeug:validTS(TSdlqout),
DLQInZukunft = werkzeug:lessTS(Now, TSdlqin),
DLQOutZukunft = werkzeug:lessTS(Now, TSdlqout),
MsgVonGleichemClient = msgVonGleichemClient(NNr, Msg, NNummern),
if
DLQInTrue and DLQInZukunft ->
Zeitunterschied = werkzeug:now2stringD(werkzeug:diffTS(TSdlqin, Now)),
MsgNew = MsgVonGleichemClient ++ ", Zeitunterschied: " ++ Zeitunterschied,
werkzeug:logging(Datei, MsgNew ++ "\n");
DLQOutTrue and DLQOutZukunft ->
Zeitunterschied = werkzeug:now2stringD(werkzeug:diffTS(TSdlqout, Now)),
MsgNew = MsgVonGleichemClient ++ ", Zeitunterschied: " ++ Zeitunterschied,
werkzeug:logging(Datei, MsgNew ++ "\n");
true ->
werkzeug:logging(Datei, MsgVonGleichemClient ++ "\n")
end.
msgVonGleichemClient(NNr,Msg,NNummern) ->
MsgVonGleichemClient = lists:member(NNr, NNummern),
if
MsgVonGleichemClient -> Msg ++ "*******";
true -> Msg
end.
Config file for server:
{sizedlq,400}.
{servername,'serverpa'}.
{cmemtime,2000}.
{hbqname,'hbqpa'}.
{node,'hbqnode'}.
{serverzeit,50}.
Config file for client:
{wartezeit,20}.
{lebenszeit,240}.
{pratikumsgruppe,'2'}.
{teamnummer,'02'}.
{servername,'serverpa'}.
{clientanzahl,5}.
{servernode,'servernode'}.
{cookie,pa}.
{rechner,'rechner'}.
There are also distributed data strutures which are essentially queues and seem to be working fine:
HBQ:
-module(hbq).
-export([startHBQ/0, checkTransfer/6,loophbq/4]).
%% HBQ !{self(), {request,pushHBQ,[INNr,Msg,TSclientout]}}
startHBQ() ->
startHBQ("./configs/server.cfg").
%% Used for starting the HBQ with a custom config file
startHBQ(Configfile) ->
%%Config und Namen auslesen
Config = loadConfig(Configfile),
Config = loadConfig(Configfile),
%%{ok,Config} = file:consult("./config/server.cfg"),
{ok,HBQName} = werkzeug:get_config_value(hbqname,Config),
%%Prozess der HBQ starten
HBQPid = spawn(?MODULE,loophbq,[[],[],Config, 1]),
%%Prozess registrieren
register(HBQName,HBQPid),
HBQPid.
loophbq(HBQ,DLQ,Config,CurrNumber) ->
receive
%%initialisere HBQ und DLQ, sendet ok an Server
{ServerPid,{request,initHBQ}} ->
HBQList = [],
Log = log(Config,["HBQ>>> initialisiert worden von ", ServerPid, ".\n"]),
{ok,DLQSize} = werkzeug:get_config_file(sizedlq,Config),
DLQ = dlq:initDLQ(DLQSize,Log),
ServerPid ! {reply,ok},
loophbq(HBQList, DLQ ,Config, CurrNumber);
%%fuegt der Msg einen Zeitstempel hinzu, fuegt sie in HBQ ein, sendet ok
{ServerPid,{request,pushHBQ,[NNr,Msg,TSclientout]}} ->
TShbqin = werkzeug:timeMillliSecond(),
NewMessage = {NNr,lists:concat(Msg,["HBQ in: ",TShbqin])},
Log = log(Config,["HBQ>>> Nachricht ",NNr, "in HBQ eingefügt.\n"]),
NewHBQ = [HBQ|NewMessage],
lists:sort(fun({A,_},{B,_}) -> A=<B end),
checkTransfer(NewHBQ, CurrNumber, Config, DLQ,TSclientout,TShbqin),
ServerPid ! {reply,ok},
loophbq(NewHBQ, DLQ ,Config, CurrNumber);
%%DLQ soll über HBQ Nachricht an Client senden
{ServerPid,{request,deliverMSG,NNr,ToClient}} ->
{ok, HBQName} = werkzeug:get_config_value(hbqname, Config),
Log = lists:concat(["HB-DLQ#", HBQName, ".log"]),
Datei = erlang:list_to_atom(Log),
log(Config, ["HBQ>>> dlq:delivermsg", NNr, pid_to_list(ToClient), "\n"]),
NNrDLQ = dlq:deliverMSG(NNr, ToClient, DLQ, Datei),
ServerPid ! {reply, NNrDLQ},
loophbq(HBQ, DLQ ,Config, CurrNumber);
%%Terminiert Prozess der DLQ
{ServerPid,{request,delHBQ}} ->
ServerPid ! {reply,ok},
ok
end.
%%CheckTransfer
checkTransfer(HBQ, Number, Config, [DLQ,Size],TSclientout,TShbqin) ->
Datei = log(Config, ["HBQ>>> Nachricht Nr ", Number, " wird in DLQ uebertragen\n"]),
FoundMatch = lists:keyfind(Number, 1, HBQ),
if FoundMatch =:= false ->
if(length(HBQ)>Size*0.667) ->
[{MinNNr,_}|_] = HBQ,
%wegen sort ist immer die kleinste NNr vorne in der Liste
NewMessage = {MinNNr-1,lists:concat(["Weiß noch nicht was hier reinsoll: ",werkzeug:timeMilliSecond()])},
NewHBQ = lists:append([{MinNNr-1,NewMessage}], HBQ),
log(Config,["HBQ>>> Fehlernachricht fuer Nachrichten ",Number," bis",MinNNr-1, " generiert.\n"]),
NewNumber = MinNNr-1,
checkTransfer(NewHBQ, NewNumber, Config,[DLQ,Size],TSclientout,TShbqin);
true -> ok
end;
true ->
{MatchNr,Msg} = FoundMatch,
dlq:push2DLQ([MatchNr, Msg, TSclientout, TShbqin], DLQ, Datei),
lists:delete(FoundMatch, HBQ),
checkTransfer(HBQ, Number+1, Config,[DLQ,Size],TSclientout,TShbqin)
end.
log(Config,Message) ->
{ok,HBQNode} = werkzeug:get_config_value(node,Config),
DateiName = lists:concat(["HB-DLQ#", HBQNode,".log"]),
Datei = erlang:list_to_atom(DateiName),
werkzeug:logging(Datei, lists:concat(Message)),
Datei.
%%Dummy-Nachrichten schreiben um Lücken in der HBQ zu füllen wenn sie kritische Größe erreicht
%%Methode um zu prüfen, ob Nachrichten in DLQ geschoben werden können, das dann auch machen
loadConfig(Configfile) ->
{ok, Config} = file:consult(Configfile),
Config.
DLQ:
-module(dlq).
-export([initDLQ/2, delDLQ/1, expectedNr/1, push2DLQ/3, deliverMSG/4]).
%%Initialisiert DLQ mit Kapazitaet Size, Log in Datei
initDLQ(Size, Datei) ->
werkzeug:logging(Datei,lists:concat(["DLQ>>> intitialisiert worden mit Groesse ",Size,".\n"])),
[[],Size].
%%Loescht DLQ
delDLQ(_Queue) -> ok.
%%Liefert NNr die als naechstes in DLQ gespeichert werden kann
%%expectedNr(Queue)
expectedNr([[], _Size]) -> 1;
expectedNr([[[NNr, _Msg, _TSclientout, _TShbqin, _TSdlqin] | _Rest], _Size]) -> NNr + 1.
%%Speichert Nachricht in DLQ, fuegt Zeitstempel hinzu, Rueckgabe: Modifizierte DLQ
%%push2DLQ([NNr, Msg, TSclientout, TShbqin], Queue, Datei)
%%Fehlt noch: Abfrage, ob das die passende Nummer ist!
push2DLQ([NNr, Msg, TSclientout, TShbqin], [DLQ,Size], Datei) ->
if
length(DLQ) < Size ->
werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", NNr, " in DLQ eingefügt.\n"])),
[[[NNr, Msg, TSclientout, TShbqin, erlang:now()] | DLQ], Size];
length(DLQ) =:= Size ->
[LastNNr, _Msg, _TSclientout, _TShbqin, _TSdlqin] = lists:last(DLQ),
werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", LastNNr, " aus DLQ entfernt.\n"])),
werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", NNr, " in DLQ eingefügt.\n"])),
[[[NNr, Msg, TSclientout, TShbqin, erlang:now()] | lists:droplast(DLQ)], Size]
end.
%%Sendet Nachricht an Leser-Client
deliverMSG(MSGNr, ClientPID, Queue, Datei) ->
%%Aendern: MSGNer = -1, flag am Ende der Reply (siehe zeile 42)
[{NewestNr,Msg}|Rest] = Queue,
if MSGNr > NewestNr ->
DummyMessage = {-1,lists:concat(["DLQ in: ",werkzeug:timeMilliSecond()])}, %% -1 Flag
werkzeug:logging(Datei, lists:concat(["DLQ>>> DummyNachricht fuer ",MSGNr," an Client ",ClientPID, " ausgeliefert.\n"])),
ClientPID ! {reply,Msg,true}
end,
%%%%%%Ab hier noch aendern bzgl Flag
FoundMatch = lists:keyfind(MSGNr, 1, Queue),
if
FoundMatch =:= false ->
deliverMSG(MSGNr+1, ClientPID, Queue, Datei),
if
MSGNr =:= NewestNr ->
{Number,Msg} = FoundMatch,
NewMessage = {Number,lists:concat(Msg,["DLQ in: ",werkzeug:timeMilliSecond()],-1)},
werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", Number, " an Client ",ClientPID, " ausgeliefert.\n"])),
ClientPID ! {reply,Msg,false};
true ->
{Number,Msg} = FoundMatch,
NewMessage = {Number,lists:concat(Msg,["DLQ in: ",werkzeug:timeMilliSecond()],0)},
werkzeug:logging(Datei, lists:concat(["DLQ>>> Nachricht ", Number, " an Client ",ClientPID, " ausgeliefert.\n"])),
ClientPID ! {reply,Msg,false}
end;
true ->
ok
end.
CMEM:
-module(cmem).
-export([initCMEM/2, delCMEM/1, updateClient/4, getClientNNr/2]).
-import(werkzeug, [get_config_value/2,lengthSL/1,logging/2,reset_timer/3,get_config_value/2,getUTC/0]).
%%Initialisiert CMEM
initCMEM(RemTime, Datei) -> werkzeug:logging(Datei, lists:concat(["CMEM>>> initialisiert mit ", RemTime, " Sekunden\n"])),
[[], RemTime].
%%Loescht CMEM
delCMEM(_CMEM) -> ok.
%%Speichert/aktualisiert Client und NNr im CMEM,
updateClient([CMEM, RemTime], ClientID, NNr, Datei) ->
ClientTS = getUTC(),
logging(Datei, lists:concat(["CMEM>>> Client ", ClientID, " wird aktualisiert.\n"])),
[lists:keystore(ClientID, 1, CMEM, {ClientID, NNr, ClientTS}), RemTime].
%%Gibt naechste vom Client erwartete NNr zurueck
%%Es wird geprueft ob Client in der Liste steht und dann
%%mit diesem Wissen eine Hilfsfunktion aufgerufen
getClientNNr([CMEM, RemTime], ClientID) ->
ClientBekannt = lists:keymember(ClientID, 1, CMEM),
isClientKnown([CMEM, RemTime], ClientID, ClientBekannt).
%%Client ist nicht bekannt: Naechste NNr = 1
isClientKnown(_CMEM, _ClientID, false) -> 1;
%% Der Client ist bekannt.
%%Zeit noch nicht abgelaufen: Gibt naechste Nummer aus
%%Zeit abgelaufen: Naechste NNr = 1
isClientKnown([CMEM, RemTime], ClientID, true) ->
{ClientID, NNr, ClientTS} = lists:keyfind(ClientID, 1, CMEM),
RemainingTime = ClientTS + RemTime,
Now = getUTC(),
if
RemainingTime >= Now -> NNr + 1;
true -> 1
end.
The client is supposed to contact the server sending it a message, the server puts it in data structures which send it back to the client under the right circumstances.
The problem is, when I compile them, the start the HBQ, then the server and then the client, I get
=ERROR REPORT==== 18-Apr-2017::10:25:46 ===
Error in process <0.104.0> with exit value: {distribution_not_started,[{auth,set_cookie,2,[{file,"auth.erl"},{line,119}]},{client,mitServerVerbinden,6,[{file,"client.erl"},{line,42}]}]}
So apparently there is an issue with the client not connecting to the server. This is my first time working with Erlang and distributed systems, so I have no idea what is going on.
Is it not enough to put the nodes and cookie into the configs and tell the components of the system to look there?
The error distribution_not_started is returned by the auth module when the erlang VM calling it does not have a name. Ensure that a -sname or -name flag is passed when starting erlang e.g.:
erl -sname test

HLA: why is EAX register holding zero value upon exiting a recursive procedure?

I am trying to use a recursive procedure to compute A-B in high-level assembly. After computing the difference, it is stored in the EAX register for display at the end of the program.
My problem: The values in registers EAX and EBX are correct before exiting the procedure, but I do not understand why EAX is always zero when A is greater than B.
Is there something about the ret() command that is causing this? What is wrong with my code? Someone please help me.
Here is the sample code:
program MainSubtractionFunction;
#include( "stdlib.hhf" );
static
iDataValue1 : int32 := 0;
iDataValue2 : int32 := 0;
DifferenceInt : int32 :=69;
procedure recursiveSubtraction( a: int32; b : int32 ); #nodisplay; #noframe;
static
returnAddress : dword;
value: int32;
begin recursiveSubtraction;
pop( returnAddress );
pop( b );
pop( a );
push( returnAddress );
mov (a, EAX);
mov (b, EBX);
CompareB:
cmp (EBX, 0);
je ExitSequence;
CompareA:
cmp (EAX, 0);
je AEqualsZero;
NeitherEqualZero:
sub (1, EAX);
sub (1, EBX);
push(EAX);
push(EBX);
call recursiveSubtraction;
AEqualsZero:
neg (EBX);
mov (EBX, EAX);
jmp ExitSequence;
BEqualsZero:
jmp ExitSequence;
ExitSequence:
ret();
end recursiveSubtraction;
begin MainSubtractionFunction;
stdout.put( "Feed Me A: " );
stdin.get( iDataValue1 );
stdout.put( "Feed Me B: " );
stdin.get( iDataValue2 );
push( iDataValue1 );
push( iDataValue2 );
call recursiveSubtraction;
mov(EAX, DifferenceInt);
stdout.put("RecursiveSubtraction of A-B = ",DifferenceInt, nl);
stdout.put("EAX = ",EAX, nl);
stdout.put("EBX = ",EBX, nl);
stdout.put("ECX = ",ECX, nl);
end MainSubtractionFunction;
ENVIRONMENT
HLA (High Level Assembler - HLABE back end, POLINK linker)
Version 2.16 build 4413 (prototype)
Windows 10
NOTE
The recursive algorithm in this question works for the following cases: positive - positive, positive - negative, and negative - positive but will not work for the case negative - negative.
SOLUTION
The problem is after returning from the recursive call to recursiveSubtraction the code will always sequentially continue to the AEqualsZero label.
NeitherEqualZero:
sub(1, EAX);
sub(1, EBX);
push(EAX);
push(EBX);
call recursiveSubtraction;
AEqualsZero:
neg(EBX);
mov(EBX, EAX);
jmp ExitSequence;
To solve this problem add an additional jmp ExitSequence after the call to recursiveSubtraction.
NeitherEqualZero:
sub(1, EAX);
sub(1, EBX);
push(EAX);
push(EBX);
call recursiveSubtraction;
jmp ExitSequence;
AEqualsZero:
neg(EBX);
mov(EBX, EAX);
jmp ExitSequence;
EXAMPLE
program MainSubtractionFunction;
#include("stdlib.hhf");
procedure recursiveSubtraction(A: int32; B: int32); #nodisplay; #noframe;
begin recursiveSubtraction;
pop(EDX); // Return Address
pop(EBX);
pop(EAX);
push(EDX); // Return Address
CompareB:
cmp(EBX, 0);
je ExitSequence;
CompareA:
cmp(EAX, 0);
je AEqualsZero;
NeitherEqualZero:
dec(EAX);
dec(EBX);
push(EAX);
push(EBX);
call recursiveSubtraction;
jmp ExitSequence;
AEqualsZero:
neg(EBX);
mov(EBX, EAX);
jmp ExitSequence;
BEqualsZero:
jmp ExitSequence;
ExitSequence:
ret();
end recursiveSubtraction;
begin MainSubtractionFunction;
stdout.put("Feed Me A: ");
stdin.geti32();
push(EAX);
stdout.put("Feed Me B: ");
stdin.geti32();
push(EAX);
call recursiveSubtraction;
stdout.put("RecursiveSubtraction of A-B = ", (type int32 EAX), nl);
end MainSubtractionFunction;

Z3 C# FiniteDomain Sort Exception / Usage?

I'm trying to use "FiniteDomainSort" in my context, but when i give it to the solver it throws some exceptions.
Remarks:
* I use MkNumeral as suggested here
* Tested with z3-4.3.0 x64 (win) and z3-4.3.2 x64 (ubuntu)
* Runs fine when I use IntSort in the same example
Example:
using System;
using System.Collections.Generic;
using Microsoft.Z3;
namespace NS { class CL { public static void Main() {
Context ctx = new Context (new Dictionary<string, string> () { { "MODEL", "true" } });
Sort BOOL = ctx.BoolSort;
Sort INT = ctx.IntSort;
FuncDecl f1 = ctx.MkFuncDecl("f1", new Sort[] {INT}, BOOL);
Expr c1 = ctx.MkNumeral ( 1, INT);
BoolExpr app1 = (BoolExpr) ctx.MkApp (f1,c1);
Solver solver1 = ctx.MkSolver();
solver1.Assert(app1);
Console.WriteLine ("[Solver 1]");
Console.WriteLine ("Check: " + solver1.Check ());
Console.WriteLine ("Model\n" + solver1.Model);
Sort TEST = ctx.MkFiniteDomainSort ("MySort", 2); // size "2" just for demonstration
FuncDecl f2 = ctx.MkFuncDecl("g", new Sort[] {TEST}, BOOL);
Expr c2 = ctx.MkNumeral ( 1, TEST);
BoolExpr app2 = (BoolExpr) ctx.MkApp (f2,c2);
Solver solver2 = ctx.MkSolver();
solver2.Assert(app2);
Console.WriteLine ("[Solver 2]");
Console.WriteLine ("Check: " + solver2.Check ());
Console.WriteLine ("Model\n" + solver2.Model);
} } }
Output:
./Problem.exe
[Solver 1]
Check: SATISFIABLE
Model
(define-fun f1 ((x!1 Int)) Bool
(ite (= x!1 1) true
true))
[Solver 2]
Stacktrace:
at <unknown> <0xffffffff>
at (wrapper managed-to-native) Microsoft.Z3.Native/LIB.Z3_solver_check (intptr,intptr) <0xffffffff>
at Microsoft.Z3.Native.Z3_solver_check (intptr,intptr) <0x00023>
at Microsoft.Z3.Solver.Check (Microsoft.Z3.Expr[]) <0x00093>
at NS.CL.Main () <0x0049b>
at (wrapper runtime-invoke) object.runtime_invoke_void (object,intptr,intptr,intptr) <0xffffffff>
Native stacktrace:
/usr/bin/cli() [0x4b8e48]
/usr/bin/cli() [0x51211b]
/usr/bin/cli() [0x424152]
/lib/x86_64-linux-gnu/libpthread.so.0(+0xfbb0) [0x7f5aee780bb0]
/some/path/libz3.so(_ZN3smt15model_generator16top_sort_sourcesERK10ptr_vectorINS_5enodeEERK7obj_mapIS2_PNS_16model_value_procEER7svectorINS_22model_value_dependencyEjE+0x3d2) [0x7f5aeac9ffc2]
/some/path/libz3.so(_ZN3smt15model_generator9mk_valuesEv+0x17c) [0x7f5aeaca10ac]
/some/path/libz3.so(_ZN3smt15model_generator8mk_modelEv+0x21) [0x7f5aeaca2161]
/some/path/libz3.so(_ZN3smt7context14mk_proto_modelE5lbool+0x43) [0x7f5aeace17d3]
/some/path/libz3.so(_ZN3smt7context6searchEv+0x21d) [0x7f5aeace854d]
/some/path/libz3.so(_ZN3smt7context15setup_and_checkEb+0x88) [0x7f5aeace8948]
/some/path/libz3.so(_ZN10smt_tacticclERK3refI4goalER11sref_bufferIS1_Lj16EERS0_I15model_converterERS0_I15proof_converterER7obj_refIN18dependency_managerIN11ast_manager22expr_dependency_configEE10dependencyESG_E+0x12ee) [0x7f5aeac395ce]
/some/path/libz3.so(_ZN17and_then_tacticalclERK3refI4goalER11sref_bufferIS1_Lj16EERS0_I15model_converterERS0_I15proof_converterER7obj_refIN18dependency_managerIN11ast_manager22expr_dependency_configEE10dependencyESG_E+0xf82) [0x7f5aeb0d1282]
/some/path/libz3.so(_Z4execR6tacticRK3refI4goalER11sref_bufferIS2_Lj16EERS1_I15model_converterERS1_I15proof_converterER7obj_refIN18dependency_managerIN11ast_manager22expr_dependency_configEE10dependencyESH_E+0x40) [0x7f5aeb0c8240]
/some/path/libz3.so(_Z9check_satR6tacticR3refI4goalERS1_I5modelER7obj_refI3app11ast_managerERS8_IN18dependency_managerINSA_22expr_dependency_configEE10dependencyESA_ERSs+0x121) [0x7f5aeb0c86a1]
/some/path/libz3.so(_ZN13tactic2solver14check_sat_coreEjPKP4expr+0x1c6) [0x7f5aeaf92476]
/some/path/libz3.so(_ZN12solver_na2as9check_satEjPKP4expr+0x115) [0x7f5aeaf94445]
/some/path/libz3.so(_ZN15combined_solver9check_satEjPKP4expr+0x16f) [0x7f5aeaf93a9f]
/some/path/libz3.so(Z3_solver_check+0xdb) [0x7f5aea95304b]
[0x40142191]
Debug info from gdb:
Could not attach to process. If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: Operation not permitted.
No threads.
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
=================================================================
Aborted
Looks like it was a bug and will be fixed in unstable.
See http://z3.codeplex.com/workitem/115

Pin Tool unexpected instrumentation result

I've got very unexpected result from Pin Tool, my tool looks for CALL/RET instructions and then log the proper message :
VOID CallBack(VOID * ip, ADDRINT esp)
{
UINT32 *RetAddrPtr = (UINT32 *)esp;
fprintf(log_info,"RET inst #%p ==> Retuen Address #%p.\n", ip, *RetAddrPtr);
}
// Pin calls this function every time a new instruction is encountered
VOID Trace(TRACE trace, VOID *v)
{
ADDRINT insAddress = TRACE_Address(trace);
// Visit every basic block in the trace
for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
{
for(INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins))
{
ADDRINT instAddress = INS_Address(ins);
if( INS_IsCall(ins) )
{
ADDRINT nextInstAddress = (ADDRINT)( (USIZE)instAddress + INS_Size(ins) );
fprintf(log_info,"CALL inst #%p ==> CALL Return Address #%p.\n", instAddress, nextInstAddress);
}
if(INS_IsRet(ins))
{
INS_InsertCall( ins,
IPOINT_BEFORE,
(AFUNPTR)CallBack,
IARG_INST_PTR,
IARG_REG_VALUE,
REG_STACK_PTR,
IARG_END);
}
}
}
}
but the result is very unusual :-/. see this is log result from program entry point:
CALL inst #0101247C ==> CALL Return Address #01012481.
RET inst #01012800 ==> Return Address #01012481.
CALL inst #0101248A ==> CALL Return Address #0101248C.
CALL inst #7C80B73F ==> CALL Return Address #7C80B744.
RET inst #7C80B751 ==> Return Address #0101248C.
CALL inst #010124E3 ==> CALL Return Address #010124E9.
RET inst #77C3538A ==> Return Address #010124E9.
CALL inst #010124F8 ==> CALL Return Address #010124FE.
RET inst #77C1F1E0 ==> Return Address #010124FE.
CALL inst #01012506 ==> CALL Return Address #0101250C.
RET inst #77C1F1A9 ==> Return Address #0101250C.
CALL inst #01012520 ==> CALL Return Address #01012525.
RET inst #010127C4 ==> Return Address #01012525.
CALL inst #01012532 ==> CALL Return Address #01012538.
CALL inst #01012539 ==> CALL Return Address #0101253E.
CALL inst #010127BA ==> CALL Return Address #010127BF.
CALL inst #77C4EE60 ==> CALL Return Address #77C4EE65.
RET inst #77C4ED04 ==> Return Address #77C4EE28. <=========
RET inst #77C4ED97 ==> Return Address #77C4EE3F. <=========
RET inst #77C4EE49 ==> Return Address #77C4EE65.
RET inst #77C4EE68 ==> Return Address #010127BF.
RET inst #010127C1 ==> Return Address #0101253E.
as you can see, there is two RET instruction which doesn't map to any CALL.
after this I opened up program in debugger and saw this :
77C4EE15 > 8BFF MOV EDI,EDI ; kernel32.GetModuleHandleA
77C4EE17 55 PUSH EBP
77C4EE18 8BEC MOV EBP,ESP
77C4EE1A 51 PUSH ECX
77C4EE1B 53 PUSH EBX
77C4EE1C 9B WAIT
77C4EE1D D97D FC FSTCW WORD PTR SS:[EBP-4]
77C4EE20 FF75 FC PUSH DWORD PTR SS:[EBP-4]
77C4EE23 E8 41FEFFFF CALL msvcrt.77C4EC69 <============
77C4EE28 8BD8 MOV EBX,EAX
77C4EE2A 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C]
77C4EE2D F7D0 NOT EAX
77C4EE2F 23D8 AND EBX,EAX
77C4EE31 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
77C4EE34 2345 0C AND EAX,DWORD PTR SS:[EBP+C]
77C4EE37 59 POP ECX ; msvcrt.77C4EE65
77C4EE38 0BD8 OR EBX,EAX
77C4EE3A E8 CBFEFFFF CALL msvcrt.77C4ED0A <==============
77C4EE3F 8945 0C MOV DWORD PTR SS:[EBP+C],EAX
77C4EE42 D96D 0C FLDCW WORD PTR SS:[EBP+C]
77C4EE45 8BC3 MOV EAX,EBX
77C4EE47 5B POP EBX ; msvcrt.77C4EE65
77C4EE48 C9 LEAVE
Pin Tool cannot see this calls ? I think maybe I used a wrong sequence of API call.
and also there is another unexpected result: there is two different CALL instructions within a function with a conditional jmp between CALLs, which means just of those CALL instructions should execute but Pin log both of them!
Pin doesn't instrument ALL the process execution, it starts it a little bit after the real process start and ends a little bit before the real exit.
The call was probably executed when process execution wasn't redirected to Pin yet this is why you see the retn and not the call.
a little piece of code to explain it :
call start_instrumentation
label ret_call_start_ins:
[...]
function start_instrumentation:
_do_stuff_
* now the process is under Pin control *
_do_stuff_under_pin_control_
retn ; the return you see without any associated call

Resources